The module is one Go binary the runtime launches: the renderer (its instruction file held byte for byte to the TypeScript one it replaces), the credentials and identity files, the licence flow of ADR 0206 and the MCP servers in state. Keeps the TypeScript module's key files, so a node moving to it keeps its key. The npm package, its tests and its build go. Both binaries were run together under the real runtime on a test bus with postgres and a stub vendor: a login was adopted by one exchange, the node bound and handed an access token, its file left with no refresh token, and no token in either state.
claude-code
The operator's agent on a machine (novox/hq design 36): its package, its machine-wide managed configuration, and the consumer side of the Anthropic licence manager (design 39, ADR 0183).
What it owns
Two directories, declared, so the mesh refuses a second module owning either:
/etc/claude-code, the agent's machine-wide managed directory, root's,0755.~/.claudeunder the operator account's home, the operator's,0700. The module owns the directory — that it exists, who owns it, its mode — and of what is inside only what it writes. Everything else in it (memory, history, projects, local settings, a person's own rules and skills) is the person's and is never read or written (hq ADR 0182). Unassigned, the module leaves the directory: the host removes a directory only when it is empty.
What it writes
Under the agent's managed directory, /etc/claude-code, owned whole by this module and rewritten
whenever the node's tool runtime collects the module's tools:
| file | holds |
|---|---|
managed-mcp.json |
the tool servers every session loads: the mesh's console as mesh, and the servers set in this module's mcp_servers setting. Exclusive: a server not listed here does not load — not one added with claude mcp add, not a project's .mcp.json, not a plugin's |
managed-settings.json |
the repositories' attribution convention, the claude.ai connectors kept beside the managed servers, and the key-helper while the node holds an API-key licence |
CLAUDE.md |
how a session on this mesh works, this node's name and role, the conventions |
Under the operator's home, only ~/.claude/.credentials.json, and only when the licence manager hands
this node a subscription token. Nothing else under the home is read or written.
Over NATS
Everything between this module and the rest of the mesh is NATS, in three kinds: an event says that something happened and carries no secret, because a stream keeps it; a request carries a token, because nothing keeps it (hq design 32 §10); and state is the current value of something every node must see, a node that joins later included — kept, so it carries no secret either (hq ADR 0201).
| what | how |
|---|---|
| what this node holds | the module's holdings state, one key for this node — the account, the kind, fingerprints and expiries, never a token — written at start and whenever the credentials file changes (hq ADR 0206) |
a person ran /login here |
the credentials file gains a refresh token this module never writes; its next report shows it, and the licence manager asks claude_code_grant for it, giving its key — the one time a refresh token leaves the node, for the manager to adopt by refreshing it |
| what this node should hold | the licence manager's bindings state, this node's key; on a newer generation this module asks anthropic-licence-manager.current for its token, sealed to the key it sends, and writes it access-token-only — so the agent here never refreshes. A node that was off reads its key when it is back |
| an MCP server registered through this module | a key in the module's servers state — all.<server> for every node, <node>.<server> for one; every node watches it and renders what applies to it, a node's own entry over the one for every node. A node that joins later, or was off, reads the whole current set at start; unregistering is a delete. An entry with a secret in its env or headers is refused by the runtime |
Tools
claude_code_status, claude_code_render, claude_code_pull, claude_code_grant (for the licence
manager), claude_code_mcp_list,
claude_code_mcp_register (this node by default; nodes: "all" or a list for more — called for this
node alone, its answer names the other nodes running claude-code), claude_code_mcp_unregister.
Settings
Per node or for the whole mesh, through mesh-controller.settings module=claude-code:
role— what this node is, in a few words; shown to every session.mcp_servers— extra tool servers, set by the operator for the mesh or a node, beside the ones registered through the tools; keyed by name, in the vendor's.mcp.jsonentry shape ({"type":"http","url":…}or{"type":"stdio","command":…,"args":[…]}). The namemeshis the module's own and cannot be set. Put a person's own servers here, or they stop loading.
On a machine that carried the predecessor
Remove these by hand, once; the mesh removes nothing it did not make (ADR 0182):
~/.claude/CLAUDE.md~/.claude/rules/00-hal-mesh.md,~/.claude/rules/conventions.md~/.claude/skills/cleanup/,~/.claude/skills/hal-switch-license/- the hand-made console entry in
~/.claude.jsonundermcpServers— it is ignored now anyway
Escalation
Writing /etc/claude-code needs root. The runtime runs as the operator account, and the module uses
that account's passwordless sudo; on a machine without it, claude_code_render says so and nothing
is written.
Code
Go, one binary (cmd/claude-code) the node's runtime launches. Tested with go test ./...; the managed
instruction file is held to the TypeScript renderer it replaced (testdata/rendered-by-typescript.json),
and the sealed box is the licence manager's own format.