Quick start¶
This sets up one host with one agent, reachable in the browser. No chat platform is
involved. Everything below assumes agentctl is already installed; see
Install.
agentctl init # scaffold/adopt the GitOps repo at /opt/agentctl
# (agents.yaml + agents.d/ + overlays + secrets.d/)
agentctl provision # host base: group, slices, dirs, backup, host crons
agentctl secret set OPENAI_API_KEY # encrypted store; value from stdin. repeat per key
The cockpit gateway and its login proxy¶
Once per host:
agentctl secret set WEBVIEW_HMAC_KEY # plus your auth driver's config — see Channels
agentctl webview-gateway install # WS router agents dial into :8735
agentctl webview-login install # browser-facing login proxy :8736
webview-gateway install also installs agentctl-hostop-coordinator.service, the durable
host-operation store (see Architecture).
Both listeners bind to localhost. Put your own HTTPS proxy in front of them; TLS and DNS are not handled by agentctl.
An agent whose channel IS the browser¶
agentctl agents add assistant --channel webview --user-email person@example.com
agentctl status # host readiness + fleet overview
The gateway routes to this agent by that login identity, so there is no bot token. Open the
cockpit at your proxied top --web address and send a message. An auth card renders;
authorize it and the agent is live. The cockpit can then be installed as a PWA.
An agent can also be reached on a chat platform at the same time. Adding a channel does not replace the cockpit. See Channels.
What you just created¶
/opt/agentctl is the source of truth. It holds agents.yaml, the per-agent agents.d/
shards, the mcp/ skills/ agents/ apps/ hooks/ overlays, and the sops-encrypted
per-owner secrets.d/ store. It is an ordinary git repo: push it, clone it on another host,
and run agentctl apply there. The age identity that decrypts the secret store stays on the
host and is never committed.
See Architecture for the layering and precedence rules, and Multi-host fleet for how a second host becomes a secrets recipient.
The first agent on a host is an admin agent by default, which means the fleet can be driven through it instead of from a shell. Admin is a role and any number of agents may hold it. See the admin role.
First run in the cockpit¶
What the person named by --user-email sees, in order, the first time they open the
proxied address.
The login page¶
The browser reaches webview-login before it reaches anything else, and what it renders is
decided by WEBVIEW_AUTH_DRIVER:
basic— a username/password form served by agentctl itself, with the accounts read fromWEBVIEW_BASIC_USERS(email:password,…). An entry with an empty password is refused at startup rather than accepted, so a trailing colon cannot open the host.oidc— alsoentra,google, and the unset default. No local form: the browser is redirected toWEBVIEW_OIDC_ISSUER's own sign-in page and returns to/auth/callback. It needsWEBVIEW_OIDC_ISSUERandWEBVIEW_OIDC_CLIENT_IDor the service will not start.
On success the proxy sets a wv_session cookie — an HMAC token over WEBVIEW_HMAC_KEY,
30 days by default, WEBVIEW_SESSION_TTL to change it — and reverse-proxies to the cockpit
with the authenticated address in X-User-Email. That address is the routing key. It is
matched against the ledger, and the whole session is scoped to the single agent it maps to.
An address that maps to no agent authenticates successfully and then sees nothing at all,
which is what a mistyped --user-email looks like from the browser.
A scoped person lands directly in their agent's cockpit; the fleet grid and the
close/back controls are removed from the page. An admin identity keeps the fleet mini-app
and can open another agent in a second tab with /?agent=<name>&host=<host>. Sign out
sits at the bottom of the left sidebar, and appears only when a login proxy is in front.
The first message is a Claude login¶
agents add provisions the agent but does not log it in — see
Using the CLI. For a claude agent
that is what the auth card is: the moment a browser opens the cockpit against an agent whose
Claude credentials are dead or absent, the web-view tier posts a three-step message into the
chat without waiting for the person to type anything.
- A
claude.comauthorize link. Open it in a browser already signed in to the account the agent should run as. - Click Authorize. The page shows a
code#statestring. - Paste that whole string — both halves and the
#— back into the cockpit as the next message.
The paste is intercepted before it becomes a turn, exchanged for credentials that are
written under the agent's own home, and the unit is restarted so it boots logged in. The
agent answers with a ✅ when it is back. /login at any point issues a fresh link; the
first one expires.
A message sent while the agent's session is not yet up is answered with
⏳ Still connecting — try again in a moment. That is the harness not being attached yet,
not a failure.
This flow is claude-only. A pi agent boots on a provider API key from the secret store
instead, and /login at one does nothing.
What is on screen¶
| where | what |
|---|---|
| header | the session control (lane name, status dot, and a count carrying the worst status of the other lanes), the mini-app launcher strip, the all-apps drawer, tile-sessions, the agent panel toggle, the notifications bell |
| left sidebar | sessions, open by default, stacked over the workspace tree rooted at ~/workspace with refresh / new folder / new file / upload |
| centre | the transcript, with the composer pinned below it — it stays put while a file tab or a mini-app owns the pane above |
| composer row | attach, camera (touch devices only), microphone for a voice note, the text box, send |
| right panel | closed by default: skills, sessions, memories, subagents, scheduled jobs |
Below 720px the header is hidden entirely and its sheet toggles move into a thumb band above the composer — the same nodes, relocated, not a second copy.
Typing / at the start of an empty composer lists the agent's activated skills, filtered as
you type; picking one inserts /<name>. That is the discovery surface for what this agent
can already do. A new agent carries the default skill set, which includes onboarding — the
agent runs its own walk-through from it, and Onboarding describes
what that covers.
The launcher strip shows the agent's active mini-apps. Activation is derived from which
MCPs that agent has wired, so it is short on a fresh agent and grows with mcp add; the
browser MCP is a default for every claude agent, so the live browser view is there from the
start. Apps that declare no MCP at all are active for everyone. See
The cockpit.
Where the files are¶
The workspace tree is the only way to browse ~/workspace, and it edits in place. An upload
from the tree lands at the path selected in it; a file attached in the composer is staged for
that one message instead. Both go through the same resumable uploader, so a large file over a
phone connection survives a dropped tab.
Once the first message works, install the cockpit as a PWA — the 30-day session is sized for exactly that. Deeper detail on the surfaces lives in The cockpit, and on the two host services in The webview gateway.