Multiple agents communicate via file inboxes
From subagent to teammate: one-shot -> persistent; anonymous -> named; no communication -> file-based inbox.
What's the difference between a subagent and a teammate?
s04's subagent is blunt: spawn -> run -> return summary -> die. One-shot, unnamed, no bidirectional communication.
s09's teammate is a named, repeatedly awakened, message-capable independent agent:
subagent (s04): spawn -> execute -> return -> destroyed
teammate (s09): spawn -> work -> idle -> work -> ... -> shutdown
The two patterns serve different needs:
- Subagent: for a concrete one-off task (e.g. review a PR).
- Teammate: for an ongoing role (e.g. a persistent reviewer who wakes up for every new commit).
The inbox is a JSONL file
How do team members communicate? s09 uses the simplest possible mechanism: append-only JSONL files.
.team/ config.json # team roster inbox/ alice.jsonl # all messages to alice appended here bob.jsonl lead.jsonl
Sending is open("alice.jsonl", "a").write(msg); reading is read the whole file, parse JSONL, then truncate to drain it.
Why files instead of an in-memory queue? Files are naturally persistent. Agent restart, process crash, even machine reboot - the messages are still there. They're also grep-able, which makes debugging a pleasure.
Watch a message travel from lead to alice
The widget below lets you send a message to alice and see what happens to the filesystem at each step.
5 message types
s09 defines 5 message types (VALID_MSG_TYPES), but only implements the first two - the remaining three are added in the s10 protocol lesson:
message- plain text message.broadcast- sent to all teammates except yourself.shutdown_request/shutdown_response- request/respond graceful shutdown (s10).plan_approval_response- plan approval (s10).
Why declare them without implementing them? s09 intentionally makes the protocol extensible - message types are an enum; adding a new one means one dictionary entry and one routing handler in _exec.