Source Built from main · latest release v0.4.0

Models and tools

Endpoints, MCP, routines, skills, context, spend.

On this page
  1. Model endpoint
  2. Claude Agent
  3. Local agent
  4. Model
  5. Default model
  6. Built-in models
  7. Engine
  8. Model choice log
  9. Call record
  10. MCP
  11. Setup wizard
  12. Routine
  13. Skill
  14. Project skill
  15. Memory
  16. Built-in prompt
  17. Completion
  18. Context window
  19. Spend
  20. Spend cap

Model endpoint

A model's HTTP interface (base URL + API key) that speaks one of two formats: OpenAI-compatible (Chat Completions), or Anthropic-compatible (Anthropic's Messages, served by Anthropic and copied by many vendors and proxies). The format is chosen on the endpoint, OpenAI-compatible when none is; the app's own loop and judgements run the same on either, only what goes over the wire differs. Anthropic, Xiaomi MiMo, Qwen (Alibaba Cloud Model Studio) and DeepSeek are built-in connectors: picked when adding, they take only a key, which the app tries on each of that vendor's plan addresses in turn, keeping the one that takes it; an endpoint whose address is one of those plans shows as that vendor, with its logo. Anthropic's own address can carry an Anthropic workspace ID (wrkspc_…, required for a personal key not scoped to one workspace), sent with every request; it has nothing to do with the workspace the Bots work in. The app does not ship with any model of its own. You can configure several endpoints; one of them is the default. A completion goes to the endpoint its model belongs to. You add endpoints in Settings, and Bots can add them with a tool too. Creating an endpoint or changing an existing one's URL, format or Anthropic workspace ID is a dangerous action. The default endpoint's URL, format and key cannot be changed, and it cannot be deleted. Details in Behavior · Completion, ADR 0066 and ADR 0072. The speech recognition service behind the message box's voice input is not an endpoint: it is set up on its own in Settings, there is one, and Bots do not use it (ADR 0073).

Behavior details

Every hop's request carries max_tokens: the model's max_output in its endpoint's list, or 32,768 when unset, reasoning tokens included. Without a cap, on 2026-09-29 three hops each wrote one sentence up to the endpoint's default of 128,000 tokens (one of them for 17 minutes, the same sentence 3,457 times), and each was posted as the turn's closing line; in a Bot↔Bot direct it also woke the other Bot, whose next hop read the whole thing again. 32,768 comes from the spend records: a normal hop's output peaked a little over 30,000, and the only hops past 32,768 were those three repetitions, so anything lower would cut normal hops that write a large file. An endpoint that rejects max_tokens with a 400 naming max_completion_tokens instead (as OpenAI's reasoning models do) gets the request again at once with that field, and that model gets it from then on. A model that writes less than that (DeepSeek's deepseek-chat at most 8,192, OpenAI's gpt-4o at most 16,384) has its endpoint refuse the cap with a 400: when the error states the model's own limit, the request goes again at once with that number; when it states none, without a cap; and that model gets the same from then on. These requests went through before hops had a cap, so a refusal like this must not fail the turn, and the cap cannot be changed in Settings. When the prompt and the cap together are over the model's context (the error says "32768 in the completion", or names the cap while talking about the context length, as vLLM does), the request goes again without a cap, that time only: the next hop sends the cap first again.

While a reply streams, the app reads only its prose, not tool arguments, code blocks or tables: over the last 6,000 characters it splits sentences (at full stops, question and exclamation marks, semicolons, ellipses and line breaks, and at an English full stop followed by a space) and compares each by its letters and digits alone, ignoring case; digits still count ("shot 11" and "shot 12" are two sentences). When the same sentence (8 characters or more) comes a fifth time in a row, or fewer than a fifth of at least 20 recent sentences are distinct, the completion is cut off on the spot as a repetition, usually within seconds. "In a row" means nothing new came between two copies, only sentences seen before: a loop has nothing between its copies but more of itself, while a per-item verdict list ("Shot 03: passed. The frame is stable, no rework needed." on every line) has each item's own name between two copies of the comment, and is not a repetition. The share of distinct sentences counts sentences of any length, so twenty identical lines of "- [x] done" that never say which item each is still count as a repetition. A finished reply is checked by the same rules again before it is posted.

These completions have failed and are not replies:

  • Repetition: as above.
  • Refusal: the endpoint's finish reason is content_filter or one of Gemini's like SAFETY; or the whole reply is at most 300 characters with no tool call and is a canned refusal (speaking as a language model and saying it cannot, or only "I can't help with that" or "抱歉,我无法协助处理这个请求"). A Bot explaining which step it cannot do and why is not a refusal. Gemini refusals had gone out as a Bot's message twice before this.
  • Incomplete: the connection closed before the reply was finished (with neither a finish reason nor [DONE]; this is what the endpoint or a proxy in between closing the connection partway looks like), the finish reason said it stopped to call tools and no whole tool call arrived, or a tool call's arguments were not whole JSON. The client first tries the same request up to three times, and only when it is still incomplete does it count as failed.
  • Overtime: one request may take this long from being sent to the end of its stream: the larger of 10 minutes and max_output ÷ the model's measured 10th-percentile speed × 1.5. The speed is stream_tps_p10 in the list; unmeasured, it is 10 minutes (a model server on this computer or network is taken to write 10 tokens a second until measured; see "Model servers on this computer or network" below). Time waiting for a free slot at the endpoint, time running tools and time asleep with the lid shut do not count.

A failed completion posts nothing, stays out of the loop and wakes nobody. The same model gets one more hop with a note saying why (for a repetition: do not restate it or write a sign-off, do the next step by calling the tool directly); if that fails too, the turn ends as failed, with a "This turn did not finish: …" line in the session and, when you are in it, a failure notification. Any normal hop in between earns the next failure another go. Not reaching the endpoint, a busy endpoint, an endpoint error and a stream that goes quiet partway (the connection stays open but no next piece arrives) are not in this list: the client has already resent the same request, and the turn ends at once. Going quiet only shows once the idle time (3 minutes) has run out, so three tries already take 9 minutes and one more hop would double that; a connection closed partway shows within seconds, so it counts as incomplete, and one more hop costs little. When a stream goes quiet or breaks off partway, its first half used to be posted as the reply or have its tool calls run; now none of it is used.

Finish reasons are read regardless of case, including Gemini's own ones that a proxy passes through as they are: STOP is stop, and max_tokens, MAX_TOKENS and Mistral's model_length all read as length. An empty finish reason is none at all: some endpoints send "" on every chunk until the last. A finish reason the client has no name for (such as eos) means the model says it is done, so the stream is whole: it is not resent as half a stream, and the reply is judged by the rules above like any other. error is the exception: OpenRouter ends a stream with it when the model behind it failed partway, so what came is only half, and it counts as incomplete. A stream that goes quiet after its finish reason (the endpoint neither sends usage and [DONE] nor closes) is taken as the reply once the idle time runs out: the model has finished, and only the endpoint's last packets are missing.

A reply cut off at the output cap (finish reason length) without repeating is carried on for one hop: the cut part is not posted but stays in the loop to carry on from, with a note to do the next step by calling the tool directly and to put long content in files, written in parts; when the cut falls inside a tool call's arguments, that call is not run and the note asks for it in parts. If the carrying-on hop reaches the cap too, the turn ends as failed for hitting the output limit.

Streamed output no longer counts as the turn making progress: it used to refresh the turn's last activity as each piece arrived, so a hop could write for any length of time without looking stuck. A completion is now bounded by its own time limit, and the stale sweep (20 minutes without any activity) covers only the time outside completions.

max_output does not show in Settings; stream_tps_p10 is written by Test in a model's attributes, and context_window (the context window, in tokens) can be seen and changed there. A Bot can change context_window, input_image and max_output with update_endpoint, time a model with measure_model, and change the default endpoint, the built-in models (builtin_models; an endpoint's model or none only) and the model ladder with update_model_settings; all run without approval (ADR 0014). Saving the list from Settings again keeps whichever of these it leaves out, and only a null sent through the API clears one (emptying the window field sends null). When one is invalid in the stored list (say 0, or a string), only that value is ignored: the model stays in the list, and the Bots using it are unaffected.

Anthropic-compatible endpoints. With an endpoint's format set to Anthropic-compatible (ADR 0066) the rules of this section hold as they are; only what goes over the wire differs:

  • Address and key: requests go to /v1/messages under the base URL, or only /messages when the base already ends in /v1. So the address to give is the kind Claude Code takes as ANTHROPIC_BASE_URL (https://api.anthropic.com, https://api.deepseek.com/anthropic). The key goes in x-api-key, with anthropic-version: 2023-06-01; refused with a 401 or 403, it is sent once more as Authorization: Bearer (some vendors and proxies take only that), and if that goes through the endpoint gets it that way from then on. Refused both ways, the key is wrong.
  • Messages: inside, the app keeps the loop in Chat Completions' shape and converts it on the way out: every system message joins the top-level system; tool results become tool_result blocks in a user turn, ahead of any text in it; neighbouring messages of one role merge into one turn; a history that opens with the Bot's own line gets a user turn of "…" before it; tool call ids keep only letters, digits, _ and - (the loop may hold ids an OpenAI-compatible endpoint gave); an image's data URI becomes a base64 image block.
  • Thinking levels: first in the form of Anthropic's newer models, thinking: {type: "adaptive"} with output_config.effort (none sends only effort: low: the newest models cannot stop thinking, and older ones without a thinking field do not think anyway). A 400 that names thinking, effort or budget_tokens steps down to thinking: {type: "enabled", budget_tokens} (low 2,048, medium 8,192, high 16,384, at most half the output cap, none when that is under 1,024); refused again, no thinking fields at all. Once a request in the stepped-down form goes through, that model on that endpoint keeps it; a step that was refused anyway is not kept. A 400 about thinking blocks in the history ("Expected thinking … but found tool_use", a signature that does not check out) is not a refusal of the fields and steps nothing down. A judgement call whose cap has no room for thinking (256 or 512 tokens) gets the effort alone in the new form, and no budget in the old one.
  • Thinking goes with the tool calls: when the model thought before calling tools, its thinking blocks (signatures included) stay in the turn's loop with those calls, unchanged, and go back with the next hop, which would be refused without them. They go back only to the endpoint and model that wrote them: a hop that moved to another model (stepping up the ladder, or to one that sees pictures) goes without them.
  • The cap: this format needs max_tokens on every request, so there is no "send it again without a cap". An error saying the context is full ("190000 + 32768 > 200000": used, cap, context) is sent again once with what room is left; one that states the model's own limit is handled as above, that number from then on. Still refused with the cap out of the way because the prompt itself is too long ("prompt is too long"), the context is full, not a bare refusal; a stream stopped at model_context_window_exceeded is a full context too (as is Mistral's model_length), not a reply cut at the output cap to carry on from. Both compact the loop first (see Context window).
  • Judgement calls carry no temperature: 0: Anthropic's newer models refuse any sampling setting.
  • Cache: one cache mark at the end of the system prompt, and for a hop another at the end of the loop, so the next hop reads up to there from the cache. Anthropic caches nothing unmarked; proxies that cache on their own ignore the marks.
  • Usage: tokens read from and written to the cache both count as input, and those read count as cached too, as Chat Completions counts them; spend is estimated from the list's rates as before.
  • Finish reasons: end_turn is a normal end, tool_use asks for tools, max_tokens is the cap, refusal is a refusal. An error event in the stream (overloaded_error, most often) makes the attempt unfinished, tried again as above.
  • The model list comes from …/v1/models?limit=1000, the key sent as above. Many compatible endpoints have no such route; then type the names in.

Model servers on this computer or network. An endpoint whose address is loopback, localhost, *.local or a private address (10/8, 172.16/12, 192.168/16, link-local) is taken as a model server on this computer or network (Ollama, LM Studio, llama.cpp's llama-server), and these rules come on top of this section's (ADR 0067):

  • The key is optional. Without one the endpoint is still picked to run on and completes the wizard, and requests carry no key header; when a Bot adds such an endpoint, the key field on the approval card may stay empty.
  • Cut prompts: such a server does not refuse a prompt it cannot hold; it cuts the start and answers anyway (Ollama 0.40 keeps the last half once over its window, with HTTP 200). So after a local request the app compares the bytes sent with the tokens the server reports reading: over 6.5 bytes a token, or over 1.6 times what the model read its earlier whole requests (of 16 KB or more) at, the prompt was cut (requests under 16 KB are not judged, and pictures are not counted); so was it when, within one conversation (one Bot in one session), a prompt longer than the one before was read as fewer tokens — Ollama drops the oldest messages to fit once a prompt is just over its window, and the reading moves only a few percent (not judged when the number of pictures changed). That step is dropped and not sent again as it was: when the turn's loop has something to condense, it is compacted into a summary first and the step goes again (see Context window); when it cannot be, or still does not fit, the turn fails with "The prompt is larger than the model's context window", followed by about how many tokens the step was, how many the endpoint read and the server's window; that window is also recorded on the model's entry. When the entry already has a window and the estimate is more than a tenth over it, the step is not sent at all. A 400 from any endpoint (an Anthropic-compatible one too) whose text says the prompt is over the context reads the same way.
  • Window and abilities: fetching such an endpoint's model list also asks the server for each model's window (Ollama: the loaded window, else the Modelfile's num_ctx, else the model's limit; LM Studio and llama.cpp alike), whether it takes pictures and whether it calls tools, and fills them into the model's attributes (never over what you typed); a model that cannot call tools is tagged "No tools" in the list.
  • Time limits: up to 15 minutes for the first token (loading the model, queueing behind another request, reading tens of thousands of tokens) and 5 minutes idle; one streamed request at a time per server, the rest queued in the app without a clock; short calls nobody waits on get at least 10 minutes, while a reading keeps its 20 seconds and falls back to the word lists.
  • Short calls do not think: organizing, judgements, readings and other short calls that name no thinking level send reasoning_effort: "none"; otherwise a reasoning model spends all 256 tokens thinking and answers nothing (measured on qwen3:8b). A model that refuses the value is asked again without it, and remembered.
  • Thinking is not the reply: a leading <think>…</think> is taken out of the reply text (on every endpoint), and a lone </think> takes everything before it along; a local model's separate thinking also goes through the repeat watch, on the same-long-sentence rule only.
  • Speed test: Test in a model's attributes sends two short requests, timing the first token and the tokens per second, and checks whether it calls a tool it is given; 60% of the speed is recorded as stream_tps_p10. It does not queue behind a Bot's step in the app, but a server that handles one request at a time makes it wait for that step.

Avoid: provider catalog, Binder, late binding, per-Bot endpoints, treating an Anthropic-compatible endpoint as Claude Agent, storing a built-in connector as another kind of endpoint, putting the Anthropic workspace ID in the key field, treating the speech recognition service as an endpoint

Claude Agent

One way a Bot can run: instead of the app's own loop, each of its turns is run by the Claude Code you installed and signed in to on this computer (through the Agent SDK), working with Claude Code's own tools and counting usage against the account it is signed in with (a Claude subscription or an API key). The app still keeps the permission mode and your approvals, Stop, the end contract, hand-overs and reviews, and hands it its own collaboration tools as mcp__deskfolk__*; the app's own judgements still run on endpoints. Only you switch a Bot's runner, in the Bot panel; the app offers no Claude sign-in and never touches its credentials, it only shows in Settings which credential is in use. When an account is out of usage, the same turn goes on in a new session on another listed Claude account that is signed in and not out; with every account out, the failure line says when, and the work picks up by itself then (ADR 0110). Details: Behavior · Claude Agent, ADR 0061.

Behavior details

Turning it on: in the Bot panel set "Runs on" to "Claude Agent (your own Claude Code)", also when creating a Bot; only you can change it — a Bot changing its own or another's is refused. Then pick the Claude model and effort. The models are the ones the Bot's account's Claude Code offers in its own /model, by its names with the value beside (Opus 5.5 · opus), Claude Code's default on top; when the list cannot be had, the aliases sonnet, opus, haiku and fable. The efforts (default, low … max) are the picked model's only, none shown for a model that takes none, and a model that does not take the current effort sets it back to the default. Creating a Bot, the setup wizard, the Roles page's Claude models, the model ladder and a ticket's model offer the same full list (ADR 0095). The endpoint pin stays: the app's own judgements about the Bot (whether to join a group line and the like) still run on an endpoint, so one is still needed.

Finding your Claude Code: the path set in Settings, the daemon's PATH, the usual install places (~/.local/bin, /opt/homebrew/bin, /usr/local/bin, the npm global dir …), then your login shell. On Windows: PATH (the native claude.exe and npm's claude.cmd both count), %USERPROFILE%\.local\bin\claude.exe and %APPDATA%\npm\claude.cmd, with no login shell step. The "Claude Agent" card in Settings › Agents shows where it was found, its version, the account (a Claude subscription, a long-lived token, an API key, a third-party platform) and the network (direct, or which proxy), and warns when it is not signed in, bills per token (an API key), sends requests elsewhere (ANTHROPIC_BASE_URL), or is older than the Agent SDK the app ships with. The app only runs it and asks it claude --version and claude auth status; it offers no sign-in and never reads its credentials — sign in by running claude in a terminal. The card and its routes exist on this Mac only.

Several accounts: Claude Code keeps each account's sign-in in a config directory — ~/.claude while CLAUDE_CONFIG_DIR is unset, the directory it names otherwise — so one computer can have several accounts signed in at once. The Claude Agent card is grouped by account: location, version and network at the top, then under Accounts a block per account — its plan and email, the directory it reads and its usage (once a Bot runs on it), the default account tagged Default and the others with Remove; the card's and the accounts' explanations sit behind a "?" beside their headings, shown on hover or a click. Under Accounts, add the other accounts' directories (a full path, ~/ works; not the root, your home folder or anything above it): the card runs claude auth status with each and lists its plan and email, or the command that signs it in (such as CLAUDE_CONFIG_DIR=~/.claude-b claude auth login). Then pick a Bot's account under "Claude account" in its panel: a Bot left alone uses the default one above (the one Claude Code finds in the app's own environment, as before). With a directory picked, the Bot's turns, the sign-in check before each and its usage run Claude Code with that directory; for ~/.claude itself CLAUDE_CONFIG_DIR is unset rather than named, since naming it makes Claude Code look for another keychain item and read as signed out. When that account is signed out, the turn stops before it starts and names the directory. Only you change a Bot's account (a Bot doing so is refused), and the phone switches among the listed ones; a directory a Bot runs on can be removed only once the Bot is moved; listing or removing one works from the computer and the phone alike (PUT /v1/runtime/claude-code/accounts); the whole Claude Agent card is on the phone too, path and Check again included — only signing in needs a terminal on the computer. Every listed directory is as off limits to the Bots' file tools and commands as ~/.claude. The app keeps the directory and reads only the session transcripts under its projects/, when you carry a terminal session on as a project session (to list and import them), never the sign-in, settings or anything else.

Network: an HTTPS_PROXY / ALL_PROXY in the daemon's environment goes to Claude Code as it is (NO_PROXY can take Anthropic out); with none, the system's HTTPS proxy (System Settings › Network › Proxies on a Mac, Settings › Network & internet › Proxy on Windows — the one browsers follow) is handed to it as HTTPS_PROXY. The app started from Finder, the Start menu or at login does not get your terminal's proxy variables, and some networks reach Anthropic only through a proxy — without this, every request is refused. Only HTTPS_PROXY is set, so a Bot's own requests to local http:// addresses stay direct. A PAC file or a SOCKS-only proxy is not followed.

How a turn runs: each turn starts a fresh Claude Code session in the turn's work dir (the workspace root until the work belongs to a job), able to read and write the whole workspace. Its first message is the situation block and the transcript window (as for any Bot; its own lines marked as its own, pictures included; the work dir as a full path on this machine, the only kind Claude Code's file tools take); the system prompt is Claude Code's own plus the Bot's profile, skills, memories and the system text every Bot gets. Your ~/.claude settings, hooks, plugins and CLAUDE.md stay out of it (the SDK's isolation mode); the keychain sign-in and an API key in the environment still work. Only Read, Write, Edit, NotebookEdit, Glob, Grep, Bash, WebFetch, WebSearch, Agent (subtasks) and TodoWrite are offered; nothing runs in the background, and /commands or @paths in the transcript are not expanded.

Boundary and approvals: reads run anywhere; writes, edits and commands go by the Bot's permission mode — they run under auto and allow all, raise the same approval card any Bot raises under ask first, and are refused read-only, whether in the workspace or not (ADR 0092). What Claude Code asks about on its own (a protected file, say) is answered by the mode too; a recursive search over your home folder is refused as always; a path under a top-level folder that does not exist (usually a workspace path written as /work/…) is refused with where the workspace is, with no card — on Windows, a file path with no drive; Claude Code's own settings and credentials (~/.claude, ~/.claude.json, the keychain) are refused outright, with no card, except the project memory it keeps (~/.claude/projects/*/memory/): Read, Glob and Grep can read it, while changing it and reaching it in a command are still refused (ADR 0102). Stop, holds and read-only turns apply as for any Bot; Stop ends Claude Code and every command it started (on Windows, the whole process tree with taskkill /T).

Working with others: progress, endings, hand-overs, reviews, delegation, questions to you, check-backs, laying out tickets, memory, skills and annotations go through the same tools as for any Bot (named mcp__deskfolk__… on its side), under the same rules; questions to you only through ask_user. Its last reply that calls no tool is the message it posts, and goes through the closing check, the hand-over of the files it cites and the end contract like any Bot's; a line sent back comes back into the same session to answer again. Text in the same message as a tool call is shown while it works and never sent. A segment on the whole job whose command or write lands in the folder of a ticket of its own moves onto that ticket at once, as any Bot's does, so a reply carrying those files goes out first and hands them over; it used to move only at submit, and a reply the end contract sent back was held back with it. When it reviews pictures it looks with its own Read, which the app records as seen.

Records: a route row per turn (no endpoint, reason claude_code; a turn that climbed onto a Claude rung keeps escalation_model as the reason it was chosen first); spend per model under the name "Claude Agent", priced as an estimate (a subscription is not billed per token); the commands it ran, files it wrote and effects it had are recorded as for any Bot.

Usage (ADR 0080): every local agent's usage is in one place. A wide window has a usage ball floating top right: a small ball whose ring is as full as what is used of the tightest window of all (rounded down, so a window not yet spent never reads 100%, and a window just touched reads "<1%", not 0%; amber from three quarters used, red from nine tenths, the ball's outline too). Drag it anywhere; dropped within 24 px of the left or right edge it docks there half tucked away and slides out when pointed at. Pointed at, the ball morphs into a column of the agents (the one shape grows from the ball into a bar, the bubbles coming in one after another; upward from a ball in the lower half): each bubble wears the agent's mark, ringed by its tightest window over all its accounts, a dashed ring for an agent with today's records only. Point at an agent and a card grows out of its bubble toward the middle of the window: that agent's turns and tokens today here, then each account (the plan as a small label, the email muted after it, the directory when it has several, Codex's credits; with several accounts each sits in an outlined box of its own, its windows inside) with a line per window — its name, when it resets, what is used and a bar of what is used; an agent with today's records only says why there is no more. The card ends with when it was checked and Refresh. Another agent's card grows out of its own bubble; crossing from the bubble to the card keeps it, and it folds back into the ball a moment after the pointer leaves all of it. A click on the ball pins it open (how touch opens it), a click on an agent pins its card; Escape or a click outside folds it. With reduced motion asked for, nothing animates. The ball's context menu has "Hide the usage widget"; the usage tab's "Show the usage widget" brings it back. Tools › Usage and the menu bar's "Show all usage…" open a Usage tab on the workbench: a bar with when it was checked and Refresh (and "Show the usage widget" while the widget is hidden), then a card per account in a grid across the tab — an agent's accounts side by side under its name and day, several agents in a row on a wide tab (cards in a row one height, heads level), one column in a narrow pane; each window is a row: its name ("Fable · 7 days" for a model's window, on one line when it fits; a long model name like Antigravity's wraps in full, "· 7 days" kept whole), ↻ when it starts over and what is used, with a bar of what is used beneath; the agents with today's records only are a row of chips at the end. Like Spend there is only one: asked for again it is brought forward, and when it is not open it goes where Settings › Behavior › Where windows open says for Usage (a new tab by default). A wide window with no workbench (a tablet on a remote connection) still opens the widget. No local agent connected, no widget. A phone has no widget: Tools › Usage opens a page in the list laid out like the usage tab in one column (a head per agent, a card per account), but each window a dial with what is used inside, its name (a long model name wrapping in full) and ↻ beneath, a card's dials centred, up to three a row and two a row from four (Antigravity's 2 × 2), with when it was checked and Refresh at the end; Back at its top left; it and the archived list are pages in the URL like the calendar (?o=usage, ?o=archived), so the phone's Back returns to the list, and a conversation opened from the archived list goes back to that list first. Settings › Agents shows one line under each account ("5h 38% · 7d 19%", both used, the same ring). The menu bar icon's menu starts with a line per account: the agent's mark inside a thin ring for the tightest window (the mark alone for an account signed out or not read), the name and what is used of the 5-hour and 7-day windows (model windows only in the panel); agents with no plan share one line ("Grok 12 turns · OpenCode 0 turns"); eight lines at most, then "Show all usage…", which opens the window and the usage tab (menu icons do not follow the light or dark menu, so the colours read on both). Claude's numbers are fetched from claude.ai by your own Claude Code (the data behind its /usage, asked through the Agent SDK's get_usage in a session that sends no prompt and is closed right after) — no model, no quota spent, and the app never reads its credentials; Codex's come from its own app-server. Accounts listed are every connected one (found in Settings › Agents and not signed out) and every one in use (Bots, agent rungs on the model ladder, built-in calls), with or without a Bot on it; each asked once (two that are the same directory once). The daemon keeps each answer five minutes and the widget and the menu bar ask about once a minute, so at most one claude starts per five minutes; with nothing on Claude nothing is asked. "Today" is per agent (spend rows under its name since local midnight, turns counted as distinct turns), not per account. The SDK marks Claude's request experimental; if Claude Code changes it, that account says it could not be read (GET /v1/usage, readable from a phone over the relay; the older GET /v1/claude-usage and GET /v1/agent-usage stay for clients not updated yet).

Failures: Claude Code missing, unable to authenticate (not signed in, or its requests refused — with Claude Code's own error line), or out of usage (with when it resets; with extra usage on, going past the plan's limit is not a failure; with another account or a known reset, see "Out of usage" below) are yours to clear, so the supervisor does not retry them, nor call the Bot back until a turn of it ends some other way (from 2026-11-11); when another wake (a job's result, a check-back) fails it the same way again, a failure line identical to the conversation's last line, while that line's Continue is unused, no longer shows, is kept for the Bot only, and raises no second notification; a Continue that fails the same way still shows; Claude Code exiting mid-turn is the app's side, also with its error line. When a request fails, the error line Claude Code writes is never posted as the Bot's reply. Steps have no limit: as on the app's own loop, a segment runs for as long as it works; its tools are never taken away, and no step count fails it as stuck. Until 2026-10-17 steps followed the engine's hop limit (160 by default, 200 on video): there every tool was taken away, and 40 steps later the session failed as stuck; before 2026-10-12 it was a fixed 200. Long renders stopped mid-work on it. See ADR 0061.

Out of usage (from 2026-11-12, ADR 0110): when the plan's five-hour or weekly limit turns a request away (extra usage carrying on does not count), the app notes the account out until the reset it reports (kept across restarts; a billing error or an account on hold, which report none, is held out for an hour and tried again), and the same turn goes on in a new session on another account listed under "Several accounts" that is signed in on a Claude plan (a claude.ai sign-in or its long-lived token; never one billed per token — an API key or a cloud platform) and not out. That session starts with the turn's own input plus an app note: the account ran out and the turn moved, and what the session before did in this turn (calls, results, what it said; the latest ~6,000 characters), with the files still there and not to be redone. Nothing shows in the conversation, no notification goes out, and the turn is no failure; the work log gets agent.account_switched. Two handles reading one directory, or signed in as the same email, are one account, and moving between them does nothing. A later turn whose Bot (or ladder rung) names an account still noted out starts on another one; the Bot panel's account is unchanged, so the Bot is back on its own once the limit is over. Built-in calls on Claude (reading, the organizer, …) pick their account the same way. With every account out, the failure line shows once, saying when it picks up by itself (「这一轮没写完:Claude 的用量额度用完了(11/5 13:10 重置,到时自动接着做)」; another account's time when that one is back sooner), with no notification; a minute after that time the app continues it as that line's Continue would — a stop of yours still holds it — unless you pressed Continue already or the job had a later turn that did not end out of usage (you spoke and it got through, you stopped it, it is at work). Codex picks up at a reset it reports the same way (with no account switch); other local agents report none and wait for you as before. Project sessions do too; see "Out of usage" in that section.

Avoid: "Claude Code engine" (the brand is not a feature name), calling the API with a subscription token, signing in to Claude inside the app, Claude Code as a completion endpoint, a Bot switching its own runner, moving to another agent when out of usage, changing the Bot's account setting when out of usage

Local agent

One way a Bot can run: each of its turns is run by an agent program you installed and signed in to on this computer — Claude Code (that is, Claude Agent), Codex, Grok, OpenCode, ZCode, Antigravity, or an ACP command you listed yourself — working with that agent's own tools and counting usage against the account it is signed in with. The app still keeps the permission mode and your approvals, Stop, the end contract, hand-overs and reviews: every call it can stop before it runs is decided first, and one it learns of only afterwards stops the turn if the mode would have asked about it or refused it; the app's own collaboration tools reach the agent over MCP (Codex: its dynamic tools). Only you switch a Bot's runner, in the Bot panel; the app offers no sign-in, never touches credentials and never changes the agent's config. Built-in calls and ladder rungs may name these agents' models too. Details: Behavior · Local agents, ADR 0079.

Behavior details

Turning it on: besides Deskfolk and Claude Agent, the Bot panel's Runner offers Codex, Grok, OpenCode, ZCode, Antigravity and any ACP agent you added in Settings (by the name you gave it); also when creating a Bot, and only you can change it. Then set the model (as that agent spells it, e.g. gpt-5.6-luna, grok-4.7, nvidia/z-ai/glm-5.3; empty for its default, with suggestions where it lists models), the effort (only the levels it takes; OpenCode takes none) and the account (Codex can list several). One that is missing or signed out is greyed with why. The endpoint pin stays, and the app's own calls about the Bot still run on an endpoint (or, set up on an agent alone, on that agent).

Settings › Agents: one line per agent, for the whole picture first: its logo, whether it can run a Bot (Ready / Sign in / Not installed), a summary (the account or plan it is signed in with and how many models it lists; one signed in with many providers, like OpenCode, reads "OpenCode Go and 6 more") and how many Bots run on it; ready ones first, then those to sign in, the ones not installed folded at the foot ("N not installed"), with "Check all again" at the top. The list is there at once: each agent as last seen (kept in the database, across restarts), and one not asked in the last minute asked again behind it, its line catching up by itself; only one never asked, and "Check all again", are waited for. A line opens to the details: in place on a wide window, one at a time; on a phone as a page of its own, Back going to the list. The details are where it was found (as for Claude Code: the path you set, PATH, the usual install places — npm globals under nvm included — then your login shell), its version, its sign-in (Codex's plan, what Grok signs in with, the providers OpenCode has credentials for; ZCode's is known at the first turn), how many models it lists, and the network (proxy as for Claude); signed out, it shows the command to run in a terminal; "Set the path…" and "Add an account…" show their fields when asked (not found, the path field is there at once). The last line, "Your own ACP agents", opens to a name, the command's full path and its arguments — any program that speaks the Agent Client Protocol (e.g. gemini --acp with an API key); one a Bot, rung or built-in call uses cannot be removed. The phone shows and sets the same.

A turn: as for Claude Agent, a fresh session per turn in the turn's work dir, the first message the situation block and transcript window; the Bot's profile, skills, system text and memories go in Codex's developer instructions and at the head of the first message for ACP agents and Antigravity (they have no system prompt of their own). What you set up in these agents is kept out of a Bot's turn as far as each allows: Codex's hooks, memories, plugins, apps, AGENTS.md and your MCP servers are off for the turn, Grok does not join its shared leader, OpenCode runs its own private server — all passed at launch; your config files are never changed. Antigravity runs as agy acp and needs agy 1.5.4 or later: with an older one the turn does not start, its failure line says "Your Antigravity is too old" and which version it needs, and its row in Settings › Agents says to update. Errors of agy's own (a model out of capacity, busy servers, a turned-off account, each written as "⚠ …" lines in place of a reply) are not posted as the Bot's words: the turn fails, its failure line quoting the last of them, and a turned-off account, like a signed-out one, is left to you and not retried.

Boundary and approvals: Claude Agent's rules, and every call stopped before it runs where the agent allows: Grok has the app read, write and run everything, decided first; OpenCode asks before every command and write; Codex asks before every command and file change; the app answers by the Bot's permission mode: reads go ahead, writes and commands go ahead under auto and allow all, put up the approval card under ask first and are refused read-only (ADR 0092). What cannot be stopped — a call the agent made without asking and reported afterwards — is checked when reported, and one the mode would have asked about or refused, or one on any agent's credentials (~/.codex, ~/.grok, ~/.claude, OpenCode's folders, ~/.dsh, ~/.gemini, the keychain…), stops the turn, saying what it did. Antigravity works with the permission you set in agy (the app does not change it) and reads, writes and runs with its own tools; what it asks about, the app answers by the Bot's permission mode, and under always-proceed it asks nothing first: the app runs it sandboxed (its commands cannot read ~/.ssh and the like) and checks each call as soon as it reports it under way, stopping the turn on one its mode would have asked about or refused — so under always-proceed an Antigravity Bot under read-only or ask first stops at its first write or command.

Collaboration: the app's own tools (posting, endings, hand-overs, reviews, delegation, asking you, check-backs…) reach ACP agents as an MCP server named deskfolk and Codex as tools of its own; Grok finds them through its tool search and OpenCode calls them from code in its execute tool, as the preface tells them. Antigravity gets them through the deskfolk MCP server too, shown there as mcp_deskfolk_…. Lines you send meanwhile: Codex takes them at once; the others with the result of the next app tool they call, or at the next turn. Insert-now cuts Codex, ACP agents and Antigravity short.

Records and usage: route rows say agent_codex and the like; spend is recorded under the agent's name (tokens from Codex and Antigravity; Grok and OpenCode report none), priced as an estimate. Once one of them is connected (or something runs on it), it shows in the usage widget (see "Usage" under Claude Agent below): Codex, Grok and Antigravity with how much of their own plan windows is used (Codex's app-server; Grok's ACP extension _x.ai/billing, one weekly window; Antigravity's agy -p "/quota", a 5-hour and a weekly window per model group, not asked of an agy older than 1.1.11, which would send it to the model as a prompt), none of it through a model or spending anything; OpenCode, ZCode and your own ACP agents with today's turns and tokens here only — never an invented percentage.

Built-in calls and the ladder: The built-in calls and the model ladder on Tools › Roles may name these agents' models. A built-in call asks the agent once in a scratch folder with no tools and cuts it off if it tries one; a ladder rung may be any agent's model and effort, and a turn that climbs to it runs on that agent.

Failures: missing, signed out and out of usage name the agent and only you can clear them, so the supervisor does not retry; an agent exiting mid-turn is the app's side; "did something that needed your OK, or touched credentials, without asking" is yours to look at before anything is retried. See ADR 0079.

Avoid: an agent as a completion endpoint, signing in to an agent inside the app, rewriting an agent's config file, reading an agent's tokens, a Bot switching its own runner, pretending to hand over without the tools

Model

A completion name that a given endpoint recognizes; each endpoint has its own list and its own default. The thinking level is pinned together with the model and never exists on its own: either neither is pinned and the app settles both, or a model is pinned and its level is set along with it. The user does not pick for each turn. From engine level 7 (the default is 8) a turn's model follows a fixed order and nothing picks per turn: the model set on the ticket, else your pin, else the Bot's default model, else the endpoint's default, with which one recorded for each turn; work that needs pictures does not land on a model marked as taking none (unless pinned), and a job that keeps failing, or keeps calling tools wrongly inside a turn, steps up a thinking level; failed hand-overs past the top level climb the model ladder you ordered (a pin or a ticket's model is never switched); a rung may be a model of one of your local agents (Claude, Codex, Grok…), and a turn on it is run by that agent; a ticket's model may be an agent's too, and that agent then does the ticket (ADR 0076, ADR 0079). Below level 7 (a data folder an older installed app that does not read the version gate holds at a lower level), an agent still picks once each time a turn starts, looking at the message, the Bot's profile, the candidate list and recent review conclusions, and answers with a model, a thinking level and a one-sentence reason. Details: Behavior · Model.

Behavior details

A completion name that a given endpoint recognizes. Each endpoint has its own list and its own default, and a name on the list can carry a routing reference price, an optional billing price, the thinking levels it supports, and what it is good at. The routing reference price is a relative number the app uses when it picks a model. The billing price is in USD per million tokens: input and output are set together, cached input can be set separately, and when left blank it uses the input price. The billing price is used to estimate spend when no reported amount is available; probing the model list does not fill in prices automatically. When the user's message starts a turn, the app picks the model and thinking level only from the list of the endpoint the Bot is pinned to (the default endpoint if it has none pinned); adding another endpoint in Settings does not bring its models into other Bots' choices. If the Bot has pinned a name that is still on that list, the model name is held to it; a pinned name that exists only on another endpoint is used as pinned. A Bot can also pin a thinking level (the completion's reasoning_effort): the level names follow that model's list (commonly none / low / medium / high, plus xhigh, max and so on when the endpoint advertises them). When probing /models, if an object carries thinking levels they are written into that model's thinking_levels automatically, and you can still edit them by hand in Settings. The thinking level is pinned together with the model and never exists on its own: either neither is pinned and the app picks both the model and the level for each message, or a model is pinned and its level is set along with it. Pinning a model without a level falls back to that model's default level (the app's order of preference for ordinary messages); switching to a model that doesn't support the current level falls back to the new model's default level; clearing the model clears the level with it; giving a level without a pinned model is rejected. You can change these with one click in the Bot panel, and a Bot can change its own with a tool. In your direct with it the composer's tool row can change them too, with the picker a project session has, opening a level at a time: Automatic and each endpoint first, an endpoint opening its models, a model its thinking levels; picking a level pins the model and the level together, and Automatic pins neither. Closed, it reads the pinned model and level, with the endpoint after them in smaller type when there is more than one. A Bot run by a local agent picks that agent's model and effort there (with the account first when Claude Code has more than one), as a project session does, from the levels that agent takes. Either way it is the Bot's own setting, the same as changing it in the Bot panel: it runs on it in groups and other conversations too. An empty pin does not mean "always use the endpoint's default model"; it means the app may pick from that endpoint's list. To use another endpoint, you must pin the endpoint explicitly. Who picks (below level 7; from level 7 see Default models below): each time a turn starts, an agent first picks once. It looks at the message, this Bot's profile, the candidate list, this Bot's recent review conclusions (each with the message and category it came from, ignored when they don't match) and recent examples that finished cleanly, and answers with a model, a thinking level and a one-sentence reason. The agent itself always runs on the default endpoint's default model; if it can't answer, or answers with something that doesn't exist, the choice falls back to rules, so the user is never stuck on model routing. Everything the user says afterward is kept verbatim (not filtered by keyword) and attached to the quoted turn, to the latest turn of the Bot that was @-mentioned, or to the latest visible turn in the session. Consecutive turns about the same thing form one correction chain. When the chain ends (the topic changes or things go quiet for a while), it is reviewed once; a turn with no follow-up is also reviewed once if the endpoint refused it, its reply was incomplete, or it hit at least two tool errors. The review looks at the whole chain plus what the turn actually did: was it the model falling short, the task itself being hard, or the request being unclear? Only a verdict that the model fell short is kept as this Bot's experience, together with which way to adjust: stronger / lighter / faster / cheaper. What is kept is a conclusion, not a score: there are no weights, offsets or caps. A conclusion that has been followed twice and still hasn't led to a cleaner result drops out of model routing, though its record stays. The experience belongs to the Bot itself and is deleted along with the Bot. What each turn chose, how it ended, how much it did and what feedback it received are all recorded. The user does not pick for each turn. The judgement call and the turn's completions use the same resolved result.

Default models (from level 7, and the default is level 8; ADR 0048): no model call picks what a turn runs on any more. It goes by a fixed order: the model you pinned on the Bot; with no pin, the Bot's default model; with no default, the endpoint's default. The thinking level is the pinned one, or, when the model does not offer it or none is pinned, the nearest it offers for this kind of message; a Bot pinned to an endpoint only chooses from that endpoint's list; a pin no endpoint lists any more runs on the endpoint's default, and you are told once; the pin stays, and once the model is listed again it is the pin again. The Bot panel shows it as "not listed" and saves other edits as usual. Before, taking a model off an endpoint's list in Settings wiped every pin on it on the spot, with nothing said: on 2026-10-03 that moved both video Bots off claude-opus. Below level 7 the pin still goes with the list. A default is set the first time it is needed: what the Bot ran on most in the last 7 days among the models the endpoints still list (a renamed or removed one does not count), at the thinking level it ran that model on most, and it is used from then on with no card asking you: pin a model on the Bot to change it (from 2026-10-04; until then a card in your direct with it said so — "runs on X (thinking Y) from now on: what it ran on most in the last 7 days (N turns)" [Keep it] [Use the endpoint's default] — with a "waiting for your answer" notification, one for each of four Bots on 2026-10-03, the day level 7 went on: asking about nothing you had to decide, used whether you answered or not). The work log records model.default_inferred. Cards already out still take their buttons: declined, nothing is inferred again. On the board a ticket can also be given a model, ahead of the pin and the default (ticket_override), for its owner's turns only; the Bot reviewing it keeps its own. The model may be an endpoint's or one of your local agents' (ADR 0079): the ticket's model decides who does it — an agent's runs those turns on that agent, as a ladder rung does; an endpoint's runs them in the app's own loop, even for a Bot that usually runs on an agent. Each turn's route record carries the reason: ticket_override, pin, default, endpoint_default, pin_unlisted, capability_filter or escalation. Reviews and learning go on as before, until level 8 replaces them with quality events and lessons.

Pictures and stepping up (from level 7; ADR 0049): a model can be marked in the endpoint settings as taking pictures, taking none, or not sure (counted as taking them). When a turn is opened by a line with a picture, or the Bot reviews a ticket with a requirement about the picture, and the model picked is marked as taking none: a pin stays and you are told once; otherwise it moves to a model marked as taking pictures (capability_filter). A picture read mid-turn is not sent to a model that takes none; the tool result says so. A job whose hand-overs failed twice in a row since its last step runs one thinking level higher (escalation), up to its model's top, and resets once the ticket is approved; a thinking level you pinned is not raised, nor one on a model measured to gain nothing from it.

The model ladder and stepping up inside a turn (from level 7; ADR 0054): in Tools → Roles → A Bot's turn you can order a few models weaker to stronger as a ladder (at most 8). When the thinking levels are used up (or the model is measured to gain nothing from them) and a job needs more, its next turn moves one model up the ladder (escalation_model), past rungs no endpoint lists any more and, for work that needs pictures, rungs marked as taking none; asking for more past the last rung stays there and you are told once. Only a model the app chose for the Bot moves along the ladder; your pin and a ticket's model only step up their thinking level; with no ladder, or a model not on it, you are told once at the top. Besides failed hand-overs, a reply that fails again after its retry, tool arguments that are not JSON twice in a row, and the same tool called wrongly three times in a row (the model's own mistakes, like bad arguments or a refused call made anyway; a missing file, a timeout or an MCP server's error do not count) each step the job up — at most once between two hand-overs, and only in thinking level, never along the ladder; the last two switch the rest of that turn to the new thinking level. The route record keeps why the model was chosen first; the trace reads "Set on this ticket · one thinking level higher". Turns on a climbed model or a ticket's model do not count toward the Bot's inferred default.

Claude models on the ladder (ADR 0076): with your Claude Code installed and signed in, the ladder can also hold the Claude models Claude Code's own /model lists (sonnet, opus, haiku and fable when it cannot be asked), each rung with its own effort (default, low … max, the ones its model takes) and account (when several are listed); one model may take another rung at another effort, such as opus high and opus max. When a Bot on the app's own loop climbs to such a rung, its next turn is handed to your Claude Code on that rung's model, effort and account, run as a Claude Agent Bot's turns are; a rung above it on an endpoint takes it back to the app's own loop. Claude models see pictures, so picture work never skips them. A Claude Agent Bot's own Claude model is your pin and does not climb; trouble inside its turn is Claude Code's to handle and steps nothing up. Only you put a Claude model on the ladder: with update_model_settings a Bot can keep, move or drop the ones already there, never add one; an account a rung spends can be taken off the list only once that rung is gone or moved to another account.

Built-in models (ADR 0077): each model call the app makes on its own can be given a model, on the Roles page (Tools → Roles; ADR 0082, a page of its own rather than part of Settings since ADR 0083; ADR 0075 began this by giving the organizer, the scribe and the picture checks a model of their own, ADR 0077 gathered the nine calls on one page under Models, and ADR 0082 joined that page with these calls' prompts as Roles). At the top you pick which engine is shown (General, Video, Coding and yours, the default starred), make it the default, make a new one from it, or read its history; below, that engine is drawn as a map the way the flow is drawn: each thing that sets steps off is a filled card — "A line of yours", "A group line naming nobody", "A Bot's turn", "A hand-in", "You accept a delivery", "You overturn an approval", "You press ✨" — and the steps it sets off are small dashed cards hung under it on lines; when every round's steps fit across, each fans out in a row under its card, otherwise they all hang down a spine on the left. Each step card names its model (for one that calls a model; what it follows when none is chosen) or its first number; one that is off is faded and says so, one that always runs has a lock, one that differs from its built-in a dot, and a prompt conflict or unreadable answers turn the dot to the warning colour. On a wide window the map runs down the left and the picked step sits on the right, each scrolling on its own, so a pick only changes the right side and nothing jumps; ↑ and ↓ move between steps. Where it is narrow (a phone, or a narrow tab or the list's place in a wide window: under 720px of its own width) the map is a page of its own and a card opens as another; in a tab, which has no page head, that page starts with "Back to the map". The step's side shows what it does, whether it runs in this engine (a switch where it can be off, "Always runs" where it cannot), its numbers (each change saved at once as the engine's new revision, the built-in's value beside it, with "Back to built-in"), and for a step that calls a model, its model and the built-in prompts it runs with (four for reading, four for the picture judge, one each for the rest), each opening in the same prompt editor. With an older Mac that has no engines yet, the map is drawn with every step on and nothing to change. A Bot's turn is a dashed node: it runs on the Bot's own model and moves up the model ladder, with every turn's prompts; picking it shows the model ladder on the right, ordered right there (ADR 0082; it used to be under Models), while every turn's prompts stay on the Prompts page, linked from the node. Not on the page: the route pick and the route review and learning (not run from level 7 and level 8), speech recognition (a service and key of its own) and the speed test. A call can be an endpoint's model, a Claude model run through your own Claude Code (the Claude Agent group; with an account to pick when more than one is listed), or unset. Unset runs as before: the first three groups on the default endpoint's default model, the composer on the default endpoint's model whose name has flash, mini, lite or fast in it, and the four as-a-Bot calls on the Bot's own model (compaction on the turn's own), none of them with a thinking level named. Only a chosen model is told how hard to think, by what the call wants: the ones you wait on (reading, the composer, judgement) the lightest level; the frequent ones (the scribe, compaction) low, else the lightest level above none; the ones that read the whole and must judge well (the organizer, the picture judge, reflection, retrospective) high (when the model does not list high, the highest it lists up to high; when it lists only higher ones, the lightest of those). A Claude model runs the call once on your Claude Code, tool-free, one turn, on the account you picked; the level becomes Claude Code's effort — none named for the lightest, low and high as they are. Calls other than reading get three places of their own, apart from reading's two, so a long settle cannot hold up the reading of your next line; a call may take its old first-byte limit plus 180 s; it spends that Claude plan's usage, billed under the call's own kind and purpose and marked Claude Agent, at an estimated price. With Claude Code missing or signed out, an error or a timeout, each call handles the failure as it did before. A call that sends pictures sends them as image blocks of its one message; every Claude model reads them, so the picture judge on a Claude model always runs on it; with an endpoint's model, a judge about to send pictures (the sample's frames, the two sides of a seam) needs it marked "takes pictures" in its attributes, and unmarked or marked as not it uses the default model for that call, while a judge that only compares words is not held to this. The organizer reads the whole plan and writes it back, so pick a strong model for it: on Opus one settle is about 20k tokens in and 6k out, far more than a reading, and each plan settles again once it goes quiet; nothing is spent until you choose, and unchosen, nothing changes. When the endpoint stops listing the chosen model, or is deleted, the call reads as unset; the model back on the list is the choice again. An organizing model chosen before is copied once, on upgrade, to the scribe and the picture judge, each now changeable on its own; organizer_model now means the organizer alone. A call you changed (a model chosen or a prompt edited) is marked beside its node on the Roles map, in the warning colour when a prompt conflicts (Settings no longer has a Roles entry); the Prompts page keeps only the every-turn, Claude Agent and tool-description groups, with a line pointing to Roles (with an older Mac that does not yet tie prompts to calls, the app's own calls stay on Prompts as before). A Bot sees builtin_models in list_endpoints and can change it with update_model_settings, but only to an endpoint's model or none, never to your Claude model (that spends your plan), as with reading.

Setting up on Claude Code alone (ADR 0078): step 2 of the wizard can take "Claude Code on this computer" in place of an endpoint. It goes on only once a signed-in Claude Code is found; step 3 picks one of the Claude models Claude Code's own /model lists (sonnet by default) and the account, and saving puts every built-in call on it (ten today), creates no endpoint, and the Bots made at the last step are Claude Agents. A workspace plus the eight built-in calls other than compaction and steps of your own on Claude models completes the wizard (steps of your own follow the picture judge when unchosen, so adding them on 2026-11-04 sent nobody set up back through the wizard); with no endpoint, putting one of them back on the default brings the wizard back. Set up this way and with no usable endpoint, a new Bot made without saying what runs it is a Claude Agent on reading's account, a teammate a Bot hires with create_bot too; the new-Bot form starts on Claude Agent; an explicit app runner is honored, and once an endpoint is added nothing switches by itself. When other agents are found and signed in on this computer (Codex, Grok, …, ADR 0079), step 2 lists them beside Claude Code and picking one works the same way: step 3 picks its model, and the first Bot and the new Bots after it run on it. With no endpoint, judgements, reflections and retrospectives still run on the Claude model chosen; Bots on an endpoint, the model ladder, and learning memories and skills from a chain wait for an endpoint.

Avoid: provider catalog, a different model name for judgement, picking per turn, thinking level only ever chosen by the app, pinning a thinking level without a model, pinning a model without setting its thinking level, roster-wide shared routing experience, recognizing model feedback by keyword, one remark pinning a model forever, a scoring formula for model choice

Default model

From engine level 7, the model and thinking level a Bot runs on when you have not pinned one: the first time it is needed, what it ran on most in the last 7 days among the models the endpoints still list (at the thinking level it ran that model on most), and used from then on, with no card asking you (pin a model on the Bot to change it). A card put up before [Keep it] [Use the endpoint's default] still takes its buttons: declined, nothing is inferred again and the Bot runs on the endpoint's default. It replaces a model call picking before every turn. Details: Behavior · Model.

Behavior details

A completion name that a given endpoint recognizes. Each endpoint has its own list and its own default, and a name on the list can carry a routing reference price, an optional billing price, the thinking levels it supports, and what it is good at. The routing reference price is a relative number the app uses when it picks a model. The billing price is in USD per million tokens: input and output are set together, cached input can be set separately, and when left blank it uses the input price. The billing price is used to estimate spend when no reported amount is available; probing the model list does not fill in prices automatically. When the user's message starts a turn, the app picks the model and thinking level only from the list of the endpoint the Bot is pinned to (the default endpoint if it has none pinned); adding another endpoint in Settings does not bring its models into other Bots' choices. If the Bot has pinned a name that is still on that list, the model name is held to it; a pinned name that exists only on another endpoint is used as pinned. A Bot can also pin a thinking level (the completion's reasoning_effort): the level names follow that model's list (commonly none / low / medium / high, plus xhigh, max and so on when the endpoint advertises them). When probing /models, if an object carries thinking levels they are written into that model's thinking_levels automatically, and you can still edit them by hand in Settings. The thinking level is pinned together with the model and never exists on its own: either neither is pinned and the app picks both the model and the level for each message, or a model is pinned and its level is set along with it. Pinning a model without a level falls back to that model's default level (the app's order of preference for ordinary messages); switching to a model that doesn't support the current level falls back to the new model's default level; clearing the model clears the level with it; giving a level without a pinned model is rejected. You can change these with one click in the Bot panel, and a Bot can change its own with a tool. In your direct with it the composer's tool row can change them too, with the picker a project session has, opening a level at a time: Automatic and each endpoint first, an endpoint opening its models, a model its thinking levels; picking a level pins the model and the level together, and Automatic pins neither. Closed, it reads the pinned model and level, with the endpoint after them in smaller type when there is more than one. A Bot run by a local agent picks that agent's model and effort there (with the account first when Claude Code has more than one), as a project session does, from the levels that agent takes. Either way it is the Bot's own setting, the same as changing it in the Bot panel: it runs on it in groups and other conversations too. An empty pin does not mean "always use the endpoint's default model"; it means the app may pick from that endpoint's list. To use another endpoint, you must pin the endpoint explicitly. Who picks (below level 7; from level 7 see Default models below): each time a turn starts, an agent first picks once. It looks at the message, this Bot's profile, the candidate list, this Bot's recent review conclusions (each with the message and category it came from, ignored when they don't match) and recent examples that finished cleanly, and answers with a model, a thinking level and a one-sentence reason. The agent itself always runs on the default endpoint's default model; if it can't answer, or answers with something that doesn't exist, the choice falls back to rules, so the user is never stuck on model routing. Everything the user says afterward is kept verbatim (not filtered by keyword) and attached to the quoted turn, to the latest turn of the Bot that was @-mentioned, or to the latest visible turn in the session. Consecutive turns about the same thing form one correction chain. When the chain ends (the topic changes or things go quiet for a while), it is reviewed once; a turn with no follow-up is also reviewed once if the endpoint refused it, its reply was incomplete, or it hit at least two tool errors. The review looks at the whole chain plus what the turn actually did: was it the model falling short, the task itself being hard, or the request being unclear? Only a verdict that the model fell short is kept as this Bot's experience, together with which way to adjust: stronger / lighter / faster / cheaper. What is kept is a conclusion, not a score: there are no weights, offsets or caps. A conclusion that has been followed twice and still hasn't led to a cleaner result drops out of model routing, though its record stays. The experience belongs to the Bot itself and is deleted along with the Bot. What each turn chose, how it ended, how much it did and what feedback it received are all recorded. The user does not pick for each turn. The judgement call and the turn's completions use the same resolved result.

Default models (from level 7, and the default is level 8; ADR 0048): no model call picks what a turn runs on any more. It goes by a fixed order: the model you pinned on the Bot; with no pin, the Bot's default model; with no default, the endpoint's default. The thinking level is the pinned one, or, when the model does not offer it or none is pinned, the nearest it offers for this kind of message; a Bot pinned to an endpoint only chooses from that endpoint's list; a pin no endpoint lists any more runs on the endpoint's default, and you are told once; the pin stays, and once the model is listed again it is the pin again. The Bot panel shows it as "not listed" and saves other edits as usual. Before, taking a model off an endpoint's list in Settings wiped every pin on it on the spot, with nothing said: on 2026-10-03 that moved both video Bots off claude-opus. Below level 7 the pin still goes with the list. A default is set the first time it is needed: what the Bot ran on most in the last 7 days among the models the endpoints still list (a renamed or removed one does not count), at the thinking level it ran that model on most, and it is used from then on with no card asking you: pin a model on the Bot to change it (from 2026-10-04; until then a card in your direct with it said so — "runs on X (thinking Y) from now on: what it ran on most in the last 7 days (N turns)" [Keep it] [Use the endpoint's default] — with a "waiting for your answer" notification, one for each of four Bots on 2026-10-03, the day level 7 went on: asking about nothing you had to decide, used whether you answered or not). The work log records model.default_inferred. Cards already out still take their buttons: declined, nothing is inferred again. On the board a ticket can also be given a model, ahead of the pin and the default (ticket_override), for its owner's turns only; the Bot reviewing it keeps its own. The model may be an endpoint's or one of your local agents' (ADR 0079): the ticket's model decides who does it — an agent's runs those turns on that agent, as a ladder rung does; an endpoint's runs them in the app's own loop, even for a Bot that usually runs on an agent. Each turn's route record carries the reason: ticket_override, pin, default, endpoint_default, pin_unlisted, capability_filter or escalation. Reviews and learning go on as before, until level 8 replaces them with quality events and lessons.

Pictures and stepping up (from level 7; ADR 0049): a model can be marked in the endpoint settings as taking pictures, taking none, or not sure (counted as taking them). When a turn is opened by a line with a picture, or the Bot reviews a ticket with a requirement about the picture, and the model picked is marked as taking none: a pin stays and you are told once; otherwise it moves to a model marked as taking pictures (capability_filter). A picture read mid-turn is not sent to a model that takes none; the tool result says so. A job whose hand-overs failed twice in a row since its last step runs one thinking level higher (escalation), up to its model's top, and resets once the ticket is approved; a thinking level you pinned is not raised, nor one on a model measured to gain nothing from it.

The model ladder and stepping up inside a turn (from level 7; ADR 0054): in Tools → Roles → A Bot's turn you can order a few models weaker to stronger as a ladder (at most 8). When the thinking levels are used up (or the model is measured to gain nothing from them) and a job needs more, its next turn moves one model up the ladder (escalation_model), past rungs no endpoint lists any more and, for work that needs pictures, rungs marked as taking none; asking for more past the last rung stays there and you are told once. Only a model the app chose for the Bot moves along the ladder; your pin and a ticket's model only step up their thinking level; with no ladder, or a model not on it, you are told once at the top. Besides failed hand-overs, a reply that fails again after its retry, tool arguments that are not JSON twice in a row, and the same tool called wrongly three times in a row (the model's own mistakes, like bad arguments or a refused call made anyway; a missing file, a timeout or an MCP server's error do not count) each step the job up — at most once between two hand-overs, and only in thinking level, never along the ladder; the last two switch the rest of that turn to the new thinking level. The route record keeps why the model was chosen first; the trace reads "Set on this ticket · one thinking level higher". Turns on a climbed model or a ticket's model do not count toward the Bot's inferred default.

Claude models on the ladder (ADR 0076): with your Claude Code installed and signed in, the ladder can also hold the Claude models Claude Code's own /model lists (sonnet, opus, haiku and fable when it cannot be asked), each rung with its own effort (default, low … max, the ones its model takes) and account (when several are listed); one model may take another rung at another effort, such as opus high and opus max. When a Bot on the app's own loop climbs to such a rung, its next turn is handed to your Claude Code on that rung's model, effort and account, run as a Claude Agent Bot's turns are; a rung above it on an endpoint takes it back to the app's own loop. Claude models see pictures, so picture work never skips them. A Claude Agent Bot's own Claude model is your pin and does not climb; trouble inside its turn is Claude Code's to handle and steps nothing up. Only you put a Claude model on the ladder: with update_model_settings a Bot can keep, move or drop the ones already there, never add one; an account a rung spends can be taken off the list only once that rung is gone or moved to another account.

Built-in models (ADR 0077): each model call the app makes on its own can be given a model, on the Roles page (Tools → Roles; ADR 0082, a page of its own rather than part of Settings since ADR 0083; ADR 0075 began this by giving the organizer, the scribe and the picture checks a model of their own, ADR 0077 gathered the nine calls on one page under Models, and ADR 0082 joined that page with these calls' prompts as Roles). At the top you pick which engine is shown (General, Video, Coding and yours, the default starred), make it the default, make a new one from it, or read its history; below, that engine is drawn as a map the way the flow is drawn: each thing that sets steps off is a filled card — "A line of yours", "A group line naming nobody", "A Bot's turn", "A hand-in", "You accept a delivery", "You overturn an approval", "You press ✨" — and the steps it sets off are small dashed cards hung under it on lines; when every round's steps fit across, each fans out in a row under its card, otherwise they all hang down a spine on the left. Each step card names its model (for one that calls a model; what it follows when none is chosen) or its first number; one that is off is faded and says so, one that always runs has a lock, one that differs from its built-in a dot, and a prompt conflict or unreadable answers turn the dot to the warning colour. On a wide window the map runs down the left and the picked step sits on the right, each scrolling on its own, so a pick only changes the right side and nothing jumps; ↑ and ↓ move between steps. Where it is narrow (a phone, or a narrow tab or the list's place in a wide window: under 720px of its own width) the map is a page of its own and a card opens as another; in a tab, which has no page head, that page starts with "Back to the map". The step's side shows what it does, whether it runs in this engine (a switch where it can be off, "Always runs" where it cannot), its numbers (each change saved at once as the engine's new revision, the built-in's value beside it, with "Back to built-in"), and for a step that calls a model, its model and the built-in prompts it runs with (four for reading, four for the picture judge, one each for the rest), each opening in the same prompt editor. With an older Mac that has no engines yet, the map is drawn with every step on and nothing to change. A Bot's turn is a dashed node: it runs on the Bot's own model and moves up the model ladder, with every turn's prompts; picking it shows the model ladder on the right, ordered right there (ADR 0082; it used to be under Models), while every turn's prompts stay on the Prompts page, linked from the node. Not on the page: the route pick and the route review and learning (not run from level 7 and level 8), speech recognition (a service and key of its own) and the speed test. A call can be an endpoint's model, a Claude model run through your own Claude Code (the Claude Agent group; with an account to pick when more than one is listed), or unset. Unset runs as before: the first three groups on the default endpoint's default model, the composer on the default endpoint's model whose name has flash, mini, lite or fast in it, and the four as-a-Bot calls on the Bot's own model (compaction on the turn's own), none of them with a thinking level named. Only a chosen model is told how hard to think, by what the call wants: the ones you wait on (reading, the composer, judgement) the lightest level; the frequent ones (the scribe, compaction) low, else the lightest level above none; the ones that read the whole and must judge well (the organizer, the picture judge, reflection, retrospective) high (when the model does not list high, the highest it lists up to high; when it lists only higher ones, the lightest of those). A Claude model runs the call once on your Claude Code, tool-free, one turn, on the account you picked; the level becomes Claude Code's effort — none named for the lightest, low and high as they are. Calls other than reading get three places of their own, apart from reading's two, so a long settle cannot hold up the reading of your next line; a call may take its old first-byte limit plus 180 s; it spends that Claude plan's usage, billed under the call's own kind and purpose and marked Claude Agent, at an estimated price. With Claude Code missing or signed out, an error or a timeout, each call handles the failure as it did before. A call that sends pictures sends them as image blocks of its one message; every Claude model reads them, so the picture judge on a Claude model always runs on it; with an endpoint's model, a judge about to send pictures (the sample's frames, the two sides of a seam) needs it marked "takes pictures" in its attributes, and unmarked or marked as not it uses the default model for that call, while a judge that only compares words is not held to this. The organizer reads the whole plan and writes it back, so pick a strong model for it: on Opus one settle is about 20k tokens in and 6k out, far more than a reading, and each plan settles again once it goes quiet; nothing is spent until you choose, and unchosen, nothing changes. When the endpoint stops listing the chosen model, or is deleted, the call reads as unset; the model back on the list is the choice again. An organizing model chosen before is copied once, on upgrade, to the scribe and the picture judge, each now changeable on its own; organizer_model now means the organizer alone. A call you changed (a model chosen or a prompt edited) is marked beside its node on the Roles map, in the warning colour when a prompt conflicts (Settings no longer has a Roles entry); the Prompts page keeps only the every-turn, Claude Agent and tool-description groups, with a line pointing to Roles (with an older Mac that does not yet tie prompts to calls, the app's own calls stay on Prompts as before). A Bot sees builtin_models in list_endpoints and can change it with update_model_settings, but only to an endpoint's model or none, never to your Claude model (that spends your plan), as with reading.

Setting up on Claude Code alone (ADR 0078): step 2 of the wizard can take "Claude Code on this computer" in place of an endpoint. It goes on only once a signed-in Claude Code is found; step 3 picks one of the Claude models Claude Code's own /model lists (sonnet by default) and the account, and saving puts every built-in call on it (ten today), creates no endpoint, and the Bots made at the last step are Claude Agents. A workspace plus the eight built-in calls other than compaction and steps of your own on Claude models completes the wizard (steps of your own follow the picture judge when unchosen, so adding them on 2026-11-04 sent nobody set up back through the wizard); with no endpoint, putting one of them back on the default brings the wizard back. Set up this way and with no usable endpoint, a new Bot made without saying what runs it is a Claude Agent on reading's account, a teammate a Bot hires with create_bot too; the new-Bot form starts on Claude Agent; an explicit app runner is honored, and once an endpoint is added nothing switches by itself. When other agents are found and signed in on this computer (Codex, Grok, …, ADR 0079), step 2 lists them beside Claude Code and picking one works the same way: step 3 picks its model, and the first Bot and the new Bots after it run on it. With no endpoint, judgements, reflections and retrospectives still run on the Claude model chosen; Bots on an endpoint, the model ladder, and learning memories and skills from a chain wait for an endpoint.

Avoid: picking again every turn, a card asking you about a default that is not yours to decide, a default that was renamed or removed from the list

Built-in models

The model chosen on its own for each call the app makes on its own: reading, the organizer, the scribe, the picture judge, the composer, and, as a Bot, joining in, reflection, retrospective and compaction (ADR 0075, ADR 0077). They are on the Roles page (ADR 0082; a page of its own under Tools since ADR 0083, not in Settings): a map draws the nine calls and the Bot's own turn by when they run, and opening a call sets its model and the built-in prompts it runs with in one place. Each can be an endpoint's model or a Claude model run through your own Claude Code; with none chosen a call runs as before (the default model, the composer on the default endpoint's flash, mini, lite or fast model, the as-a-Bot calls on the Bot's own model). Only a chosen model is told how hard to think: the lightest for the ones you wait on, low for the scribe and compaction, high for the organizer, the picture judge, reflection and retrospective. The organizer reads the whole plan and writes it back, so pick a strong model for it: on Opus one settle is about 20k tokens in and 6k out; a picture judge on an endpoint's model uses it only when it is marked as taking pictures, and the default model otherwise (every Claude model takes pictures). A Claude model spends your Claude plan's usage, billed under the same kind and purpose as before; a Bot can move these only to an endpoint's model or to none. Details: Behavior · Model.

Behavior details

A completion name that a given endpoint recognizes. Each endpoint has its own list and its own default, and a name on the list can carry a routing reference price, an optional billing price, the thinking levels it supports, and what it is good at. The routing reference price is a relative number the app uses when it picks a model. The billing price is in USD per million tokens: input and output are set together, cached input can be set separately, and when left blank it uses the input price. The billing price is used to estimate spend when no reported amount is available; probing the model list does not fill in prices automatically. When the user's message starts a turn, the app picks the model and thinking level only from the list of the endpoint the Bot is pinned to (the default endpoint if it has none pinned); adding another endpoint in Settings does not bring its models into other Bots' choices. If the Bot has pinned a name that is still on that list, the model name is held to it; a pinned name that exists only on another endpoint is used as pinned. A Bot can also pin a thinking level (the completion's reasoning_effort): the level names follow that model's list (commonly none / low / medium / high, plus xhigh, max and so on when the endpoint advertises them). When probing /models, if an object carries thinking levels they are written into that model's thinking_levels automatically, and you can still edit them by hand in Settings. The thinking level is pinned together with the model and never exists on its own: either neither is pinned and the app picks both the model and the level for each message, or a model is pinned and its level is set along with it. Pinning a model without a level falls back to that model's default level (the app's order of preference for ordinary messages); switching to a model that doesn't support the current level falls back to the new model's default level; clearing the model clears the level with it; giving a level without a pinned model is rejected. You can change these with one click in the Bot panel, and a Bot can change its own with a tool. In your direct with it the composer's tool row can change them too, with the picker a project session has, opening a level at a time: Automatic and each endpoint first, an endpoint opening its models, a model its thinking levels; picking a level pins the model and the level together, and Automatic pins neither. Closed, it reads the pinned model and level, with the endpoint after them in smaller type when there is more than one. A Bot run by a local agent picks that agent's model and effort there (with the account first when Claude Code has more than one), as a project session does, from the levels that agent takes. Either way it is the Bot's own setting, the same as changing it in the Bot panel: it runs on it in groups and other conversations too. An empty pin does not mean "always use the endpoint's default model"; it means the app may pick from that endpoint's list. To use another endpoint, you must pin the endpoint explicitly. Who picks (below level 7; from level 7 see Default models below): each time a turn starts, an agent first picks once. It looks at the message, this Bot's profile, the candidate list, this Bot's recent review conclusions (each with the message and category it came from, ignored when they don't match) and recent examples that finished cleanly, and answers with a model, a thinking level and a one-sentence reason. The agent itself always runs on the default endpoint's default model; if it can't answer, or answers with something that doesn't exist, the choice falls back to rules, so the user is never stuck on model routing. Everything the user says afterward is kept verbatim (not filtered by keyword) and attached to the quoted turn, to the latest turn of the Bot that was @-mentioned, or to the latest visible turn in the session. Consecutive turns about the same thing form one correction chain. When the chain ends (the topic changes or things go quiet for a while), it is reviewed once; a turn with no follow-up is also reviewed once if the endpoint refused it, its reply was incomplete, or it hit at least two tool errors. The review looks at the whole chain plus what the turn actually did: was it the model falling short, the task itself being hard, or the request being unclear? Only a verdict that the model fell short is kept as this Bot's experience, together with which way to adjust: stronger / lighter / faster / cheaper. What is kept is a conclusion, not a score: there are no weights, offsets or caps. A conclusion that has been followed twice and still hasn't led to a cleaner result drops out of model routing, though its record stays. The experience belongs to the Bot itself and is deleted along with the Bot. What each turn chose, how it ended, how much it did and what feedback it received are all recorded. The user does not pick for each turn. The judgement call and the turn's completions use the same resolved result.

Default models (from level 7, and the default is level 8; ADR 0048): no model call picks what a turn runs on any more. It goes by a fixed order: the model you pinned on the Bot; with no pin, the Bot's default model; with no default, the endpoint's default. The thinking level is the pinned one, or, when the model does not offer it or none is pinned, the nearest it offers for this kind of message; a Bot pinned to an endpoint only chooses from that endpoint's list; a pin no endpoint lists any more runs on the endpoint's default, and you are told once; the pin stays, and once the model is listed again it is the pin again. The Bot panel shows it as "not listed" and saves other edits as usual. Before, taking a model off an endpoint's list in Settings wiped every pin on it on the spot, with nothing said: on 2026-10-03 that moved both video Bots off claude-opus. Below level 7 the pin still goes with the list. A default is set the first time it is needed: what the Bot ran on most in the last 7 days among the models the endpoints still list (a renamed or removed one does not count), at the thinking level it ran that model on most, and it is used from then on with no card asking you: pin a model on the Bot to change it (from 2026-10-04; until then a card in your direct with it said so — "runs on X (thinking Y) from now on: what it ran on most in the last 7 days (N turns)" [Keep it] [Use the endpoint's default] — with a "waiting for your answer" notification, one for each of four Bots on 2026-10-03, the day level 7 went on: asking about nothing you had to decide, used whether you answered or not). The work log records model.default_inferred. Cards already out still take their buttons: declined, nothing is inferred again. On the board a ticket can also be given a model, ahead of the pin and the default (ticket_override), for its owner's turns only; the Bot reviewing it keeps its own. The model may be an endpoint's or one of your local agents' (ADR 0079): the ticket's model decides who does it — an agent's runs those turns on that agent, as a ladder rung does; an endpoint's runs them in the app's own loop, even for a Bot that usually runs on an agent. Each turn's route record carries the reason: ticket_override, pin, default, endpoint_default, pin_unlisted, capability_filter or escalation. Reviews and learning go on as before, until level 8 replaces them with quality events and lessons.

Pictures and stepping up (from level 7; ADR 0049): a model can be marked in the endpoint settings as taking pictures, taking none, or not sure (counted as taking them). When a turn is opened by a line with a picture, or the Bot reviews a ticket with a requirement about the picture, and the model picked is marked as taking none: a pin stays and you are told once; otherwise it moves to a model marked as taking pictures (capability_filter). A picture read mid-turn is not sent to a model that takes none; the tool result says so. A job whose hand-overs failed twice in a row since its last step runs one thinking level higher (escalation), up to its model's top, and resets once the ticket is approved; a thinking level you pinned is not raised, nor one on a model measured to gain nothing from it.

The model ladder and stepping up inside a turn (from level 7; ADR 0054): in Tools → Roles → A Bot's turn you can order a few models weaker to stronger as a ladder (at most 8). When the thinking levels are used up (or the model is measured to gain nothing from them) and a job needs more, its next turn moves one model up the ladder (escalation_model), past rungs no endpoint lists any more and, for work that needs pictures, rungs marked as taking none; asking for more past the last rung stays there and you are told once. Only a model the app chose for the Bot moves along the ladder; your pin and a ticket's model only step up their thinking level; with no ladder, or a model not on it, you are told once at the top. Besides failed hand-overs, a reply that fails again after its retry, tool arguments that are not JSON twice in a row, and the same tool called wrongly three times in a row (the model's own mistakes, like bad arguments or a refused call made anyway; a missing file, a timeout or an MCP server's error do not count) each step the job up — at most once between two hand-overs, and only in thinking level, never along the ladder; the last two switch the rest of that turn to the new thinking level. The route record keeps why the model was chosen first; the trace reads "Set on this ticket · one thinking level higher". Turns on a climbed model or a ticket's model do not count toward the Bot's inferred default.

Claude models on the ladder (ADR 0076): with your Claude Code installed and signed in, the ladder can also hold the Claude models Claude Code's own /model lists (sonnet, opus, haiku and fable when it cannot be asked), each rung with its own effort (default, low … max, the ones its model takes) and account (when several are listed); one model may take another rung at another effort, such as opus high and opus max. When a Bot on the app's own loop climbs to such a rung, its next turn is handed to your Claude Code on that rung's model, effort and account, run as a Claude Agent Bot's turns are; a rung above it on an endpoint takes it back to the app's own loop. Claude models see pictures, so picture work never skips them. A Claude Agent Bot's own Claude model is your pin and does not climb; trouble inside its turn is Claude Code's to handle and steps nothing up. Only you put a Claude model on the ladder: with update_model_settings a Bot can keep, move or drop the ones already there, never add one; an account a rung spends can be taken off the list only once that rung is gone or moved to another account.

Built-in models (ADR 0077): each model call the app makes on its own can be given a model, on the Roles page (Tools → Roles; ADR 0082, a page of its own rather than part of Settings since ADR 0083; ADR 0075 began this by giving the organizer, the scribe and the picture checks a model of their own, ADR 0077 gathered the nine calls on one page under Models, and ADR 0082 joined that page with these calls' prompts as Roles). At the top you pick which engine is shown (General, Video, Coding and yours, the default starred), make it the default, make a new one from it, or read its history; below, that engine is drawn as a map the way the flow is drawn: each thing that sets steps off is a filled card — "A line of yours", "A group line naming nobody", "A Bot's turn", "A hand-in", "You accept a delivery", "You overturn an approval", "You press ✨" — and the steps it sets off are small dashed cards hung under it on lines; when every round's steps fit across, each fans out in a row under its card, otherwise they all hang down a spine on the left. Each step card names its model (for one that calls a model; what it follows when none is chosen) or its first number; one that is off is faded and says so, one that always runs has a lock, one that differs from its built-in a dot, and a prompt conflict or unreadable answers turn the dot to the warning colour. On a wide window the map runs down the left and the picked step sits on the right, each scrolling on its own, so a pick only changes the right side and nothing jumps; ↑ and ↓ move between steps. Where it is narrow (a phone, or a narrow tab or the list's place in a wide window: under 720px of its own width) the map is a page of its own and a card opens as another; in a tab, which has no page head, that page starts with "Back to the map". The step's side shows what it does, whether it runs in this engine (a switch where it can be off, "Always runs" where it cannot), its numbers (each change saved at once as the engine's new revision, the built-in's value beside it, with "Back to built-in"), and for a step that calls a model, its model and the built-in prompts it runs with (four for reading, four for the picture judge, one each for the rest), each opening in the same prompt editor. With an older Mac that has no engines yet, the map is drawn with every step on and nothing to change. A Bot's turn is a dashed node: it runs on the Bot's own model and moves up the model ladder, with every turn's prompts; picking it shows the model ladder on the right, ordered right there (ADR 0082; it used to be under Models), while every turn's prompts stay on the Prompts page, linked from the node. Not on the page: the route pick and the route review and learning (not run from level 7 and level 8), speech recognition (a service and key of its own) and the speed test. A call can be an endpoint's model, a Claude model run through your own Claude Code (the Claude Agent group; with an account to pick when more than one is listed), or unset. Unset runs as before: the first three groups on the default endpoint's default model, the composer on the default endpoint's model whose name has flash, mini, lite or fast in it, and the four as-a-Bot calls on the Bot's own model (compaction on the turn's own), none of them with a thinking level named. Only a chosen model is told how hard to think, by what the call wants: the ones you wait on (reading, the composer, judgement) the lightest level; the frequent ones (the scribe, compaction) low, else the lightest level above none; the ones that read the whole and must judge well (the organizer, the picture judge, reflection, retrospective) high (when the model does not list high, the highest it lists up to high; when it lists only higher ones, the lightest of those). A Claude model runs the call once on your Claude Code, tool-free, one turn, on the account you picked; the level becomes Claude Code's effort — none named for the lightest, low and high as they are. Calls other than reading get three places of their own, apart from reading's two, so a long settle cannot hold up the reading of your next line; a call may take its old first-byte limit plus 180 s; it spends that Claude plan's usage, billed under the call's own kind and purpose and marked Claude Agent, at an estimated price. With Claude Code missing or signed out, an error or a timeout, each call handles the failure as it did before. A call that sends pictures sends them as image blocks of its one message; every Claude model reads them, so the picture judge on a Claude model always runs on it; with an endpoint's model, a judge about to send pictures (the sample's frames, the two sides of a seam) needs it marked "takes pictures" in its attributes, and unmarked or marked as not it uses the default model for that call, while a judge that only compares words is not held to this. The organizer reads the whole plan and writes it back, so pick a strong model for it: on Opus one settle is about 20k tokens in and 6k out, far more than a reading, and each plan settles again once it goes quiet; nothing is spent until you choose, and unchosen, nothing changes. When the endpoint stops listing the chosen model, or is deleted, the call reads as unset; the model back on the list is the choice again. An organizing model chosen before is copied once, on upgrade, to the scribe and the picture judge, each now changeable on its own; organizer_model now means the organizer alone. A call you changed (a model chosen or a prompt edited) is marked beside its node on the Roles map, in the warning colour when a prompt conflicts (Settings no longer has a Roles entry); the Prompts page keeps only the every-turn, Claude Agent and tool-description groups, with a line pointing to Roles (with an older Mac that does not yet tie prompts to calls, the app's own calls stay on Prompts as before). A Bot sees builtin_models in list_endpoints and can change it with update_model_settings, but only to an endpoint's model or none, never to your Claude model (that spends your plan), as with reading.

Setting up on Claude Code alone (ADR 0078): step 2 of the wizard can take "Claude Code on this computer" in place of an endpoint. It goes on only once a signed-in Claude Code is found; step 3 picks one of the Claude models Claude Code's own /model lists (sonnet by default) and the account, and saving puts every built-in call on it (ten today), creates no endpoint, and the Bots made at the last step are Claude Agents. A workspace plus the eight built-in calls other than compaction and steps of your own on Claude models completes the wizard (steps of your own follow the picture judge when unchosen, so adding them on 2026-11-04 sent nobody set up back through the wizard); with no endpoint, putting one of them back on the default brings the wizard back. Set up this way and with no usable endpoint, a new Bot made without saying what runs it is a Claude Agent on reading's account, a teammate a Bot hires with create_bot too; the new-Bot form starts on Claude Agent; an explicit app runner is honored, and once an endpoint is added nothing switches by itself. When other agents are found and signed in on this computer (Codex, Grok, …, ADR 0079), step 2 lists them beside Claude Code and picking one works the same way: step 3 picks its model, and the first Bot and the new Bots after it run on it. With no endpoint, judgements, reflections and retrospectives still run on the Claude model chosen; Bots on an endpoint, the model ladder, and learning memories and skills from a chain wait for an endpoint.

Avoid: a built-in call that can only follow the default model with no way to name its own, a model that cannot see pictures judging against a sample, the scribe at the highest thinking level, the reading model taken for the organizer's, a Bot moving a built-in call onto your Claude model

Engine

How the app wraps a conversation: whether it works in jobs (jobs: filing, plans and tickets, work dirs, the end contract, delegation, hand-overs and reviews, large jobs and the supervisor, on and off together), whether the scribe, the closing check, the settle, escalation, retrospective, reflection, waiting on your word, laying large jobs out first, the capability ceiling, the supervisor's pick-ups and checks from your words run, and the numbers for the intake ceiling, hop pacing, the settle's quiet time, check-back spacing and count, the supervisor's pick-ups and the capability ceiling, and it can carry a System section of its own, offer fewer tools, and add steps of your own at the moments the app already has (before or after a call, as a turn ends, on a hand-in, after an approval, after you send work back), judged by a rule, a command or a model, a "no" doing only what that moment's fixed list allows (ADR 0085, ADR 0103, ADR 0105). A floor is not in it: your lines in order, Stop and holds, permission modes and approvals, the spend ledger and cap, compaction. Steps standing on jobs stop with it; reading can be off only while jobs is, since an approval reads your words. Four are built in: General (the default: no scribe or reflection), Video and Coding are three templates of one way of working; Plain leaves it out: your lines open no job, Bots just work, and whether it is done is yours to judge. What you change keeps only what differs from the built-in, each change is a revision, and you can make your own from any of them. A call about a job runs under the engine of the job's conversation, any other under its own conversation's, else Settings' default. Seen and changed on Roles, drawn like the flow; a conversation's is chosen in a group's settings or a Bot's Actions in your direct. Not the engine level (engine_level, see Schema gate). Details: Behavior · Engine.

Behavior details

ADR 0085, ADR 0103. How the app wraps a conversation: a floor (your lines taken in order, Stop and holds, permission modes and approval cards, the spend ledger and daily cap, compaction, output caps and repeat guards, your words kept) is code; whether it works in jobs, the steps hung on them and their numbers are the engine. Not the engine level (engine_level, see the glossary's Schema gate): that is how far a data folder has been migrated, the engine is how you choose to run.

Steps (PLAYBOOK_STEPS, by where they hang):

Where Step Can be off Numbers (default)
Your line Intake ceiling no waits at most 45 s for the line ahead
Reading only while Jobs is off —
Jobs (jobs) yes —
Scribe yes at most 8 entries per line
Checks from your words yes —
Large jobs laid out first yes —
A group line naming nobody Judgement yes —
A Bot's turn Hop pacing yes asked how it is going every 40 hops (only asked; the tools stay)
Compaction no —
Closing check yes —
Settle yes a job quiet 30 s before it is filed
A Bot's own check-backs no at least 5 minutes, at most six an hour per job
Supervisor pick-ups yes called back after 2 minutes left alone, at most three pick-ups an hour per job
A hand-in Acceptance checks and the picture judge no —
Waiting on your word yes —
Escalation yes one step up after 2 failures in a row
Capability ceiling yes the same one 3 times running, or more than 6 failures
A delivery you accept Retrospective yes —
An approval you overturn Reflection yes —
You press ✨ Composer no —

The scribe, checks from your words, laying large jobs out first, the closing check, the settle, the supervisor's pick-ups, the acceptance checks, waiting on your word, escalation, the capability ceiling, the retrospective and reflection all stand on Jobs: off with it, your settings kept for when it comes back. A step that cannot be off would, with Jobs on, break the kernel: with the acceptance checks not running, a hand-over bound to a check of yours would wait for good; with reading off, so would one waiting on your word. The models and prompts of reading, judgement, compaction, the composer, the picture judge, the settle, the scribe, reflection and retrospective stay global and are set on the same map (Built-in models, Built-in prompts). Numbers are whole and ranged (the settle's quiet from 10 to 600 s, say). A turn may call tools for as many hops as it needs (since 2026-10-17; before, the tools went at 160 hops, 200 on video, and a limit you saved is passed over when read). The benchmark's switches (ablation) still apply and win over an engine.

The four built in (the first three are templates of one way of working, tuned on the conversations up to 2026-10-11; numbers in ADR 0085):

  • General (the default): no scribe, no reflection — nothing written down or proposed behind your back; the rest at the defaults, the retrospective included (from 2026-10-14: Bots improving their own memories and skills after a delivery is part of what the app promises). The settle stays: it keeps a job's board true. With the scribe off, only a line finding fault with work already handed over is still kept, as a proposed entry (the fallback the scribe has when it reads nothing).
  • Video: the scribe stays; the settle waits 60 s so a fan-out of shots is filed once; a Bot's own check-backs are at least 15 minutes apart, at most three an hour; no escalation; more than 5 failed hand-overs stop and ask you.
  • Coding: no scribe; the rest at the defaults.
  • Plain (自由): not this way of working, only the floor. Jobs and hop pacing are off; reading and judgement are on.


An engine with no jobs (Jobs off, as in Plain): a conversation's lines never open a job. Nothing reads which job a line is about, and neither a quote nor a path files it under one; every turn is at the desk with no job bound, a first effect opens none, and the shell starts at the workspace root. A Bot is not offered work_on, delegate, submit, review or plan_items, and is refused if it calls them; the System section is the same text less what only holds in a job, the situation block has no desk text and always names the workspace root; your edits of the System section and the agent preface were written for the jobs and stay out, other prompts hold. An ending does not read the Bot's words or weigh obligations and promises, progress lines are not counted, and a question asking your OK goes through; one thing stays: your line in your direct left without a word goes back once, then you are told. There are no plans, tickets, hand-overs, reviews, jobs on the flow or supervisor, and whether it is done is yours to judge. Stops are as ever: typing stop stops it (in an engine with reading off too, only the Stop button does), and approval cards, permission modes and the spend cap hold. A routine still fires, as a turn with no job and no standing plan. Check-backs can be booked and ring. A direct a Bot opened still calls it back when it goes quiet.

Rules that can go alone while Jobs is on: only those where the way of going on without them already runs. Work items, the end contract and hand-overs are one whole and do not come apart. Waiting on your word off: hand-overs go as a routine's do, through once their gates pass; a fault you find still sends one back, and so does a reviewer. Large jobs off: a job's size is not read, nothing generated or handed over is refused, and whether to lay out or have a sample is up to the lead. The ceiling off: work goes on trying without stopping to ask. Pick-ups off: work cut off waits for your Continue and a ticket left alone is not chased, while hand-overs' checks and approvals and the restart repairs still run. Checks from your words off: nothing new is offered, and what you confirmed goes on being measured.

An engine's own System section and tools: on Roles, open "A Bot's turn" to write a System section for this engine alone (starting from the one it reads now), kept by language and all yours: no update changes it or merges anything into it, and Back to built-in returns to the other. What a Bot reads is the engine's own, then the one for no jobs (where there are none) or your global edit, then what ships. It is checked as an edit of a built-in prompt is (GET /v1/playbooks/:id/system reads what is in force). In the same place, groups of tools can be switched off: the roster and conversations, routines, endpoints, models and MCP, prompts and records. A group switched off is not offered, is refused if called, and the paragraph about it goes from the shipped text; what you wrote yourself stays. Files, speaking, a profile, skills, memory and annotations are always there, and plans and hand-overs go with Jobs. All of it is in the engine's difference with its revisions, and goes along when you build a new engine on it.


Steps of your own (ADR 0105): an engine can also hang steps of your own on the moments the app already has, at most 12, kept in its difference with its revisions and taken along when you build on it. On Roles they come after the built-in steps of their round, marked as yours, their second line the moment and what a "no" does; each round's "+ Add a step" opens starter templates (leave .env alone, lint TypeScript after writing, run the tests before ending, probe handed-in videos, check the reply against your rules) and a blank step, each a draft switched off until you save it.

Moment What a "no" can do Default timeout (max) Needs jobs
Before a call (a write, a delete, a command, an MCP tool) refuse the call, the reason to the Bot; or let it through with the output beside it 10 s (60) no
After a call beside the call's result, to the Bot 10 s (60) no
As a turn ends (an ending that says done or answered) send it back to go on; or tell you 120 s (600) no
On a hand-in sent back as a failed check would, counting towards the ceiling 120 s (600), in the checks' lane yes
After approval (yours, a reviewing Bot's, or the app's on its checks) tell you 120 s (600), on the scheduler's next tick, in the background yes
After you send work back (an approved one included) tell you as above yes

How it judges: a rule only matches, and a match is a no; a command passes on exit 0 and otherwise fails with its output's tail as the reason, run in the workspace (the root by default, or a folder you set) with the acceptance checks' clean environment, reading a JSON of what happened on stdin (the moment, the call, its paths, the reply, the files handed in, the conversation and Bot) and DESKFOLK_EVENT, DESKFOLK_STEP, DESKFOLK_PATHS (one a line), DESKFOLK_COMMAND and DESKFOLK_WORKSPACE; one that reaches outside the workspace does not run; a model is asked whether what happened keeps your rule and why, on the model of the Steps of your own call on Roles (else the picture judge's), billed as step. What a step looks at is only kinds of tool (around a call) and path globs relative to the workspace: around a call its files, as a turn ends the files it wrote, on a hand-in and after it the files handed in; anything about what words say is a model step's, never a word list. A step that cannot judge (timed out, would not start, a model that did not answer or whose answer could not be read) lets things through and shows on the flow as an error. A send-back as a turn ends shares the segment's two with the end contract; with none left the turn ends as it would and you are told which step still failed; a reply about to be sent back goes out first, and the Bot hears it after. Telling you is a line in the conversation that no Bot reads. A hand-in step can hold a hand-over back and is not counted as a check of yours, so it never lets through one nobody else stands behind. A refusal before a call is step_refused, no failure of the turn. An external agent's calls the app only hears of afterwards have no "before"; only a step after a call sees them. In an engine with no jobs, the steps that need jobs are drawn faded with why, their settings kept. The panel's "Try it on a sample" (POST /v1/playbooks/:id/custom-steps/try) refuses, sends back and tells nothing and puts nothing on the flow; what you leave out of the sample is the newest of its kind, and a model step's try is billed. Each judgement is a call_runs row (role = custom_step, with custom_step, and submission_id on a hand-in); the flow folds a step's runs under one card and counts a "no" as gone wrong. Your phone can add and change them too, as it can command checks.

Moving between engines: a job already open stops where it is, woken by nothing, deleted by nothing, taking no new lines, and a line elsewhere citing it is not filed under it; the supervisor passes over it and the work log says no_jobs; an appointment on it stays due, not voided, and rings once you move back; a turn already running finishes. Moving a conversation with open jobs, or the default, to an engine with none says first what it would leave standing (GET /v1/playbooks/impact). The job's page says why it stands still.

Changing and making your own: a change is to one engine and keeps only what differs from its built-in (playbooks.diff); a field you never touched follows a new default, and "differs from built-in" and resetting a step come straight from it. Every change is an append-only revision (playbook_revisions: before, after, who), numbered; when two windows change it at once, the later is refused and asks you to reload. Any engine can be the base of one of your own, which you name, rename and remove; it cannot be removed while it is the default, and conversations using it go back to the default. On a wide window all of this is done in the engine list down the left of Roles, kept like the conversation list: one row per engine (its name, the default starred, when it last changed, a line about it), the one shown tinted, its map to the right. The list's + makes a new one from the engine shown; a right-click on a row, or its ⋯, has make default, new from this, rename, history and remove. Naming and renaming happen in the row itself (Enter keeps, Escape drops), removing asks first, and the history shows beside the map where the picked step was. Narrow (a phone, a narrow tab) it is still a row of engine chips over the map.

Which engine a call runs under: a call about a job (the settle, checks, the ceiling, a retrospective…) runs under the engine of the job's conversation, wherever the line was said; one about no job under its own conversation's; a Bot↔Bot direct or a job's thread under the conversation it came from. That conversation's engine if it names one (sessions.playbook_id), else Settings' default (default_playbook), else General. A custom engine since removed reads as the default. Every call record keeps the engine it ran under and how many times it had been changed (playbook_id, playbook_revision); opening a step on the flow says "Engine Video · revision 2".

On upgrade: conversations that name none run General, so the scribe and reflections stop there; for a conversation that should keep its ledger, choose Video for it, or switch those steps on in General on Roles. From 2026-10-14 the retrospective is on again in General, and in engines you built on General (they keep only what differs, so one that never touched this step follows the built-in); deliveries passed over before then because their engine ran none are not looked back on afterwards.

Where it is chosen: a conversation's engine is chosen in a group's Actions and in a Bot's Actions in your direct (an Engine row: follow the default, which it names, or one of the engines; PUT /v1/sessions/:id/playbook), showing what the Mac says the conversation runs; it is not there on an older Mac without engines. A new Bot's direct can be given one when the Bot is made, and the create-group request takes playbook_id too.

Bot templates and first launch: each built-in engine has a few Bot templates ready (General: Assistant, Translator, Researcher; Video: Video Director, Story Writer, Subtitle Editor, Reviewer; Coding: Developer, Frontend Engineer, Backend Engineer, Designer), their duties and boundaries drawn from the Bots used most in the records. When the wizard saves setup and the roster is still empty, its last step is "Pick a way and the first Bots": a card for each engine, and picking one lists its templates, ticked to begin with General's Assistant, Video's Director, Writer and Subtitle Editor (not the Reviewer: one director with you reviewing did better than a reviewer Bot), and Coding's Developer (six Bots on one dev group each took up every line). Each opens to change its name, duties and boundaries; while a ticked one is not filled in, the button is greyed, the field says why, and a folded row says it needs filling in. Making them makes each in turn with its direct on that engine; one the daemon refuses (a name already used) stops there, opens with the reason under its field, the ones made before it are ticked ✓ and not made twice, and the engine can no longer change. One Bot opens its direct; two or more also make a group ("Assistants", "Video production" or "Development") on the same engine, led by the first (PUT /v1/sessions/:id/lead), and open it; a group that cannot be made opens the first Bot's direct and says so. Settings' default engine stays General. The step can be skipped. When this computer lists Claude Code sessions you had in a terminal, the step is called "Get started" and has two cards on top: "Make bots to work with" (the default, the above) and "Carry on a terminal session"; the latter shows the import sheet's own list by directory, and picking a session and pressing Carry on imports it as a project session, takes the wizard down and opens it, with no Bot made (ADR 0095); back on the Bots, the drafts are as you left them. The new-Bot sheet starts with the same templates, a row per engine: one fills in the name, duties and boundaries and picks its engine in the Engine row below ("follow the default" when it is the default's), which can be changed.

Bots: can read playbooks and playbook_revisions with query_data but cannot change an engine; a Bot hiring a teammate cannot choose its direct's engine.

Avoid: the floor made into steps that can be switched off, work items, the end contract and hand-overs taken apart, the engine taken for the engine level, a Bot changing an engine without your consent, choosing an engine per Bot rather than per conversation, changing your engine on upgrade, a step of your own writing state itself, a word list as a step's condition, a step of yours letting through a hand-over nobody else stands behind

Model choice log

The model and thinking level a turn ran on and why (set on the ticket, your pin, the default model, the endpoint's default, and whether it stepped up or climbed the ladder), which category the message counts as, how the turn ended (a failed completion carries its failure kind), how long it took and how many steps it made; below engine level 8, also the model feedback that later lands on that turn, the review of its correction chain, and the lessons recorded. It sits on that turn's card on the flow board and no longer has a separate entry point or page: a line at the bottom of the Bot card shows the model, thinking level and category, with a separate mark for feedback, for blame placed on the model, and for a failed completion; clicking that line expands everything below the card, and clicking a piece of feedback jumps back to the original words. The flow board toolbar can light up the cards that have feedback or whose review blamed the model and dim the rest, without changing the shape of the whole job. It is viewed by job, not by session: when a job spans several sessions, all of its choices are on the same board. It does not go into the main transcript and shows no tokens or spend; the Local API can still list it per session.

Avoid: routing log, a separate model choice log page, a log button on the session top bar, going into the main transcript, stuffing it into the current conversation settings, putting spend statistics here, treating criticism of the content as model feedback

Call record

One record per use of a model call the app makes on its own — reading, the organizer, the scribe, joining in, the picture judge, the composer, compaction, reflection, retrospective (ADR 0083): which call, which built-in prompt and which version of it, the model and thinking it ran on, which line, turn, job, ticket and Bot it was about, how it came out (worked, did not, an answer that did not read) and what it concluded, the raw answer (clipped), and how long it took. The same words of a Bot read again in another turn are a record of their own (the earlier reading reused, no new call). On the flow they are steps: under a line of yours come its reading, where it was filed and the scribe, then the turns it woke; on a group line naming nobody each Bot's judgement is a step, and the turn of the Bot that took it up hangs from its judgement; a turn's compactions, readings of its words and the settle after it hang under that turn; the picture judge, reflections and retrospectives hang under the last card before them. Each step says what it concluded; one that did not work or said no is drawn in the warning colour, counted on its round and can be lit with one press; opened, the inspector beside the flow (a sheet from the bottom when narrow) shows the model, prompt version, time taken and raw answer, and "Change this call" unfolds that call's model and prompts there, to change in place. A job's flow draws only the steps that did not work or said no until one press draws them all (the readings and the filing among them); a line's own flow always draws them all. A line filed under no job opens its own flow from its right-click menu too. Records go with a deleted or cleared conversation, each conversation keeps its newest 2000, and Bots can read them as a record. They are on the flow only: never in the main transcript, never read back to the organizer. Details: Behavior · Call record.

Behavior details

ADR 0083. Each use of one of the app's model calls writes a call_runs row (so does each judgement of a step of your own, a command's and a rule's included, ADR 0105): role (which call), prompt_id and prompt_revision (which built-in prompt and which version; none for the default), the provider, model and thinking, the message_id, turn_id, task_id, ticket_id, bot_id and check_run_id it was about, outcome (ok, failed, unreadable) and fail_kind, verdict (the conclusion, a JSON shape per call), the raw answer (at most 4000 characters), its spend row and how long it took. A reading the word lists made in place of a model is recorded too, its verdict marked as by the word lists; the same words of a Bot read again in another turn come from the reader's cache and are recorded all the same (cached, no new call), so every place a reading was applied shows. The picture judge writes one row per batch of a check run, each carrying that run's id.

The flow takes the records on the job, and about its lines and turns, from steps on GET /v1/tasks/:id/trace (without the raw answer, which GET /v1/call-runs/:id fetches when a step is opened). An opened step does not hang under its card but fills the inspector beside the flow, scrolling inside (since 2026-10-12, ADR 0086; before, it lay over the flow's right edge); narrow, the inspector is a sheet from the bottom, and on a phone Back puts it away first. When the panel covers the step's card, the board slides until the card is clear. The raw answer shows unfolded in the panel; folded, it stays folded from step to step, and is not fetched. "Change this call" unfolds the call's settings in the panel, the same as that call's on Roles (model, Claude account, its prompts), saying which call it changes and that it holds for every later use; a prompt opens in its editor over the whole window (a page on a phone), and Escape or Back closes the editor before the panel; Escape in the model picker closes only the picker. Roles still opens from Tools. A raw answer that is JSON throughout (or JSON in one code fence) is drawn as a tree you can fold (svelte-json-discovery), coloured with the app's light or dark; one that is not JSON, or was clipped at 4000 characters mid-value, shows as its text. Steps sit beside the cards, never among them: the organizer and the plan facts, which read the cards back to a model, read what they did. A line filed under no job is drawn on its own by GET /v1/messages/:id/trace: the turns it woke, the ones those woke, and the records about any of them; a line that woke nobody is its own card and its steps. The phone can read both. Since 2026-10-17 (ADR 0094) a job's flow draws only the steps that did not work or said no: on a long job most steps are readings of a Bot's words ("still at it"), and drawn they outnumbered the turns. A turn that hung from a step left out hangs from the nearest step or card above it that is still drawn. "Show all steps" on the toolbar draws them all and "Only steps that went wrong" folds them back, kept per browser (real-bot-trace-steps-all; the old real-bot-trace-steps is no longer read, so every browser starts from the new default); "Steps that went wrong N" is there either way. A line's own flow (a line filed under no job, opened from its right-click menu) is your card and its steps, so it always draws them all and has no such switch.

Records go with a deleted or cleared conversation (a raw answer can paraphrase what you said), and each conversation keeps its newest 2000, older ones dropped as new ones are written. They are written at every engine level; each new one is published as call_run.created, which an open flow reloads on. Bots can read call_runs through the records (query_data), so a retrospective can cite them.

Avoid: recording only failed calls, putting steps among the cards the organizer reads, seeing how only filed lines were read, leaving out which prompt version a call ran with

MCP

Roster-level servers: stdio (command / args) or HTTP / Streamable HTTP (url + optional headers). Every Bot can call the configured tools. You add servers in Settings, and Bots can also add, edit and remove them with tools. Adding a server or changing its command·args / url / headers is a dangerous action. An HTTP server's Authorization is pasted on the approval card and goes into the Keychain, never into tool arguments. Deleting an MCP server is not a dangerous action. The app records the usage instructions a server ships with; you or a Bot can also write a usage note for each server (what it does, when to use it, when not to), which goes into every step's "MCP this turn" section ahead of the server's own instructions. Leave it blank when the server's instructions are enough. Editing the note is not a dangerous action, and changing the connection does not clear it. All tools of an enabled, successfully connected server stay available to every Bot, direct, group and routine; they are never filtered out by message keywords or language. After a server is added, changed or re-enabled, the current turn's next step and other Bots' later completions can use it; once it is disabled or deleted, it can no longer be called. To hand an image from the workspace to a parameter that only accepts an image URL or data URI, the Bot writes workspace://<path relative to the workspace root> in the argument, and the app replaces it with the image's data URI before sending (shrinking the image first if it is over half a megabyte); the transcript and the next step still show the short reference. A remote server can't read this Mac's disk, and the model can't copy out a whole image's base64.

Avoid: per-Bot MCP, Bot as a tool permission boundary, hiding configured capabilities by keyword, available only in the turn that installed it, stdio only, hand-editing a server's own instructions

Setup wizard

The empty state of Settings: it is complete once the workspace path is set and there is either a usable endpoint (its URL and a saved key; an address on this computer needs no key) or a signed-in local agent on this computer with the built-in calls on its models (ADR 0078, ADR 0079). With an empty roster it has one more step: a way of working (an engine) and the first Bots (Bot templates), with a group on that engine when there are two or more (ADR 0085); when this computer has Claude Code sessions from a terminal, the step can carry one on as a project session instead (ADR 0095); the step can be skipped. It has no route of its own; it slides out over the sidebar only and does not take over the main transcript.

Avoid: /setup, full-screen onboarding, making Settings the main transcript

Routine

Recurring work attached to one Bot and triggered by the calendar. v1 has routines only, no event triggers. Each routine has a standing plan (it does not take the session's current plan and does not go through the organizer); each time it comes due, a new ticket NN-<date> opens under that plan, and that turn works in the ticket's directory (in a direct on an engine with no jobs there are none of these: it is a turn with no job). When it comes due, the daemon inserts a system line under that Bot's name into your direct with the Bot, "Routine '': ", to wake it; as with a check-back, no message is sent in your name. A routine runs unattended by design: what each run hands over is approved once its gates pass, with no card asking you to approve it; when a result is wrong, say so, and a line read as finding fault still sends it back to rework at once. A check-back is not a routine; see "Check-back".

Avoid: cron job (in anything user-facing), skill-pack automation, sending the routine's content in your name, a daily card asking you to approve what a routine handed over

Skill

A named procedure attached to one Bot: a short description (when to use it) + a Markdown body (how to do it). It belongs to that Bot only (from engine level 8 you can share a copy of it with every Bot, which is then a project skill); it is not a workspace file, and not MCP. Enabled skills enter the system prompt of every step of that Bot as a catalog; a body is read into the current turn's loop with a tool when needed. A skill is a procedure, MCP is a capability: the Bot looks at the skill catalog first, and on a match reads the body and follows it, calling any MCP tools the body names by name; only when no skill matches does it pick tools straight from the "MCP this turn" section. Skills add no tools and do not replace MCP. A skill can declare the names of the MCP servers its body depends on; any not connected this turn are marked in the catalog, and when the body cannot be followed, the Bot says so plainly or asks, rather than making do with other tools. When a body is read, any mcp_ tool name written in it that is not among this turn's tools is flagged, and the Bot looks up the current name in the "MCP this turn" section and fixes the body. A Bot can add, delete and edit its own skills with tools, and you can edit them in the profile; edits insert no transcript entry. From engine level 8 a retrospective may change the Bot's own skill too: only a sentence added after a passage, a passage appended, or one sentence corrected, with none of its commands, file names or names in backticks lost, and each change yours to undo. A skill cannot waive approval, cannot add tools, and cannot widen the permission mode.

Avoid: skill pack, /skill, plugin, workflow, using the profile as a procedure, sharing without your confirmation, auto-injecting bodies by keyword

Project skill

From engine level 8, the copy of one Bot's skill you shared with every Bot: it is in every Bot's skill catalog (marked with whose it was), read by name and followed, but no Bot can change it; the owner's later edits reach it only when you share it again on the Project skills card. A Bot with a skill of its own by the same name uses its own. Details: ADR 0052.

Avoid: a Bot sharing its own skill, edits syncing to everyone on their own, treating a project skill as one Bot's private skill

Memory

A fact a Bot has noted down itself that still holds across sessions: a topic + a one-sentence conclusion. It belongs to that Bot only and enters only its own context (other Bots can read it through the records, but never into their context, and cannot write it); deleting the Bot deletes it too, while archiving keeps it. The Bot writes it itself with a tool. From engine level 8 (the default) there is no learning step: what goes wrong becomes a quality event, and lessons are enforced by the app, the events themselves never written into memory; once a job you accepted is delivered, the Bots that made it hold a retrospective, which may write, rewrite, merge and delete their own memories (at most three written and three deleted at a time, each one yours to undo on the board) — ways of working, defaults and preferences that hold across jobs, not the job's requirements. Below level 8, the learning step after a chain ends can also write one: when review blames the model, when the Bot hit tool errors but finished, or when the request was unclear and the user corrected it over more than one turn (in that case it records only the terms the user supplied — the form of the deliverable, the scope, who it is for, the defaults — and does not change skills). The learning step sees what you said afterwards and the calls that failed in that chain, keeps only a conclusion that names something concrete, and without the call keeps nothing. A memory is not distilled from the transcript for the Bot in the background, and the transcript is not summarized into the profile. All enabled memories enter the system prompt of every step of that Bot, with no retrieval and no relevance ranking, in the order they were last written, newest last. A memory is a past conclusion, not a source of truth: when it conflicts with this turn's transcript, the transcript wins, and one that no longer holds gets edited or deleted. Noting the same topic again overwrites it; no second entry sits beside it. When the Bot opens a new topic, it is shown its other memories from the same session in the last day, and deletes the old one if the new one revises it. The number of entries is capped, and when it is full the Bot must decide what to drop first; nothing is silently pushed out. You can view, edit, disable and delete memories, but you do not create them for the Bot; each one carries the message it was noted from, and you can jump back to it; one a retrospective wrote names the job it came from. The division of labor: the profile is who you are, a skill is how to do it, a memory is what you have learned; how every Bot works is in the built-in prompts.

Avoid: retrieval-based memory, vector store, feeding raw transcripts back in, distilling transcripts in the background, treating memory as a source of truth, memory shared across Bots, user-created memories, unlimited memory catalog

Built-in prompt

The fixed text the app sends models: every turn's System section, the notes opening the Skills, Memory and MCP sections, the Claude Agent preface, each tool's description, and the app's own calls (organizer, line readings, scribe, join judgement, composer suggestions, narrowed reflection, retrospective, seams checks, sample-standard check). They are the defaults of the developer's way of working: in Settings › Prompts you change them or restore the default, and every change can be undone; a Bot can propose one with edit_prompt / reset_prompt, a change to the app's setup that goes by its permission mode: you let it through on an approval card, under allow all it applies at once, and read-only refuses it. In the app's own calls the answer format code reads is locked; your text only says where it goes ({format}). A change applies to every Bot from the next call (an engine with a System section of its own, or with no jobs, does not read your edit of that section); when an update brings a newer default it is merged into your version line by line, and one that does not merge leaves yours in force, marked for you to choose. How one Bot works goes into its skills, a fact it learned is a memory, your requirements live in the requirements ledger — none of them in a prompt. The app's shell — approvals, holds, gates, checks — is code, and no prompt loosens it. Details in Behavior · Built-in prompt and ADR 0064.

Behavior details

The fixed text the app sends models, one slot each (apps/daemon/src/prompts/registry.ts): every turn's System section (turn.system), the notes opening the Skills, Memory and MCP sections (turn.skills / turn.memory / turn.mcp), the Claude Agent preface (agent.preface), each tool's description (tool.<name>, not its parameters), and the app's own calls (call.*). Unedited, a slot is its default rendered for the engine level and the shell, word for word what it was before; your version replaces that rendered text whole. The Chinese-only ones (organizer, line readings, scribe, join judgement, composer suggestions) are used whatever the app's language.

  • Where: Settings › Prompts (after MCP). It is in sections as Models is: every turn, Claude Agent, the app's own calls, and the tool descriptions. A wide window shows them as tabs under the search, one page each, every tab counting what is edited in it (in the warning colour when one is in conflict with a newer default); a phone lists them first, each saying how many prompts it holds, how many are edited and whether one is in conflict, and opens one as a page of its own, with Back going to that list first. One line a prompt: the title and what it is; the tool descriptions are a grid of tool names on their own page, under nine headings by what the tools are for: files and commands; speaking and ending turns; plans and hand-overs; roster and conversations; profile, skills and memory; routines; annotations; endpoints, models and MCP; prompts and records. A default carries no mark; an edited one says who edited it (you / which Bot / the app merging a newer default), a conflict with a newer default, and how many answers did not read; while any is edited, an All / Edited filter sits beside the search. The search stays on top and looks through every section: while it holds text or Edited is on, there are no tabs, and what it finds is listed by section in one list. The editor has three views — Text, Diff vs default and History — and keeps the one you are on when you switch language: the text fills the page with the placeholders in a line under it and the answer format folded. It saves a second after you stop (at once when you leave Text); the saves of one sitting fold into one change in the history, but typing that change back out is a change of its own, and what comes after starts another (a space added and deleted is two). Each comparison marks the characters that changed within a line, a lone space included. Saves are guarded by the revision you saw; if it changed elsewhere the latest is loaded and what you typed can be copied. Undo the latest change, restore any version, restore the default after a confirm. The phone can do the same.
  • The answer format is locked: in the app's own calls the format code reads is not in your text; your text holds one {format} (exactly once) where it goes. The context compaction's answer (call.compact) is the summary itself and no code parses it, so it has no {format} and all of it is yours to edit. The seams and standard checks also take {item} and {rules}, the Claude Agent preface {workspace} and {cwd}; a missing, repeated or unknown placeholder is not saved. Join judgement and composer answers are read from the first {, so those may hold none once filled.
  • A Bot proposes: list_prompts / read_prompt are always available (reading works under a hold too). edit_prompt changes text the way the retrospective changes a skill — replace a passage that occurs exactly once, add after one, append a paragraph; reset_prompt restores the default. Both are applied to the current text and checked first, then wait on an approval card (prompt-edit) listing what is taken out and put in, the Bot's reason, and how far the change reaches ("Reach: every Bot, every step" and the like). It is a change to the app's setup: a Bot in allow all applies it with no card, a read-only one is refused, the other modes card it as before (ADR 0092); every change is still recorded and undoable. A lesson about one kind of work or a few Bots belongs in their own skills, not here. When you allow it, it is applied again to the text as it is then; one that no longer fits goes back to the Bot. Once allowed, the card offers Undo (while it is still the latest change) and Open in settings, which opens that prompt's editor at its History with this change opened.
  • A newer default: when an update brings one, at open (and when the engine level rises) it is merged into your version line by line: a clean merge is written as the app's change and can be undone; one that does not merge leaves yours in force, marked "New default · conflict", for you to keep yours or take the new default. The boot log says what was done to each, and which are edited.
  • Answers that do not read: an answer to one of the app's own calls that came back and could not be read (not a timeout, an endpoint error or one cut off at its cap) is logged as prompt.parse_failed with the prompt and revision; settings show the count since your edit, or over the last 7 days on a default.
  • Where things belong: what every Bot should do goes into a built-in prompt; how one Bot works into its skills; a fact it learned is a memory; your requirements stay in the requirements ledger in your words. A Bot proposes such a change only when you ask it to analyze or improve something — there is no background tuning; set up a routine to do it periodically.

Avoid: letting a Bot change a prompt without your approval, rewriting your requirements into a prompt, loosening approvals or gates through a prompt, a System section per Bot, background self-tuning, editing the answer format code reads

Completion

One streaming HTTP request to the endpoint within a turn: Chat Completions, or Messages on an Anthropic-compatible endpoint. A turn's tool loop can make several completions. A failed completion is not an interruption, and it does not replay earlier tool calls. Every completion has an output cap (the model's max_output in its endpoint's list, 32,768 tokens when unset) and a time limit that counts only the completion itself. One that starts repeating itself, is only a canned one-line refusal, breaks off before it is finished or runs past its time limit has failed and is not a reply: nothing of it is posted, it wakes nobody, and it is tried again; if that fails too the turn ends as failed. One cut off at the output cap without repeating is carried on once. Details: Behavior · Completion.

Behavior details

Every hop's request carries max_tokens: the model's max_output in its endpoint's list, or 32,768 when unset, reasoning tokens included. Without a cap, on 2026-09-29 three hops each wrote one sentence up to the endpoint's default of 128,000 tokens (one of them for 17 minutes, the same sentence 3,457 times), and each was posted as the turn's closing line; in a Bot↔Bot direct it also woke the other Bot, whose next hop read the whole thing again. 32,768 comes from the spend records: a normal hop's output peaked a little over 30,000, and the only hops past 32,768 were those three repetitions, so anything lower would cut normal hops that write a large file. An endpoint that rejects max_tokens with a 400 naming max_completion_tokens instead (as OpenAI's reasoning models do) gets the request again at once with that field, and that model gets it from then on. A model that writes less than that (DeepSeek's deepseek-chat at most 8,192, OpenAI's gpt-4o at most 16,384) has its endpoint refuse the cap with a 400: when the error states the model's own limit, the request goes again at once with that number; when it states none, without a cap; and that model gets the same from then on. These requests went through before hops had a cap, so a refusal like this must not fail the turn, and the cap cannot be changed in Settings. When the prompt and the cap together are over the model's context (the error says "32768 in the completion", or names the cap while talking about the context length, as vLLM does), the request goes again without a cap, that time only: the next hop sends the cap first again.

While a reply streams, the app reads only its prose, not tool arguments, code blocks or tables: over the last 6,000 characters it splits sentences (at full stops, question and exclamation marks, semicolons, ellipses and line breaks, and at an English full stop followed by a space) and compares each by its letters and digits alone, ignoring case; digits still count ("shot 11" and "shot 12" are two sentences). When the same sentence (8 characters or more) comes a fifth time in a row, or fewer than a fifth of at least 20 recent sentences are distinct, the completion is cut off on the spot as a repetition, usually within seconds. "In a row" means nothing new came between two copies, only sentences seen before: a loop has nothing between its copies but more of itself, while a per-item verdict list ("Shot 03: passed. The frame is stable, no rework needed." on every line) has each item's own name between two copies of the comment, and is not a repetition. The share of distinct sentences counts sentences of any length, so twenty identical lines of "- [x] done" that never say which item each is still count as a repetition. A finished reply is checked by the same rules again before it is posted.

These completions have failed and are not replies:

  • Repetition: as above.
  • Refusal: the endpoint's finish reason is content_filter or one of Gemini's like SAFETY; or the whole reply is at most 300 characters with no tool call and is a canned refusal (speaking as a language model and saying it cannot, or only "I can't help with that" or "抱歉,我无法协助处理这个请求"). A Bot explaining which step it cannot do and why is not a refusal. Gemini refusals had gone out as a Bot's message twice before this.
  • Incomplete: the connection closed before the reply was finished (with neither a finish reason nor [DONE]; this is what the endpoint or a proxy in between closing the connection partway looks like), the finish reason said it stopped to call tools and no whole tool call arrived, or a tool call's arguments were not whole JSON. The client first tries the same request up to three times, and only when it is still incomplete does it count as failed.
  • Overtime: one request may take this long from being sent to the end of its stream: the larger of 10 minutes and max_output ÷ the model's measured 10th-percentile speed × 1.5. The speed is stream_tps_p10 in the list; unmeasured, it is 10 minutes (a model server on this computer or network is taken to write 10 tokens a second until measured; see "Model servers on this computer or network" below). Time waiting for a free slot at the endpoint, time running tools and time asleep with the lid shut do not count.

A failed completion posts nothing, stays out of the loop and wakes nobody. The same model gets one more hop with a note saying why (for a repetition: do not restate it or write a sign-off, do the next step by calling the tool directly); if that fails too, the turn ends as failed, with a "This turn did not finish: …" line in the session and, when you are in it, a failure notification. Any normal hop in between earns the next failure another go. Not reaching the endpoint, a busy endpoint, an endpoint error and a stream that goes quiet partway (the connection stays open but no next piece arrives) are not in this list: the client has already resent the same request, and the turn ends at once. Going quiet only shows once the idle time (3 minutes) has run out, so three tries already take 9 minutes and one more hop would double that; a connection closed partway shows within seconds, so it counts as incomplete, and one more hop costs little. When a stream goes quiet or breaks off partway, its first half used to be posted as the reply or have its tool calls run; now none of it is used.

Finish reasons are read regardless of case, including Gemini's own ones that a proxy passes through as they are: STOP is stop, and max_tokens, MAX_TOKENS and Mistral's model_length all read as length. An empty finish reason is none at all: some endpoints send "" on every chunk until the last. A finish reason the client has no name for (such as eos) means the model says it is done, so the stream is whole: it is not resent as half a stream, and the reply is judged by the rules above like any other. error is the exception: OpenRouter ends a stream with it when the model behind it failed partway, so what came is only half, and it counts as incomplete. A stream that goes quiet after its finish reason (the endpoint neither sends usage and [DONE] nor closes) is taken as the reply once the idle time runs out: the model has finished, and only the endpoint's last packets are missing.

A reply cut off at the output cap (finish reason length) without repeating is carried on for one hop: the cut part is not posted but stays in the loop to carry on from, with a note to do the next step by calling the tool directly and to put long content in files, written in parts; when the cut falls inside a tool call's arguments, that call is not run and the note asks for it in parts. If the carrying-on hop reaches the cap too, the turn ends as failed for hitting the output limit.

Streamed output no longer counts as the turn making progress: it used to refresh the turn's last activity as each piece arrived, so a hop could write for any length of time without looking stuck. A completion is now bounded by its own time limit, and the stale sweep (20 minutes without any activity) covers only the time outside completions.

max_output does not show in Settings; stream_tps_p10 is written by Test in a model's attributes, and context_window (the context window, in tokens) can be seen and changed there. A Bot can change context_window, input_image and max_output with update_endpoint, time a model with measure_model, and change the default endpoint, the built-in models (builtin_models; an endpoint's model or none only) and the model ladder with update_model_settings; all run without approval (ADR 0014). Saving the list from Settings again keeps whichever of these it leaves out, and only a null sent through the API clears one (emptying the window field sends null). When one is invalid in the stored list (say 0, or a string), only that value is ignored: the model stays in the list, and the Bots using it are unaffected.

Anthropic-compatible endpoints. With an endpoint's format set to Anthropic-compatible (ADR 0066) the rules of this section hold as they are; only what goes over the wire differs:

  • Address and key: requests go to /v1/messages under the base URL, or only /messages when the base already ends in /v1. So the address to give is the kind Claude Code takes as ANTHROPIC_BASE_URL (https://api.anthropic.com, https://api.deepseek.com/anthropic). The key goes in x-api-key, with anthropic-version: 2023-06-01; refused with a 401 or 403, it is sent once more as Authorization: Bearer (some vendors and proxies take only that), and if that goes through the endpoint gets it that way from then on. Refused both ways, the key is wrong.
  • Messages: inside, the app keeps the loop in Chat Completions' shape and converts it on the way out: every system message joins the top-level system; tool results become tool_result blocks in a user turn, ahead of any text in it; neighbouring messages of one role merge into one turn; a history that opens with the Bot's own line gets a user turn of "…" before it; tool call ids keep only letters, digits, _ and - (the loop may hold ids an OpenAI-compatible endpoint gave); an image's data URI becomes a base64 image block.
  • Thinking levels: first in the form of Anthropic's newer models, thinking: {type: "adaptive"} with output_config.effort (none sends only effort: low: the newest models cannot stop thinking, and older ones without a thinking field do not think anyway). A 400 that names thinking, effort or budget_tokens steps down to thinking: {type: "enabled", budget_tokens} (low 2,048, medium 8,192, high 16,384, at most half the output cap, none when that is under 1,024); refused again, no thinking fields at all. Once a request in the stepped-down form goes through, that model on that endpoint keeps it; a step that was refused anyway is not kept. A 400 about thinking blocks in the history ("Expected thinking … but found tool_use", a signature that does not check out) is not a refusal of the fields and steps nothing down. A judgement call whose cap has no room for thinking (256 or 512 tokens) gets the effort alone in the new form, and no budget in the old one.
  • Thinking goes with the tool calls: when the model thought before calling tools, its thinking blocks (signatures included) stay in the turn's loop with those calls, unchanged, and go back with the next hop, which would be refused without them. They go back only to the endpoint and model that wrote them: a hop that moved to another model (stepping up the ladder, or to one that sees pictures) goes without them.
  • The cap: this format needs max_tokens on every request, so there is no "send it again without a cap". An error saying the context is full ("190000 + 32768 > 200000": used, cap, context) is sent again once with what room is left; one that states the model's own limit is handled as above, that number from then on. Still refused with the cap out of the way because the prompt itself is too long ("prompt is too long"), the context is full, not a bare refusal; a stream stopped at model_context_window_exceeded is a full context too (as is Mistral's model_length), not a reply cut at the output cap to carry on from. Both compact the loop first (see Context window).
  • Judgement calls carry no temperature: 0: Anthropic's newer models refuse any sampling setting.
  • Cache: one cache mark at the end of the system prompt, and for a hop another at the end of the loop, so the next hop reads up to there from the cache. Anthropic caches nothing unmarked; proxies that cache on their own ignore the marks.
  • Usage: tokens read from and written to the cache both count as input, and those read count as cached too, as Chat Completions counts them; spend is estimated from the list's rates as before.
  • Finish reasons: end_turn is a normal end, tool_use asks for tools, max_tokens is the cap, refusal is a refusal. An error event in the stream (overloaded_error, most often) makes the attempt unfinished, tried again as above.
  • The model list comes from …/v1/models?limit=1000, the key sent as above. Many compatible endpoints have no such route; then type the names in.

Model servers on this computer or network. An endpoint whose address is loopback, localhost, *.local or a private address (10/8, 172.16/12, 192.168/16, link-local) is taken as a model server on this computer or network (Ollama, LM Studio, llama.cpp's llama-server), and these rules come on top of this section's (ADR 0067):

  • The key is optional. Without one the endpoint is still picked to run on and completes the wizard, and requests carry no key header; when a Bot adds such an endpoint, the key field on the approval card may stay empty.
  • Cut prompts: such a server does not refuse a prompt it cannot hold; it cuts the start and answers anyway (Ollama 0.40 keeps the last half once over its window, with HTTP 200). So after a local request the app compares the bytes sent with the tokens the server reports reading: over 6.5 bytes a token, or over 1.6 times what the model read its earlier whole requests (of 16 KB or more) at, the prompt was cut (requests under 16 KB are not judged, and pictures are not counted); so was it when, within one conversation (one Bot in one session), a prompt longer than the one before was read as fewer tokens — Ollama drops the oldest messages to fit once a prompt is just over its window, and the reading moves only a few percent (not judged when the number of pictures changed). That step is dropped and not sent again as it was: when the turn's loop has something to condense, it is compacted into a summary first and the step goes again (see Context window); when it cannot be, or still does not fit, the turn fails with "The prompt is larger than the model's context window", followed by about how many tokens the step was, how many the endpoint read and the server's window; that window is also recorded on the model's entry. When the entry already has a window and the estimate is more than a tenth over it, the step is not sent at all. A 400 from any endpoint (an Anthropic-compatible one too) whose text says the prompt is over the context reads the same way.
  • Window and abilities: fetching such an endpoint's model list also asks the server for each model's window (Ollama: the loaded window, else the Modelfile's num_ctx, else the model's limit; LM Studio and llama.cpp alike), whether it takes pictures and whether it calls tools, and fills them into the model's attributes (never over what you typed); a model that cannot call tools is tagged "No tools" in the list.
  • Time limits: up to 15 minutes for the first token (loading the model, queueing behind another request, reading tens of thousands of tokens) and 5 minutes idle; one streamed request at a time per server, the rest queued in the app without a clock; short calls nobody waits on get at least 10 minutes, while a reading keeps its 20 seconds and falls back to the word lists.
  • Short calls do not think: organizing, judgements, readings and other short calls that name no thinking level send reasoning_effort: "none"; otherwise a reasoning model spends all 256 tokens thinking and answers nothing (measured on qwen3:8b). A model that refuses the value is asked again without it, and remembered.
  • Thinking is not the reply: a leading <think>…</think> is taken out of the reply text (on every endpoint), and a lone </think> takes everything before it along; a local model's separate thinking also goes through the repeat watch, on the same-long-sentence rule only.
  • Speed test: Test in a model's attributes sends two short requests, timing the first token and the tokens per second, and checks whether it calls a tool it is given; 60% of the speed is recorded as stream_tps_p10. It does not queue behind a Bot's step in the app, but a server that handles one request at a time makes it wait for that step.

Avoid: treating one completion as a turn, treating a completion timeout as an interruption, posting a cut-off or repeating reply as the closing line, treating half a stream as a reply, counting streamed output as the turn making progress

Context window

What the model actually sees in a turn: the profile, the catalog of enabled skills, the system instructions, the "MCP this turn" section, this Bot's memory, the situation block, the most recent stretch of the transcript, and this turn's tool loop. The system instructions, the notes opening the skills, memory and MCP sections, and the tool descriptions are built-in prompts: what you changed applies from the next hop. The full history exists only in the database, for you to browse and for search; it is not stuffed into the model wholesale, and judgement calls use a separate, shorter window without images. For an oversized tool result, the full JSON is first saved in the workspace, and the window holds only a bounded preview and full_result_path. When a turn's loop grows past what fits (an endpoint refuses it as over the context, or it reaches 75% of a known window), its older hops are condensed into a summary by the turn's own model (or the one chosen for Compaction under Tools → Roles) and the newest stay word for word, on the editable built-in prompt "Context compaction". Details: Behavior · Context window.

Behavior details

What the model actually sees in a turn: the profile, the catalog of enabled skills, the system instructions, the "MCP this turn" section, this Bot's memory, the situation block (in a group it has the present members, what each of the others does (their duties, cut short), who the user confirmed as the group's lead — told to the lead itself as its job: lay out with plan_items what others should make, then delegate on those tickets — live turns, who woke the Bot and the user's latest message; on 2026-10-04's real-model runs a lead that saw only the others' names wrote the slogans itself in two of four jobs, and laid the job out once it was told; every turn has this job's plan (Goal, Process, Progress), what you said in the job (the first 4 and the latest 6 lines), the requirements ledger's entries that hold for it, its acceptance checks, the ticket list, this turn's ticket, the files already handed over, the trace, and the Bot's own pending check-back; when no plan has been organized yet it falls back to the original request, and the first turn is marked "This is the first turn of this job"; all of it is read from rows already in the database, and the turn itself does not ask the model for a summary), the most recent stretch of the transcript (including the pixels of raster attachments, only the newest ones within a single budget; a user message with annotations expands, after its body, each annotation's id, which Bot it is for, path, position, quote or cropped image, and remark (page text and text you wrote is folded onto one line or indented line by line, so it cannot pose as the next item); cropped images and raster attachments spend the same budget and are sent to the model as pixels, and once the budget is used up, a cropped image leaves only the annotation's text), and this turn's tool loop. The full history exists only in the database, for you to browse and for search; it is not stuffed into the model wholesale. Judgement calls use a separate, shorter window without images. For an oversized tool result, the full JSON is first saved in the workspace, and the window holds only a bounded preview and full_result_path; the Bot can go on to extract the fields it needs or decode the file with the shell, and a truncated preview is not treated as the original result being lost.

Compacting a turn that no longer fits (ADR 0068): every hop sends the turn's whole tool loop again, so a long turn can outgrow the model's context. The loop is compacted at two moments: when a hop is refused as over the context (any endpoint's 400 saying the prompt is over the context, a local server's cut or pre-send stop, a stream stopped at a full context), after which the hop goes again; and when the model's entry names a context window (local servers fill it in; for a cloud model you can set it in the model's attributes) and this turn's hops reported usage, before a hop estimated at 75% of the window by this turn's bytes per token. A cloud model without a window gets no token estimate and is compacted only after a refusal. What is compacted is the loop's older hops: it splits at one of the Bot's own lines; the newest hops stay word for word (at most a fifth of what fits, each call with its results and thinking), as do the notes and messages read in after the last hop; the rest is written out — each entry labelled as the Bot's words, a call, a tool's result, or a note or message, results cut shorter tier by tier, keeping their start and end, and the oldest left out when even that does not fit, the previous summary first — and sent with the line that started the turn to the turn's own model (or the one chosen for Compaction under Tools → Roles, at low thinking; the split is still sized by the turn's own model's window), without tools. Its words are the built-in prompt "Context compaction" (call.compact), yours to edit; the answer is the summary, which replaces those hops inside an app note (the originals are gone from the context; read files again for details; large tool results are whole under tool-results/), and the Bot carries on from it; a later compaction folds the earlier summary in. What fits is the window at this turn's bytes per token, or without a window the largest request this turn got through (a floor). Refused again before a hop goes through, or when the instructions, transcript and tool definitions alone take three quarters of what fits or less than 8,000 bytes could be condensed, or when the summary call gives nothing back, the turn fails with "The prompt is larger than the model's context window" as before. The summary call is billed under the turn in spend ("Context compaction"), and from level 8 the work log gets a turn.compacted; nothing is posted in the chat. Hops count on: compacting does not reset them. Claude Agent turns are compacted by Claude Code itself, not here.

Avoid: automatic summaries into the profile, a semantic-retrieval memory layer, a background distiller, estimating by token count, feeding earlier turns' tool results back in

Spend

An append-only ledger of calls on this machine; eight kinds of endpoint call each record one row: turn completion, judgement, model routing before a turn opens, correction-chain review, each learning step after a review, input suggestions, organizing, and acceptance checks. A call that shares its kind with others also records its purpose and gets a line of its own in the view (the scribe, line reading and the retrospective bill under organizing, an acceptance check's calls that look at frames are picture judgements, and a project session's runs bill under turns as "Project sessions"). When the provider returns cost_in_usd_ticks, the call is recorded as reported; with no reported cost, it is estimated when both input and output tokens are present and a billing price is configured. The app has a separate spend view; the session top bar, list rows, settings and the model choice log show no spend figures. Stopping every Bot once a day has cost so much is another entry, Spend cap. Details: Behavior · Spend.

Behavior details

An append-only ledger of calls on this machine. Eight kinds of endpoint call each record one row per call: turn completion, judgement, model routing before a turn opens, correction-chain review, each learning step after a review, input suggestions, organizing, and acceptance checks. A call that shares its kind with others also records its purpose (purpose): the scribe is billed under organizing with the scribe as its purpose, and the calls of a continuity check that send frames under acceptance checks as picture judgements; line reading, a reflection and a retrospective are billed under organizing too, each as a line of its own; the summary call of a context compaction is billed under turn completion as a line of its own, "Context compaction", on the turn it condensed, and counts with the turns; a project session's runs are billed under turn completion too, as a line of their own, "Project sessions", on the run, with no Bot and the session's name: Claude Code a row per model per result at the price it estimates, marked Claude Agent (its totals go on from the session's earlier runs when it resumes, so only what this run adds is billed); Codex a row per model call, tokens only, with no price. Model routing and organizing belong to decision routing; review, learning steps, reflections and retrospectives together make up feedback routing; judgement is listed on its own, and input suggestions, acceptance checks, the scribe and picture judgements fall under "Other"; input suggestions, organizing, the scribe and acceptance checks belong to no Bot. A built-in call set to a Claude model is billed under the same kind and purpose as before, marked Claude Agent, at Claude Code's estimated price. In the view's category breakdown a purpose is a line of its own, and "Organizer" is only the organizer's own calls; filtering by a category or a line splits them the same way, and a purpose nothing was billed with yet takes no line; nor does a category or line with no calls in the chosen range. Each row stores the actual model, endpoint and thinking level, plus the session and Bot names at the time it was written; rows are kept when you delete a session, clear history or delete a Bot, deleted objects show their name snapshot marked "Deleted", and rows whose model could not be found during migration show "Unrecorded model". Tokens come only from the endpoint's usage; when missing, they show "—". When the provider returns cost_in_usd_ticks, the call is recorded as reported; with no reported cost, it is estimated when both input and output tokens are present and a billing price is configured. Estimates follow the currently configured prices: setting, changing or clearing a model's price recomputes all of its calls on that endpoint that have no reported cost, and a model removed from the list keeps its existing estimates. Cached input uses the cache price (left blank, it falls back to the input price; missing cached tokens count as 0); reasoning tokens are already included in output and are not added again. Reported and estimated amounts are totaled separately, and incomplete coverage is noted; in the view a row shows only the side it has, and a side with no figure anywhere in the range takes no room. The app has a separate spend view: a pane tab on desktop, an overlay on narrow screens and phones; you can filter it by time, model, session, Bot and call category, and see trends and per-call details; a detail row can jump back to its trigger message. The session top bar, list rows, settings and the model choice log show no spend figures. The time range and dimensions are saved only on this machine.

Avoid: treating estimates as reported or merging them into one amount, estimating missing tokens with a tokenizer, folding judgement into turns, MCP tools' own bills

Spend cap

A USD amount you enter on the spend view's Overview, counted per day: once the calls made since local midnight on the computer that runs the daemon have cost that much, reported or estimated, the app stops every Bot with a stop of its own; live turns end at once, and routines, check-backs and the supervisor's call-backs are held. That stop does not end with your next line: it is listed under Stopped in the sidebar with the cap, and only your Lift lets the Bots go. After a Lift it stops nothing more that day; a new cap or the next day counts afresh. Calls with no price do not count; a local agent's runs count at the price it estimates, a project session's too, though the cap stops only Bots. No cap is set by default. Details: Behavior · Spend cap and ADR 0088.

Behavior details

How much a day may cost: enter a USD amount under Daily cap at the top of the spend view's Overview; clear it, or press No cap, for none. There is none by default (ADR 0088).

  • What counts: every call since local midnight on the computer that runs the daemon, at its reported cost where there is one and its estimate where not. A call with neither does not count. Runs of a local agent (Claude Code, Codex…) count at the price it estimates, even when they spend a subscription; so do a project session's (Codex reports no price, so its do not). Reaching the cap still stops only Bots: a project session has no hold, and a run going on keeps going.
  • When it is reached: the daemon looks every 15 seconds and, once it is, stops every Bot with one stop of the app's own (source: spend_cap): live turns end at once, and routines, check-backs, the supervisor's call-backs and Bots' lines to each other are held, as after "Stop every Bot". It can be up to 15 seconds late, and a hop already running spends a little more meanwhile.
  • Going on: this stop does not end with your next line; a Bot you speak to can only answer read-only. It is listed under Stopped in the sidebar with the cap; your Lift lets the Bots go, and the work it ended goes on as after any lifted stop.
  • Once a day: after a Lift it stops nothing more that day, however much more is spent; a new cap, higher or lower, counts afresh, and so does the next day from midnight.
  • Not done: a cap per conversation, per Bot or per job; a warning before it is reached; what MCP tools bill on their own.

Avoid: budget, daily limit, circuit breaker, automatic shutdown, a cap per conversation or per Bot, lifting it by a line