Cockpit · multi-agent
Tutorial · Cockpit

An agent team in Cockpit

Cockpit's real power is the multiplexer: many agents in one window, each in its own folder. Here you wire up three, an orchestrator, a backend and a frontend, and let the orchestrator drive the other two with the internal cockpit CLI.

What you'll build

Three agent tabs, side by side in a single Cockpit workspace. Each one is an ordinary terminal running your harness of choice (this tutorial uses claude; codex or piwork the same way), started in its own subfolder so it picks up that folder's brief and boots into a role.

They coordinate through Cockpit itself. The orchestrator opens the worker tabs, types instructions into them and reads their output back, using the cockpit CLI that exists inside every Cockpit terminal. No network, no account, no extra service: it is the app you already have open, driven by the same verbs a human uses.

Worth reading first
The CLI reference lives in the Cockpit docs, and Layouts and tasks shows how a .ckp file recreates a window like this one on any machine.

Before you start

  • Cockpit installed, from the download page. Nothing else is required: Cockpit needs no account and no cloud.
  • A harness on your PATH, the one you already use. Cockpit runs it as a normal process, so whatever works in your terminal works in a tab.

1. Lay out the folders

An agent's identity comes from where it starts, so give each teammate a folder with its own brief:

project layout — text
my-app/
├── orchestrator/
│   └── AGENTS.md
├── backend/
│   └── AGENTS.md
└── frontend/
    └── AGENTS.md

AGENTS.md is the standing brief an agent reads when it starts in a folder (Claude Code also reads CLAUDE.md). Give each one a clear job, and tell the orchestrator how to reach the others.

orchestrator/AGENTS.md — markdown
# Orchestrator

You coordinate two workers that run in other Cockpit tabs: `Backend` and
`Frontend`. You do not write app code yourself. You split the work, dispatch
it, and integrate the results.

## How you work
- Dispatch with the internal CLI, one instruction per worker:
  `cockpit send --tab-id <tab> --enter "<instruction>"`
- Read a worker back with `cockpit read-tab <label> --lines 80` instead of
  asking the human what it printed.
- A worker is busy while `working` is true in `cockpit list-tabs --json`.
  Wait for it to flip to false before reading the final answer.
- Reconcile mismatches (the API shape against what the UI needs) and report
  back to the human.

Keep each instruction small and explicit: say what you want and what "done"
looks like.
backend/AGENTS.md — markdown
# Backend

You own the server and API in this folder. You work only here.

## How you work
- The orchestrator types instructions straight into your terminal. Treat them
  as prompts from the human.
- Keep the API contract (routes, payloads) explicit, and print it when you are
  done, because the orchestrator reads your output to pass it on.
- If an instruction is ambiguous, say what is missing instead of guessing.
frontend/AGENTS.md — markdown
# Frontend

You own the UI in this folder. You work only here.

## How you work
- Build against the contract the backend printed. If you need a route or a
  field that does not exist, say so and stop: the orchestrator coordinates it.
- When you are done, print what changed, in one short list.
One folder, one teammate
Keeping each agent in its own subfolder is what keeps the briefs, the histories and the edits apart. Three folders, three tabs, three roles.

2. Open the three tabs

Open my-app/ as a workspace. Then open a terminal in each subfolder and start your harness there. The fastest way is from the Files panel: right-click a folder and open a terminal in it, then run claude.

Split the canvas so all three are visible at once, the orchestrator on one side and the workers on the other, and rename each tab by double-clicking it: Orchestrator, Backend, Frontend. Those labels are how the CLI addresses a tab, and unlike ids they survive a restart of the app.

Do it once by hand, or commit the whole geometry as a team.ckp and let Cockpit build the window for you:

team.ckp — yaml
panes:
  - name: Orchestrator
    cwd: orchestrator
    command: claude
  - name: Backend
    cwd: backend
    split: right
    command: claude
  - name: Frontend
    cwd: frontend
    split: down
    command: claude
any Cockpit terminal
$
cockpit orchestrate team.ckp
Labels, not ids
Tab ids (t0, t1…) are handed out per app boot, so never hardcode one in a brief or a script. Address a tab by its label, or discover the id of the moment with cockpit list-tabs.

3. Teach the orchestrator the CLI

Every terminal Cockpit opens has cockpit on its PATH, and only those terminals do. So the orchestrator can already drive its teammates; it just needs to know the verbs. Ask it to look around:

Orchestrator · prompt — text
Run `cockpit list-tabs --json` and tell me which tabs you can reach.
Orchestrator · tool call — text
$ cockpit list-tabs --json
[
  { "id": "t0", "label": "Orchestrator", "workspacePath": "/Users/me/my-app", "working": true  },
  { "id": "t1", "label": "Backend",      "workspacePath": "/Users/me/my-app", "working": false },
  { "id": "t2", "label": "Frontend",     "workspacePath": "/Users/me/my-app", "working": false }
]

Four verbs are enough to run a team. If you use Claude Code, cockpit install-skill installs a skill that teaches all of them, so the brief can stay short.

the four verbs
$
# dispatch an instruction and press Enter for it
cockpit send --tab-id Backend --enter "Expose GET /todos and POST /todos"

# see who is still thinking (working: true) and who is done
cockpit list-tabs --json

# read a worker's answer without touching its window
cockpit read-tab Backend --lines 80

# open a worker beside you, mid-flight, if the work needs one more pair of hands
cockpit new-tab --cwd ./docs --title Docs --split v
Enter is a keystroke
A bare cockpit send types the text and leaves it in the composer. Use --enter (or a separate cockpit send-key Enter) to submit it, because a newline inside the text is a line break for the harness, not a send.

4. Run the orchestration

Now give the orchestrator something real. You talk only to it; it talks to the others.

Orchestrator · prompt — text
Add a "todos" feature: an API to list and create todos, and a page
that shows them with a form to add one. Coordinate Backend and Frontend.

It breaks the work in two and types one instruction into each worker. The send returns as soon as the text is delivered, so it is a dispatch, not a blocking call:

Orchestrator · tool calls — text
$ cockpit send --tab-id Backend --enter \
    "Expose GET /todos and POST /todos (title:string). Print the JSON shape when done."
sent

$ cockpit send --tab-id Frontend --enter \
    "Build a Todos page: list todos and a form to add one. Wait for the API shape first."
sent

Each worker sees the instruction in its own tab, does the work in its own folder, and prints the result. The orchestrator polls for the turn to end, then reads the answer:

Orchestrator · tool calls — text
$ cockpit list-tabs --json | grep -A1 Backend
  { "id": "t1", "label": "Backend", "working": false }

$ cockpit read-tab Backend --lines 40
  Added GET /todos and POST /todos.
  Todo: { id: string, title: string, done: bool }

With the contract in hand it unblocks the frontend, forwarding the exact shape, and reports the finished feature back to you. Three agents, three folders, one coordinated change, and you watched all of it happen.

Who is working right now
You do not have to poll to know: each tab shows its own turn status (working, waiting on you, done), with a chime when the window is focused and a system notification when it is not. The same signal the orchestrator reads from working in list-tabs --json.

Why do this in Cockpit

You could run three terminals, but then nothing connects them. Here the whole team lives in one window: every agent streams its own work in its own tab, the orchestrator dispatches and reads without you copying text around, and the layout comes back when you reopen the app. Add a terminal tab for the dev server, and the build, the agents and their traffic are all in front of you at once.

From here: commit the .ckp and a .cockpit/tasks.json so a teammate gets the same window on clone (Layouts and tasks), or move the team onto a bigger machine and keep driving it over SSH (Remote hosts).