Use your AI team
August 29, 2026 · View on GitHub
中文版: orchestration-cn.md
You don't memorize tool names — you just say it. Tell your session "hand this refactor to codex and report back", and it hires a Codex session, supervises it to completion, and brings back a short report — status, files changed, tests pass/fail — for you to review. Once a session is connected, there is no extra install step: the ccteam MCP server ships its own instructions, so it already knows how to run the team. The work keeps running after you close your laptop, and every hop is on the ledger.
This is Claude Code's Task tool, except the "subagent" is a full vendor session — Codex, Grok, DSH, another Claude — possibly on another machine, and everything it does is recorded and inspectable.
1. Three ways in
| Where you are | How you use the team |
|---|---|
| Phone / IM (Telegram, Lark) | just message your session; say "ask codex and grok too" and it fans the question out to several vendors, then weighs the answers itself. Install the team-brain persona (marketplace) and one session becomes your chief of staff |
| Web console | open sessions in the browser, watch the team tree, review diffs, track cost |
| Inside your coding agent — Claude, Codex, Grok, OpenCode, Kimi, DSH or Pi (this guide's focus) | delegate with one sentence, in plain language — every MCP-connected session already knows the team tools |
The full manual for the human surfaces is usage.md. This guide is about the third row — commanding a whole team from inside your everyday AI session.
2. The mental model (30 seconds)
Think of a small team where you are the lead:
- You = the lead. You say what you want, review results, decide what ships.
- Codex = the colleague who grinds through long work. Multi-file implementation, migrations, test-fixing, mechanical slogs.
- Grok = quick answers / second opinions. "Where's the bottleneck", "which of these three is right" — minute-scale answers (needs the grok CLI on that machine).
- Claude = the deepest reasoner. Decomposition, verdicts, the review gate before a merge.
Each colleague is a session with a durable id (s47). A session runs on whatever machine its project is bound to (local or a satellite). Close your laptop and it keeps working; what it spent and what it changed is all on your daemon's ledger.
One iron rule: when you want to "call another agent", never shell out to codex exec / claude -p yourself. That run has no session id, no cost accounting, no completion signal, and is invisible in the team view. If it's worth delegating, it's worth being on the ledger — say it, and the session goes through the proper channel (session_*).
3. The phrases you say
Your session hides the tool calls. You say the left column; the right column happens:
| You say | What happens |
|---|---|
| "hand codex the RFC-12 implementation — work in the background, report back with a diff summary and test results" | a codex session grinds in the background; ONE notification when the task completes and the child goes idle, then you review the diff yourself with git diff |
| "ask grok for a quick second opinion on this stack trace — wait for the answer" | a grok session spins up, waits a minute or two inline, pastes the answer back |
| "put this design question to codex and grok independently, then give me consensus / disagreements / your verdict" | the fan-out compare: two sessions answer blind, your session weighs the evidence and rules |
| "before merge, have a different vendor review this diff — MERGE / BLOCK with reasons" | a cross-vendor review gate: the builder never rubber-stamps its own work |
| "which vendors are available here, and what do my routing notes say?" | one status call: the vendor panel for this project's bound host, plus the selected project override/global fallback carried verbatim |
| "what sessions are running? what did that fan-out cost?" | the team tree: who reports to whom, busy or idle, per-member model and cost |
| "stop s47" | explicitly closes that session (state stays on disk, resumable later) |
Rule of thumb: long work → background + completion notification (close the laptop); quick questions → wait inline. Wire your session once (§8), then these phrases work as-is in your everyday session.
4. Making delegation pay (best practices, in plain language)
These turn "it works" into "it's good". They're one sentence each — fold them into how you phrase the ask:
- Brief clearly, and demand a short report with no code dumps. The single biggest lever. One line — "reply in ≤25 lines: STATUS / files changed / test results / open questions, no diffs" — makes the reply ten times denser; otherwise a screenful of logs floods your own context.
- Long work runs in the background; quick answers wait inline. Implementation goes to codex async (it reports back like a colleague); only minute-scale answers you need for your next sentence are worth an inline grok wait.
- Review the diff yourself; don't have it read aloud. The colleague reports which files and why; you read the code with
git diff. - Gate merges with a different model. Codex implements; before merging, have a Claude or Grok session review the same diff — cross-vendor review catches what same-model review rubber-stamps.
- Run where the environment is. GPU tests live on the Linux box? Join it as a satellite, register the repo there, and delegate into that project — the work runs on that machine automatically.
- Set the limits once, then trust them. Delegation depth, fan-out, and daily budgets are guardrails the daemon enforces with a stated reason. Configure once, then delegate without worrying.
- One task per dispatch. Three asks in one message = one muddled report you must untangle; three dispatches = three clean checkpoints.
5. A real example (how a real feature shipped)
The lead says: "merge the settings 'Hosts' and 'Status' pages into one adaptive page."
- A codex session
s47starts on it in the background (async). - Minutes later it reports: changed
SettingsView / App / CSS / i18n+ tests, Vitest 379 green, build passes, and notes it "also fixed 3 pre-existing lint errors". - The lead (an orchestrating Claude) runs
git diffitself: merge is clean, the 3 lint fixes were already red in the repo and the changes are safe. - It starts a claude session
s49as a cross-model reviewer, waits a minute inline, gets the verdict: MERGE, no blockers. - Done.
s49is stopped;s47stays around for follow-ups.
The lead said two sentences in total. Two sessions from different vendors did the work and reviewed each other, every hop on the ledger and in the team view.
6. Model routing (who does what, without guessing)
Picking the right colleague for a task rests on three layers, kept deliberately separate:
- Facts, probed. One
statuscall returns a vendor panel for the host your project is bound to: installed/version per vendor, an honest auth signal (ready/not_ready/unknown— being on PATH never masquerades as logged in, andunknownnever blocks a spawn), budget state, and whether the host is online or the snapshot is stale. Remote hosts report over their satellite channel; an offline host shows its last snapshot markedstale, never the local machine's abilities in disguise. - Catalog, advisory. Model ids, display names, and alias tiers from two sources kept separate and labeled: runtime last-seen (catalogs the adapters already capture, with an observed-at) and the hub
models.json(community-maintained). Each vendor's spawn recipe carries its reasoning-effort ladder alongside — the levels that vendor itself declared, else ccteam's CLI-verified pinned set. The ladders genuinely differ (claudelow…max, codexlow…xhigh, groklow|medium|high, kimilow|high|max, opencode publishes no shared ladder at all, and pi's is per model — it declares which levels the model you picked actually supports), so read one rather than reusing another vendor's spelling. The catalog is a reference, never a spawn allowlist:model/effortpass through verbatim at spawn, a model absent from the catalog spawns all the same, and a stale catalog can at worst recommend something outdated — it blocks nothing. What it will not do is swallow your pick: name a model or an effort the vendor refuses and the spawn comes back as an error, never as a session quietly running at the default. - Opinions, your text. Global routing lives in
~/.ccteam/routing.md(the shared home initializer creates a neutral starter when missing and never overwrites it); an optional project override lives in<project>/.ccteam/routing.md. When the project file exists it replaces the global file completely—the two are not merged. Both are plain markdown with no schema.statustransports the selected file verbatim (source/sha/truncation noted) to whichever session asks—identical text for a planner on any vendor, on any host—and ccteam never parses or executes it.
For a remote project, routing remains main-daemon control-plane configuration: <project> means the daemon-side project data home recorded in the catalog. ccteam does not silently synchronize or read routing files from a satellite worktree.
The workflow is one call, then spawn. Call status, read the panel and the notes, then session_spawn with explicit vendor / model / effort. If you do aim at a vendor that isn't there, the spawn fails fast with the list of what that host does have — failure is discovery too.
A routing.md looks like this — write only the exceptions:
# Routing notes
Default: omit `model` — vendor defaults track their latest releases.
| Task type | Vendor / model / effort | Why |
|---|---|---|
| Long refactors, migrations | codex / sol-max / high | grinds without wobbling |
| Quick second opinion | grok / (vendor default) / low | minute-scale answers |
| Final review before merge | claude / opus / high | catches what the builder rubber-stamps |
Comparing vendors is an in-session move, not a separate product feature. To put a question to the team:
- Fan out —
session_spawnthe same self-contained question to 2+ vendors (async, one task each,titlelabels the matchup). - Let each answer independently — separate sessions, no cross-contamination.
- Collect at the turn boundary — the completion notification fires as each child goes idle;
session_collectpicks up anything you're still missing (an absent or failed member is noted, never killed). Every completion notification is one header line —s12 done · turn 7 · ctx 19%(⚠from 85%;s12 FAILED (<kind>) …on failure) — followed by the answer excerpt, nothing else; andsession_collect/session_list/ inline dispatch results carrycontext_pctas a number, so you can decide reuse vs. fresh session without another call: keep dispatching to a child while its context is comfortably low; once it nears the warning band, spawn a new one for the next task and let the old one idle. Interim notes carry no status, so they cost nothing extra. - Synthesize the verdict yourself — consensus, disagreements, and your call. Optionally dispatch the collected answers back to one child for rebuttal, or spawn a third session as tie-breaker.
The bill stays visible. session_list and session_collect rows carry the accrued cost_usd / tokens_total per member, so a fan-out's cost is a sum you can read, not a surprise.
7. Formations (openings for a multi-vendor team)
Six openings ship as cards on the web console (Home, and Team → Charter) — each prefills the launcher with a vendor lineup; the plan itself is always yours, said in plain language:
- Commander & crews (总控-工班) — a strong-reasoning controller plans, decomposes and accepts; codex builds, grok scouts the ecosystem; completion notifications flow back to the controller. The expensive model pays only for decomposition and acceptance — volume work rides cheaper specialists.
- Daily driver & advisor (主力-顾问) — grok or codex drives the routine work; when it hits a wall, spawn an advisor session on the same repo, take the plan, let the driver execute, stop the advisor. The expensive model bills only for the hard minutes.
- Cross review (交叉互审) — one vendor writes, a different vendor reviews the diff cold, disagreements return to the controller. Different models make uncorrelated mistakes; the overlap catches what self-review rubber-stamps.
- Bake-off (并行竞标) — the same hard problem to 2–3 vendors in parallel; compare, keep the best, merge the good ideas. Worth it when the solution space is wide.
- Research triangulation (调研三角) — grok mines X and real-time chatter, claude does the deep web read, codex verifies against the source; one controller merges. No single harness has all three windows.
- Cost pyramid (金字塔用工) — kimi/opencode grind the mechanical bulk (renames, formatting, test triage); failures escalate to an expensive model. The ledger shows the savings per member.
Three more that need no card:
- Overseer (监工模式) — spawn risky-ops sessions with
permission_mode:"hitl"(approvals pop to your IM) while bulk workers run skip. Risk gets a gate, volume keeps its speed. - Standing watch (定时值守) — schedule messages on a session (composer clock / scheduled API): grok sweeps the ecosystem every morning, claude files a weekly repo-health note. The daemon only fires the schedule; the thinking happens in the session.
- Many machines (跨机编队) — bind heavy projects to a beefy satellite host; the topology wears host badges while transcripts and cost stay in one console.
8. Wire up once
For config-writable vendors, there is nothing to install for orchestration itself: ccteam config mcp (one-time) registers the ccteam server with Claude, Codex, Grok, OpenCode, and Kimi, and the server's own instructions teach any connected session the delegation flow. DSH is the vendor that works both ways: ccteam can hire DSH directly (/new dsh or session_spawn {vendor:"dsh", ...}) — the hire runs inside that identity's own DSH web runtime and shows up live in the DSH page's sidebar, plugin preloaded, and a DSH session you start from DSH's own web UI can become a delegation parent after dsh plugin --profile web add @ccteam/ccteam-ui plus the daemon URL and enrollment credential from Settings → Access. Its first tool call asks for a project slug if the session has not been bound yet. Pi is different: ccteam writes none of its config and instead loads its own bridge into the Pi sessions it spawns, so a managed Pi session can delegate while a pi you started by hand stays untouched. Want a standing orchestrator persona on top (routing habits and review gates baked in)? Install team-brain from the marketplace — a persona choice, not a prerequisite. What you do need:
ccteam startis running on this machine.- You have a registered ccteam project and know its slug; config-writable CLI sessions can also resolve it from their working directory.
- You're in a plain vendor CLI session for the config-writable vendors, or in DSH's web UI with
@ccteam/ccteam-uiconnected. (Some SDK-driven sessions don't load user-scope MCP config; see §9.)
Verify in 60 seconds:
ccteam doctor --verify-mcp # 8 tools, 0 stubs — drift exits 1
claude mcp list # server `ccteam` — ✔ Connected
grok mcp doctor # the Grok axis: handshake OK, 8 tools discovered
9. When something's off
| Symptom | What it is → what to do |
|---|---|
| "tool not available / no such tool" | this session didn't load ccteam. Use a plain vendor CLI session; for DSH, install @ccteam/ccteam-ui and paste the Access credential in DSH Settings. SDK sessions can call POST http://localhost:7331/mcp directly with an enrollment credential (Authorization: Bearer ccteam-enroll:<id>:<secret>, minted under Settings → Access, plus the Mcp-Session-Id returned at initialize) — same tools, and the caller gets its own ledger row, so its spawns are its children rather than roots. |
| "it's been silent forever" | it's working, not stuck. Go do something else and come back for the report. |
| "project not found" | you're not in a registered project directory. cd into one, or say the project name so the session passes project:"<slug>". |
| "grok doesn't work" | that machine doesn't have the grok CLI. ccteam status / capabilities shows which vendors this machine actually has. |
| "did the delegation double-fire?" | session_spawn/session_dispatch take an idempotency_key — a retry with the same key never creates a duplicate. Ask for one on flaky links, or check session_list before retrying. |
Appendix: tool reference (for skill authors / manual orchestration)
You normally never spell these out — your session drives them from your plain-language ask. But if you're writing a persona or skill or orchestrating by hand, ccteam exposes eight tools under the ccteam MCP server, visible in Claude as mcp__ccteam__<name>:
session_spawn— hire a colleague (and hand over the first task in the same call).{vendor, title, task?, wait_seconds?, notify?, idempotency_key?, role?, model?, effort?, permission_mode?, project?}.vendor=claude(default) /codex/grok/opencode/kimi/dsh/pi. There is noprotocolparameter — the wire channel is derived from the vendor (claude/codex = stream-json; grok/opencode/kimi/dsh = acp; pi = its own RPC); passing one is a hard error, the same ashost.dshandpirun only on the daemon's own machine: spawn either into a project bound to a satellite and you get a plain error, never a silent relocation. Hired DSH sessions run inside the identity's DSH web runtime (visible and joinable from the DSH page), cold-resume by sid, and report raw token usage, with no user plugin install required. DSH also takes amode— its agent preset picks the toolset:standard|ptc|minimal|creator; omitted defaults tostandard(the vendor's own default; hires also run permission presetdanger-full-access, so tools execute without approval prompts). Every other vendor refuses a non-emptymode.rolenames a.claude/agents/<role>.mdpersona — omit for roleless (the bare vendor reads the project's ownCLAUDE.md/AGENTS.md, the right default more often than not); grok/opencode/kimi/dsh are roleless-only today and ignore the role argument.model/effortpass through verbatim to the vendor — omit them to ride the vendor default; the model catalog is advisory and never gates what you may pass.title≤80 chars, ledger/team-view label only — never enters any prompt.permission_mode:"hitl"pops approve/deny to the bound IM chat. There is nohostparameter — the execution machine is inherited from the project's binding; passing one is a hard error.wait_seconds>0waits inline for the first answer; default is async. Always returns a newsid; the response'scallernames the authenticated spawner —ambient:<sid>(a ccteam session, or a hand-started agent that enrolled atinitialize; either way that sid becomes the child'sparent_sid) oradmin:<sid>/admin(the localmcp.sockescape hatch, which spawns a root unless it names its own sid). If you expected a parent edge and see a bareadmin, your call did not arrive with a per-process identity — over HTTP that means the enrollment handshake was skipped.session_dispatch— send another task to an existing session ({sid, task, wait_seconds?, notify?, idempotency_key?}). Forwarded verbatim as a user turn, zero injection. Async by default: when the child's vendor turn completes and it goes idle you get ONE notification that says so explicitly (a chatty child's mid-turn narration never notifies — it stays in the ledger).notifyselects the mode:"final"(default) /"all"(every assistant message, debug firehose) /"off"(ledger-only; booleans still parse). The notification marks the child idle/waiting — if the task isn't actually done, that's your cue to dispatch the next step (the "silently stalled child" failure mode is gone: idle always signals).wait_seconds(≤600) blocks until the turn actually finishes and returns the FINALresult_text(interim narration never ends the wait), orstatus:"pending"on timeout — the child keeps running, never cancelled. Every mode covers that one task: the turn boundary ends the watch, so a session that keeps living its own life afterwards never keeps reporting to you. Dispatching to a session you did not delegate is a handoff — it runs and is recorded, but subscribes you to nothing unless you passnotifyexplicitly (notify_deliverable:falsetells you which you got). Dispatching to yourself or an ancestor is rejected (cycle guard).session_collect— read a session's output without joining it ({sid, tail?, n?, since?, max_chars?}). Watchactivity:working= mid-turn (poll again, passsince:<last turn_id>for the delta) /idle= turn done (read). Returns are bounded (max_charsdefault 10 000): long turns keep a 70 % head / 30 % tail excerpt with an explicit marker; the full text is always in the ledger. Also carries the accrued ledger:cost_usd(priced vendors) andtokens_total(raw token count — present for every vendor that reports usage, so codex/grok/opencode/kimi/dsh sessions are not blank).session_list— the roster (busy/idle,context_pct, cost/tokens,parent_sid), most recently active first; passtree:truefor the delegation tree over the filtered rows. A row carriesresidencyonly when ccteam holds no process for it:releasedmeans the session is real and resumes on your next dispatch (reuse it — do not spawn a duplicate),stoppedmeans its user ended it. Accepts{project?, activity?, limit?, tree?}(default cap 30 rows;truncated/totalappear only when the cap bit; null/empty fields are omitted) so a big fleet never floods your context. The web team view renders the same graph live.session_stop— explicitly stop onesid(state stays on disk, cold-resumable). ccteam has exactly two automatic brakes: the daily per-vendor budget cap refuses new work, and live-session capacity gracefully evicts the least-recently-active idle session — creation never fails for capacity.- Plus
status(daemon health + sessions + today's cost, and the vendor panel for the caller project's host — installed/auth/budget per vendor, per-vendor spawn recipes, advisory model catalog, routing notes verbatim; see §6), its bare-name discovery aliasgrok_claude_codex_kimi(identical response; exists so hosts that surface tool names only can still find the vendor keywords), andchat_send_file(send a file from the daemon's filesystem back to your bound chat).
Identity & trust (honestly): a ccteam-spawned session carries a per-session (sid, secret) principal and can only act within its own project, with delegation guardrails (depth 2, fan-out 10 per parent, 50 delegated per project, cycle rejection, budgets) enforced by the daemon with a stated reason. A hand-started session of your own enrolls on its first call — the enrollment credential in the vendor's config, or in DSH's plugin settings, says whose it is; the daemon issues that process its own identity at initialize, and it becomes a real ledger row whose spawns are its children. Most hand-started sessions are still not ccteam-driven, so completion notifications have nowhere to land (notify_deliverable:false) — use wait_seconds for short tasks or poll session_collect; DSH plugin sessions are the exception, because the plugin can deliver follow-ups back into the DSH conversation. Because a user-scoped credential names no project, pass project:"<slug>" on your first call: the first project you name is your workspace for the rest of the session, ccteam never guesses it from your working directory, and only projects your own user can see are accepted. The per-session secret is defense in depth under a single OS user, not a hard boundary — same-uid processes can ultimately read each other's env. What it buys: agents can't accidentally act cross-project or as each other, and every action is attributed to an authenticated caller. Hard isolation (per-agent OS users / sandboxes) is deliberately out of scope for now.