Model or dataset
firstintent/ccteam avatar
firstintent/ccteam

ccteam: five control surfaces over six coding agents, and a hook that fails closed

ccteam turns the coding agents you already run (Claude Code, Codex, Grok, DeepSeek Harness, Kimi, Pi) into one team — any session can spawn, dispatch, and collect work from any vendor on any machine, while you steer it all from Telegram, Lark, or a browser tab. 把你在用的编程 agent 编成一支团队,跨厂商跨机器派活,Telegram/飞书/网页统一指挥。

627 stars24 forksRustMIT

At a glance

What is it?
ccteam is a Rust daemon that gives Claude Code, Codex, Grok, Kimi, DeepSeek Harness and Pi a shared identity, a routing table, delivery guarantees, guardrails and a cost ledger, then lets you drive all of it from Telegram, Lark, a browser tab, a Claude session, or a JavaScript flow file. The best-engineered piece is the pre-agent policy hook, which denies on a broken script and relays its own stderr to whoever asked.
Who is it for?
Use ccteam if you already run two or more coding CLIs and lose track of what each one is doing. Do not adopt it expecting every vendor to run on every machine, because satellite execution is documented as Claude sessions only.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Six agents in the description, five in the README's own list

The repository description names six coding agents: Claude Code, Codex, Grok, DeepSeek Harness, Kimi and Pi. The README's headline paragraph names five, dropping Pi.

The per-agent characterisations in the README are the pitch, one line each. Claude Code plans the deepest. Codex grinds long jobs without wobbling. Grok answers fastest. Kimi does bulk work on a tiny bill. DSH, which is DeepSeek Harness, hires live inside your own DeepSeek Harness web space, side by side with you. And Pi is described as one CLI over many providers, with `anthropic/...` and `openai/...` forms, on your own machine.

What ccteam adds is named in one sentence: identity, routing, delivery guarantees, guardrails and a cost ledger. The framing is that each CLI is brilliant alone but works in isolation, with one terminal and one context and no colleagues.

The division of labour implied by that list is worth noting. Five of the six are hosted model services reached through a CLI, and one, Pi, is a local multiplexer over several providers. ccteam sits above all of them and, by its own account, leaves how the team organises itself to prompts you version.

Five control surfaces, and the web console is a chat shell

There are five ways in, and they share one backend.

The first is a chat app. You paste a bot token once under Settings, then Access, and the chat becomes a console: completion notifications, human-in-the-loop approve and deny buttons, and shipped files all land in the same thread. The command vocabulary is small: a command to pick a project so your next message talks to it, a command to spawn more sessions with vendor and role and effort, an at-sign form to address any session directly, status and sessions and stop, and an inbox command that schedules a one-shot user turn.

The second is a browser. The installer runs the daemon and a status command reprints the link, which carries a LAN address, a port and a token. The README insists it is a chat shell and not a dashboard, with no create-session form: you pick project, host, vendor and model in one control and type.

The third is from inside a Claude session, where any registered session can hire the others and an honest working or idle signal means nobody has to guess from silence.

The fourth is a satellite machine that dials out to your daemon.

The fifth is code, which the next section covers.

A policy hook that fails closed and ships its reason back

The delegation gate is a file at `<project>/.ccteam/hooks/pre-agent`. It can be any executable, it is re-read on every call, and it gates every delegation whether a human, an agent or a flow made it.

The contract is stated in full. The hook is handed the caller, the request, and the live per-harness quota map on standard input. Exit `0` allows. Exit `2` denies, and the script's own standard error is relayed verbatim to the calling agent. A broken script refuses distinguishably rather than silently opening.

Three decisions in there matter more than the mechanism. Failing closed means a typo in the hook stops work rather than waving it through. Relaying stderr means the agent that was refused learns why, which is what lets it retry correctly instead of guessing. And re-reading on every call means a hook can carry a budget or a time window without restarting anything.

The quota map on stdin is the other half. Because the hook can see live per-harness headroom, a policy can be written in terms of spend rather than in terms of which vendor was asked.

The flow runner is driven from the shell, and the three commands are the whole surface:

sh
ccteam flow new branch-review
ccteam flow run branch-review.flow.js --args '{"base":"main"}' --budget 5
ccteam flow eval <run-id>

At-least-once delivery, idempotency keys, and write-before-notify

The daemon's behaviour under failure is described in a single clause and it is the most technically specific sentence in the README.

Notifications are at-least-once across restarts, which means a message may arrive twice and the receiver has to cope. Idempotency keys are how. A child's turn is written to disk before its parent is told, so the parent never learns about work that was not durably recorded. And guardrails refuse runaway fan-out with a reason, so an agent that tries to hire fifty sessions is stopped and told why rather than being silently throttled.

The flow runner extends the same discipline upward. A flow is a plain JavaScript script using `agent()`, `parallel()`, `pipeline()` and `phase()` over real cross-harness hires, with every leaf its own session on the ledger. Runs are journaled, so a run survives a daemon restart and a resume flag picks it back up, with the workers outliving the runner.

The brakes are explicit flags rather than configuration: a parallelism limit, a maximum agent count and a maximum cost, all passed on the command line alongside a budget.

Satellites run Claude sessions, and that limit is stated

The multi-machine story is the one with a documented ceiling.

A satellite is registered with a join token under Settings, then Access. It dials out to your daemon rather than being dialled, which means a laptop behind NAT works without port forwarding. Projects are bound to a host and run where they live, so spawning into the GPU-box project runs its tests on the GPU box while transcripts, cost and the team view stay in one console. Switching machines, in this model, is switching projects.

Then the limitation, in one sentence: satellite execution currently runs Claude sessions, and the other vendors run on the daemon's machine.

So the multi-machine feature is real but partial, and the partiality follows from what a satellite can and cannot reach. If your team is mostly Claude Code sessions, the feature does what you want. If your cheapest bulk work runs on Kimi, that work stays on the daemon host regardless of where the project directory lives.

This is the first thing to check against your own mix of agents, because it determines whether the host field in the console is a convenience or a routing constraint.

One install path, enforced by a comment about two binaries

The Makefile is four targets and a long comment explaining why it cannot grow a fifth without breaking things.

`make gate` is the full pre-push gate: format, clippy, tests and the SPA. `make install` builds a release and copies it, then restarts the daemon. `make start` runs the daemon in the foreground for development. `make wipe` resets runtime state while keeping secrets, config and routing.

The comment is the interesting part. `make install` and `install.sh` must install the same file, because otherwise a machine ends up with two ccteam binaries and whichever sorts first on PATH silently wins. The failure it describes is quoted as a user symptom: I rebuilt and it still misbehaves.

The fix is structural rather than documentary. The install ladder lives in exactly one place, `install.sh`, and the Makefile asks that script where to install by calling its print-install-dir flag. The comment explicitly says reimplementing the ladder in the Makefile would recreate the very drift it prevents, and that the fallback covers a checkout without the script.

The daemon is self-managed rather than delegated to an init system, launched with setsid, and the install target migrates any legacy systemd or launchd unit it finds.

rmux is pinned at 0.5 while the harness comment still says 0.3

The workspace declares eight member crates: core, cost, cli, hooks, im, flow, harness and web. Seven of them get a workspace dependency entry; `ccteam-cli` is a member without one, which is consistent with a binary crate.

The workspace package sets version 0.11.2, edition 2021, a minimum Rust of 1.85, and an MIT licence, with resolver version 2.

The execution surface is a family of four crates named for a tmux-compatible daemon SDK, described in the manifest as the unified-mux execution surface, all pinned to the 0.5 minor. That is what the byte-faithful web terminal in the console is built on: the comment names the stream and chunk types it relies on and notes that 0.5 adds window-creation APIs plus tmux-compatibility and terminal-event fixes.

The dependency policy is written as a prohibition rather than a description. The internal crates arrive transitively and must not be added as direct dependencies, and one adjacent crate is intentionally not pulled because ccteam owns its own TUI rendering.

The member comments carry the project's archaeology in issue and wave numbers, and one of them is now behind the code: the harness crate describes itself as a placeholder pinning rmux-sdk 0.3, while the dependency line above it has moved to 0.5.

Editorial conclusion

Use ccteam if you already run two or more coding CLIs and lose track of what each one is doing. Do not adopt it expecting every vendor to run on every machine, because satellite execution is documented as Claude sessions only. Before wiring a delegation gate, read the pre-agent hook contract, since exit 2 is a denial and a broken script refuses rather than opening, and decide whether a cost ledger and daily budget caps are constraints you want before you point real work at it.

Frequently asked questions

What does ccteam do?

It turns coding agents you already run into one team. The description names Claude Code, Codex, Grok, DeepSeek Harness, Kimi and Pi, and ccteam adds what individual CLIs lack: identity, routing, delivery guarantees, guardrails and a cost ledger, with any session able to spawn, dispatch and collect work from any vendor.

How do I control ccteam from Telegram or Lark?

Paste a bot token once under Settings, then Access, and the chat becomes a console: completion notifications, human-in-the-loop approve and deny buttons, and shipped files arrive in the same thread. Commands cover picking a project, spawning a new session with a vendor and role, addressing a session directly with an at-sign, health and fleet and cost status, stopping a session, and scheduling a delayed user turn through an inbox command.

Does ccteam run agents on other machines?

You register a satellite with a join token under Settings, then Access, and it dials out to your daemon, so a laptop behind NAT works. Projects are bound to a host and run where they live. One limit is stated plainly: satellite execution currently runs Claude sessions, while the other vendors run on the daemon's machine.

What are flows in ccteam?

A flow is a plain JavaScript script the runner executes, using `agent()`, `parallel()`, `pipeline()` and `phase()` over real cross-harness hires, with every leaf becoming its own session on the cost ledger. You scaffold one with a flow-new command, run it with args and a budget, and grade a finished run with a flow-eval command. Runs are journaled so they survive a daemon restart and can be resumed.

Official sources

  1. firstintent/ccteam on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/firstintent-ccteam.svg)](https://hysenlabs.com/projects/firstintent-ccteam)