What you'll build
A small monorepo with an API and a web app. By the end, opening the project gives you three terminals in the right folders, a task list with both servers ready to play, and a new worktree that recreates the whole thing by itself.
my-app/
├── .cockpit/
│ └── tasks.json # what runs
├── dev.ckp # what opens
├── api/
│ └── package.json
└── web/
└── package.jsonEverything here is Cockpit-local: no account, no mesh, no agents required. If you want agents on top of this, follow An agent team in Cockpit next.
Before you start
- Cockpit installed — macOS, Windows, or Linux, from the download page.
- A project folder open as a workspace. Anything with a couple of subfolders works; the commands below assume
npm, but the runner is generic.
1. Write your first layout
Create dev.ckp at the root of the project. A layout is YAML, and the smallest useful one is three lines:
panes:
- name: Agent
cwd: .
command: claudeRight-click the file in Cockpit's tree and choose Open layout. A tab named Agent opens at the project root and types claude for you. Apply it again: nothing happens. A pane whose name already exists is skipped, so a layout is safe to re-run and never closes anything.
name becomes the tab's stable label — the one the cockpit CLI can address by name instead of by a boot-scoped id, and the same label you would otherwise set by double-clicking the tab.
2. Add splits and folders
Now the real geometry. cwd is relative to the .ckp file (forward slashes only, so the file works on every OS), and split says where each pane is born relative to the one created before it: tab (default), right, or down.
# dev.ckp — one layout, committed with the project
autorun: worktree
panes:
- name: Agent
cwd: .
command: claude
- name: API
cwd: api
split: right
- name: Web
cwd: web
split: downYou can also apply it from inside any Cockpit terminal, which is how an agent sets up its own workspace:
cockpit orchestrate dev.ckp
That one line is the payoff. Every time you fork the workspace onto a fresh git worktree, Cockpit applies the layout by itself — and since a new worktree starts empty, the splits come out exactly as written. Keep a single autorun file at the root: with two or more, none of them runs, because ambiguity is never guessed.
3. Declare your tasks
Cockpit already detects tasks from package.json and pubspec.yaml with no configuration — open the Tasks panel and your scripts are there. You write .cockpit/tasks.json when you want more than that: a monorepo, interactive keys, environment profiles.
{
// .cockpit/tasks.json — JSONC: comments and trailing commas are fine
"tasks": [
{
"label": "api",
"cwd": "api",
"command": "npm",
"args": ["run", "dev"],
"kind": "watch",
"interactiveKeys": [
{ "key": "q", "label": "Quit", "icon": "stop" }
]
},
{
"label": "web",
"cwd": "web",
"command": "npm",
"args": ["run", "dev"],
"kind": "watch",
"profiles": [
{ "name": "dev" },
{ "name": "staging", "env": { "API_URL": "https://staging.example.com" } }
]
}
]
}The file goes at the root of the workspace you open — discovery is literal, with no walking up the tree. Each task's cwd is relative to that file, which is what lets one file at the monorepo root drive every subpackage. Hit play and the output streams into its own tab, with stop and restart controls and any interactiveKeysyou declared as buttons that write straight to the process' stdin.
profiles are launch configs: a chip cycles them before you press play, appending args and merging env. The runner stays generic on purpose — a Flutter flavor or a --dart-define is just more args.
For a process that does not watch files itself (flutter run is the classic case), add a watch block: paths to observe, ignore to keep build folders from looping, and onChange pointing at an interactiveKeys label ("Hot reload") or "__restart__". Skip it for Vite or Next, which already reload on their own.
4. Let an agent use them
Both files are reachable from the internal cockpitCLI, which exists only inside Cockpit's terminals. That means an agent in one tab can start your dev server, read what it printed, and open a file for you to look at — without a screenshot or a screen scrape.
# what can I run here? cockpit list-tasks # tail the dev server's output cockpit read-task json:api --lines 80 # open a worker tab beside me and drive it id=$(cockpit new-tab --cwd web --title Web --split h) cockpit send --tab-id "$id" --enter "npm run build"
Task ids are stable per workspace: json:<label> for the ones you declared, npm:<script> and flutter:run for detected ones. The full command surface is in the Cockpit reference.
5. Commit them
Both files belong in git. dev.ckp is your working geometry, and .cockpit/tasks.json is how the project is run — the same reason a Makefile is committed. A teammate clones, opens the folder in Cockpit, and gets your terminals and your task list. Point $schema at tasks.schema.json from the repository and their editor will autocomplete the fields as well; Cockpit ignores the field when running.
From here: put a team of agents into those panes, or read the Cockpit reference for every field, flag, and the theme format.