team — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited team (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Run a third-party provider model as a real Claude Code teammate: you start it with the native Agent tool, Claude Code creates the pane and does all the team plumbing, and cc-fleet's launcher swaps the teammate's LLM backend to the provider. Same tool stack and team coordination as a native teammate; your main session's own auth stays untouched.
Wrong lane? A fire-and-forget one-shot or flat batch → /cc-fleet:subagent; a scripted multi-phase run → /cc-fleet:workflow; full arbitration in cc-fleet-shared/routing.md.
When this skill cites cc-fleet-shared/<file>.md, OPEN it with the Read tool at ../cc-fleet-shared/<file>.md relative to this SKILL.md — the cited content is load-bearing, not optional background.
Execution environment — check before running anything. Confirm your shell tool executes on the host where cc-fleet is installed. In sandboxed or remote agent sessions, a tool named Bash may run on an isolated machine with a different filesystem, PATH, processes, and tmux server —command not found, a healthy-lookingdoctorwhose leaves can't reach your files, or a wrong working directory should prompt you to verify whether you are in a sandbox shell, not conclude that cc-fleet is broken. If so, route commands through a host-executing bridge tool (for example, desktop-commander) and pass host paths for any files you reference; do not retry the same Bash call expecting different results. If no host-executing tool is available, stop and explain that cc-fleet must run on its installation host.
Precondition — `cc-fleet teammate check` must pass. Before the first teammate of a provider/slot in this session, run cc-fleet teammate check [<provider>] [--slot strong|fast] --json via Bash and require ok:true and protocol equal to 1. Use its agent_type verbatim as the Agent call's subagent_type. ok:false → dispatch on error_code + detail (cc-fleet-shared/troubleshooting.md); never call Agent with a ccf-* type after a failed check. A protocol other than 1 means cc-fleet and the plugin are out of step — tell the user to update both (cc-fleet update, then /plugin update) and use /cc-fleet:subagent meanwhile. check also writes the provider profile and starts the local proxy a codex / openai-* provider needs; --no-probe skips its reachability probe (up to 10s).
Where this lane works. Only a terminal claude session (Claude Code ≥ 2.1.278, macOS/Linux) whose teammates open in panes: teammateMode tmux (inside or outside tmux), or auto while the lead runs inside tmux or iTerm2. The Claude desktop app, claude -p and SDK sessions have no agent team (TEAMMATE_LANE_UNAVAILABLE); in-process teammates would silently run on Claude, not the provider (TEAMMATE_MODE_IN_PROCESS); Windows has no teammate lane (UNSUPPORTED_ON_WINDOWS). In all of these, go straight to /cc-fleet:subagent or /cc-fleet:workflow. A terminal session (in tmux or iTerm2) can get the same TEAMMATE_LANE_UNAVAILABLE / no_session_team: with printenv CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS empty or not 1/true/yes/on, agent teams are off because cc-fleet teammate setup never ran — degrade now and offer the one-time setup below; with it on, cc-fleet could not identify the team (after /clear or a resume), and the user starts a new claude inside tmux or iTerm2. Dispatch on detail, not the code alone (cc-fleet-shared/troubleshooting.md).
One-time setup is the user's call. TEAMMATE_SETUP_REQUIRED / launcher_not_configured means cc-fleet teammate setup never ran — so does no_session_team in a terminal session with agent teams off (above), because check stops at the missing team before it looks at the launcher. Setup writes cc-fleet's launcher shim, the ccf-* agent definitions, and env.CLAUDE_CODE_TEAMMATE_COMMAND (plus agent teams, if off) in ~/.claude/settings.json. Tell the user what it changes; run cc-fleet teammate setup --yes --json only after they agree (add --teammate-mode tmux when their teammateMode is unset or in-process), or let them run it. They must then restart claude inside tmux — until they do, check may return LEAD_RESTART_REQUIRED, and returns no_session_team if agent teams were off before setup. Check stops before it reads teammateMode on these paths; if setup's JSON shows teammate_mode in-process, ask before rerunning it with --teammate-mode tmux, before the restart.
Steps 1 and 3 are cc-fleet via Bash with --json; steps 2, 4 and 5 are native tools.
1. cc-fleet teammate check [<provider>] [--slot strong|fast] --json
← Bash; require ok:true and protocol == 1; keep .agent_type and .team
The provider arg is OPTIONAL — omitted, the default provider applies
(see "The provider ask ladder").
2. Agent({description: "<3-5 words>", name: "<name>", subagent_type: "<agent_type>",
prompt: "<task>. When done, send your result to team-lead with SendMessage — once."})
← native; `name` is what makes it a teammate (`description` is the Agent tool's
own required field). Repeat for more teammates (the same agent_type needs no second check).
3. ~10s later: cc-fleet ps --json --check
← Bash; find the row whose agent_id is "<name>@<team>"
state running → carry on; failed / bypassed → TaskStop it and report
(see "Watching for stuck teammates").
4. SendMessage({to: "<name>", message: "<next task>. Report back with SendMessage."})
← native, as often as you like; the teammate keeps its context.
Wait for its message or idle notification — WITH a timeout (a teammate on a
failed provider API never goes idle).
5. report to the user, then ASK before ending it. On confirm:
SendMessage({to: "<name>", message: {type: "shutdown_request", reason: "<why>"}})
← native; the teammate approves and exits, Claude Code closes its pane.
Stuck teammate → TaskStop; no task id → cc-fleet teardown <pane_id> --socket <tmux_socket_path> --json*Never, on a `ccf-` type:**
name — it would run as an in-process subagent on Claude, not the provider (BAD_AGENT_CALL / missing_name);model — it overrides the provider routing (model_param); the slot comes with the type (ccf-<p>.strong / ccf-<p>.fast, from teammate check --slot);isolation or cwd — neither starts a teammate (isolation / cwd).The plugin's PreToolUse guard blocks these, and any ccf-* call while the lane is not ready, with a deny reason cc-fleet: <CODE>(<detail>): … — dispatch it like a check failure; never retry the same call. There is one implicit team per session, which Claude Code creates and removes itself: team_name is ignored, and the old TeamCreate / TeamDelete tools and cc-fleet spawn (now COMMAND_REMOVED) are gone.
cc-fleet teammate check --slot strong --json # Bash; default provider
# → {"ok":true,"protocol":1,"provider":"glm","slot":"strong","model":"glm-4.6",
# "agent_type":"ccf-glm.strong","team":"session-7c8f769b",...,"warnings":[]}
Agent({description: "Split API handlers", name: "worker-1", subagent_type: "ccf-glm.strong", prompt: "Refactor src/api/handlers.go: split each handler into its own file under src/api/handlers/. Keep tests passing. When done, send your result to team-lead with SendMessage — once."}) # native
cc-fleet ps --json --check # ~10s later: worker-1@session-7c8f769b running
# … its SendMessage arrives (timeout + ps --check meanwhile); report; end it only after the user confirms:
SendMessage({to: "worker-1", message: {type: "shutdown_request", reason: "refactor done"}})cc-fleet teammate check kimi --json # → agent_type "ccf-kimi"
cc-fleet teammate check deepseek --slot strong --json # → agent_type "ccf-deepseek.strong"
Agent({description: "Translate intro", name: "zh-1", subagent_type: "ccf-kimi", prompt: "Translate docs/intro.md to zh-CN beside it. SendMessage team-lead once when done."})
Agent({description: "Translate api", name: "zh-2", subagent_type: "ccf-kimi", prompt: "Translate docs/api.md to zh-CN beside it. SendMessage team-lead once when done."})
Agent({description: "Copy-edit zh", name: "polish", subagent_type: "ccf-deepseek.strong", prompt: "Wait for my next message; I will send you the outputs to copy-edit."})
cc-fleet ps --json --check # all three running?
# … when zh-1 and zh-2 report:
SendMessage({to: "polish", message: "Copy-edit docs/intro.zh-CN.md and docs/api.zh-CN.md for tone consistency. SendMessage me the result."})
# report first; end them on the user's confirm (shutdown_request to each).cc-fleet default --json: if it returns a provider (source "configured" or "auto"), use it and STATE it in your kickoff line (e.g. "using glm (default)").cc-fleet list --json (name + default_model + the one-line note in cc-fleet-shared/providers.md). After they pick, run cc-fleet default <chosen> so you never ask again. (cc-fleet default <p> is user-layer; only run it to FILL a blank default, never with --force.)STOP freezes the affected provider operation and any unapproved provider switch, not independent authorized work. The error table's single rate-limit retry remains allowed; do not retry uncertain writes before establishing their prior result. Main-session handling is allowed only where the workflow already permits it and the user has not required that provider. Changing a provider or the saved default still requires the corresponding explicit authorization.
Model tier within a provider: fan-out / leaf work → omit --slot (or --slot fast); judge / synthesis / sustained work → --slot strong. The provider's roster decides the actual model — see cc-fleet-shared/providers.md. A teammate takes only a configured slot, never a literal model id: a model the user names must first be configured as a slot (cc-fleet edit <provider> --strong-model <id>, user-run).
A teammate reports by calling SendMessage to the lead; the harness delivers it to you. Wherever its pane lives, you talk to it only through SendMessage. Two provider-specific notes:
SendMessage: "You appear done — reply with your result via SendMessage." If the second ask still yields nothing, read the pane directly — don't bother the user: cc-fleet ps --json # → the teammate's tmux_socket_path + pane_id
tmux -S <tmux_socket_path> capture-pane -t <pane_id> -p | tail -40Safe: the provider API key is never in the pane (resolved via apiKeyHelper, never printed). tmux_socket_path is the tmux server's socket path for tmux -S (it replaced 0.3.x's tmux_socket, a -L name). A row with backend in-process or unknown (iTerm2 native panes) has no tmux pane to read.
The one runtime difference from a native teammate. A provider teammate's brain is the provider API: on 429 / out-of-balance / 401 its claude process retries in a loop and never goes idle, never messages you — either would need the very LLM that's down. The error shows only in its pane, never in your inbox. So you must poll.
cc-fleet ps --json --check. Each row has a state:running — normal; --check then adds status (ok | error | unknown) plus error_class + detail on error — only the class, never raw pane text.failed — the launcher refused to start it (the row's error_code uses the check vocabulary; error_class launch_failed). TaskStop it, fix the cause per cc-fleet-shared/troubleshooting.md, re-run teammate check, start a fresh teammate.bypassed — it started WITHOUT cc-fleet's launcher, so it runs on Claude, not the provider (error_class launcher_bypassed). TaskStop it at once and report; re-run teammate check before trying again.orphaned — its lead session is gone (a crashed lead). Not yours to reuse; after asking, clean up with cc-fleet teardown <team> --json.Note the key: this runtime detection dispatches on `error_class` (lower_snake), a DIFFERENT key from the `error_code` (UPPER_SNAKE) that teammate check and subagent failure envelopes carry — don't switch on the wrong one. For status:
ok — keep waiting (within your ceiling).unknown — pane couldn't be captured (teammate exited / tmux down). Confirm with cc-fleet ps --json; treat a vanished teammate as failed.error — act now, per error_class:error_class | Meaning | What you do |
|---|---|---|
insufficient_balance | Provider out of balance / quota. | Retrying can't help. Stop the teammate; STOP, tell the user, propose the next provider, wait for confirm (provider ask ladder, step 4). |
auth | Provider rejected the key (401/403). | Stop the teammate. Tell the user to rotate the key — file backend: cc-fleet edit <provider> --api-key-stdin <<<"$NEW_KEY" (or --api-key-file <path>); other backends via the secret manager. A codex provider has no key: the user runs cc-fleet codex login --credential <its secret_ref> (protocol codex-oauth and secret_ref in cc-fleet list --json). Don't start another teammate on the same provider. Never the raw key in argv. |
rate_limit | Provider 429. | Stop the teammate; wait a bit and start a fresh one, or propose a switch (confirm first). Never keep a wedged teammate looping. |
api_error | Generic provider failure (5xx, overloaded, rejected). | Stop the teammate; retry once, or propose a switch (confirm first). On a codex provider, read the pane first: codex login required or codex auth rejected is a login failure — don't retry; the user runs cc-fleet codex login --credential <its secret_ref>. |
cloudflare_blocked | The ChatGPT backend's edge blocked this IP/client — not a key problem. | Stop the teammate; switch network or retry later; don't rotate credentials. |
ps --check is the first probe; the raw pane is a fine fallback.Stop just the wedged teammate (siblings keep running) with TaskStop — Claude Code kills its pane and removes it from the team. Without a task id, use cc-fleet teardown <pane_id> --socket <tmux_socket_path> --json or cc-fleet teardown <name>@<team> --json: it re-verifies the teammate's identity (pane, exact argv, process start) and kills only cc-fleet provider teammates. It returns {ok, target, killed[], skipped[]}; a skipped entry with reason IDENTITY_MISMATCH means that pane no longer holds the teammate (nothing was killed), IN_PROCESS means only TaskStop can stop it. cc-fleet teardown <team> --json kills every provider teammate of the team — for orphans after a lead crash. teardown never edits ~/.claude/teams; Claude Code removes the member when the lead exits. Then surface it and propose the fallback — another provider (a new teammate + re-SendMessage after the user confirms) or native Agent({description: "<3-5 words>", subagent_type: "general-purpose", model: "sonnet", prompt: "<task>"}). Never leave a teammate wedged and keep waiting.
Claude Code picks the pane; you drive the teammate with native SendMessage either way, and Claude Code closes its panes when the lead exits.
auto inside tmux) → a split pane in your visible window; hide/show available (below).tmux -S <tmux_socket_path> attach. hide/show returns SWARM_UNSUPPORTED.ps shows backend unknown; hide/show returns BACKEND_UNSUPPORTED), or, when iTerm2's it2 integration is missing, a detached tmux server as with tmux outside tmux (SWARM_UNSUPPORTED). teammate check reports this as backend_hint iterm2-or-tmux-external.Declutter the layout without killing the process:
cc-fleet hide <target> [--socket <tmux_socket_path>] --json # pane → detached "claude-hidden" session; keeps running
cc-fleet show <target> [--socket <tmux_socket_path>] --json # pane → back to its origin window, re-tiled; focus stays on the lead<target> = pane id %42 · name@team. Add --socket when the envelope says AMBIGUOUS_TARGET (the same pane id exists on several tmux servers). The old forms (bare team, team/member) return BAD_ARGS. The origin window is recorded on the pane itself at hide time.
SendMessage still works, teardown still cleans it.SWARM_UNSUPPORTED / BACKEND_UNSUPPORTED are terminal no-ops, not tmux failures; attach or use the terminal app instead.error_code, not prose: SWARM_UNSUPPORTED / BACKEND_UNSUPPORTED / PANE_NOT_FOUND / NOT_HIDDEN / NO_ORIGIN / AMBIGUOUS_TARGET / IDENTITY_MISMATCH (the pane no longer holds that teammate) / TMUX_FAILED / BAD_ARGS (malformed or old-form target) / UNSUPPORTED_ON_WINDOWS / INTERNAL. Hiding an already-hidden pane is idempotent ok.Agents Board (human-facing): bare cc-fleet → Tab to a live board of every provider teammate (ps --check health, HIDDEN column, h/s hide/show). You use cc-fleet ps --json --check programmatically, not the TUI.
type before teammate check passes**, or without name, or with model / isolation / cwd`.SendMessage. (Reading a pane for a result is fine.)ps --check.shutdown_request or TaskStop; clean up orphans with cc-fleet teardown.apiKeyHelper; keys never enter env / ps aux / history.--json failure carries a code (cc-fleet-shared/troubleshooting.md).~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.