-
Notifications
You must be signed in to change notification settings - Fork 1
Multi Agent Pool
The Agent dispatch UX wrapper prefixes prompts with
Use the <agent> sub-agent to …, but that sub-agent runs inside the same
single Claude child process as the main project console — so truly parallel
work (e.g. reviewer reading files while a frontend agent writes Compose UI in
the same project) is impossible through it alone.
The sub-agent pool is 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.
Sub-agent turns share the same ClaudeConcurrencyGate as the main project
console — one Anthropic account is one in-flight pool, so they must be counted
together to avoid bursting into a 429. The cap is claude.maxConcurrentTurns
(default 3); excess turns queue (with a "동시 작업 한도 도달 — 대기 중" console
notice) and proceed in order as turns finish. Adjustable live in /settings
(no restart, v1.90.0+ — setLimit). See
Troubleshooting → Rate limited (429) for tuning guidance.
| 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 authentication (Bearer token or vibe_session cookie).
vibe-coder is single-admin — see Security Model.
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. The
conversation_turns.agent_namecolumn distinguishes main-console turns (null) from sub-agent turns ('<name>'). Restart-safe. See Conversation History for the schema. -
Agent filter UI.
/projects/{id}/historyhas a dropdown ((main only)/(all)/@<name>) plus a row badge so sub-agent origin is visible at a glance. Pagination preserves the choice via the?agent=query parameter. -
Agent definitions 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.
-
Custom Agents — managing
~/.claude/agents/*.mdfiles (the registry the pool reads). - Multi-Console — 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.