Using Flockdeck
Agents and models
Every agent pane runs a coding agent of your choosing at a model of your choosing. Claude Code is the default and behaves exactly as it always has; the picker is how you reach anything else.
Picking one
The plain Ctrl+Shift+T and Ctrl+Shift+D stay one keystroke and
take the default agent, because that is what you want almost every time. To
choose deliberately, use New agent tab (choose agent)… or
Split right (choose agent)… from the command palette, or click the ▾ beside
the + that opens a new tab.
The picker lists agents in two groups, installed and not installed. An agent you have not got is shown greyed with where to get it rather than hidden: somebody who has never installed Codex should still learn that Flockdeck would run it. Expand an agent for its models, with its default marked. Each model carries its tier — small, mid or top, how capable and so how costly it is among that agent's own — and a model of an API agent its published price per million tokens, in and out, with the day it was read. A command-line agent's models show no price: the same model may be billed per token or covered by a subscription, and only you know which. Every price comes from one table compiled into Flockdeck, each rate with the day it was read from the provider's own pricing page. It changes with releases; nothing is fetched. The chat's status line and the estimates in the pane header are priced from the same table. At the foot of the picker, Set as default for makes the choice stick, either for this project or for every project, so the one-keystroke split keeps doing the right thing. Use the default for every project removes this project's own choice.
The pane header names what is running, beside the branch and in the same dim
weight — claude · sonnet, codex · gpt-5.6-sol. A shell pane shows nothing there,
because there is nothing to choose. For the API agents, and for Claude Code
where its status line is read, what the conversation has spent and how near its
usage limit it is follow;
Spend and limits explains the figures.
Two kinds of agent
CLI agents are the tools you would run in a terminal yourself: Claude Code,
Codex, Gemini, Aider, opencode, Cursor's agent. Flockdeck runs the command in the
pane's pseudo-terminal, so it behaves exactly as it does anywhere else and uses
whatever login that tool already has. Nothing is installed for you; an agent
whose command is not on your PATH is the greyed kind.
API agents talk to a model API directly. There is no wrapper CLI, no node
and no Python: Flockdeck runs its own chat client, flockdeck chat, in the pane. It is
a real terminal chat client — streamed answers, a status line carrying the
model, its token counts and, for a model in the price table, the running cost,
and tools for reading files, editing them and
running commands; the ones that write a file or run a command ask before they
act. A command can be let through for the rest of the session by answering
always; a write is asked about every time. Always is not offered for a
command that can run anything at all — a shell, git config, npm exec,
docker run — and a command with an option that writes a file wherever it
says or runs a program it names, such as git log --output or
go test -exec, is asked about even after always. Anthropic, OpenAI and
Google are built in, and so is a plain OpenAI-compatible endpoint, which is how
a local server — Ollama, LM Studio, vLLM — or a gateway becomes an agent.
The price table holds Anthropic's, OpenAI's and Google's models. A model is
priced only when its id is one the table names, or a dated snapshot of one
such as claude-haiku-4-5-20251001; any other id, including one that only
begins like a priced model, is shown in tokens with no dollars, because a
made-up price is worse than none.
An endpoint's address
The OpenAI-compatible endpoint ships with no address, because none would be
right for everybody, so it waits under not installed until it has one.
Pick it and the picker asks for the address there and then: type where the
model server answers, starting http:// or https:// — http://127.0.0.1:11434/v1
for Ollama, http://127.0.0.1:1234/v1 for LM Studio — and press Enter.
Escape puts the field away without saving anything.
How much of the address to give depends on the path. For an OpenAI-compatible
endpoint, /v1 is added only to a bare address such as
http://127.0.0.1:11434. An address with a path of its own — .../v1, or a
gateway's https://gateway.example/openai — is taken as the whole of the API's
root, and nothing is added to it. So give the path your server or gateway
documents, /v1 included where it has one. For the Anthropic and Gemini
agents, the API's version is added unless the address already ends in it. A
request's full address pasted in, ending /chat/completions, /messages or
/models, has that part taken off first.
An address on this machine needs no key, so a local model server is offered the moment its address is saved. One anywhere else, such as a gateway, needs a key as well, set under API keys….
Any other API agent that has been given an address — one of your own, or a built-in pointed at a proxy — shows it beside its name. Open the agent with the right arrow and choose its Address row to change it. Saved empty, the address is taken away, and a built-in goes back to its vendor's own.
An address that is not one is refused under the field, with what to type
instead: localhost:11434 is answered with http://localhost:11434. An
address with a name or password in it is refused too, because it is shown in
the picker; the key goes under API keys…. A pane already running keeps
the address it started with until it is restarted. From a terminal, flockdeck
keys endpoint <agent> <address> does the same, and default in place of the
address goes back to the vendor's own.
Not every agent can do everything
Most of what Flockdeck does beyond drawing a terminal depends on the agent cooperating, and they do not all cooperate in the same ways.
| If the agent | Then |
|---|---|
| reports its own lifecycle | its status dot says what it is really doing, rather than what its output looks like |
| can resume by id | restoring a layout brings its conversation back, not only its pane |
| writes a transcript | it can be resumed from it; Claude Code's is also where fan out reads a plan and what past conversations lists |
| has a trust question | a fan-out can answer it ahead of time for the worktrees it cuts |
| answers a start-up hook | its briefing survives a compaction, rather than being said once and summarised away |
An agent that does none of it still works perfectly well: it is a terminal with a program in it, which is where every one of these features started. Where a capability is missing Flockdeck falls back rather than failing — status comes from the terminal bell and a quiet timer; fan out reads the screen; resume is not attempted, and the pane starts fresh.
Of the built-in agents, Claude Code and the four API agents report their own
lifecycle and answer the start-up hook. Codex, Gemini CLI, Aider, opencode and
Cursor Agent are read from their terminals, and are not briefed. An entry in
agents.json can have the briefing put in front of such an agent's opening
task instead, with "caps": {"context": "prompt"}, and can give it
"patterns" — "waiting" and "idle", each a list of phrases its output
shows in that state — so that its status is read from what it prints as well. They are plain text, not expressions, and
case does not matter; none of the built-ins has any yet.
Aider is handed its opening task with --message, which Aider treats as a
single message, so a pane started with a task (by a fan-out, say) may end when
the task does.
Keys, for the API agents
A CLI agent uses the login it already has, and Flockdeck never sees it. An API
agent needs a key, which is looked for in that agent's own environment
variables first — ANTHROPIC_API_KEY, OPENAI_API_KEY and the rest — then in
Flockdeck's own store, and last in FLOCKDECK_API_KEY, which any API agent
reads. A vendor's own variable is read only by an agent talking to that
vendor's own address: a built-in given a gateway's or a proxy's address is
never sent the key you exported for the vendor, and uses the one stored for it.
| Command | What it does |
|---|---|
flockdeck keys set openai |
Reads the key from stdin, so it misses shell history |
flockdeck keys list |
Which agents have one, not what it is |
flockdeck keys clear openai |
Forgets the one Flockdeck stored |
Or set them from the window: API keys…, in the command palette, lists every API agent with set or not set beside it — and, for one that is not, the environment variables it would look in — and offers Set… and Clear.
Keys are kept in keys.json in the state directory, readable only by you. A
key reaches exactly one place: the environment of the chat process for the pane
that needs it. It is never logged, never written into a saved layout and never
shown — the interface will not read one back to you. An endpoint that needs no key at all, such
as a local server on loopback, counts as available without one.
Adding your own: agents.json
The picker is the built-in agents overlaid with your own file, agents.json in
the state directory — %AppData%\flockdeck on Windows, ~/Library/Application
Support/flockdeck on macOS, ~/.config/flockdeck on Linux.
{
"version": 1,
"defaults": { "agent": "claude", "model": "" },
"projects": {
"C:\\code\\api": { "agent": "codex", "model": "gpt-5.6-terra" }
},
"agents": [
{ "id": "claude", "defaultModel": "sonnet" },
{
"id": "local",
"name": "Local llama",
"runner": "api",
"api": {
"wire": "openai",
"baseURL": "http://127.0.0.1:11434/v1"
},
"models": [{ "id": "qwen3-coder" }]
}
]
}
Entries are matched to the built-ins by id and merged field by field: the
claude entry above changes its default model and leaves everything else
alone. An id matching no built-in is an agent of your own. "hidden": true
takes one out of the picker without removing it. A model's "tier" —
"small", "mid" or "top" — is set or corrected the same way; anything else
is named in the notice and ignored.
The file is read fresh every time the picker opens, so editing it by hand takes effect without a restart.
Routing
A fan-out multiplies whatever its model costs, and many of its tasks are mechanical: run the tests, rename a symbol, fix a typo. Routing pre-sets each row of a fan-out to a model suited to the work — a smaller one for mechanical work, a stronger one for hard work — and leaves every other row exactly as it was. It is off until you turn it on, in Settings › Agents › Routing, for every project or for one.
What it chooses is shown before anything starts. A routed row's model is
pre-set in its select, with a ↘ routed tag (↗ for a stronger model) whose
tooltip says which rule chose it and, for an API agent, what the two models
cost. Changing the select makes the row yours again, and Use the run's
model for every task, beside the line saying how many rows were routed,
does that for all of them. What was shown is what runs. A pane started on a
routed model says so in its header — claude · haiku ↘ — with the rule in
its tooltip.
Routing moves work between the models of the agent the run is on, never to another agent, and only between models whose tier it knows. Claude Code's Default is whatever the CLI is set to, which might be its smallest model or its largest, so routing leaves work on it alone: choose a model for the run in the fan-out, or make one your default, for routing to choose from it.
Suggest and Automatic are the same for a fan-out, since the dialog asks before anything starts either way. Never go below keeps routing off the smaller tiers for a project where the work matters.
The policy is kept in agents.json — and only there, never in a file inside a
repository, so a repository you clone cannot change what your key spends:
{
"routing": {
"mode": "suggest",
"floor": "",
"rules": [
{ "name": "run the tests", "tier": "small",
"when": { "task": "^(re-?)?run (the |all )?(unit |integration )?tests?\\b" } },
{ "name": "schema changes", "tier": "top",
"when": { "files": ["**/migrations/**", "**/*.sql"] } },
{ "name": "design work", "model": "opus", "agent": "claude",
"when": { "task": "\\bdesign\\b" } }
]
},
"projects": {
"C:\\code\\payments": { "routing": { "mode": "suggest", "floor": "mid" } }
}
}
Rules are tried in order and the first that matches decides; a task no rule
matches is left alone. Every condition in when must hold: task is a
regular expression matched without regard to case; minWords and maxWords
bound the task's length; files are globs matched against the paths the task
names (** is any number of directories, and a glob with no / matches a
file's name anywhere); kind is fanout, spawn or turn; agent is an
agent's id. A rule asks for a tier, or for one agent's model. Leave
rules out for the built-in ones, which Settings lists; "rules": [] means
none. A project's own policy replaces the one for every project whole. A rule
that cannot be used — a pattern that is not one, a tier that is not one — is
named in the notice and skipped, and the rest still apply.
Saving a default from a Flockdeck that has no routing — 0.2.10 or older —
writes a project's entry back without its routing, so a project's policy is
lost that way.
Routing makes no request. It decides from these rules alone and
makes no request of any kind; the routed mark on a pane travels only as the
rest of the pane's state does, to your own paired devices when remote access
is on. What it chose, and whether you kept it, is kept
in routing.jsonl in the state directory, for your own numbers: the rule's
name and the models, never the task. Settings has Clear routing history,
and to turn all of it off, set every project to Off. A file that does not parse is a notice in the
interface and nothing worse — the built-in agents carry on, because a typo in a
settings file is not a reason to be unable to start work.