Events carry what happened and no secret; tokens travel on requests (design 32 §10). The manager's licence.rotated/switched events make the module ask anthropic-licence-manager.current; at start it asks once to catch up. A refresh token appearing in the credentials file is a login: it is pushed to the manager's adopt at once, sealed to the manager's key — the one time a refresh token travels. A switch replaces the old licence's grant whole, removes the API key and its helper, and rewrites oauthAccount in ~/.claude.json. New tools register and unregister MCP servers on this node, or with nodes: all / a list via an mcp.registered event every node consumes; called for one node, the answer names the other nodes running claude-code. 26 tests.
74 lines
4.2 KiB
Markdown
74 lines
4.2 KiB
Markdown
# 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`.
|
|
- `~/.claude` under 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 two 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).
|
|
|
|
| what | how |
|
|
|---|---|
|
|
| the licence manager rotated a licence, or switched this node | its `licence.rotated` / `licence.switched` event; this module then asks `anthropic-licence-manager.current` for its token, sealed to the key it sends |
|
|
| this node starts | it asks `current` once, so a node that was off catches up |
|
|
| a person ran `/login` here | the credentials file gains a refresh token this module never writes; it asks `anthropic-licence-manager.adopt` at once with the grant sealed to the manager's key — the one time a refresh token travels, because the login made the manager's stale |
|
|
| an MCP server registered for more nodes than this one | an `mcp.registered` / `mcp.unregistered` event every node's claude-code consumes; a node that was off takes it when it is back |
|
|
|
|
## Tools
|
|
|
|
`claude_code_status`, `claude_code_render`, `claude_code_pull`, `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.json` entry shape
|
|
(`{"type":"http","url":…}` or `{"type":"stdio","command":…,"args":[…]}`). The name `mesh` is 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.json` under `mcpServers` — 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.
|