Skip to Content
Developer GuideDaemon01 · System Architecture

Daemon Architecture

Overview

A qwen serve process is one daemon = one workspace. It hosts a single Express HTTP server, owns an @qwen-code/acp-bridge instance, and spawns one ACP child process (qwen --acp) that runs the actual agent runtime. Multiple clients (CLI TUI, IDE companion, IM channel bots, web BFFs, custom scripts) connect over HTTP + SSE and either share one ACP session (sessionScope: 'single', default) or split sessions by conversation thread (sessionScope: 'thread').

Inside the ACP child, MCP servers are shared workspace-wide through McpTransportPool (F2): a single (server-name + config-fingerprint) tuple maps to one MCP transport, regardless of how many sessions discover it. The bridge’s MultiClientPermissionMediator (F3) coordinates permission votes across all connected clients under one of four policies.

This doc gives the system-level picture that the rest of this documentation set builds on. Each critical flow is shown as a Mermaid sequence diagram; per-component implementation details live in the other 18 docs.

Process topology

The daemon process and the ACP child are connected by an AcpChannel (default: a real subprocess stdio pipe pair; inMemoryChannel for tests). Everything the daemon does is shaped by this split: HTTP and SSE traffic terminate in the daemon, agent decisions and tool invocations happen in the child, and the bridge connects the two.

Package map

Three trust boundaries matter: the HTTP edge (serve/auth.ts middleware chain), the bridge-to-ACP-child boundary (NDJSON over stdio, no auth; the child trusts the bridge implicitly), and the agent-to-MCP-server boundary (the agent may invoke tools that touch the host).

Workflow 1: HTTP request lifecycle

Non-streaming routes (prompt, cancel, model switch, metadata, workspace CRUD) terminate as a single JSON reply. Streaming output is delivered out-of-band on the SSE channel, not as a chunked HTTP body on this connection. See workflow 2.

Workflow 2: SSE event delivery and replay

The ring buffer is bounded (eventRingSize, default 8000). A reconnecting client whose Last-Event-ID is older than the ring’s head receives a synthetic catch-up signal and must call loadSession / resumeSession to rebuild deeper state. Slow clients trigger slow_client_warning at 75% queue fill and client_evicted at the cap.

Workflow 3: Multi-client permission mediation

Cross-policy escape hatch: any client may vote CANCEL_VOTE_SENTINEL to short-circuit the request as cancelled / agent_cancelled. The bridge guards against wire callers smuggling the sentinel via the normal optionId field (InvalidPermissionOptionError).

Workflow 4: MCP transport pool acquire / release / restart

releaseSession(sessionId) uses the reverse sessionToEntries index to release every entry the session holds in O(refs). On daemon shutdown, drainAll() sets the draining flag (refusing new acquires) and waits for every entry to close under a configurable timeout.

Workflow 5: Lifecycle — startup and graceful shutdown

The two-phase shutdown matters because in-flight HTTP requests, in-flight SSE subscribers, and the ACP child’s in-flight tool calls all need bounded teardown windows. If anything blocks past those deadlines, the force-close path takes over so a stuck child cannot keep the daemon process alive.

Critical files

ConcernFile
Bootstrappackages/cli/src/serve/run-qwen-serve.ts
Express apppackages/cli/src/serve/server.ts
Capability registrypackages/cli/src/serve/capabilities.ts
Auth middlewarepackages/cli/src/serve/auth.ts
Bridgepackages/acp-bridge/src/bridge.ts
BridgeClientpackages/acp-bridge/src/bridgeClient.ts
Permission mediatorpackages/acp-bridge/src/permissionMediator.ts
EventBuspackages/acp-bridge/src/eventBus.ts
MCP transport poolpackages/core/src/tools/mcp-transport-pool.ts
Workspace MCP budgetpackages/core/src/tools/mcp-workspace-budget.ts
Workspace FSpackages/cli/src/serve/fs/
SDK DaemonClientpackages/sdk-typescript/src/daemon/DaemonClient.ts
SDK SessionClientpackages/sdk-typescript/src/daemon/DaemonSessionClient.ts
Event schemapackages/sdk-typescript/src/daemon/events.ts

References

Last updated on