222 lines
16 KiB
Markdown
222 lines
16 KiB
Markdown
---
|
|
layer: to-be
|
|
status: designed
|
|
code: []
|
|
updated: 2026-10-03
|
|
decisions:
|
|
- 02-DECISIONS/0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md
|
|
- 02-DECISIONS/0182-inside-a-home-the-mesh-owns-what-it-places-and-holds-the-rest-as-found.md
|
|
- 02-DECISIONS/0183-the-anthropic-licence-manager-is-a-module-and-hands-tokens-to-the-agent-over-the-bus.md
|
|
- 02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md
|
|
- 02-DECISIONS/0155-a-definition-names-no-installation-and-how-that-is-checked.md
|
|
- 02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md
|
|
- 02-DECISIONS/0027-a-provision-names-what-the-consumer-is-coupled-to.md
|
|
- 02-DECISIONS/0109-a-package-registry-seat-is-one-per-ecosystem.md
|
|
- 02-DECISIONS/0175-one-tool-runtime-per-node-serves-every-modules-tools-on-the-host-side.md
|
|
---
|
|
|
|
# 36 — The operator's agent on a machine: the `claude-code` module
|
|
|
|
**The agent a person runs at a terminal, put on the machine by the mesh, instructed by the mesh, pointed
|
|
at the console, and holding the licence the manager hands it.** It is a member of the family
|
|
[to-be 29 §2](29-a-node-has-operator-accounts.md) names, the modules that touch a person's machine, and
|
|
its counterpart is [39 — The Anthropic licence manager](39-the-anthropic-licence-manager.md).
|
|
|
|
What it replaces: the predecessor's module of the same name and a sibling, which placed six files under
|
|
the operator's home. The predecessor is retired; the six files are still on both workstations telling
|
|
every session to use tools that no longer exist.
|
|
|
|
**Three rules shape everything below.** The host is module-agnostic: it installs the package and gives
|
|
the module a state directory, and knows no vendor, no agent, no path under a home. The controller has no
|
|
part beyond resolving what it resolves for every module. And the module handles its own files: the
|
|
mesh's part of the agent's configuration is written by the module's own code, from what the mesh
|
|
delivered it and what the manager handed it.
|
|
|
|
## 1. Where the mesh's configuration lives: the agent's managed directory, not the home
|
|
|
|
The agent reads a machine-wide, administrator-owned configuration directory under `/etc`, documented
|
|
by the vendor: a managed settings file that outranks every user and project setting; a key in it that
|
|
adds HTTP tool servers *beside* a person's own without blocking them; and a managed instruction file every
|
|
session reads before the user's and the project's. The agent has **no** machine-wide directory for
|
|
rules, skills, slash commands or hooks; those exist only under a home or a project.
|
|
|
|
So the mesh's part of the agent's configuration lives there, **owned whole by the module**, and the home
|
|
is left alone. What the predecessor shipped as two rule files and two skills folds into the managed
|
|
instruction file and the manager's tools:
|
|
|
|
| the predecessor placed | becomes |
|
|
|---|---|
|
|
| `~/.claude/CLAUDE.md` | the managed instruction file: how a session on this mesh works (§3) |
|
|
| `~/.claude/rules/00-hal-mesh.md`, `~/.claude/rules/conventions.md` | sections of the same file: this node's identity, the repositories' conventions |
|
|
| `~/.claude/settings.json`, merged | the managed settings file: the mesh's keys only, outranking nothing a person did not also set |
|
|
| `~/.claude/skills/hal-switch-license/SKILL.md` | the manager seat's `switch` verb, listed by the console, and a sentence in the instruction file saying to use it |
|
|
| `~/.claude/skills/cleanup/SKILL.md` | nothing; it named the predecessor's forge |
|
|
| the console's entry in the agent's user-scope state | the managed settings' tool-server key, from the console's provision (§4) |
|
|
|
|
**The home.** Under [ADR 0182](../../02-DECISIONS/0182-inside-a-home-the-mesh-owns-what-it-places-and-holds-the-rest-as-found.md)
|
|
every path under `~/.claude` is *found*, with one exception: the agent's credentials file, which the
|
|
module's own code writes for a subscription licence (§5). The person's memory, history, projects, local
|
|
settings, their own rules, skills and tool servers are never read or written by the mesh. **The six
|
|
predecessor files are the operator's to remove, once, on each workstation**; the module's documentation
|
|
lists them, and until they go the agent reads stale instructions beside the mesh's.
|
|
|
|
## 2. What the module declares and what its code writes
|
|
|
|
**Declared, applied by the host:** the agent's package (§7); the module's state directory; a facts file
|
|
in that directory carrying the node's name and the console's endpoint, and a settings file carrying the
|
|
role and the extra tool servers, merged from the module's settings layers — the bundle is told the two
|
|
files' paths, because a bundle's words are paths and constants only (ADR 0192); the bus, the console's provision, and that it uses the `anthropic-licence-manager` seat.
|
|
Nothing under the home, nothing under `/etc`.
|
|
|
|
**Written by the module's code**, from the facts file and the manager's hand-over, whenever either
|
|
changes:
|
|
|
|
| path | content |
|
|
|---|---|
|
|
| the managed settings file | the mesh's keys: the tool servers (the console, plus any the operator declared as settings), the attribution trailers, and — for an API-key binding only — the key-helper that serves the key |
|
|
| the managed instruction file | §3 |
|
|
| the agent's credentials file under the operator's home | for a subscription binding only: the access token the manager handed over, as the operator, readable by the operator alone, atomic, no refresh token |
|
|
| the module's keypair in its state | made once, the private half never leaves (§5) |
|
|
|
|
Writing under `/etc` and as the operator under the home are two escalations the module's code performs
|
|
for itself; the mesh does not run the module as root for everyone, and the caller does not know
|
|
([ADR 0175](../../02-DECISIONS/0175-one-tool-runtime-per-node-serves-every-modules-tools-on-the-host-side.md)).
|
|
|
|
**Which settings keys are the mesh's.** A key is the mesh's when it encodes a rule of the mesh: the tool
|
|
servers that reach the mesh, the attribution convention of its repositories, the key-helper a binding
|
|
requires. The model, the spinner, the drafts and every other preference are the person's, and the
|
|
predecessor's experience with the model key is the evidence: a mesh that sets a preference reverts a
|
|
person's choice on every push.
|
|
|
|
## 3. What the instruction file says
|
|
|
|
Prose, not a paste; the file is the module's.
|
|
|
|
**How a session on this mesh works.** The console is the only path to the mesh, and its tools are the
|
|
vocabulary: the record is asked through the records module, symptom first — the literal error text before
|
|
a hypothesis ([ADR 0153](../../02-DECISIONS/0153-the-record-is-read-by-a-module-and-the-console-lists-it.md));
|
|
the mesh is asked and changed through the controller seat's verbs; the forge through the forge module's
|
|
tools; a licence through the `anthropic-licence-manager` seat's verbs, never by editing a file. The hard
|
|
rules in new words: a file the mesh manages is changed through the verb that owns it or through the
|
|
catalogue, never on disk; a store's database is never written by hand; main is never pushed; the mesh
|
|
creates no symlinks and nobody else does; a package is declared, not installed by hand. The glossary's
|
|
words, none of the predecessor's.
|
|
|
|
**Who this node is.** The node's name, from the facts file; the node's role, from the module's settings
|
|
on the node's layer; and that the other nodes are asked of the controller's `nodes` verb rather than
|
|
listed here, because a table is a copy that drifts.
|
|
|
|
**The repositories' conventions.** Concise commit messages in the imperative, about why; a branch, a
|
|
pull request and a human approval for every merge; test before pushing, because nodes update unattended;
|
|
the playbooks in the record.
|
|
|
|
## 4. The console
|
|
|
|
> **Revised 2026-10-03, building it.** The vendor's managed-settings key for tool servers refuses any
|
|
> URL that is not `https://`, including one on loopback, so it cannot carry the console. The module
|
|
> owns the vendor's **exclusive** managed tool-server file instead (operator's choice): the console as
|
|
> `mesh`, over HTTP on loopback, and every server in the module's `mcp_servers` setting — and no other.
|
|
> A server added by hand, a project's own file and a plugin's servers stop loading; claude.ai's
|
|
> connectors are kept by a managed setting. A person's own servers move into the setting, for the mesh
|
|
> or for one node. Stdio straight to the bus, through the runtime's own client, was weighed and left
|
|
> for later: it needs a verb the delivered runtime does not have, and a session holding its own bus
|
|
> connection breaks on a credential rotation.
|
|
|
|
**Other tool servers** a person wants on every machine, or on one, are a declared setting of this module
|
|
— mesh layer or node layer — rendered into the same managed file. The person sets them with the
|
|
controller's `settings` verb on this module, so the list stays declared state; a tool of this module
|
|
cannot set it, because a bundle calls nothing (ADR 0192). The agent's own HTTP-only constraint for managed servers applies; a person's local
|
|
command-based servers stay their own, in their own file.
|
|
|
|
**The entry's name is `mesh`.** The hand-made entry both workstations carry today is named after this
|
|
installation, which a definition may not be ([ADR 0155](../../02-DECISIONS/0155-a-definition-names-no-installation-and-how-that-is-checked.md));
|
|
it is the person's to remove, and until then the agent sees the mesh's tools twice.
|
|
|
|
## 5. The licence: the consumer side
|
|
|
|
[ADR 0183](../../02-DECISIONS/0183-the-anthropic-licence-manager-is-a-module-and-hands-tokens-to-the-agent-over-the-bus.md)
|
|
decides it; to-be 39 is the manager's half. This module:
|
|
|
|
- **makes a keypair** in its state the first time it runs, and answers `claude_code_public_key` with the
|
|
public half when the manager asks;
|
|
- **serves `apply`**: the manager's hand-over, a token sealed to the module's key, with the licence's
|
|
name and kind. A rotation of the same licence is applied only if newer within one lineage; a switch is
|
|
applied regardless, because across licences the expiries are unrelated. The answer says applied or
|
|
refused and why, and never echoes a token;
|
|
- **is reconciled, never pulls**: the manager asks every bound node on a schedule and after every
|
|
rotation, so a node that was away receives its token when it is back; between visits it keeps the last
|
|
token, and `licence_status` says how long it has left;
|
|
- **writes** for a subscription licence the credentials file as the operator, access-token-only; for the
|
|
API-key licence sets the key-helper in the managed settings to a small program that prints the key
|
|
from the module's state, so no file under the home is touched;
|
|
- **holds a login for the manager to collect**: when the credentials file holds a full grant it did not
|
|
write — a person logged in — it answers `claude_code_pending_login`, when the manager asks, with the
|
|
grant sealed to the key the manager gives in its request and the account's identity read from the
|
|
agent's state file; the manager decides, and the next hand-over strips the refresh token;
|
|
- **serves `licence_status`**: which licence and kind this node holds, when the token expires, whether
|
|
the file matches what was handed over — by fingerprint, never by value.
|
|
|
|
Switching is the seat's `switch` verb, asked through the console; this module only applies what it is
|
|
handed. *2026-10-03:* every exchange is started by the manager, because a tools bundle answers calls and
|
|
has no bus credential to make them ([ADR 0192](../../02-DECISIONS/0192-a-tools-bundle-declares-what-it-is-given-and-the-runtime-hands-it-to-that-bundle-alone.md),
|
|
ADR 0183's dated note). The tool names follow the catalogue's `<module>_<verb>` form.
|
|
|
|
## 6. Scope, settings and the order of assignment
|
|
|
|
**Every node with an operator account** ([ADR 0181](../../02-DECISIONS/0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md)).
|
|
All four nodes carry one since 2026-10-03. **Per node:** the role. **Per mesh or per node:**
|
|
extra tool servers. **Prerequisite:** the manager holds its seat and has adopted the licences.
|
|
|
|
**Order:** the manager assigned and a refresh observed; the console's provision in the catalogue; this
|
|
module on one workstation; the six predecessor files and the hand-made console entry removed there; a
|
|
new session read to confirm it sees the mesh's instruction file, the console's tools under `mesh`, and
|
|
its licence; then the rest.
|
|
|
|
## 7. The package
|
|
|
|
The module declares the agent's package. The distribution every node runs does not carry it in its
|
|
repositories: the two workstations have it from a build the predecessor's helper made from the community
|
|
repository, and nothing updates it since. On those two the declaration is satisfied. **On a fresh machine
|
|
the host's package manager refuses it, in its own words, and the module is not applied there.** The
|
|
answer is a package repository for this ecosystem as a seat
|
|
([ADR 0109](../../02-DECISIONS/0109-a-package-registry-seat-is-one-per-ecosystem.md)), fed by the builder
|
|
and trusted by every node's package manager; not built, and not this module's to build. The vendor's own
|
|
installer is rejected: it puts a self-updating binary under the person's home, invisible to the mesh.
|
|
|
|
## How it is checked
|
|
|
|
| Check | Defends |
|
|
|---|---|
|
|
| the module's definition names no node, path or login, declares nothing under a home or `/etc`, and no file resource carries a secret | ADR 0112, ADR 0155, ADR 0183 |
|
|
| on a lab machine with an account and a seeded home holding a person's rule file and the predecessor's leftovers: after assign, the managed directory holds the mesh's files, the home is byte-identical except the credentials file, which is owned by the operator and names no refresh token; after unassign, the managed directory's files are gone and the home is untouched | ADR 0182, the host's agnosticism |
|
|
| on a lab machine with no account, the assignment is refused naming the fact | ADR 0181 |
|
|
| a switch asked of the seat through the console changes the licence and the token on the node; no tool answer and no log line holds a token | ADR 0183 |
|
|
| the API-key binding writes nothing under the home and the agent authenticates through the helper | ADR 0183 |
|
|
| the console's provision resolves by co-location; a machine without the console refuses the module by name | ADR 0027, ADR 0152 |
|
|
| a new session on the assigned workstation lists the console's tools under `mesh` and answers "which node am I" from the instruction file | the exit of the build |
|
|
|
|
## What this does not settle
|
|
|
|
- **Several operator accounts on one node** (ADR 0181 decides one).
|
|
- **A worker's own licence on a machine.** Every interactive session shares the node's one agent
|
|
directory and its licence, however many run. A worker runs from a home of its own with an agent
|
|
directory in it, bound to its own licence through the manager (to-be 39 §5); that is for when workers
|
|
exist, and nothing here changes for it.
|
|
- **The package repository seat** (§7).
|
|
- **How the module's tools are run** is decided: the node's tool runtime, host-side
|
|
([ADR 0175](../../02-DECISIONS/0175-one-tool-runtime-per-node-serves-every-modules-tools-on-the-host-side.md)).
|
|
The managed files and the credential write are tools of this module that runtime serves. Until the
|
|
runtime exists on every node, the module's code runs as a supervised process of its own
|
|
([ADR 0150](../../02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md)),
|
|
which changes nothing in what it writes.
|
|
|
|
## References
|
|
|
|
- [ADR 0181](../../02-DECISIONS/0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md),
|
|
[ADR 0182](../../02-DECISIONS/0182-inside-a-home-the-mesh-owns-what-it-places-and-holds-the-rest-as-found.md),
|
|
[ADR 0183](../../02-DECISIONS/0183-the-anthropic-licence-manager-is-a-module-and-hands-tokens-to-the-agent-over-the-bus.md) — the decisions
|
|
- [39 — The Anthropic licence manager](39-the-anthropic-licence-manager.md), [34 — The console](34-the-console.md), [29 — A node has operator accounts](29-a-node-has-operator-accounts.md)
|
|
- [research 018](../../01-RESEARCH/018-the-operators-machine-as-modules/00-overview.md) — the operator's machine as modules, and where tools run
|
|
- the vendor's documentation on managed settings, managed tool servers, the managed instruction file and the key-helper, read 2026-10-02
|
|
- the predecessor's two modules and the six files on the workstations, read 2026-10-02
|