2026-03-19 23:18:24Claude (MCP):
[mcp] Revamp agent lifecycle section with concrete SDK patterns and code sketches
Minsky/Agent_IRC_Architecture.md ..
@@ 154,37 154,65 @@
Two-layer approach:
-
**Layer 1 — Supervisor push (primary).** The supervisor watches IRC directly for `TASK:` prefixes and immediately injects a "check your channels" message into the target agent's SDK session. Near-zero dispatch latency.
+
**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.
-
**Layer 2 — Polling (fallback/health).** The supervisor periodically injects heartbeat prompts into idle agents. This catches messages the supervisor missed (e.g., during its own restart) and proves the agent is still alive.
+
**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.
-
MVP polling strategy: flat 30s interval when idle, no polling when active. Add backoff (30s → 60s → 120s cap) later if idle token costs warrant it.
+
#### Response iteration
+
+
Supervisor code that drives an agent turn:
+
+
```python
+
await agent.client.query(prompt)
+
async for message in agent.client.receive_response():
Multiple agents run concurrently via `asyncio.gather()` or by scheduling each agent's loop as a separate task.
### Idle detection
-
A Haiku-class classifier determines whether an agent is idle. No conversation state needed — just a single SDK `create_message` call:
+
A Haiku-class `ClaudeSDKClient` call (single turn, no session state needed):
-
> "Here's the last 5 minutes of this agent's IRC activity. Is it idle? yes/no"
+
```python
+
async with ClaudeSDKClient(options=haiku_options) as checker:
+
await checker.query(
+
f"Here is the last 5 minutes of IRC activity for agent '{nick}'. "
+
f"Is it idle? Respond with only: yes or no.\n\n{activity}"
+
)
+
async for msg in checker.receive_response():
+
if isinstance(msg, ResultMessage):
+
idle = msg.result.strip().lower() == "yes"
+
```
-
Pennies per evaluation. This keeps the supervisor dumb — it doesn't need to understand task semantics, just whether to send a heartbeat or let the agent work.
+
Pennies per evaluation. The supervisor doesn't need to understand task semantics — just whether to send a heartbeat or let the agent work.
### Context monitoring
-
The Claude Code SDK does not expose a "% context used" metric. Each response includes per-turn `usage.input_tokens`. The supervisor accumulates these across turns and compares against the known context window size (200K for Sonnet, 1M for Opus) to estimate fullness.
+
`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.
-
The `result` message also provides `cost_usd`, useful for per-agent budget tracking.
+
Thresholds:
+
- **80% of context window** — warn the agent, suggest wrapping up current subtask before the next one starts.
+
- **90% of context window** — trigger shift-change sequence immediately.
### Context exhaustion and shift-changes
-
When an agent's estimated context usage crosses a threshold (e.g., 80% of window):
+
When the accumulated token estimate crosses the shift-change threshold:
-
1. Supervisor tells the agent to produce a handoff summary.
-
2. Agent writes the summary to the project wiki.
-
3. Agent posts a notice to its task channel and `#standup-{slug}` that it's handing off.
-
4. Supervisor kills the session.
-
5. Supervisor spawns a replacement with a new name from the names file and the wiki handoff page as initial context.
+
1. Supervisor calls `agent.client.query()` with a handoff prompt: "Write a handoff summary to the wiki and post a notice to your channels."
+
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}`.
+
3. Supervisor drains `receive_response()` to completion and records the final `session_id` from the `ResultMessage`.
+
4. Supervisor closes the `ClaudeSDKClient` context (`async with` exits).
+
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.
+
6. New agent reads the handoff page on its first turn and posts an introduction to its channels.
-
This is the "shift change" pattern — natural for an org metaphor. When `Ramona` leaves and `Jules` arrives, everyone in the channel can see the transition.
+
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.