Architecture
What runs where, who can talk to what, where the data lives and what is trusted. A quick look at the whole Ship before you install it.
At a glance
A Ship is a few Docker containers on your machine. One of them, the Helm, holds everything that matters. The crew members run in containers of their own that can reach nothing but the Helm.
What runs where
The Helm
One container, helm: a single Go program. It runs the crew's sessions, routes Slack, enforces the rules, keeps the ship's log and carries out the stop. The Bridge is built into it. It is the only part that holds state, and the only container with a way out of the machine.
The crew containers
One crew image for every crew member. A turn runs claude -p in a fresh container, which is removed when the turn ends, so nothing a turn starts can outlive it. A container kept ready for the next turn is the crew member on watch.
The Docker socket proxy
The Helm never sees the Docker socket. A small proxy passes on only the engine calls it needs: containers, exec, networks. It cannot pull images, so Docker Compose fetches the crew image for the Helm.
The stuurman command
On your machine, outside Docker: install, start, stop, status, logs, doctor and upgrade. It keeps the list of the Ships on this machine. It is not the Helm, and it has no all stop (see Install and commands).
A crew container runs as a user that is not root, with a read-only root filesystem, every capability dropped and limits on memory, CPU and processes (1 GiB, 1 CPU and 256 processes unless you set others on the Crew page). Its /tmp and home folder are in memory and go with the container.
Who can talk to what
Three Docker networks, and a token for each turn.
- front
- The Helm's way out: to Slack, Anthropic, GitHub, and to the web on the crew's behalf. The Bridge's port is published here, on
127.0.0.1of your machine only. - control
- Internal, with no route out. The Helm and the socket proxy, and nothing else.
- crew
- Internal, with no route out. The crew containers reach the Helm's three listeners here, which are not published. The Bridge refuses every request that comes from this network.
- the turn's token
- Made when a turn starts and given to that turn alone. All three listeners learn from it which crew member asks, and from nothing else. It is useless once the turn ends.
So a crew member has exactly three ways to the world, each through the Helm:
- Claude itself goes to the Anthropic gateway, which removes what the container sent, adds the real Claude token and passes the request to Anthropic. The container holds a placeholder; the real token never enters it.
- Every other connection goes to the egress gateway, which is the turn's web proxy. Public hosts are allowed and logged. Private, loopback and reserved addresses, cloud metadata and the Ship's own networks are always blocked, and 16 paste and file-drop sites wait for review. A program that ignores the proxy cannot connect at all.
- Acting on the world, such as posting in Slack, committing the cabin, proposing a sign-on or asking for a secret, is a call to the crew tools, an MCP server the Helm serves. Each call is checked, written to the ship's log and refused while the Ship is halted. The same listener is the way to an MCP server outside the Ship.
A message from Slack takes this path from end to end on The crew and Slack.
Where the data lives
Everything is in the Ship's folder, ~/stuurman/<id> for a Ship that stuurman install made. Apart from Docker's images, the stuurman command and its list of Ships, nothing of the Ship is kept anywhere else on the machine.
~/stuurman/<id>/
├── .env the secret key, your user, the port, the Ship's ID
├── compose.yaml the release's containers and networks
└── data/
├── helm/ the Helm's alone
│ ├── stuurman.db SQLite: turns, ship's log, approvals, settings, encrypted secrets
│ ├── HALT present while the Ship is halted
│ ├── sessions/ each crew member's Claude session folder
│ ├── claude-managed/ extension-sets/ extensions/
│ ├── software/ what each crew member installs for itself
│ ├── safe-ca/ the public certificate of the Ship's authority
│ └── log-archive/ ship's log entries the upkeep archived
└── ship/ the Ship's repository, in Git
├── ARTICLES.md CREW.md
├── identity/<name>/ SOUL.md, crew.yaml (read-only to the crew member)
├── cabins/<name>/ the crew member's own folder
├── marketplace/ the Ship's own extensions
└── _signed-off/ crew that signed off; nothing is deleted
- The database is one SQLite file. The secrets in it, the Claude token, the Slack tokens, the deploy key and the safe's values, are encrypted with the key in
.env. Without that key they cannot be read. - The Ship's repository is
data/ship. The Helm makes every commit, a crew member's through itscommittool, and scans each one for secrets first. No crew container mounts the repository; it sees only its own cabin. - On GitHub, if you name a private repository on the Settings page, the Helm pushes
mainthere every night over SSH, straight from the Helm and not through the egress gateway. GitHub's host keys are built into the Helm, and the push is never forced. - Backing up is copying
.envanddata/with the Helm stopped (see Backing up).
What is trusted
The Helm
Trusted. It is plain software, not an agent, and it holds every secret. What it enforces is in its code; nothing a crew member writes changes it.
The Captain
You, by your passkey on the Bridge, or by your Slack member ID in the Ship's own workspace. Whoever can run commands on the machine can also stop the Ship.
The crew
Not trusted with secrets, and its words carry no authority. Text from Slack, a web page or an extension is data, never an order. A crew member uses a secret through a stand-in, never holding it (see The safe).
The First Mate
A crew member with duties, bound by the same rules. It decides only what the Helm's rule gives it: a host in doubt, a skill of text only, another crew member's request for a secret. Its own requests, and the rest, come to you.
Said plainly, what the design does not stop:
- A crew member misled by a hostile page can send what is in its cabin to an ordinary website, and Claude's own web search and web fetch go through Anthropic, unfiltered. Keep no secret in a cabin.
- Crew containers can reach each other directly on the crew network. Nothing listens there unless a turn starts it, and a crew container holds no secret of the Ship.
- The socket proxy is a coarse filter. What a container may mount is limited by the Helm's own code, so a Helm process that was taken over could still start a container with any mount.
- A service your machine offers on its public address is a public address to the egress gateway. The Bridge is not: it is on
127.0.0.1only.
How a decision travels
An approval is one row in the Helm's database, shown in two places.
- The First Mate proposes, or a crew member asks, with a crew tool. The Helm knows who from the turn's token.
- The Helm decides who answers, by a rule in its code: some requests are the First Mate's to decide, everything else is yours.
- Yours appear as a card in
#bridgeand on the Bridge's Approvals page. The first answer, in either place, decides; the other place then shows it. - The Helm carries out what was approved, writes it to the ship's log and tells the one who asked. No approval is answered while the Ship is halted.
How the stop works
All stop first writes the file data/helm/HALT and reads it back. Then the egress gateway cuts every open connection, every crew container of the Ship is removed, the queue of waiting messages is dropped and the scheduler stops. It needs neither Claude, nor Slack, nor the database, and a Helm that starts while the file is there starts halted (see Stopping, backing up, upgrading).