v2.0 · MIT · file-based · hive-GOD
A minimal file-based protocol to coordinate multiple Claude Code instances across separate sessions.
No daemon. No server. No cloud. Just files on your machine.
v2.0 adds dual-GOD orchestration, a TaskProvider layer (pluggable task managers per domain), a drain-on-Stop hook, and per-agent token/cost telemetry.
If you run more than one Claude Code session — one per project, one per role, one per repo — you quickly hit a wall: the sessions don't talk to each other. You become the human postman, copy-pasting context, briefs and handoffs between terminals.
Agent Team OS removes the postman.
Same task. Without agent-team-os, and with it.
Without agent-team-os
You are the postman. Context lives in your head.
With agent-team-os
ops$ /send dev bug-fix
→ msg-...json written to inboxes/dev/
dev$ claude (later, in another terminal)
=== Agent Team OS ===
Inbox: 1 pending
- brief/bug-fix from ops
dev$ /read msg-...
dev$ /reply msg-... response
→ thread auto-closed, ops will see the reply at next SessionStart
Context lives in the bus. Threads are preserved.
Three diagrams. The whole protocol.
No daemon listens. Each session writes to and polls the filesystem on its own schedule. The hook only fires when a session boots.
flowchart LR
subgraph S["Multiple Claude Code sessions"]
direction TB
A[session 01
ops]
B[session 02
dev]
C[session 03
growth]
D[session 04
...]
end
FS[("~/.agent-team-os/
filesystem")]
A -- write msg --> FS
B -- write msg --> FS
C -- write msg --> FS
D -- write msg --> FS
FS -. SessionStart
reads inbox .-> A
FS -. SessionStart
reads inbox .-> B
FS -. SessionStart
reads inbox .-> C
FS -. SessionStart
reads inbox .-> D
Request → response never has both sessions live at the same time. Filesystem is the rendezvous. Threads remember.
sequenceDiagram
autonumber
participant Ops as ops session
participant FS as ~/.agent-team-os/
participant Dev as dev session
Ops->>FS: /send dev bug-fix
Note over FS: msg-...json written to
inboxes/dev/
Note over FS: outbox/YYYY-MM-DD.jsonl
appended (audit)
Note over FS: threads/thread-...json
opened
Dev->>FS: SessionStart hook
FS-->>Dev: inbox banner
"1 pending: brief from ops"
Dev->>FS: /read msg-...
Note over FS: msg moved to .read/
Dev->>FS: /reply msg-... response
Note over FS: reply written to inboxes/ops/
thread auto-closed
Ops->>FS: SessionStart hook
FS-->>Ops: inbox banner
"1 response from dev"
By default every agent can message every other (a graph, not a tree). Cross-domain messages auto-cc the hub via a non-blocking cc-notify, so the hub keeps visibility without being a bottleneck. Need hard isolation? Declare blocked pairs in AGENT_MAP.json — the deny mechanism is still there.
flowchart TB
hub((hub))
dev((dev))
growth((growth))
ops((ops))
hub <--> dev
hub <--> growth
hub <--> ops
dev <--> growth
dev <--> ops
growth <--> ops
dev -.cc.-> hub
growth -.cc.-> hub
ops -.cc.-> hub
Each session sees what's waiting for it the moment you open it.
Versioned JSON with from, to, intent, payload, deadlines.
Pick up a conversation a week later. Threads are preserved.
Everyone talks to everyone; cross-domain traffic auto-cc's the hub. Optional deny-pairs for hard isolation.
Append-only JSONL of every message sent, for free.
/inbox /read /send /reply /handoff /thread /bus
In any Claude Code session:
/plugin marketplace add mariomosca/claude-plugins
/plugin install agent-team-os@mariomosca-claude-plugins
git clone https://github.com/mariomosca/agent-team-os.git ~/agent-team-os
cd ~/agent-team-os
./install.sh
v2 · optional — the installer also copies a Stop hook (drain-on-Stop: blocks a session from closing while its inbox has unhandled messages) but does not register it, since it affects every session. Enable it explicitly by adding "Stop" to your settings.json hooks — see SETTINGS-DIFF.md. Reading this repo as an agent? Start from AGENTS.md.
A folder structure, a JSON schema, a handful of bash helpers and slash commands.
~/.agent-team-os/
AGENT_MAP.json # path -> agent + routing rules
registry/<agent>.json # agent card (active, last_seen)
inboxes/<agent>/ # pending msg-*.json
inboxes/<agent>/.read/ # local archive after read
threads/<thread-id>.json # conversation history
outbox/YYYY-MM-DD.jsonl # append-only audit log
locks/ # mkdir-based atomic locks
Each Claude Code session detects its identity from its current working directory via AGENT_MAP.json. A SessionStart hook registers the agent and prints any pending inbox messages. Slash commands handle the rest.
See the README on GitHub for architecture diagrams and the full message schema.
Because context is finite. One instance per role — engineering, marketing, ops — keeps each session focused, lets each one carry its own conventions, skills and memory, and stops them from stepping on each other's toes.
The cost is coordination. Agent Team OS is the cheapest possible coordination layer.
Per-recipient atomic locks via mkdir. The bash helper acquires a lock before writing to an inbox and releases it after. Brief contention is handled with a short retry loop.
The bash helpers and message schema work standalone — you can write to ~/.agent-team-os/inboxes/<agent>/ from any shell. The hooks and slash commands are the Claude Code integration. If you wrap another agent runtime around the same filesystem layout, it joins the bus.
Reading a message moves it to inboxes/<agent>/.read/ automatically. Pending inbox stays small; archive grows but is read-once. The append-only outbox is a JSONL log per day under outbox/ — easy to rotate.
It's just a directory. rsync ~/.agent-team-os/ user@host:~/.agent-team-os/ or commit the whole thing to a private repo. Path-based agent rules in AGENT_MAP.json may need updating per machine.
Don't put them there. Payloads are size-capped (10KB suggested) and the convention is to pass heavy or sensitive content by reference (context_refs) — file paths, GitHub issue URIs, knowledge-graph node IDs.
Not in v1. Inbox is read on SessionStart and on each UserPromptSubmit (for urgent/high priority alerts). A fswatch-based realtime delivery is on the v1.1 roadmap.