agent-team-os

v2.0 · MIT · file-based · hive-GOD

agent-team-os

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.

agent-team-os architecture cover

The problem

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.

Show me

Same task. Without agent-team-os, and with it.

Without agent-team-os

  1. 1. Open ops session, draft a bug-fix brief.
  2. 2. Copy brief to clipboard.
  3. 3. Switch terminal, open dev session.
  4. 4. Paste brief, prepend "ops asked me to:".
  5. 5. Dev does the work, writes a result.
  6. 6. Copy result, switch back to ops, paste.
  7. 7. Forget what was decided 3 days later.

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.

Architecture

Three diagrams. The whole protocol.

1. Sessions meet at the filesystem

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

2. A message has a lifecycle

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"

3. Full-mesh with hub awareness

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

What it gives you

Inbox per agent

Each session sees what's waiting for it the moment you open it.

Structured messages

Versioned JSON with from, to, intent, payload, deadlines.

Threaded replies

Pick up a conversation a week later. Threads are preserved.

Full-mesh + cc-awareness

Everyone talks to everyone; cross-domain traffic auto-cc's the hub. Optional deny-pairs for hard isolation.

Audit log

Append-only JSONL of every message sent, for free.

Slash commands

/inbox /read /send /reply /handoff /thread /bus

Install

Option A — As a Claude Code plugin (recommended)

In any Claude Code session:

/plugin marketplace add mariomosca/claude-plugins
/plugin install agent-team-os@mariomosca-claude-plugins

Option B — Manual

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.

How it works

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.

Why not just use one Claude Code instance?

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.

FAQ

What happens if two sessions write at the same time?

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.

Do I need Claude Code to use the bus?

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.

What if the inbox grows large?

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.

How do I migrate between machines?

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.

What about secrets in messages?

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.

Realtime delivery between live sessions?

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.