docs/developers/daemon/00-index.md
This is the developer-facing technical documentation for qwen-code daemon mode: the qwen serve HTTP daemon, the @qwen-code/acp-bridge package, the workspace-scoped MCP transport pool, multi-client permission mediation, typed daemon event schema v1, the TypeScript SDK daemon client, and the adapters that connect to the daemon.
It complements, rather than replaces, these existing docs:
| Existing doc | Audience | Source of truth for |
|---|---|---|
../../users/qwen-serve.md | Operators | User quickstart, flags, threat model |
../qwen-serve-protocol.md | Protocol implementers | HTTP route catalog, request/response shapes, error codes |
../examples/daemon-client-quickstart.md | SDK users | End-to-end TypeScript walkthrough |
../daemon-client-adapters/ | Adapter authors | Client adapter design notes |
../../design/f2-mcp-transport-pool.md | F2 maintainers | Workspace MCP transport pool design v2.2 |
If you want to start a daemon and use it, read qwen-serve.md first. If you want to build a client against the wire format, read qwen-serve-protocol.md. If you want to understand, extend, or debug the daemon internals, read this set.
Pick the path that matches your goal:
20 -> 17 -> 19.01 -> 02 -> 03 -> 08 -> 09 -> 10 -> 11 -> 12.01 -> 09 -> 10 -> 13 -> (14 / 15 / 16).01 -> 03 -> 05 -> 06.01 -> 03 -> 04 -> 12.19 -> 18 -> 17 -> 20.01-architecture.md - system architecture, process topology, package map, and all seven top-level sequence diagrams.02-serve-runtime.md - runQwenServe bootstrap, Express app, middleware chain, graceful shutdown.03-acp-bridge.md - @qwen-code/acp-bridge package internals, session multiplexing, channel factory, ACP child spawn.04-permission-mediation.md - MultiClientPermissionMediator, four policies, N1 timeout invariant, cancel sentinel.05-mcp-transport-pool.md - McpTransportPool (F2), pool entries, reverse index, restart, drain.06-mcp-budget-guardrails.md - WorkspaceMcpBudget, modes (off/warn/enforce), hysteresis, refused-batch coalescing.07-workspace-filesystem.md - WorkspaceFileSystem sandbox, path policy, audit, BridgeFileSystem contract.08-session-lifecycle.md - create / attach / load / resume, X-Qwen-Client-Id, heartbeat, eviction, metadata.09-event-schema.md - typed event schema v1: all 43 known event types with payloads, reducers, forward compatibility.10-event-bus.md - EventBus, monotonic IDs, ring replay, Last-Event-ID, slow-client backpressure, client_evicted.11-capabilities-versioning.md - capability registry, protocol version, schema version, conditional advertisement.12-auth-security.md - bearer middleware, host allowlist, CORS deny, mutation gate, --require-auth, /health exemption, device flow.13-sdk-daemon-client.md - TypeScript SDK: DaemonClient, DaemonSessionClient, DaemonAuthFlow, SSE parser, event reducers, ui/* transcript layer.14-cli-tui-adapter.md - shared UI transcript layer and the legacy CLI TUI daemon adapter relationship.15-channel-adapters.md - DaemonChannelBridge shared base plus DingTalk, WeChat (Weixin), Telegram, Feishu per-channel adapters.16-vscode-ide-adapter.md - DaemonIdeConnection, loopback-only enforcement, webview bridging.17-configuration.md - env vars, CLI flags, settings.json keys that affect the daemon.18-error-taxonomy.md - typed errors per layer with remediation.19-observability.md - QWEN_SERVE_DEBUG, debugging recipes, telemetry gaps.20-quickstart-operations.md - shortest startup path, curl checks, route map, and embedded invocation recipes.qwen --acp) to host the actual agent runtime. The bridge multiplexes one ACP child across many connected clients.@qwen-code/acp-bridge package (packages/acp-bridge/). Owns session multiplexing, the permission mediator, the event bus, and the channel factory.packages/acp-bridge/src/bridgeClient.ts. Wraps one ACP ClientSideConnection, and handles requestPermission, sendPrompt, and cancelSession.spawnChannel runs qwen --acp as a subprocess; inMemoryChannel runs it in-process for tests.packages/sdk-typescript/src/daemon/DaemonClient.ts. The TypeScript SDK HTTP-level facade over the daemon.packages/sdk-typescript/src/daemon/DaemonSessionClient.ts. Session-scoped wrapper that tracks lastSeenEventId for SSE replay.packages/acp-bridge/src/eventBus.ts. Per-session in-memory pub/sub with monotonic IDs, a bounded ring, and per-subscriber backpressure.BridgeFileSystem. F2: workspace-scoped MCP transport pool. F3: multi-client permission mediation. F4: protocol completion and daemon client surfaces.packages/core/src/tools/mcp-transport-pool.ts. F2 workspace-scoped pool sharing one MCP transport per server name and config fingerprint.first-responder, designated, consensus, or local-only. Decides how multi-client permission votes resolve.X-Qwen-Client-Id of the client that initiated the prompt currently requesting permission. The designated policy only accepts votes from this id.packages/core/src/tools/mcp-pool-entry.ts. One entry in McpTransportPool: one MCP transport, a refcount of attached sessions, and an idle drain timer.single (one ACP session shared by all clients) or thread (one session per conversation thread). The default is single.GET /session/:id/events).--workspace or cwd). One daemon process equals one workspace.Use these anchors when moving from the docs into the latest main code:
| Surface | Implementation anchors | Primary docs |
|---|---|---|
| Bootstrap and HTTP assembly | packages/cli/src/serve/runQwenServe.ts, server.ts, /demo | 02, 20 |
| ACP bridge and session multiplexing | packages/acp-bridge/src/bridge.ts, packages/acp-bridge/src/bridgeTypes.ts, @qwen-code/acp-bridge | 03, 08 |
| Permission mediation | packages/acp-bridge/src/permissionMediator.ts, fromLoopback: boolean, policy.* | 04, 12 |
| MCP transport pool | packages/core/src/tools/mcp-transport-pool.ts, mcp-pool-key.ts, pid-descendants.ts, session-mcp-view.ts, /mcp refresh, MCPCallInterruptedError | 05, 06 |
| MCP budget guardrails | packages/core/src/tools/mcp-workspace-budget.ts, ServeMcpBudgetStatusCell.scope, budgets[] | 06 |
| Workspace filesystem | packages/cli/src/serve/fs/, assertTrustedForIntent(trusted, intent), meta.matchedIgnore, includeIgnored | 07 |
| Event schema and SSE writer | packages/sdk-typescript/src/daemon/events.ts, packages/cli/src/serve/server.ts, formatSseFrame, packages/cli/src/acp-integration/session/emitters/ToolCallEmitter.ts, ToolCallEmitter.resolveToolProvenance, tool_call.provenance, serverId | 09, 10 |
| Event resync | state_resync_required, awaitingResync, RESYNC_PASSTHROUGH_TYPES, asKnownDaemonEvent, unrecognizedKnownEventCount | 09, 10 |
| Capabilities | packages/cli/src/serve/capabilities.ts, mcp_server_restart_refused.reason, MCP_RESTART_REFUSED_REASONS.has | 11 |
| Auth and device flow | packages/cli/src/serve/auth.ts, packages/cli/src/serve/auth/deviceFlow.ts | 12 |
| TypeScript SDK daemon client | packages/sdk-typescript/src/daemon/{DaemonClient,DaemonSessionClient,DaemonAuthFlow,sse,events,types}.ts, MCP_RESTART_DEFAULT_TIMEOUT_MS | 13 |
| Shared UI transcript layer | DaemonUiEventType, DaemonSessionProvider, packages/webui/src/daemon/ | 13, 14, ../daemon-ui/README.md |
| Channels and IDE adapters | packages/channels/, packages/vscode-ide-companion/src/services/daemonIdeConnection.ts | 15, 16 |
docs/developers/daemon-ui/ and adapter design notes.packages/zed-extension/) - it launches qwen --acp over stdio directly and bypasses the daemon.--no-http-bridge still falls back to http-bridge today; a stable in-process serve mode would need new docs when it lands.| Area | Current state | Primary docs |
|---|---|---|
| Bootstrap / listen path | qwen serve lazy-loads runQwenServe, validates auth/workspace/budget/settings, builds an Express app, then calls app.listen and blocks forever until signal. | 02, 20 |
| Auth / network guardrails | Loopback defaults to no bearer; non-loopback requires bearer; --require-auth extends bearer to loopback and /health; Host allowlist and default CORS deny are active. | 12, 17 |
| Session lifecycle | POST /session, load, resume, metadata patch, heartbeat, eviction, idle reaping, prompt pending limits, and graceful close are documented. | 08, 10 |
| ACP bridge | Single ACP child multiplexed by default; sessionScope supports single and thread; BridgeFileSystem, context filename, env overrides, and channel idle timeout are wired. | 03, 07 |
| MCP pool / budget | Workspace MCP pool is on by default unless QWEN_SERVE_NO_MCP_POOL=1; guardrail events and restart semantics are documented. | 05, 06 |
| Permissions | F3 mediator supports first-responder, designated, consensus, and local-only; invalid settings fail explicitly. | 04, 12 |
| Area | Current state | Primary docs |
|---|---|---|
| HTTP routes | The route catalog lives in qwen-serve-protocol.md; this daemon set only references it and explains implementation ownership. | ../qwen-serve-protocol.md, 20 |
| Event schema | EVENT_SCHEMA_VERSION = 1; 43 known event types; id-less subscriber synthetic frames; _meta.serverTimestamp stamped at SSE write boundary. | 09, 10 |
| Capabilities | SERVE_PROTOCOL_VERSION = 'v1'; 66 registered tags; 10 conditional tags. | 11 |
| Session shell | POST /session/:id/shell exists behind --enable-session-shell, bearer auth, and session-bound X-Qwen-Client-Id; capability tag is conditional. | 11, 17, 20 |
| Rate limiting | Optional per-tier HTTP rate limit is exposed by CLI flags/env and conditional capability tag. | 11, 17 |
| Area | Current state | Primary docs |
|---|---|---|
| TypeScript SDK daemon client | DaemonClient, DaemonSessionClient, DaemonAuthFlow, SSE parser, event reducers, feature preflight, and UI transcript exports are documented. | 13 |
| Shared UI transcript layer | SDK daemon/ui/* normalizes daemon events into 37 UI semantic event types, reduces them into transcript blocks, and provides renderers/conformance helpers. | 14, ../daemon-ui/README.md, ../daemon-ui/MIGRATION.md |
| Web UI daemon consumer | packages/webui/src/daemon/ consumes the SDK transcript store through React providers and adapters. | 14, ../daemon-client-adapters/web-ui.md |
| CLI TUI / channels / VS Code | Legacy paths still exist; migration to shared transcript primitives is documented as follow-up work, not completed behavior. | 14, 15, 16 |
| Area | Current state | Primary docs |
|---|---|---|
| Configuration | Full qwen serve flags, env vars, settings.json, ServeOptions, BridgeOptions, and important constants are collected in one page. | 17 |
| Quickstart / operations | Shortest startup path, launch recipes, curl checks, demo page auth behavior, route split, shutdown behavior, and embedded invocation recipes are covered. | 20 |
| Errors | Boot-time explicit failures, route errors, bridge errors, EventBus errors, filesystem errors, and mediator errors are summarized with remediation. | 18 |
| Observability | QWEN_SERVE_DEBUG, curl recipes, useful events, telemetry gaps, and investigation checklists are documented. | 19 |
| Surface | Status |
|---|---|
docs/developers/daemon-client-adapters/tui.md | Historical draft for the old DaemonTuiAdapter spike; current shared UI transcript architecture is in doc 14. |
packages/cli/src/ui/daemon/DaemonTuiAdapter.ts | Legacy experimental adapter still in-tree. New shared UI work should prefer SDK daemon/ui/*. |
--no-http-bridge | Accepted for compatibility but falls back to http-bridge and prints stderr. |
DAEMON_KNOWN_EVENT_TYPE_VALUES; old SDKs must treat unknown types as forward-compatible.sessionScope: 'thread' is the current per-conversation-thread split; avoid reintroducing older client-scoped wording._meta and ACP payload data._meta are distinct. Tool-call provenance lives under the ACP payload; server emit timestamps live on the SSE envelope.This doc set reflects the daemon mode surface currently merged into main, including the follow-up work from #4412. It intentionally describes current behavior instead of earlier F-series planning snapshots.