-
Notifications
You must be signed in to change notification settings - Fork 1
Multi Agent Pool
Introduced in v0.44.0 as Phase 23.
Before v0.44.0 the Agent dispatch UX wrapper (v0.36.0 / v0.41.0)
prefixed prompts with Use the <agent> sub-agent to …, but the resulting
sub-agent ran inside the same single Claude child process as the main
project console. Truly parallel work (e.g. reviewer reading files while a
frontend agent writes Compose UI in the same project) was therefore impossible.
v0.44.0 ships an independent process pool: SubAgentSessionManager keyed by
(projectId, agentName). Each agent gets its own:
-
claudechild process - session-id file (
<workspace>/<projectId>/.vibecoder/agent-sessions/<agent>.id) - LogHub WebSocket topic (
console-agent-<projectId>-<agentName>) - console UI
All sub-agent processes share the same project workspace, so they collaborate on the same source tree.
The main ClaudeSessionManager keeps a single child per
project. Re-keying it to (projectId, agentName) would touch every caller
of sendPrompt(projectId, text) (history persistence, action handler,
publish services, status service, etc.) for marginal gain. A parallel
SubAgentSessionManager is ~200 LOC and keeps the existing console path
untouched.
| Event | Behaviour |
|---|---|
First prompt to a fresh (projectId, agentName)
|
Spawns new claude child in the project root. Auto-prefixes the prompt with Use the <agentName> sub-agent to so Claude Code dispatches its standard sub-agent. |
| Second+ prompt | Stdin write into the same persistent child. Prefix not re-added (firstPromptSent flag in AgentSession). |
| Idle 30 minutes | SIGTERM (5 s grace → SIGKILL). Session-id is preserved; the next prompt spawns a new child with --resume <savedId>. |
| User clicks "새 세션" |
startNew(...) terminates + deletes the session-id file + resets the console ring. |
| User clicks ■ 중지 |
cancelTurn(...) terminates the alive child but keeps the session-id so the next prompt resumes the same conversation. |
| Process exits unexpectedly |
process_crashed system frame is broadcast; next prompt attempts resume. |
The 30-minute reaper is shared with ClaudeSessionManager design (same idle
timeout default) so operator memory budgets stay predictable.
| Route | Purpose |
|---|---|
/projects/{id}/agents |
Index — every registered .agents/*.md with a live running / idle badge and an "Open console →" link. Header link from the main console (@ sub-agents → chip). |
/projects/{id}/agents/{agent}/console |
Per-agent console. Trimmed view of the main console — no slash chips, no template picker, no agent dispatch dropdown (you're already inside one agent). ■ stop + 새 세션 buttons present. |
All routes require requireApiWrite() (admin or member; viewers get
403 viewer_readonly — see JSON API role guards).
TOKEN=… # Bearer from POST /api/auth/login
# Send a prompt to a sub-agent
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"text":"List the Compose files you would touch to add a settings screen."}' \
http://localhost:17880/api/projects/myapp/agents/frontend/console/prompt
# → {"ok":true}
# Cancel current turn (SIGTERM child, keep session-id)
curl -X POST -H "Authorization: Bearer $TOKEN" \
http://localhost:17880/api/projects/myapp/agents/frontend/console/cancel
# List active agents for a project
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:17880/api/projects/myapp/agents/active
# → {"projectId":"myapp","agents":["frontend","reviewer"]}/ws/projects/{projectId}/agents/{agentName}/console/logs — same protocol
as the main console:
- Cookie-based auth on handshake (Origin check applied); Bearer first-frame fallback for non-browser clients
- Replay + live merge with monotonic
seq - Frames:
ConsoleSessionStarted,ConsoleAssistant,ConsoleToolUse,ConsoleToolResult,ConsoleError,ConsoleDone,ConsoleSystem,ConsoleReplayBegin/End
Unlike the main console, this WebSocket is read-only on the client side. Prompts are sent via the REST endpoint above. Incoming text frames from the client are drained but ignored — keeps the WebSocket healthy without duplicating prompt dispatch.
<workspace>/<projectId>/
├── … source files …
└── .vibecoder/
├── claude-session.id # main console session
└── agent-sessions/
├── reviewer.id # @reviewer session
├── frontend.id # @frontend session
└── backend.id # @backend session
A single workspace, multiple session files, multiple live processes.
- ✅ Persistent history — landed in v0.49.0.
conversation_turns.agent_namecolumn distinguishes main-console turns (null) from sub-agent turns ('<name>'). Restart-safe. See Conversation History for the schema. A dedicated agent filter on the/projects/{id}/historypage is still planned — today all turns appear mixed. -
Agent definitions still go through
~/.claude/agents/*.md. Manage them at /agents. The pool reads the same registry — remove an agent there and its existing process keeps running until terminated; the next-prompt path falls back to the trivial "agent not registered" 404. -
No per-agent role / ACL split today. Anyone with
canWriteon a project can spawn / prompt any agent there.
-
Custom Agents — managing
~/.claude/agents/*.mdfiles (the registry the pool reads). - Multi-Console — earlier N-pane iframe approach for parallel project consoles. Multi-Agent-Pool is the corresponding story at the agent level inside one project.
-
Architecture Overview — where
SubAgentSessionManagerfits in the bigger picture.