Blame

bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
1
---
2
category: reference
3
tags: [agents, irc, mcp, architecture]
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
4
last_updated: 2026-03-16
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
5
confidence: medium
6
---
7
8
# Agent IRC Architecture
9
10
An architecture for multi-agent coordination over IRC, where a human (the PM) and AI agents share a message bus. The goal is to externalize the coordination layer that currently lives inside Claude Code's context window, so that agents preserve context for their actual work, the human can participate from a phone or terminal, and the whole system is observable by just reading the chat.
11
12
## The problem
13
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
14
The current agent workflow runs everything inside a single Claude Code session tree. The orchestrator dispatches managers via `Task`, managers dispatch workers, questions relay back up the chain. This works, but:
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
15
16
- The orchestrator's context fills up relaying messages it doesn't need to reason about.
17
- The human is behind a three-hop relay for every question (worker → manager → orchestrator → human → back). You have to be at the terminal.
18
- There's no way to observe what agents are doing without being the orchestrator. No dashboard, no logs, no lurking.
19
- You can't intervene in a task without going through the orchestrator.
20
21
## The idea
22
23
Put everyone on IRC. The PM, the EM, the workers — all peers on a shared message bus. The coordination protocol moves from in-process function calls to channel messages. Everything is observable by joining the channel. The human can participate from a phone IRC client, a terminal, or both.
24
25
## Org structure
26
27
**PM (you)** — sets priorities, answers product questions, makes scope decisions. Hangs out in `#project-{slug}`. Doesn't manage the sprint — that's the EM's job. Can peek into any channel but mostly watches the project channel for decisions that need input.
28
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
29
**PM delegate** — optionally, a Claude.ai session connected to the IRC MCP, acting as the PM's mouthpiece when the PM is AFK. The PM talks to Claude.ai from their phone or browser; Claude.ai speaks on the PM's behalf in the channels. This sidesteps the mobile IRC client problem entirely — the PM's interface is whatever Claude.ai runs on.
30
31
**EM (coordinator)** — a long-running Claude Code SDK session (Opus) that runs the team. Breaks down requirements into tasks, assigns work, tracks progress, makes implementation decisions, surfaces product questions to the PM (or PM delegate). Lives in `#project-{slug}` and `#standup-{slug}`. Shields the PM from implementation noise.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
32
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
33
**Managers** — Claude Code SDK sessions (Opus) that own individual tasks. Follow the proceed workflow: plan, implement, test, review, fix, document. Each manager gets a `#work-{task-id}` channel for its workers. Reports status and completions to `#standup-{slug}`.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
34
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
35
**Workers** — Claude Code SDK sessions (Sonnet/Haiku) dispatched by managers for specific jobs: implementation, testing, review, documentation. Operate in `#work-{task-id}` channels. Disposable — when context fills up, they summarize and exit.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
36
37
The EM decides what needs the PM's input vs. what it can handle itself. Rule of thumb: anything that changes scope, user-facing behavior, or architecture goes to `#project-{slug}`. Anything that's purely implementation strategy, the EM decides. The EM should also push back on the PM when something is technically inadvisable, just like a real EM would.
38
39
## Channel topology
40
41
All channels exist on a single IRC server. Multiple projects share the server, namespaced by slug.
42
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
43
- **#project-{slug}** — PM + EM coordination. Product decisions, priority calls, scope questions. Low traffic, high signal.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
44
- **#standup-{slug}** — EM + managers. Task assignments, status updates, completion reports. The sprint board. PM can lurk here if they want more detail.
45
- **#work-{task-id}** — manager + workers for a specific task. Implementation discussion, test results, review feedback. Noisy and disposable. Created when a task starts, abandoned when it completes.
46
- **#errors** — dead-letter channel. Any agent that hits an unrecoverable failure posts here. Monitored by the EM and optionally by the PM.
47
48
## Agent naming
49
50
Agents get human names, not mechanical identifiers. A conversation between `schuyler`, `Harper`, and `Dinesh` is immediately readable. A conversation between `em-robot`, `mgr-e2-cdn`, and `worker-3` is a SCADA dashboard.
51
52
Names also help with the shift-change problem. When `Ramona` hits context exhaustion and hands off to `Jules`, that's a legible event — new person joined, picked up the thread. If `worker-3` gets replaced by another `worker-3`, it's invisible, and that invisibility is exactly the kind of thing that causes confusion.
53
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
54
A names file (`names.txt`, one per line) lives in the repo. The supervisor pops a name off the list when spawning a process and passes it as the IRC nick. The name also goes into the agent's system prompt so it knows who it is. Names are not reused within a session — once `Ramona` exits, that name is retired until the list resets.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
55
56
The EM gets a persistent name that doesn't rotate — it's the one constant in the channel. Think of it as the team lead who's always there. Managers and workers get fresh names each time they're spawned.
57
58
## Transport abstraction
59
60
IRC is the first backend, but the architecture shouldn't be welded to it. A thin transport interface keeps options open:
61
62
```python
63
class Transport(Protocol):
64
async def send(self, channel: str, message: str, sender: str) -> None: ...
65
async def read(self, channel: str, since: datetime | None = None) -> list[Message]: ...
66
async def create_channel(self, name: str) -> None: ...
67
async def list_channels(self) -> list[str]: ...
68
async def get_members(self, channel: str) -> list[str]: ...
69
70
@dataclass
71
class Message:
72
channel: str
73
sender: str
74
text: str
75
timestamp: datetime
76
```
77
78
The IRC implementation wraps an async IRC client library (`bottom` or `irc`). A Zulip or Matrix implementation could be swapped in later — Zulip's topic-per-stream model maps particularly well (stream = project, topic = task).
79
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
80
## MCP bridge
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
81
82
A FastMCP server wraps the transport and exposes tools to agents. This is the only interface agents use — they never touch IRC directly.
83
84
### Design principle: conversational, not structured IPC
85
86
A core goal of this architecture is that a human can join any channel and immediately understand what's happening. If agents are posting JSON blobs, the channels are just as opaque as Claude Code's `Task` tool — you've traded one black box for a noisier one.
87
88
Agents communicate in natural language. The EM assigns a task by saying so in plain English. The manager reports a plan the same way. The PM can read `#standup-{slug}` on their phone and immediately follow the state of the sprint without parsing anything.
89
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
90
The only concession to machine-parseability is **lightweight conventions** for the supervisor — the EM prefixes task assignments with `TASK:` so the supervisor can pattern-match without NLP. Everything else is natural language.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
91
92
### Tools
93
94
| Tool | Description |
95
|------|-------------|
96
| `send_message(channel, text)` | Post a message to a channel. |
97
| `read_messages(channel, since?, limit?)` | Read recent messages from a channel. Returns newest-first. |
98
| `create_channel(name)` | Create a new channel (used by EM when spinning up task channels). |
99
| `list_channels()` | List active channels. |
100
| `get_members(channel)` | List who's in a channel. |
101
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
102
That's it. No `post_task`, `claim_task`, `poll_for_task`. Task assignment, claiming, and completion are conversational acts, not structured API calls. The EM says "do this," the manager says "on it," the manager says "done."
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
103
104
Task state is tracked by the EM reading channel history and reasoning about it, not by a state machine. This is less reliable than a database but vastly more observable and simpler to build. If it breaks, you can see exactly where it broke by reading the channel.
105
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
106
### Message length
107
108
ergo supports the IRCv3 `maxline` capability, allowing messages up to ~8KB (vs. the traditional 512-byte limit). The MCP bridge should negotiate `maxline` on connect. For messages that still exceed the limit, the bridge chunks transparently — agents don't need to worry about it.
109
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
110
### Configuration
111
112
```
113
TRANSPORT_TYPE=irc
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
114
IRC_SERVER=<proxmox-host-ip>
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
115
IRC_PORT=6667
116
IRC_NICK=mcp-bridge
117
MCP_PORT=8090
118
```
119
120
The MCP server maintains a single IRC connection and multiplexes tool calls from multiple agents. Agents identify themselves via a `sender` parameter so messages get the right nick attribution.
121
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
122
## Shared state: robot.wtf wiki
123
124
IRC is ephemeral conversation. Durable shared state lives on a robot.wtf project wiki, accessed by agents via the wiki MCP.
125
126
- **Sprint state** — EM writes current task assignments, status, and blockers to a project wiki page. Survives EM shift-changes without replaying IRC history.
127
- **Handoff summaries** — outgoing agents write their handoff doc to the wiki. Incoming agent reads it as initial context.
128
- **Task specs and plans** — managers write plans to wiki pages before implementing. PM can review from anywhere.
129
- **Decision log** — architectural decisions, scope changes, PM rulings captured durably.
130
131
This means agents get **two MCP servers** in their config: the IRC bridge for communication, and robot.wtf for persistent shared state. IRC is the conversation, the wiki is the record.
132
133
EM recovery after a crash or shift-change: read the project wiki pages to reconstruct sprint state. No dependence on IRC `chathistory` depth.
134
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
135
## Agent lifecycle: long-running with shift-changes
136
137
Agents are long-running Claude Code SDK sessions. They persist across tasks, preserving context — a worker that just finished refactoring the auth module still has that code in context when the next auth-related task comes in.
138
139
### Why the SDK, not the CLI
140
083b67 Claude (MCP) 2026-03-20 03:47:44
[mcp] docs: update Agent_IRC_Architecture to reflect Python Agent SDK with preset+append
141
The Claude Code CLI is designed for a human at a terminal — prompt handling, display rendering, and keybindings are all overhead when the consumer is a daemon. The Python Agent SDK (`claude-agent-sdk`) provides programmatic conversation management without that overhead.
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
142
083b67 Claude (MCP) 2026-03-20 03:47:44
[mcp] docs: update Agent_IRC_Architecture to reflect Python Agent SDK with preset+append
143
The SDK's `query()` function includes the full Claude Code toolset — Read, Edit, Bash, Glob, Grep, and all other tools available in interactive Claude Code — without any extra configuration. The key is the **preset+append** system prompt pattern:
ddf7b3 Claude (MCP) 2026-03-19 23:03:33
[mcp] Add SDK vs CLI finding: SDK lacks Claude Code system prompt and tools
144
083b67 Claude (MCP) 2026-03-20 03:47:44
[mcp] docs: update Agent_IRC_Architecture to reflect Python Agent SDK with preset+append
145
```python
146
system_prompt={
147
"type": "preset",
148
"preset": "claude_code",
149
"append": "Your name is Harper. You are the EM..."
150
}
151
```
ddf7b3 Claude (MCP) 2026-03-19 23:03:33
[mcp] Add SDK vs CLI finding: SDK lacks Claude Code system prompt and tools
152
083b67 Claude (MCP) 2026-03-20 03:47:44
[mcp] docs: update Agent_IRC_Architecture to reflect Python Agent SDK with preset+append
153
This preserves Claude Code's full system prompt (tool usage patterns, git conventions, safety guardrails) while appending role-specific instructions on top.
e80ba1 Claude (MCP) 2026-03-19 23:17:48
[mcp] Correct SDK finding: ClaudeSDKClient includes full Claude Code toolset
154
083b67 Claude (MCP) 2026-03-20 03:47:44
[mcp] docs: update Agent_IRC_Architecture to reflect Python Agent SDK with preset+append
155
**Implementation note (2026-03-20):** The MVP initially used a Node.js subprocess wrapper (`sdk_wrapper.js`) calling the TypeScript `@anthropic-ai/claude-code` SDK, with `systemPrompt` which **replaced** the default prompt. This was corrected to use the Python Agent SDK with preset+append, eliminating the Node.js dependency entirely.
156
157
Key properties:
158
- Agents get the same coding capabilities as interactive Claude Code.
159
- No Node.js subprocess — the Python SDK calls `query()` directly.
160
- Session continuity via `resume=session_id` in `ClaudeAgentOptions`.
161
- Each `send()` call creates a new `query()` invocation; sessions are stateless between calls, resumed by ID.
ddf7b3 Claude (MCP) 2026-03-19 23:03:33
[mcp] Add SDK vs CLI finding: SDK lacks Claude Code system prompt and tools
162
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
163
### Polling and dispatch
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
164
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
165
Two-layer approach:
166
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
167
**Layer 1 — Supervisor push (primary).** The supervisor watches IRC directly for `TASK:` prefixes and immediately calls `client.query()` on the target agent's session with a "check your channels" prompt. Near-zero dispatch latency.
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
168
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
169
**Layer 2 — Polling (fallback/health).** A flat 30-second heartbeat: the supervisor calls `client.query()` on idle agents with a brief check-in prompt. This catches messages the supervisor missed (e.g., during its own restart) and confirms the agent process is alive. Add backoff (30s → 60s → 120s cap) later if idle token costs warrant it.
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
170
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
171
#### Response iteration
172
173
Supervisor code that drives an agent turn:
174
175
```python
176
await agent.client.query(prompt)
177
async for message in agent.client.receive_response():
178
if isinstance(message, AssistantMessage):
179
agent.last_active = datetime.utcnow()
180
elif isinstance(message, ResultMessage):
181
agent.session_id = message.session_id
182
agent.input_tokens_total += message.usage.input_tokens
183
agent.cost_usd_total += message.cost_usd
184
break
185
```
186
187
Multiple agents run concurrently via `asyncio.gather()` or by scheduling each agent's loop as a separate task.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
188
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
189
### Idle detection
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
190
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
191
A Haiku-class `ClaudeSDKClient` call (single turn, no session state needed):
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
192
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
193
```python
194
async with ClaudeSDKClient(options=haiku_options) as checker:
195
await checker.query(
196
f"Here is the last 5 minutes of IRC activity for agent '{nick}'. "
197
f"Is it idle? Respond with only: yes or no.\n\n{activity}"
198
)
199
async for msg in checker.receive_response():
200
if isinstance(msg, ResultMessage):
201
idle = msg.result.strip().lower() == "yes"
202
```
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
203
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
204
Pennies per evaluation. The supervisor doesn't need to understand task semantics — just whether to send a heartbeat or let the agent work.
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
205
206
### Context monitoring
207
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
208
`ResultMessage` provides `usage.input_tokens` per turn and `cost_usd` for budget tracking. The supervisor accumulates `input_tokens` across turns and compares against the known window size (200K for Sonnet, 1M for Opus) to estimate fullness. There is no built-in "% context used" metric — the accumulated token count is the proxy.
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
209
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
210
Thresholds:
211
- **80% of context window** — warn the agent, suggest wrapping up current subtask before the next one starts.
212
- **90% of context window** — trigger shift-change sequence immediately.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
213
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
214
### Context exhaustion and shift-changes
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
215
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
216
When the accumulated token estimate crosses the shift-change threshold:
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
217
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
218
1. Supervisor calls `agent.client.query()` with a handoff prompt: "Write a handoff summary to the wiki and post a notice to your channels."
219
2. Agent writes the summary to the project wiki (via wiki MCP) and posts a shift-change notice to its task channel and `#standup-{slug}`.
220
3. Supervisor drains `receive_response()` to completion and records the final `session_id` from the `ResultMessage`.
221
4. Supervisor closes the `ClaudeSDKClient` context (`async with` exits).
222
5. Supervisor pops a new name from `names.txt`, spawns a fresh `ClaudeSDKClient` with `--append-system-prompt` containing the agent's role, new name, channel assignments, and a pointer to the wiki handoff page.
223
6. New agent reads the handoff page on its first turn and posts an introduction to its channels.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
224
4546a8 Claude (MCP) 2026-03-19 23:18:24
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
225
Session resume (`session_id`) is **not** used for shift-changes — a new session with a clean context is the point. Session resume is instead useful for **supervisor restarts**: if the supervisor crashes and restarts, it can reconnect to existing agent sessions by replaying the stored `session_id` values rather than forcing a shift-change on every live agent.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
226
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
227
## Git strategy
228
229
Multiple agents edit the same repos simultaneously. Branch isolation via git worktrees.
230
231
### Worktree lifecycle
232
233
The **supervisor** creates worktrees before spawning agents. Agents never touch `git worktree add/remove`.
234
235
```
236
~/projects/repo/ # bind-mounted, main branch (protected)
237
~/projects/repo/.worktrees/
238
agent-task-42/ # worktree for task 42
239
agent-task-71/ # worktree for task 71
240
```
241
242
Supervisor sequence per task:
243
1. `git worktree add .worktrees/agent-task-{id} -b task/{id}`
244
2. Spawn agent session with `cwd` set to the worktree
245
3. Pass the branch name in the agent's system prompt
246
247
### Branch and merge strategy
248
249
- **Main branch is protected.** Agents never get the main worktree path, only task worktree paths.
250
- **Agents commit freely** to their `task/{id}` branch and push when done.
251
- **Human PM merges.** No auto-merge for MVP. The supervisor or EM can rebase branches and annotate PRs, but the merge button stays with the human.
252
- **Conflict prevention:** the EM avoids assigning overlapping file sets to concurrent agents. When conflicts happen anyway, the supervisor flags them for human resolution.
253
254
### Cleanup
255
256
- **Normal completion:** supervisor waits for push, then `git worktree remove`. Branch retained until merged.
257
- **Agent crash:** supervisor commits any uncommitted work with `[INCOMPLETE]` prefix, removes worktree, flags task for reassignment.
258
- **On supervisor restart:** reconcile state against `git worktree list`, clean up orphans.
259
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
260
## Architecture components
261
262
Three independent components, deployed separately for independent failure domains:
263
264
### 1. ergo IRCd
265
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
266
- Runs in an LXC container on a Proxmox server (16GB RAM).
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
267
- Set-and-forget after initial configuration.
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
268
- IRCv3 `chathistory` enabled for convenience, but not load-bearing — sprint state lives on the wiki.
269
- `maxline` capability enabled for longer messages.
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
270
- No TLS needed for LAN traffic in MVP.
271
272
### 2. IRC MCP bridge (FastMCP)
273
274
- ~200 lines of Python.
275
- Wraps the transport abstraction with IRC backend.
276
- Exposes the five tools above.
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
277
- Negotiates `maxline` with ergo; chunks messages transparently if needed.
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
278
- Connects to ergo over LAN.
279
- Runs in a Docker container on the desktop.
280
281
### 3. Agent supervisor
282
82f820 Claude (MCP) 2026-03-19 23:18:55
[mcp] Revamp agent supervisor section with concrete ClaudeSDKClient design
283
A Python asyncio process that manages the lifecycle of all `ClaudeSDKClient` agent sessions. It is the only component that directly constructs or destroys agent sessions.
284
285
#### Agent session wrapper
286
287
```python
288
@dataclass
289
class AgentSession:
1a9ab8 Claude (MCP) 2026-03-20 03:47:53
[mcp] docs: update AgentSession wrapper to match actual implementation
290
name: str # IRC nick / human name
291
model: str # e.g. "claude-opus-4-6"
292
system_prompt: str # role-specific prompt (appended to Claude Code defaults)
293
cwd: str # working directory (worktree path)
294
mcp_servers: dict[str, dict] # MCP server configs (irc-bridge, dev-wiki)
295
context_tracker: ContextTracker # tracks token usage and shift threshold
296
297
session_id: str | None # from ResultMessage; used for resume
298
_alive: bool # set to False on kill()
299
_lock: asyncio.Lock # serializes send() calls
300
_send_timeout: float # timeout for each query() call (default 300s)
82f820 Claude (MCP) 2026-03-19 23:18:55
[mcp] Revamp agent supervisor section with concrete ClaudeSDKClient design
301
```
302
1a9ab8 Claude (MCP) 2026-03-20 03:47:53
[mcp] docs: update AgentSession wrapper to match actual implementation
303
Each `send()` call creates a `query()` invocation with `ClaudeAgentOptions` including:
304
- `system_prompt={"type": "preset", "preset": "claude_code", "append": self.system_prompt}`
305
- `resume=self.session_id` (if resuming a session)
306
- `permission_mode="bypassPermissions"` (agents run unattended)
307
- `mcp_servers` for IRC bridge and wiki access
308
82f820 Claude (MCP) 2026-03-19 23:18:55
[mcp] Revamp agent supervisor section with concrete ClaudeSDKClient design
309
#### Session construction
310
311
```python
5a3749 Claude (MCP) 2026-03-20 03:48:06
[mcp] docs: update session construction to match actual supervisor implementation
312
async def spawn_em(self) -> AgentSession:
313
name = self.cfg.em_name
314
model = self.cfg.em_model
315
tracker = ContextTracker(
316
window_size=ModelTier.context_window(model),
317
threshold_pct=self.cfg.shift_threshold_pct,
82f820 Claude (MCP) 2026-03-19 23:18:55
[mcp] Revamp agent supervisor section with concrete ClaudeSDKClient design
318
)
5a3749 Claude (MCP) 2026-03-20 03:48:06
[mcp] docs: update session construction to match actual supervisor implementation
319
session = AgentSession(
320
name=name,
321
model=model,
322
system_prompt=self._load_prompt("em"),
323
cwd=self.cfg.project_dir,
324
mcp_servers=self._mcp_servers(),
325
context_tracker=tracker,
326
)
327
self.agents[name] = ManagedAgent(session=session, task_id=None, role="em")
328
return session
82f820 Claude (MCP) 2026-03-19 23:18:55
[mcp] Revamp agent supervisor section with concrete ClaudeSDKClient design
329
```
330
5a3749 Claude (MCP) 2026-03-20 03:48:06
[mcp] docs: update session construction to match actual supervisor implementation
331
`_load_prompt(role)` reads `prompts/{role}.md` — a plain text string that gets appended to Claude Code's default system prompt via the preset+append pattern. Content includes: agent name, role description, channel assignments, workflow instructions, and decision rules.
332
333
MCP servers are configured with explicit transport types:
334
```python
335
def _mcp_servers(self) -> dict[str, dict]:
336
return {
337
"irc-bridge": {"type": "sse", "url": self.cfg.mcp_bridge_url},
338
"dev-wiki": {"type": "sse", "url": self.cfg.wiki_mcp_url, ...},
339
}
340
```
82f820 Claude (MCP) 2026-03-19 23:18:55
[mcp] Revamp agent supervisor section with concrete ClaudeSDKClient design
341
342
#### Supervisor restart recovery
343
344
On startup, the supervisor reads a persisted state file containing `{nick, role, task_id, channels, session_id, tokens, cost, worktree_path}` for each live agent. For each entry:
345
346
- If the session is still resumable (`session_id` is valid), reconnect with `resume=session_id` and send a check-in prompt.
347
- If resume fails, treat it as a shift-change: spawn a replacement and have it read the last handoff wiki page.
348
349
This means a supervisor crash does not force context loss — agent sessions can be reconnected.
350
351
#### Responsibilities summary
352
353
| Responsibility | Mechanism |
354
|---|---|
355
| Spawn/retire agents | `ClaudeSDKClient` async context manager |
356
| Dispatch on `TASK:` | Direct IRC read → `client.query()` |
357
| Heartbeat / idle check | 30s loop → Haiku idle classifier → `client.query()` |
358
| Context monitoring | Accumulate `ResultMessage.usage.input_tokens` |
359
| Shift-change | Handoff prompt → close → `spawn_agent()` with wiki path |
360
| Supervisor restart recovery | Persisted state file + `session_id` resume |
361
| Git worktrees | `git worktree add/remove` before/after agent spawn |
362
| Budget tracking | Accumulate `ResultMessage.cost_usd` per session |
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
363
364
```
365
Desktop (128GB RAM) Proxmox (16GB RAM)
366
┌──────────────────────────────┐ ┌──────────────────┐
367
│ docker-compose │ │ LXC container │
368
│ ┌────────────┐ ┌───────────┐│ │ ┌──────────────┐ │
369
│ │ Supervisor │ │ IRC MCP ││ LAN │ │ ergo │ │
370
│ │ (SDK) │ │ Bridge ││◄────►│ │ IRCd │ │
371
│ └────────────┘ └───────────┘│ │ └──────────────┘ │
372
│ bind: ~/projects │ └──────────────────┘
373
└──────────────────────────────┘
374
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
375
│ IRC client (terminal) or Claude.ai (PM delegate)
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
376
PM
377
```
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
378
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
379
Agents receive two MCP server configs:
380
1. **IRC bridge** — communication with other agents and the PM
381
2. **robot.wtf wiki** — persistent shared state (sprint status, handoff summaries, task specs, decisions)
382
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
383
## Relationship to existing Agent_Workflow
384
385
What carries forward unchanged:
386
387
- Role definitions (manager, implementer, test runner, Groucho/Chico/Zeppo/Fixer/Documenter)
388
- The proceed workflow (plan → implement → test → review → fix → document)
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
389
- Model assignments (Opus for EM and managers, Sonnet for workers, Haiku for idle detection and documentation)
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
390
- Review and fix loop limits (3 attempts before escalating)
391
- Worker dispatch guidance (what context to give each worker type)
392
393
What changes:
394
395
- Coordination moves from in-process `Task`/`run_in_background` to IRC channel messages via MCP
396
- The orchestrator role splits: strategic coordination stays with the EM, human interaction moves to the channel
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
397
- Question relay is replaced by direct channel participation — the PM is in the room (or their Claude.ai delegate is)
398
- Task state lives on the wiki, conversation happens on IRC
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
399
- Claude Code CLI replaced by Claude Code SDK for programmatic lifecycle management
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
400
401
## MVP scope
402
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
403
1. **ergo IRCd** in LXC on Proxmox. Single binary, default config, enable `chathistory` and `maxline`.
404
2. **IRC MCP bridge** (~200 lines Python). FastMCP wrapping the transport abstraction. Five tools. Docker container.
405
3. **Agent supervisor** — Python, Claude Code SDK, Haiku idle-checker, shift-change logic, worktree management. Docker container.
731b96 Claude (MCP) 2026-03-16 17:37:43
[mcp] Update Agent IRC Architecture with refined design decisions from brainstorming session
406
4. **docker-compose** for bridge + supervisor on the desktop, bind-mounting the project directory.
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
407
5. **robot.wtf project wiki** for shared state (already exists).
408
6. **One EM process** — Opus, system-prompted as the engineering manager.
409
7. **One manager process** — spawned when the EM posts a task.
410
8. **PM** — connected to ergo from terminal (weechat/irssi).
411
9. **One end-to-end task** — EM assigns, manager runs the proceed workflow, PM observes from IRC, state persisted to wiki.
412
413
Not in MVP: multiple parallel workers, TLS, remote MCP auth (for Claude.ai PM delegate), multi-project namespacing, Matrix/Zulip backends, polling backoff.
414
415
## Future: PM delegate via Claude.ai
416
417
Once the IRC MCP bridge is exposed as a remote MCP server (with auth), a Claude.ai session can connect to it and act as the PM's delegate. The PM talks to Claude.ai from their phone or browser; Claude.ai participates in IRC channels on their behalf. This replaces the need for a mobile IRC client entirely.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
418
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
419
This requires the bridge to be internet-accessible with authentication — not in MVP scope, but the architecture supports it naturally since the bridge already multiplexes by `sender`.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
420
421
## Open questions
422
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
423
- **ergo `maxline` default.** Verify the actual default and maximum configurable value. Agent plan summaries could be multi-KB.
424
- **SDK `query()` API stability.** The session resume API (`resume` option) needs verification against current SDK version. Field names may have changed.
bc7b82 Claude (MCP) 2026-03-16 04:43:54
[mcp] Recreate Agent IRC Architecture design doc (lost during wiki dev work)
425
426
## Resolved questions
427
88448e Claude (MCP) 2026-03-16 17:45:47
[mcp] Comprehensive update: research findings, wiki shared state, git strategy, polling, PM delegate, resolved open questions
428
- **Structured vs. conversational task format.** Conversational wins. The whole point of using IRC is human observability. The only structured convention is a `TASK:` prefix on assignments.
429
- **CLI vs. SDK.** SDK. The CLI's terminal processing is overhead for daemon use.
430
- **Single process vs. separate bridge and supervisor.** Separate. Independent failure domains.
431
- **Launch-per-task vs. long-running agents.** Long-running. Preserves context across related tasks.
432
- **Deployment topology.** ergo in LXC on Proxmox, bridge + supervisor in docker-compose on desktop (128GB RAM).
433
- **Polling strategy.** Two-layer: supervisor push for immediate dispatch, flat 30s polling as fallback/health check. Backoff deferred.
434
- **Git branch strategy.** Supervisor-managed worktrees, branch-per-task, human merges, protected main.
435
- **Context monitoring.** Supervisor accumulates `usage.input_tokens` per turn from SDK responses. No built-in SDK metric.
436
- **Durable state.** robot.wtf project wiki via MCP. IRC is ephemeral conversation, wiki is the record. EM recovery reads wiki, not IRC history.
437
- **Mobile IRC client.** Deferred. PM uses terminal for MVP. Future path: Claude.ai as PM delegate via remote MCP, bypassing the mobile client problem entirely.