Host-Mode Manual Subscribe
Scope. Operator playbook for the manual / fourth-resort path that asks a core daemon to start hosting a curated CG's opaque SWM ciphertext without waiting for any of the three automatic discovery paths to fire.
This runbook covers when to reach for it (and when not to), how to call it safely, and what the four discovery paths each look like so you can tell from a log whether the manual call is actually needed.
Operator-only — NOT an agent MCP tool. This endpoint changes which node hosts a curated CG's opaque ciphertext, which is a trust-boundary decision the curator owns. Always invoke it via a direct
curl(or wrap it in the operator'sdkgCLI / deploy scripts). It is intentionally not registered as an MCP tool onmcp-dkg, so an agent cannot autonomously enroll its connected core as a host. The earlierdkg_request_hostingtool was removed in the PR #672 Codex review pass for exactly this reason (review commentid=3302086584); therequestHostModeclient method inpackages/mcp-dkg/src/client.tsstays only for use inside operator scripts.
TL;DR
Almost always you should let LU-6 Phase B's automatic discovery do its job. The manual subscribe is a last-resort tool — reach for it only when all three automatic paths have demonstrably failed for a CG, and a late-joining member is asking for catchup that cores can't yet serve.
The four discovery paths
A core daemon picks up curated-CG hosting assignments through one of four mechanisms. The first three are automatic; the fourth is what this runbook covers.
1
Chain-event auto-subscribe
packages/agent/src/dkg-agent.ts (ContextGraphCreated handler inside the chain poller)
Curator registers an accessPolicy=1 CG on-chain with a nameHash commitment. Cores in the sharding table with swmHostMode enabled subscribe immediately on event arrival.
2
Discovery beacon
packages/agent/src/dkg-agent.ts (DKG_CG_DISCOVERY_TOPIC gossip subscription + BEACON_REANNOUNCE_INTERVAL_MS re-announce timer)
Curator pre-registers a CG (before any on-chain transaction) and starts re-announcing it on the discovery topic. Cores hear the beacon and subscribe. Used for pre-reg / off-chain-only CGs.
3
Periodic reconciler
packages/agent/src/dkg-agent.ts (hostModeReconcilerTimer, sweepSwmHostModeSubscriptions)
Catches anything the first two paths missed (chain event lost in a re-org, beacon missed during a restart, etc.). Sweeps every locally-known CG and ensures host-mode subscription state is in sync. Idempotent.
4
Operator-driven manual subscribe (this runbook)
packages/cli/src/daemon/routes/memory.ts (POST /api/shared-memory/host-mode/subscribe)
Operator explicitly POSTs a contextGraphId. The daemon enables host-mode for it the same way the reconciler would.
Paths 1–3 cover the documented Phase B happy path: a curator registers a CG, cores see it, cores host it. Path 4 exists for the gaps those three don't cover.
When to reach for the manual path
Use the manual subscribe only when you can demonstrate at least one of:
Off-chain CG / no chain commitment. The curator did not register on-chain and does not run the discovery beacon (e.g. a one-off curated CG used inside an organization that lives entirely off-chain). Paths 1 and 2 cannot fire; path 3 only reconciles CGs the local node already knows about, so a fresh core needs to be told the id.
Coverage gap during rollout. Fewer than
minimumRequired- Signaturescapable cores are connected to the curator, and you (the operator) want to deliberately enroll a specific core as an opaque host. This is a transitional tool while testnet core capacity ramps; once enough cores are auto-subscribed via paths 1–3, this case goes away.Late-joining member catchup is failing AND the failure log shows "no cores hold ciphertext for this CG" rather than a decryption / permission error. (If a member's catchup fails with
AEAD verify failed, the issue is membership/key distribution, not host-mode subscription — manually subscribing more cores will not help.)
Do not use this as a routine subscribe call. If you find yourself reaching for it on every fresh CG, paths 1–3 are not firing correctly and that's the real bug to fix — file a ticket against the discovery poller, not against the daemon that needed the manual nudge.
Preconditions
Target daemon must be a core node (
nodeRole === 'core') withswmHostModeenabled in~/.dkg/config.json. Edge nodes have host mode disabled by build; the endpoint returns a no-op on those. For registered-CG hosting and node-operator authorization, the Core should also have a non-zero node profileidentityId; see Core Node Profile Registration.Operator must have the daemon's
~/.dkg/auth.token(sameBearerscheme every other/api/*route uses).Target CG must be curated (
accessPolicy === 1). Public CGs use the plaintext SWM substrate and don't need an opaque host.
How to call it
A successful response looks like:
Other documented response shapes:
{"subscribed": false, "alreadySubscribed": true, "hostingEnabled": true}— the daemon was already subscribed to this CG (paths 1–3 already fired, or you called this twice). Safe; idempotent.{"subscribed": false, "alreadySubscribed": false, "hostingEnabled": true, "memberMode": true}— local node is already a CG member of this CG. Member-mode takes precedence; the daemon refuses to wire a second handler. This means you don't need host mode for this CG on this node — the member-mode handler already covers it.{"subscribed": false, "alreadySubscribed": false, "hostingEnabled": false}— node has noswmHostModeStore, i.e. host mode is disabled at config time. Not a core node, orswmHostMode: falsein config.HTTP
400— missing/blankcontextGraphId.HTTP
501— daemon build does not exposeenableSwmHostModeFor.HTTP
500—enableSwmHostModeForthrew. The body'serrorfield carries the underlying message; the daemon log has the full trace.
How to verify the subscribe took effect
After a successful POST:
The daemon log on the core should include
Host-mode subscribed CG=<id>(or the persistence-queue equivalent).GET /api/shared-memory/host-mode/statsreports the CG in itssubscribedCgIdsarray (alongsideenabled,cgCount,totalBytes,totalEntries). This is the host-mode store diagnostics endpoint, served bypackages/cli/src/daemon/routes/memory.tsand backed byDKGAgent.getSwmHostModeStats(). Entries insubscribedCgIdsare always the canonical wire-form id (the curator-committednameHash, lowercase 0x-prefixed 32-byte hex) regardless of whether the CG was subscribed via the chain-event path, the beacon, the reconciler, or a manual subscribe call — seecanonicalSwmHostModeKeyinpackages/agent/src/dkg-agent.tsfor the rationale (PR #672 reviewid=3302086589). If you POSTed a cleartext id, expect the corresponding hash to come back here, not the original cleartext. Example response after a single subscribe:totalBytes/totalEntriesstay at zero until the first gossiped SWM envelope lands and is persisted — see step 3.Within a few seconds, gossiped SWM envelopes for that CG should start showing up in the core's
swm-host-modesubstrate. With no curator currently writing, you won't see ingest until the next write — that's normal.A member running
POST /api/shared-memory/catchupagainst this core should now get a non-zerototalInsertedTriples(assuming the member holds the AEAD chain key — see SCENARIO D inscripts/devnet-test-rfc38-late-joiner.sh).
How to stop hosting
The current daemon exposes a manual subscribe route and a stats route; it does not expose a POST /api/shared-memory/host-mode/unsubscribe route. If you need to stop hosting before a supported per-CG unsubscribe API exists, use an operator maintenance path outside this endpoint: disable swmHostMode for the daemon and restart to stop host-mode handlers, or perform a reviewed cleanup of the persisted host-mode store record and restart. Do not script a manual unsubscribe curl against this daemon version.
Anti-patterns
Don't loop the manual call as a substitute for the reconciler. The reconciler is what guarantees eventual consistency for CGs whose chain event was missed; replacing it with a polling script hides whatever bug is preventing the reconciler from converging.
Don't call this on a CG you're also a member of. The daemon rejects with
memberMode: true; if you got there by misreading the topology, you don't need host mode — your member handler is already authoritative.Don't wire it into MCP-tool calling patterns that an agent invokes automatically. Operator-only by design: an agent that reaches for host mode is bypassing the curator's authority over who hosts the curated CG. The previous
dkg_request_hostingMCP tool was removed in PR #672 (Codex reviewid=3302086584) for this exact reason — there is no agent-facing entrypoint. If you want a friendlier CLI wrapper, add it to the operator-sidedkgCLI (which is human-invoked), not tomcp-dkg(which agents drive).
Related
packages/cli/src/daemon/routes/memory.ts— endpoint implementation.packages/agent/src/dkg-agent.ts—enableSwmHostModeFor, the agent-side handler the endpoint delegates to.packages/agent/src/dkg-agent.ts—ContextGraphCreatedhandler, discovery beacon, and host-mode reconciler — the three automatic paths this runbook supplements.scripts/devnet-test-rfc38-late-joiner.shSCENARIO D — the end-to-end happy path this endpoint participates in.
Last updated
Was this helpful?