The licence manager (Go) and claude-code's half of ADR 0206 #262

Merged
mesh-admin merged 2 commits from feat/the-licence-manager into main 2026-10-04 10:31:26 +00:00
Contributor

novox/hq ADR 0206 (with ADR 0183, design 39, design 36).

claude-licence-manager (new, Go)

Holds the anthropic-licence-manager seat. One binary: the seat's verbs and the daemon in one launched bundle; prepare is the run-once schema step.

  • Reads every node's claude-code.holdings state; a report with a refresh token it does not hold is a candidate.
  • Asks that node's claude_code_grant with its public key; the grant comes back sealed (same box as claude-code's TypeScript, byte for byte, tested both ways).
  • Adopts by refreshing: newest login first, once per account; failure records the login dead; the vendor's account, if named, must match the node's report.
  • One rotation source: every exchange under a lease per licence in postgres; cadence/floor/failure-notify/cooldown/refresh-expiry warning as in design 39.
  • bindings state per consumer with a monotonic generation; current answers the access token only, sealed to the consumer's key.
  • Verbs: licences, bindings, bind, switch, release, refresh, usage, adopt (API key from a file), current. Events: licence.adopted/refused/failing, usage.read — no token anywhere.
  • Tests: 9 rule tests on a memory store with a stub vendor, the store against real postgres, race detector clean. Built on the real builder from this branch (build-1791109141611090924).

claude-code

  • Reports what the node holds as holdings state at start and on every credentials change (fingerprints and account, never a token).
  • claude_code_grant hands the full grant over only when asked, sealed.
  • Watches claude-licence-manager.bindings for its node; a newer generation fetches current; writes access-token-only.
  • Licence events and login push removed. ask now reads the runtime's answer as a value, and seats are addressed as seat:… (the old form addressed a module subject nothing answers). Tests 28/28.

Not done here

Nothing is assigned. Going live adopts real logins: the first refresh spends each node's refresh token.

novox/hq ADR 0206 (with ADR 0183, design 39, design 36). ## claude-licence-manager (new, Go) Holds the `anthropic-licence-manager` seat. One binary: the seat's verbs and the daemon in one launched bundle; `prepare` is the run-once schema step. - Reads every node's `claude-code.holdings` state; a report with a refresh token it does not hold is a candidate. - Asks that node's `claude_code_grant` with its public key; the grant comes back sealed (same box as claude-code's TypeScript, byte for byte, tested both ways). - **Adopts by refreshing**: newest login first, once per account; failure records the login dead; the vendor's account, if named, must match the node's report. - One rotation source: every exchange under a lease per licence in postgres; cadence/floor/failure-notify/cooldown/refresh-expiry warning as in design 39. - `bindings` state per consumer with a monotonic generation; `current` answers the access token only, sealed to the consumer's key. - Verbs: licences, bindings, bind, switch, release, refresh, usage, adopt (API key from a file), current. Events: licence.adopted/refused/failing, usage.read — no token anywhere. - Tests: 9 rule tests on a memory store with a stub vendor, the store against real postgres, race detector clean. Built on the real builder from this branch (build-1791109141611090924). ## claude-code - Reports what the node holds as `holdings` state at start and on every credentials change (fingerprints and account, never a token). - `claude_code_grant` hands the full grant over only when asked, sealed. - Watches `claude-licence-manager.bindings` for its node; a newer generation fetches `current`; writes access-token-only. - Licence events and login push removed. `ask` now reads the runtime's answer as a value, and seats are addressed as `seat:…` (the old form addressed a module subject nothing answers). Tests 28/28. ## Not done here Nothing is assigned. Going live adopts real logins: the first refresh spends each node's refresh token.
mesh-admin added 1 commit 2026-10-04 10:19:35 +00:00
claude-licence-manager holds the anthropic-licence-manager seat: it reads
every node's holdings state, adopts a login it does not hold by refreshing
it (newest first, once per account), keeps each grant alive under a lease,
publishes what each consumer should hold as its bindings state with a
generation, and answers current sealed to the consumer's key. Postgres
store prepared by a run-once step; grants encrypted with the vault's key.

claude-code reports what its node holds (fingerprints and account, never a
token), hands its grant over only when the manager asks, watches its
binding and fetches the token on a newer generation, and writes
access-token-only. Its ask now reads the runtime's answer as a value and
addresses seats as seats.
jschoubben added 1 commit 2026-10-04 10:27:39 +00:00
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.
mesh-admin merged commit b485379505 into main 2026-10-04 10:31:26 +00:00
mesh-admin deleted branch feat/the-licence-manager 2026-10-04 10:31:27 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#262