The carbon6 assistant — Design
An agent inside carbon6 that can do anything you can do in its UI, answer questions about carbon6 and its setup, and ask you for whatever it needs.
"What can I do in carbon6?" "Which models are set up for vision?" "Create an enrollment token for a new worker."
1. Decisions
| Question | Decision |
|---|---|
| One agent or several? | One agent type with many short conversations. It is not one endless conversation, and it is not specialised agents. |
| Where does it run? | In the head. Its tools are head operations, and it must work before any worker is attached. |
| Confirmations | Ask before destructive operations. Everything else runs without asking unless your own policies say otherwise. |
| Secrets | They never pass through the model. Results that contain one are shown to you as a card. |
2. Shape
- Entry points:
- "Ask carbon6", from ⌘K, the header and the phone layout;
- an assistant session in the sessions list, like any other.
- Each question starts a short session of the kind
assistant. It carries the page you're on as context, such as "viewing workerbuild-1" or "Settings → Memex".- Sessions are cheap and searchable, and run concurrently.
- What should last across conversations goes to memory notes and the memex, not into an ever-growing transcript.
- Long-running work is delegated: "every morning…" or "watch CI…" becomes an automation, workflow or ordinary session that the assistant creates through the same operations. The assistant does not stay running.
- Model: a setting,
assistant_model(a connection and model; default: the default session model). Model routing by label applies as usual. Any API connection works, including a ChatGPT plan. Claude Code connections do not, because the head runs the loop itself.
3. The operation catalog
UI parity comes from a catalog, not from hand-written tools.
- Every API route has an entry:
op: a stable dotted name, e.g.workers.enrollments.create,settings.memex.get;area: sessions, fleet, connections, memex, mail, automations, settings, …;summaryanddescription, with the description taken from the route's doc comment;methodandpath;inputandoutput: JSON Schemas generated from thec6-apitypes;effect:read,write,destructive(delete, revoke, overwrite, send) orsecret(the output holds a secret);choices: for inputs whose valid values come from live data, the op that lists them, e.g.connection ← connections.list.
- A parity test fails when a route has no catalog entry, or an entry has no route. That keeps "everything in the UI is doable through the assistant" true as carbon6 grows.
- The docs (README, docs/*.md) are indexed by section, so "how do I…" answers can quote them.
- The same catalog later drives a generic
c6 <op>in the CLI.
4. Tools
The assistant has five tools, so its context stays small however many operations there are.
| Tool | Does |
|---|---|
c6_discover(query, area?) | Searches the catalog and the docs. Returns ops (name, summary, effect) and doc passages. With no query, it lists the areas: "what can I do". |
c6_describe(op) | Returns an op's full input and output schema and where its choices come from. |
c6_call(op, input) | Runs an op through the head's own handlers, as you. A result with a secret is replaced by {"shown_to_user": true, …non-secret fields}, and the secret goes to the UI as a card. |
c6_ask(title, fields) | Asks you for inputs. See §5. |
memex_search / memex_get | Already exist; for questions about your knowledge, within its scope (§6). |
The system prompt tells it to discover before acting, and never to guess values. When a required input is missing or ambiguous, it asks.
5. Asking for inputs
c6_ask takes fields in JSON Schema terms (type, enum, default, description) plus choices_from (an op). The UI renders a form in the transcript:
- dropdowns filled from live data, such as your actual connections and workers;
- defaults filled in;
- validation against the schema;
- it works on a phone.
The tool waits for the submitted values, the same way an approval waits. Cancelling ends the tool call with "cancelled by the user".
6. Safety
- Destructive operations ask first.
c6_callon adestructiveop raises the existingApprovalevent: the op, the input, and a one-line consequence ("revokes worker build-1; its sessions stop"). The call waits on the existing approval endpoint, with the same inbox, notifications and signed approval links. This check lives in the head (the head runs this loop), so it doesn't depend on the worker's policy engine. Your own policies (toolc6_call, input regex on the op) still apply on top:askordenyfor anything else. - Secrets: see
c6_call. API tokens, enrollment tokens and login links reach you only. The transcript keeps a redacted copy. - Scope: by default the assistant's memex scope is the default one, so no mail or photos. A scope rule can widen it; its labels are
assistant. Mail can't instruct it unless you let mail in. Even then, destructive operations still ask first. - Identity: it acts as you, with your permissions, and every call is logged as a tool call in its session.
7. Build order
- Catalog and reading:
- catalog plus parity test;
- the head-hosted
assistantsession kind, usingc6-agent's loop in the head; c6_discover,c6_describe, andc6_callforreadops;- "Ask carbon6" in the UI;
- evals: "what can I do", "which models are set up for vision", "is any worker offline", …
- Acting:
write,destructiveandsecretops;- the approval check for destructive ops;
- secret cards;
c6_askforms.- Evals: "create an enrollment token for a new worker" (asks for a name, shows a card), "add an Ollama connection", "revoke worker X" (asks first).
- Context:
- page context;
- suggested next steps ("this worker is offline: re-enroll?");
c6 <op>generated from the catalog.
8. As built
- Code:
c6-head/src/catalog.rsholds the operations: every HTTP route the UI uses, plus the memex methods it calls.c6-head/src/assistant.rsholds the head's worker connection, the conversation actors and the tools.
- The head's own worker: a
workersrow with the rolehead.- It is attached to the registry in-process and hidden from the worker list.
- It cannot be revoked, deleted or used for ordinary sessions.
- Its conversations' commands go through the normal command queue, and their events go through
sessions::ingest. - A conversation's actor rebuilds its state from the log after a restart.
- Requests for files, git or terminals on it get an error right away.
c6_callruns operations as you:- HTTP operations go through the head's own router, with an in-process
InternalCallmarker that the sign-in check accepts. Outside requests cannot set it. - Memex operations go through
memex::callwithmade_by: assistant.
- HTTP operations go through the head's own router, with an in-process
- Asking first:
- before destructive operations;
- before a list replacement that drops entries (compared by name or id with the current list);
- when one of your policies matches
c6_calland its input (ask). Adenyrefuses the call. - Approvals are ordinary
Approvalevents, decided through the existing endpoint.
- Questions:
- The question is a
Questionevent (asked, answered, cancelled); your answer is anAnswercommand (POST /api/v1/sessions/{id}/answers/{call_id}). - Secret fields come back to the model as placeholders.
c6_callreplaces them with the value. - The log records
[secret].
- The question is a
- Secret outputs:
- The secret is an ephemeral
SecretCardon the session's live stream. It is shown while the conversation is open and is never stored. - The tool result says
[shown to the user].
- The secret is an ephemeral
- API:
POST /api/v1/assistant(prompt and page context);GET/PUT /api/v1/settings/assistant;GET /api/v1/catalogandPOST /api/v1/catalog/call(for the CLI: destructive operations needconfirmed).
- CLI:
c6 ops [words]andc6 op <name> key=value…. - UI:
- ✦ Ask in the header (⌘J), with the focused column as context;
- question forms;
- secret cards;
- Settings → Assistant.
- Not built: the assistant does not wait for the sessions it starts (it reports that it started them).
Realms (OS step 8)
- A conversation works in one realm: the realm picked in the header when it starts. With "All realms" it is root, which administers carbon6 and reaches every realm.
- Its operations are admitted like that realm's API token. It reaches the realm's sessions, collections, decisions, triggers, views, series and knowledge. Administration (workers, connections, realms, grants, settings) answers 403, and the assistant is told to send you to "All realms" for it.
- Its instructions are the
assistant.baseprompt as the realm has it (a realm can override it), with{{realm}}naming the realm. - Commons is not a place to work in.
9. Open questions
- Should the assistant be able to start ordinary sessions on workers and follow them (for example "run the tests in proj X and tell me")? It can through the ops; the question is whether it should wait for results in the same conversation.
- Voice input on the phone.