* Add Bugbot consensus review context Document the validation-state and sub-epoch-summary invariant so automated PR review has the same consensus context as local agents. * Route Bugbot to repository context docs Keep Bugbot guidance focused on subsystem context routing so automated reviews use the same module map as local agents. * Add generated repository context docs Include the expanded module context map and route Bugbot to the same subsystem docs used by local agents. * Add EDC agent context pointer Include the generated EDC agent guidance alongside the Cursor agent context docs. * Fold EDC guidance into AGENTS Keep agent context entrypoints consolidated in AGENTS.md and remove the separate EDC pointer. * Remove generator name from agent guidance Keep AGENTS.md focused on repository context locations rather than the tooling used to produce them. * Consolidate context corpus into one source-verified canonical set - Normalize all subsystem docs to canonical names without chia- prefix, removing the split between old and new-dominant corpora. - Merge new-dominant content into consensus.md, full-node.md, wallet.md; split networking.md into server.md, protocols.md, apis.md; add types.md. - Rename 15 genuinely-new subsystem docs; fold chia-root.md into architecture-overview.md. - Remove filter-branch leakage (filter_challenge, predictable filter, protocol 0.0.38) from types.md, protocols.md, harvester.md. - Correct factual inaccuracies: /push_tx vs wallet queue semantics, Err sign/ban policy, protocol import-time coverage, server peer-serving, address-manager mutation rule, wallet tx-store rollback, ValidationState speculative advancement, block-creation default, MempoolItem fallback. - Replace unreachable verification SHA with PR-head commit. - Consolidate test guidance into one small router plus 12 on-demand testing/ docs; remove duplicate auto-attached test guides. - Make INDEX.md the authoritative routing manifest; update BUGBOT.md, AGENTS.md, and context-routing.mdc to reference one canonical corpus. - Replace context-chia-*.mdc rules with canonical narrow rules; remove recursive .cursor/** rule and consolidate duplicate tooling rules. - Tighten clvm-execution.md: remove stale cost_calculator.py reference, fix block-creation default, replace opcode catalogue with pointer. * Trim redundant context and testing docs after value audit - Trim benchmarks.md: remove per-script Workload Groups narration that is obvious from opening each script; keep fidelity, coupling, and fragility sections. - Trim testing/patterns.md: slim to the module-by-module setup map and layered-assertion list; remove block/tx/assertion how-to that duplicates per-area testing docs. - Trim testing/full-node.md: slim to starter template and sync-convergence tip; remove fixture list and assertion patterns duplicated by patterns.md and architecture.md. - Fold testing/service-wiring.md per-cluster correlation details into testing/architecture.md; delete service-wiring.md (high overlap with architecture.md). - Fix protocols.md: correct NewSignagePointHarvester2 message-ID wording (ID reassigned to 66, not literally the same ID). - Update INDEX.md and testing-guide.mdc router to reflect service-wiring.md removal. * Fix verification SHA to reference the main source baseline The docs were verified against source at PR base24db9ad390(origin/main), nota5647a9327(the original PR head, which only adds context docs and is not a meaningful source baseline). The chia/ source tree is identical across both commits since the PR changes no production code. * Fix remaining V2 filter-branch leakage in harvester.md and types.md - harvester.md: replace calculate_effective_plot_filter_bits() and calculate_min_plot_strength() (filter-branch-only) with the actual main source path: calculate_prefix_bits() with NUMBER_ZERO_BITS_PLOT_FILTER_V2 and height adjustments, then passes_plot_filter(); strength bounds checked by check_plot_param() against MIN_PLOT_STRENGTH/MAX_PLOT_STRENGTH. - harvester.md: use meta_group (actual PartialProofsData field name) instead of "meta group". - types.md: correct that candidate height feeds prefix-bit reductions for both V1 and V2, not just V1; calculate_prefix_bits() branches on V1/V2 constants and height thresholds.
9.9 KiB
Chia Daemon Module Context
Verified: 2026-07-12 against 24db9ad390. If source contradicts this doc, trust source and update the doc.
chia/daemon/ is the local process-control and keychain RPC boundary. It is not
part of the peer wire protocol: clients and node services connect to a local TLS
websocket, exchange JSON envelopes from chia.util.ws_message, and either ask
the daemon to perform privileged local work or ask it to relay messages to a
registered service websocket.
When To Read This
Read this for local daemon websocket routing, service start/stop supervision, keychain proxying, plotter process management, daemon message envelopes, and GUI/service event fanout. For service-specific RPC endpoint semantics, read rpc.md plus the concrete service context.
Implementation Authority
WebSocketServeris the daemon authority. It owns the TLS websocket listener, service registration table, daemon command dispatch, child-process table, plotting queue, keyring status notifications, and shutdown coordination.DaemonProxyis the generic client-side request/response adapter. It owns request-id waiters and the listener task that turns daemon responses back into per-request events.KeychainServeris the remote keychain authority behind daemon commands. It maps requestkc_user/kc_servicepairs to cachedKeychaininstances and normalizes keychain exceptions into daemon JSON errors.KeychainProxyis a compatibility layer over local or remote keychain access. In local mode it directly calls aKeychain; in remote mode it reconnects to the daemon and reconstructs returned private keys from returned entropy.- Process launching and killing are local OS authority.
launch_service(),launch_plotter(),kill_processes(), andwindows_signal.kill()are the points where daemon commands become child processes, PID files, signals, and plotter log files.
Why This Is Tricky
Public RPC docs show the daemon as a websocket route for service commands. In source, the daemon is also the local privilege concentrator: it can expose keychain operations, launch or kill services, mutate plotter queue state, and relay GUI/service messages by registered service name. That makes message envelope compatibility and registration cleanup security-relevant even though this is not P2P traffic.
Wrong Assumptions To Avoid
- Do not apply peer-protocol sender maps, binary streamable framing, or P2P rate limits to daemon messages.
- Do not treat service registration as harmless metadata; registered names become routing authorities for local clients.
- Do not route arbitrary user-supplied command lines through service launch paths.
- Do not normalize keychain errors without checking CLI, GUI, daemon proxy, and remote keychain compatibility.
Wire And Routing Contracts
- Daemon messages are JSON dictionaries with
command,ack,data,request_id,destination, andorigin.format_response()flips origin/destination, preserves the request id, and setsack=True. destination != "daemon"is pure service forwarding. The daemon does not interpret the command or payload if the destination is registered; it serializes the original message and sends it to all websockets registered under that destination.register_serviceadds the current websocket toconnections[service]. Multiple registrations of the same websocket for the same service collapse through the set; one websocket may register for multiple services andremove_connection()must remove it from all of them.- There is no peer-style protocol enum, streamable binary framing, node-type map,
or rate limiter here. The primary gate is mutual TLS using daemon private
certs plus local config (
self_hostname,daemon_port,daemon_max_message_size,daemon_heartbeat). - Malformed JSON or unexpected message shape is caught around
handle_message()and returned as a daemon error response to the sender. Debug logging must pass throughredact_sensitive_data()before recording message contents.
TLS, Startup, And Shutdown
- The daemon server uses
ssl_context_for_server()with client certificates required. The daemon has a default minimum TLS policy plus a daemon-local compatibility escape hatch for internal daemon connections only. async_run_daemon()runschia_init(), initializes daemon logging, acquiresdaemon_launch_lock_path(root_path), createsWebSocketServer, installs async signal handlers, and waits onshutdown_event.stop()cancels ping/status tasks, kills every tracked service process, clearsservices, and setsshutdown_event.exit()closes theWebServerand must awaitawait_closed()becauseWebServer.close()only schedules cleanup.DaemonProxy.start()creates its listener task after connecting and then sleeps briefly before returning._get()registers the waiter before sending and has a source-defined response timeout.
Keychain And Secret Handling
- Keychain commands are intercepted before normal daemon command dispatch by
membership in
keychain_commands. Adding a keychain RPC requires updating this list,KeychainServer.handle_command(), and usuallyKeychainProxy. KeychainServer.run_request()uses streamable JSON conversion for newer typed request/response classes (get_key,get_keys, public-key and label operations). Older commands are hand-parsed dictionaries and have more varied error shapes.- Public-key responses intentionally override
to_json_dict()to expose onlyfingerprint,public_key, andlabel; do not reuse private-key response shapes for public-only APIs. - Remote private-key reads return public key hex plus entropy hex. The proxy rebuilds the mnemonic and private key and verifies the derived G1 matches the returned public key before handing it to callers.
- Passphrase operations mutate global keyring cache/state and notify
wallet_uivia queuedkeyring_status_changedmessages.unlock_keyring()may also runcheck_keys()once when the daemon was started with--wait-for-unlock.
Service And Plotter Process Model
start_serviceaccepts only names validated byvalidate_service(). A service is considered running if the daemon has a live tracked process or a registered websocket for that service, which supports services started outside the daemon.- Child processes inherit a copied environment with
CHIA_ROOTset to the daemon root. Frozen builds map service names to packaged executables; source runs useshutil.which()or the raw service name. - PID files live under
root_path / "run"and are best-effort. On kill, the PID file is renamed to.pid-killedwhen possible; failure to write or rename PID files is intentionally non-fatal. - Plotting is a special daemon-managed pseudo-service named
chia_plotter.plots_queueis in-memory state; plotter subscribers receive full queue state on registration and incrementalstate_changed/log_changedmessages later. - Plotter command construction is per-plotter (
chiapos,bladebit,madmax) and mutates command args before launch by appending-Dso child plotters use the daemon for keychain access. - Serial plotting is coordinated by queue name and
PlotState: only one non-parallelRUNNINGitem per queue should exist. Completion is detected by tailing the plotter log for plotter-specific final words, not by only waiting on process exit.
Fragility Hotspots
- Broadening service forwarding or registration is security-sensitive because registered service names become routing authorities for all local daemon clients.
- Changing response envelope fields breaks
DaemonProxy._get()and GUI/RPC clients that key offrequest_id,origin,destination, andack. - Keychain error compatibility is uneven but tested. Normalizing errors is useful
only if CLI, GUI, daemon tests, and
KeychainProxy.handle_error()are updated together. - Be careful with task lifetime: ping, state-change delivery, daemon-proxy
listeners, keychain reconnect loops, and plotter tasks are deliberately
referenced via
create_referenced_task()or cancelled viacancel_task_safe(). KeychainProxy.close()awaits the reconnect task after settingshut_down. Any change to reconnect-loop exit conditions can make shutdown hang.- Plotter queue state and service process state are updated from async tasks without an explicit lock. Keep state transitions small and preserve ordering of SUBMITTED -> RUNNING -> FINISHED/REMOVING notifications.
launch_service()splitsservice_commandon spaces. Today daemon-controlled service names are allowlisted and the only appended option is the testing flag; do not start passing arbitrary user-supplied command lines through this path.- Windows process groups and signal mapping are special-cased. Changes to
creation flags or
windows_signal.kill()need Windows-specific validation.
Test And Audit Strategy
chia/_tests/core/daemon/test_daemon.pycovers daemon command responses, passthrough routing to a full node, keychain RPCs, passphrase status events, plotting queue transitions, logging redaction, bad JSON, and plotter options.chia/_tests/core/daemon/test_daemon_register.pycovers multi-service registration and connection cleanup semantics.chia/_tests/core/daemon/test_keychain_proxy.pycovers local-vs-remoteKeychainProxybehavior, private/public key reconstruction, and error mapping.chia/_tests/core/test_daemon_rpc.pyis the minimal daemon client smoke test.chia/_tests/cmds/test_daemon.pyanchors CLI daemon startup, keyring unlock flow, and daemon launcher behavior.
Source Pointers
- Daemon websocket server and process control:
chia/daemon/server.py. - Client/proxy adapters:
chia/daemon/client.py,chia/daemon/keychain_proxy.py. - Remote keychain command handling:
chia/daemon/keychain_server.py. - Plotter process queue:
chia/daemon/server.py,chia/plotters/. - Message envelope helpers:
chia/util/ws_message.py.