To-be 40 revised for the tools refactor; the manager starts every exchange (ADR 0183 dated note, designs 36 and 39)
Design 38's WP1-WP4b ran: the node's tool runtime is live on all four machines as the operator account, tools are bundles given only their declared words, and a bundle has no bus credential. So the wait on design 38 WP3 is over, the agent module calls nothing and the manager starts every exchange (key, hand-over, waiting login, reconcile), and the manager's daemon now waits on WP4c's record instead. Accounts are stated on all four, sudo -n works for each, the agent is installed on all four; the plan's WP0 shrinks and WP2 gets a configuration-only live proof before any licence.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
layer: to-be
|
||||
status: designed
|
||||
code: []
|
||||
updated: 2026-10-02
|
||||
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
|
||||
@@ -63,8 +63,9 @@ lists them, and until they go the agent reads stale instructions beside the mesh
|
||||
## 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, the operator account, the console's endpoint, the module's
|
||||
settings; the bus, the console's provision, and that it uses the `anthropic-licence-manager` seat.
|
||||
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
|
||||
@@ -119,9 +120,9 @@ resolves it; a machine without the console refuses the module by name. [To-be 34
|
||||
amended in the same change; issue 192 (open) found the gap.
|
||||
|
||||
**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 key. A module tool, `mcp_configure`,
|
||||
validates a server and sets the setting through the controller's settings verb, so the list stays
|
||||
declared state. The agent's own HTTP-only constraint for managed servers applies; a person's local
|
||||
— mesh layer or node layer — rendered into the same managed key. 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
|
||||
@@ -133,29 +134,34 @@ it is the person's to remove, and until then the agent sees the mesh's tools twi
|
||||
[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 registers the public half with the seat;
|
||||
- **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;
|
||||
- **pulls** at start and when its token nears expiry, by the seat's `current` verb, and keeps the last
|
||||
token when the manager does not answer, saying so;
|
||||
- **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;
|
||||
- **offers a login to the manager**: when the credentials file changes by a person's login, it reads the
|
||||
account's identity from the agent's state file and offers the grant to the seat, sealed to the manager's
|
||||
key, for adoption; the manager decides;
|
||||
- **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.
|
||||
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)).
|
||||
None has one today; the operator states them first. **Per node:** the role. **Per mesh or per node:**
|
||||
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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
layer: to-be
|
||||
status: designed
|
||||
code: []
|
||||
updated: 2026-10-02
|
||||
updated: 2026-10-03
|
||||
decisions:
|
||||
- 02-DECISIONS/0183-the-anthropic-licence-manager-is-a-module-and-hands-tokens-to-the-agent-over-the-bus.md
|
||||
- 02-DECISIONS/0024-model-access-is-a-provision.md
|
||||
@@ -74,8 +74,9 @@ Carried from the predecessor, where each rule was earned by an incident:
|
||||
|
||||
## 4. Handing a token to a node
|
||||
|
||||
Every node that runs the agent module registers that module's public key with the seat when it first
|
||||
runs. From then on:
|
||||
**The manager starts every exchange** (ADR 0183's dated note of 2026-10-03): the agent module is a
|
||||
tools bundle, which answers and calls nothing. The manager asks each bound node's module for its public
|
||||
key the first time and keeps it. From then on:
|
||||
|
||||
- **On rotation**, the manager calls `claude-code.apply@<node>` on every node bound to the rotated
|
||||
licence, with the new token sealed to that node's module key. The module answers *applied*, or
|
||||
@@ -83,11 +84,12 @@ runs. From then on:
|
||||
- **On a switch**, the same call with the other licence's token, and the binding is the authority: the
|
||||
module applies a bind without comparing expiries, because across two licences the numbers are
|
||||
unrelated.
|
||||
- **On a pull** — the module starting, or finding its token near expiry — the module calls the seat's
|
||||
`current` verb for its binding and is answered sealed the same way.
|
||||
- **On a schedule**, every few minutes, the manager visits each bound node: a node whose token is near
|
||||
expiry, or that did not answer last time, is handed its current token. A node that was away is
|
||||
served when it is back, with nothing for it to ask.
|
||||
- **Never as an event.** What the manager emits names the licence and the outcome and carries no token.
|
||||
|
||||
A node whose module has not registered a key cannot be handed a token, and the manager says so by name
|
||||
A node whose module does not answer for its key cannot be handed a token, and the manager says so by name
|
||||
rather than falling silent. A node whose module refuses — a wrong identity, a stale grant within one
|
||||
lineage — is recorded as drift and reported.
|
||||
|
||||
@@ -119,9 +121,9 @@ already keeps.
|
||||
A licence enters the mesh one of two ways, and the token never passes through a prompt, a terminal or an
|
||||
argument:
|
||||
|
||||
- **From a node's login.** A person logs in on a node, as they always have. The agent module there reads
|
||||
the account's identity from the agent's own state file, and offers the full grant to the seat sealed
|
||||
to the manager's key. The manager adopts it into the licence the node is bound to **only if the
|
||||
- **From a node's login.** A person logs in on a node, as they always have. On its next visit the manager
|
||||
asks that node's module for a waiting login, giving its own public key; the module answers with the
|
||||
full grant sealed to it and the account's identity read from the agent's own state file. The manager adopts it into the licence the node is bound to **only if the
|
||||
identity matches** that licence's recorded account; a licence not yet identified is identified by its
|
||||
first adoption; a mismatch is refused and notified, because the predecessor once filed one account's
|
||||
grant into another's row this way.
|
||||
@@ -135,8 +137,8 @@ argument:
|
||||
|
||||
**The seat's verbs**, the contract every future holder must serve: `licences` (each with kind,
|
||||
identity, expiry, failures, who is bound), `bindings`, `bind`, `switch`, `release`, `refresh` (now, one
|
||||
or all), `usage` (current and history), `adopt`, `register` (a node's module key), `current` (a
|
||||
consumer's token, sealed, asked by the consumer's module).
|
||||
or all), `usage` (current and history), `adopt`, and `visit` (reconcile one node now). A node's key and
|
||||
a consumer's token are not seat verbs: the manager asks the node, by the agent module's own tools.
|
||||
|
||||
## 8. Settings
|
||||
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
layer: to-be
|
||||
status: designed
|
||||
code: []
|
||||
updated: 2026-10-02
|
||||
updated: 2026-10-03
|
||||
decisions:
|
||||
- 02-DECISIONS/0183-the-anthropic-licence-manager-is-a-module-and-hands-tokens-to-the-agent-over-the-bus.md
|
||||
- 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/0175-one-tool-runtime-per-node-serves-every-modules-tools-on-the-host-side.md
|
||||
- 02-DECISIONS/0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md
|
||||
- 02-DECISIONS/0192-a-tools-bundle-declares-what-it-is-given-and-the-runtime-hands-it-to-that-bundle-alone.md
|
||||
- 02-DECISIONS/0149-the-live-mesh-is-the-test-bed.md
|
||||
- 02-DECISIONS/0027-a-provision-names-what-the-consumer-is-coupled-to.md
|
||||
---
|
||||
@@ -18,209 +20,189 @@ decisions:
|
||||
broken into packages that each end at something a person can see run, in the order their
|
||||
dependencies allow.** The two designs are the authority on *what* is built; this document holds the
|
||||
packages, their order, their sizes and their proofs, and is wrong the moment it disagrees with them.
|
||||
It is the shape [design 38](38-building-the-operators-machine.md) gave the operator's machine, applied
|
||||
to the two modules that make its agent work.
|
||||
It is the shape [design 38](38-building-the-operators-machine.md) gives the operator's machine.
|
||||
|
||||
*Revised 2026-10-03, after design 38's WP1–WP4b ran:* the node's tool runtime is live on all four
|
||||
machines, tools are bundles it serves and each is given only the words its artifact declares, and a
|
||||
bundle has no bus credential of its own. Three things in the first version of this plan changed with
|
||||
that: the wait on design 38's WP3 is over; the agent module calls nothing, so the manager starts every
|
||||
exchange (ADR 0183's dated note); and the manager's own process now waits on a different question,
|
||||
named under WP4.
|
||||
|
||||
## How this is built, and where it is run
|
||||
|
||||
**On the live mesh, by the operator's decision** ([ADR 0149](../../02-DECISIONS/0149-the-live-mesh-is-the-test-bed.md),
|
||||
and design 38's words on the same day). Every package is written with unit tests, committed on one
|
||||
branch per repository ([playbook 07](../../00-META/process/07-feature-branches.md)), and proven on the
|
||||
machines: the control node first for the manager, one workstation first for the agent, then the rest.
|
||||
The cost accepted: a broken agent module leaves a workstation's agent without the mesh's instructions
|
||||
or with a stale token until the next push; the person's own files under the home are never in reach of
|
||||
the failure, by [ADR 0182](../../02-DECISIONS/0182-inside-a-home-the-mesh-owns-what-it-places-and-holds-the-rest-as-found.md).
|
||||
**On the live mesh, by the operator's decision** ([ADR 0149](../../02-DECISIONS/0149-the-live-mesh-is-the-test-bed.md)).
|
||||
Every package is written with unit tests, committed on one branch per repository
|
||||
([playbook 07](../../00-META/process/07-feature-branches.md)), and proven on the machines: one
|
||||
workstation first for the agent, the control node first for the manager, then the rest. A broken agent
|
||||
module leaves a workstation's agent without the mesh's instructions or with a stale token until the next
|
||||
push; the person's own files under the home are out of the failure's reach, by
|
||||
[ADR 0182](../../02-DECISIONS/0182-inside-a-home-the-mesh-owns-what-it-places-and-holds-the-rest-as-found.md).
|
||||
|
||||
Each package names what proves it. A package that cannot name its proof is divided until it can.
|
||||
|
||||
## What exists already, measured
|
||||
|
||||
Counted 2026-10-02 in the repositories and on the machines. Nothing here is new ground; every package
|
||||
reshapes something standing.
|
||||
Measured 2026-10-03 on the four machines and in the repositories.
|
||||
|
||||
| Piece | Today | Becomes |
|
||||
|---|---|---|
|
||||
| the vendor's refresh, the sealed box, the grant file | `anthropic-manager` in the catalogue: a token-endpoint client, a sealed-box primitive, adoption of a grant sealed to a node's key; assigned to nothing | the manager's refresh and adoption, with the lease, the floor and the cadence the predecessor's manager had |
|
||||
| the credentials write, the refresh-token strip, the identity read | `anthropic-consumer` in the catalogue: tested; assigned to nothing | the agent module's write, unchanged in shape |
|
||||
| the predecessor's manager and consumer | two modules in the retired system: the lease per licence, the expiry floor, the lineage comparison, the identity guard, three touchpoints with fallbacks, cooldowns on alarms | ported as logic with its tests; nothing of its registry or its bus |
|
||||
| the host's `process` and `archive` shapes | fetch a bundle by digest and run it supervised; fetch and unpack an artifact | **unchanged** — the manager's daemon is one process; both modules' tools are bundles |
|
||||
| the manifest's `uses`, `claims`, `invokes seat:<seat>.<verb>`, node-scoped `provides` with `serves: {port}` | all four exist and are used by other modules | **unchanged** — the agent uses the seat and invokes its verbs; the console provides its endpoint |
|
||||
| the console | a container per node, MCP on loopback, no provision | gains one provision; becomes the node-tools runtime's serving mode under design 38's WP3 |
|
||||
| the agent's package | present on both workstations from a build the predecessor's helper made; the distribution's repositories do not carry it | declared; satisfied where present, refused where not, until a package repository seat exists |
|
||||
| the operator account | a column on every node record, **empty on all four** | stated by the operator, before anything home-scoped lands |
|
||||
|
||||
**One dependency decides the order.** Both modules serve tools and the agent module's tools write
|
||||
under `/etc` and, as the operator, under the home. Under [ADR 0175](../../02-DECISIONS/0175-one-tool-runtime-per-node-serves-every-modules-tools-on-the-host-side.md)
|
||||
tools run in the node's tool runtime, host-side, which design 38 builds in its WP1–WP3. Writing a
|
||||
per-module tool container for these two modules would be building the pattern that record retires, so
|
||||
**the live proofs of WP3 to WP5 below wait for design 38's WP3.** Everything before a live proof —
|
||||
manifests, code, tests — does not, and is written now.
|
||||
| the node's tool runtime | live on all four, a host process; **runs as the operator account**; listens for the console on loopback at a port its own code fixes; launches or imports every assigned module's tools bundle and hands each its declared words | serves the agent module's tools; gains one provision for its endpoint (WP1) |
|
||||
| the operator account | **stated on all four** — the runtime runs as it | read by the agent module from the runtime's own words |
|
||||
| escalation | passwordless `sudo` for the operator account on all four — a fact about the machines, checked by nobody | how the agent module writes its managed directory under `/etc` |
|
||||
| the agent itself | installed on all four, at four different versions, all above the one the managed tool-server key needs | declared as the module's package |
|
||||
| a bundle's words | paths and constants written with `${dir:…}` and `${port:…}` only; a fact the mesh knows reaches a bundle as a file whose path is a word | the agent module's facts file and settings file |
|
||||
| a bundle calling a tool | **not possible**: a bundle answers calls; it holds no bus credential | the manager starts every exchange |
|
||||
| a module's own long-running process with a bus credential | **undecided** — design 38's WP4c names it as the question its next record answers | the manager's daemon (WP4) |
|
||||
| the vendor's refresh, the sealed box, the grant file | `anthropic-manager` in the catalogue, built on the controller placement ADR 0183 moved away from; assigned to nothing | its client ported into the manager; the module retired (WP6) |
|
||||
| the credentials write, the strip, the identity read | `anthropic-consumer` in the catalogue; tested; assigned to nothing | ported into the agent module with its tests; the module retired (WP6) |
|
||||
| the predecessor's manager and consumer | the lease per licence, the expiry floor, the lineage comparison, the identity guard, three touchpoints, cooldowns | ported as logic with its tests |
|
||||
|
||||
## The order the work allows
|
||||
|
||||
```
|
||||
WP0 the operator states the facts (the live mesh) ── accounts, roles, licences to adopt
|
||||
WP1 the console provides its endpoint (mesh-catalog) ── small, independent
|
||||
WP2 the licence manager, built and tested (mesh-catalog) ──┐ independent of each other;
|
||||
WP3 the agent module, built and tested (mesh-catalog) ──┘ both wait on design 38 WP3 to run
|
||||
│
|
||||
WP4 the manager live on the control node (the live mesh) ── three licences adopted, a refresh seen
|
||||
WP5 the agent live on one workstation (the live mesh) ── the hand-over, the switch, the instructions
|
||||
WP6 the rest of the nodes, and the predecessor's remains ── adoption from a login, the retirements
|
||||
WP0 the operator names the licences and each node's role (the live mesh) ── an hour
|
||||
WP1 the runtime provides its endpoint (mesh-tools) ── small
|
||||
WP2 the agent module (mesh-catalog) ──┐ WP2 needs WP1;
|
||||
WP3 the manager's code, built and tested (mesh-catalog) ──┘ WP3 is independent
|
||||
│
|
||||
WP2 live: one workstation, configuration only — no licence yet ── the first live proof
|
||||
│
|
||||
WP4 the manager live on the control node ── waits on design 38 WP4c's record (a process's bus credential)
|
||||
WP5 the licence end to end on one workstation
|
||||
WP6 the rest of the nodes, and the predecessor's remains
|
||||
```
|
||||
|
||||
WP1, WP2 and WP3 touch different directories of one repository and meet only at the seat's name and
|
||||
the provision's name; they are built in parallel. WP4 is the first time anything on a machine changes.
|
||||
WP5 is the proof of the whole.
|
||||
## WP0 — The operator names the licences and each node's role
|
||||
|
||||
## WP0 — The operator states the facts
|
||||
*The live mesh. An hour, and it is the operator's.* The accounts are stated already. What remains: the
|
||||
names of the two subscription licences and the API key; each node's role, as the agent module's setting
|
||||
on the node layer once the module is registered.
|
||||
|
||||
*The live mesh. An hour, and it is the operator's.*
|
||||
**Proof.** The module's settings list a role for every node; the licences have names.
|
||||
|
||||
The account on each node record, through the controller's node command — none is stated today, and
|
||||
[ADR 0181](../../02-DECISIONS/0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md)
|
||||
refuses a home-scoped module without one. The role of each node, as the agent module's setting on the
|
||||
node layer, once the module exists. Which three licences exist and what each is called.
|
||||
## WP1 — The runtime provides its endpoint
|
||||
|
||||
**Proof.** The controller's node command lists an account for every node.
|
||||
*mesh-tools. An hour.*
|
||||
|
||||
## WP1 — The console provides its endpoint
|
||||
**What changes.** The `node-tools` manifest provides a node-scoped provision, `mcp-endpoint`, serving
|
||||
the port its code listens on, the way the local model server serves its API
|
||||
([ADR 0027](../../02-DECISIONS/0027-a-provision-names-what-the-consumer-is-coupled-to.md)). Co-location
|
||||
resolves it. The runtime's port stays what its code fixes; assigning it is
|
||||
[issue 192](../../04-ISSUES/192-the-meshs-tools-reach-a-person-only-by-a-registration-made-by-hand/00-report.md)'s
|
||||
second question and not this package's.
|
||||
|
||||
*mesh-catalog. Half a day.*
|
||||
**Proof.** The plan for a workstation carrying a consumer of `mcp-endpoint` shows it bound to the
|
||||
runtime's port; the controller's tests and the catalogue's checks pass.
|
||||
|
||||
**What changes.** The console's manifest gains a node-scoped provision — working name
|
||||
`console-endpoint`, fixed when the manifest is written — serving the port the machine gave it, as the
|
||||
local model server already does for its API. Co-location resolves it
|
||||
([ADR 0027](../../02-DECISIONS/0027-a-provision-names-what-the-consumer-is-coupled-to.md),
|
||||
[to-be 34](34-the-console.md) as amended). When design 38's WP3 moves the console into the node-tools
|
||||
module, the provision moves with it; it is a line in a manifest either way.
|
||||
## WP2 — The agent module
|
||||
|
||||
**Proof.** The controller's plan for a workstation shows a consumer of the provision bound to the
|
||||
console's port; the same consumer on a machine without the console is refused naming the provision;
|
||||
the catalogue's tests pass.
|
||||
|
||||
## WP2 — The licence manager, built and tested
|
||||
|
||||
*mesh-catalog. Two to three days; the largest package.*
|
||||
|
||||
**What is written**, as design 39 says:
|
||||
|
||||
1. **The manifest.** Claims the mesh-scoped seat `anthropic-licence-manager` with its verbs; requires a
|
||||
database, a `secret` for the key its grants are encrypted with, and the bus; a `bundle` of tools; a
|
||||
`process` for the daemon that refreshes, collects usage and notifies, on a schedule; declared
|
||||
settings for the cadence, the usage threshold and the cooldown, each with a default; `invokes` the
|
||||
agent module's `apply`.
|
||||
2. **The store.** Migrations for licences, bindings, usage and audit, with the lease and the
|
||||
notification slot as columns, numbered and idempotent.
|
||||
3. **The refresh.** The token-endpoint client and the sealed box from `anthropic-manager`; the plan
|
||||
(floor, cadence, forced, cannot) and the lease from the predecessor, as pure functions with their
|
||||
tests; the vendor's reason logged on failure; counted failures, one notification per cooldown.
|
||||
4. **Adoption.** From a file on the manager's node for the API key; from a sealed grant a node offers;
|
||||
the identity guard that refuses a mismatch and notifies.
|
||||
5. **Usage.** The vendor's reading per licence on a schedule, stored raw and normalised
|
||||
([ADR 0054](../../02-DECISIONS/0054-model-usage-is-recorded-at-two-grains.md)), one notification
|
||||
per threshold crossing.
|
||||
6. **The verbs**: `licences`, `bindings`, `bind`, `switch`, `release`, `refresh`, `usage`, `adopt`,
|
||||
`register`, `current` — the last answering a consumer's token sealed to the key that consumer
|
||||
registered.
|
||||
7. **The hand-over**: on rotation or switch, one call to `claude-code.apply@<node>` per bound node,
|
||||
the token sealed to that node's key, the answer recorded.
|
||||
|
||||
**Proof, before anything runs live.** Unit tests: two refresh runs started together rotate one grant
|
||||
once; a grant with a mismatching identity is refused; a worker bound to a dead licence is refused and
|
||||
never lent another; every event the daemon emits is free of a token; the hand-over payload opens only
|
||||
with the registered key. The catalogue's checks: no installation named, no secret in a declared file.
|
||||
|
||||
## WP3 — The agent module, built and tested
|
||||
|
||||
*mesh-catalog. Two days.*
|
||||
*mesh-catalog. A day and a half.*
|
||||
|
||||
**What is written**, as design 36 says:
|
||||
|
||||
1. **The manifest.** The agent's package; the state directory; the facts file carrying the node's
|
||||
name, the operator account and its home, the console's bound port, the role and the extra tool
|
||||
servers from settings; requires the console's endpoint and the bus; `uses` the seat and `invokes`
|
||||
its `register`, `current` and `adopt`; a `bundle` of tools. **No file resource under a home or
|
||||
1. **The manifest.** The agent's package. A state directory. A facts file in it, rendered by the mesh:
|
||||
the node's name and the console's address from `mcp-endpoint`. A settings file in it, merged from
|
||||
the module's settings layers: the node's role and the extra tool servers. A tools bundle whose
|
||||
words name the two files, the state directory and nothing else. **No file resource under a home or
|
||||
under `/etc`.**
|
||||
2. **The renderer.** From the facts file and the current binding, the managed settings file (the tool
|
||||
servers under the entry `mesh`, the attribution trailers, and the key-helper for an API-key binding)
|
||||
and the managed instruction file (§3 of design 36), written under the agent's managed directory
|
||||
with the escalation the tool performs for itself; idempotent; re-run when the facts file changes.
|
||||
3. **The keypair**, made once in the state directory, the public half registered with the seat at
|
||||
start and at every start.
|
||||
4. **The consumer side**: `apply` (a rotation applied only if newer within one lineage, a switch applied
|
||||
regardless, the answer naming the outcome and never a token); the pull at start and near expiry;
|
||||
the credentials write as the operator, access-token-only, from `anthropic-consumer` with its tests;
|
||||
the key-helper program for the API key; the offer of a login to the seat, sealed, after reading the
|
||||
account's identity.
|
||||
5. **The tools**: `apply`, `licence_status`, `mcp_configure` (validates a server, sets the module's
|
||||
setting through the controller's settings verb), `render` (re-render now, for a person).
|
||||
6. **The documentation**: the six predecessor files and the hand-made console entry a person removes
|
||||
on a workstation that carried the predecessor.
|
||||
2. **The renderer**, run whenever the runtime collects the module's tools: from the two files, the
|
||||
managed settings file (the tool servers under the entry `mesh`, the attribution trailers, the
|
||||
key-helper for an API-key binding) and the managed instruction file, written under the agent's
|
||||
managed directory through the account's escalation, only when their content changed.
|
||||
3. **The keypair**, made once in the state directory; X25519 and an authenticated cipher from the
|
||||
language's own library, so the bundle carries no dependency.
|
||||
4. **The tools**: `claude_code_status` (what is rendered, what licence is held, when its token expires,
|
||||
fingerprints only); `claude_code_render` (render now); `claude_code_public_key`;
|
||||
`claude_code_apply` (a sealed token, applied only if newer within one lineage unless it is a switch;
|
||||
the credentials write as the operator, access-token-only, atomic; the key-helper program for an API
|
||||
key); `claude_code_pending_login` (a full grant found in the credentials file, sealed to the key the
|
||||
caller gives, with the account's identity).
|
||||
5. **The documentation**: the six predecessor files and the hand-made console entry a person removes.
|
||||
|
||||
**Proof, before anything runs live.** Unit tests: the renderer writes only the mesh's keys and leaves
|
||||
every other key of a seeded settings file; the credentials write strips a refresh token and is atomic;
|
||||
the lineage comparison from the predecessor, with its cases; a login offer carries the identity it read.
|
||||
The catalogue's checks pass.
|
||||
**Proof, before anything runs live.** Unit tests: the renderer writes the mesh's keys and nothing else;
|
||||
it writes nothing when nothing changed; the credentials write strips a refresh token and is atomic; the
|
||||
lineage cases from the predecessor; a sealed hand-over opens only with the module's key; no tool's answer
|
||||
contains a token. The catalogue's checks pass.
|
||||
|
||||
**Proof, live, on one workstation, configuration only.** Assign the module; set the node's role; push.
|
||||
The agent's managed directory holds the two files; everything under the person's agent directory is
|
||||
byte-identical to before; a new session lists the mesh's tools under `mesh` and answers *which node am
|
||||
I* from the managed instruction file. `claude_code_status` answers through the console. No licence is
|
||||
touched: the module writes the credentials file only when it is handed a token.
|
||||
|
||||
## WP3 — The manager's code, built and tested
|
||||
|
||||
*mesh-catalog. Two to three days.*
|
||||
|
||||
**What is written**, as design 39 says: the manifest (the seat and its verbs, a database, a `secret`
|
||||
for the key the grants are encrypted with, a tools bundle, a process bundle for the daemon, settings
|
||||
with defaults); the store's migrations; the refresh with its plan, lease, floor and cadence as pure
|
||||
functions; the vendor client from `anthropic-manager`; adoption from a file and from a node's waiting
|
||||
login with the identity guard; usage and its threshold; the visit — key, hand-over, waiting login — per
|
||||
bound node; the seat's verbs.
|
||||
|
||||
**Proof, before anything runs live.** Unit tests: two refresh runs started together rotate one grant
|
||||
once; a mismatching identity is refused; a worker bound to a dead licence is refused and never lent
|
||||
another; nothing the daemon emits carries a token; a hand-over sealed for one node opens with no other
|
||||
node's key.
|
||||
|
||||
## WP4 — The manager live on the control node
|
||||
|
||||
*The live mesh. Half a day, after design 38's WP3.*
|
||||
*The live mesh. Half a day.* **Waits on design 38 WP4c's record** — how a module's own long-running
|
||||
process is given a bus credential and its subscriptions — because the daemon must call the agent module
|
||||
on every node. Until that record exists, nothing in this plan works around it: no tool container, no
|
||||
credential copied by hand.
|
||||
|
||||
**Order.** Assign the manager on the control node; push. Adopt the API key from a file there. Adopt
|
||||
the two subscription grants: a login in a throwaway home on the control node, offered to the seat the
|
||||
way a node's agent module will. Bind each node's agent to a licence.
|
||||
**Order.** Assign the manager on the control node; push. Adopt the API key from a file there. Adopt the
|
||||
two subscription grants: a login on a workstation carrying the agent module, collected by the manager's
|
||||
visit. Bind each node's agent to a licence.
|
||||
|
||||
**Proof.** Through the console: `anthropic-licence-manager.licences` lists three licences with
|
||||
identity and expiry; within the cadence, the audit shows a rotation and `licences` shows a later
|
||||
expiry; a forced `refresh` on one licence is logged with the vendor's answer; the two retired catalogue
|
||||
modules are still assigned to nothing.
|
||||
**Proof.** Through the console: `anthropic-licence-manager.licences` lists three licences with identity
|
||||
and expiry; within the cadence the audit shows a rotation and a later expiry; a forced `refresh` is
|
||||
logged with the vendor's answer.
|
||||
|
||||
## WP5 — The agent live on one workstation
|
||||
## WP5 — The licence end to end on one workstation
|
||||
|
||||
*The live mesh. Half a day. The proof of the whole.*
|
||||
|
||||
**Order.** Set the workstation's role in the module's settings. Record the checksums of everything
|
||||
under the person's agent directory. Assign the module; push. Remove the six predecessor files and the
|
||||
hand-made console entry. Start a new session.
|
||||
**Order.** Record the checksums under the person's agent directory. Bind the workstation to a
|
||||
subscription licence. Remove the six predecessor files and the hand-made console entry. Start a session.
|
||||
|
||||
**Proof.** The managed directory holds the settings and instruction files, owned by root. Everything
|
||||
under the person's agent directory is byte-identical to before except the credentials file, which is
|
||||
owned by the operator, readable by nobody else, and names no refresh token. The new session lists the
|
||||
mesh's tools under `mesh` once, answers *which node am I* from the instruction file, and makes a model
|
||||
request. `anthropic-licence-manager.switch` to the second subscription licence changes the token on
|
||||
the workstation within a minute, and neither the verb's answer nor either module's log holds a token.
|
||||
Switched to the API-key licence, the credentials file is left as it was and the agent authenticates
|
||||
through the key-helper. Switched back.
|
||||
**Proof.** Everything under the person's agent directory is byte-identical but the credentials file,
|
||||
which is owned by the operator, readable by nobody else, and names no refresh token. A session makes a
|
||||
model request. `switch` to the second subscription licence changes the token on the workstation within a
|
||||
minute, and neither the verb's answer nor either module's log holds a token. Switched to the API key, the
|
||||
credentials file is left as it was and the agent authenticates through the key-helper. Switched back.
|
||||
|
||||
## WP6 — The rest of the nodes, and the predecessor's remains
|
||||
|
||||
*The live mesh and mesh-catalog. One day.*
|
||||
|
||||
**Order.** Assign the module on the second workstation and on the servers whose account is stated;
|
||||
remove the predecessor's files on the second workstation. Log in on a workstation under a licence's
|
||||
account and watch the offer be adopted — and under the wrong account, and watch it refused and
|
||||
notified. Retire `anthropic-manager` and `anthropic-consumer` from the catalogue. Set designs 36 and
|
||||
39 to `implemented` for what runs, with the as-is written
|
||||
*The live mesh and mesh-catalog. One day.* The module on every node, the predecessor's files removed on
|
||||
the second workstation; a login under a licence's account collected and adopted, and one under the wrong
|
||||
account refused and notified; `anthropic-manager` and `anthropic-consumer` retired from the catalogue;
|
||||
designs 36 and 39 set to `implemented` with the as-is written
|
||||
([playbook 02](../../00-META/process/02-graduation.md)).
|
||||
|
||||
**Proof.** Every node with an account runs the module and `licence_status` answers on each; the
|
||||
refused login's notification arrived; the catalogue has no module built on the old placement.
|
||||
**Proof.** `claude_code_status` answers on every node; the refusal's notification arrived; the catalogue
|
||||
has no module built on the old placement.
|
||||
|
||||
## What is deliberately not here
|
||||
|
||||
- **The package repository seat** for a distribution that does not carry the agent's package
|
||||
(design 36 §7). A fresh node refuses the module in the package manager's words until it exists.
|
||||
- **The package repository seat** for a distribution that does not carry the agent's package (design 36
|
||||
§7). The four machines have the package; a fifth would refuse the module in its package manager's
|
||||
words.
|
||||
- **Escalation as a checked fact.** The agent module's write under `/etc` relies on the operator
|
||||
account's passwordless `sudo`, true on all four and checked by nothing. A machine without it refuses
|
||||
the render in the tool's own words; making escalation a reported capability is design 38's to decide.
|
||||
- **An automated switch on exhaustion.** The readings are kept from WP4; the policy is a later record.
|
||||
- **Workers and the mesh's own sessions as consumers.** The manager's bindings and fallbacks know them
|
||||
from WP2; the consumers themselves do not exist yet ([to-be 15](15-the-agent-session.md),
|
||||
[ADR 0003](../../02-DECISIONS/0003-agents-are-persistent-employees.md)).
|
||||
- **Whether a refresh token is single-use.** WP4 may measure it on a licence deliberately refreshed
|
||||
twice; the design holds either way.
|
||||
- **Workers and the mesh's own sessions as consumers.** The manager knows them from WP3; the consumers do
|
||||
not exist yet ([to-be 15](15-the-agent-session.md)).
|
||||
- **Whether a refresh token is single-use.** WP4 may measure it; the design holds either way.
|
||||
|
||||
## How this list is kept true
|
||||
|
||||
Each package's proof is run when the package is finished and its line here gains the date and the
|
||||
commit, as design 38 does. A package whose proof fails is not reworded; the failure is recorded under
|
||||
it and the package stays open. When WP5 is proven, designs 36 and 39 move to `in-progress` with their
|
||||
owning repository, and when WP6 is proven to `implemented`, with the as-is written.
|
||||
commit, as design 38 does. A package whose proof fails is not reworded; the failure is recorded under it
|
||||
and the package stays open. When WP2's live proof runs, design 36 moves to `in-progress` with its owning
|
||||
repository; when WP5's does, design 39 does too; and when WP6's does, both move to `implemented`, with
|
||||
the as-is written.
|
||||
|
||||
Reference in New Issue
Block a user