Design 58 and 36: identities carry logins, run for an identity, a bus password per identity (ADR 0411 to 0414, research 057)
mesh/merge-gate head 98b731d5d1ff merged into trunk 375e77690b8a — pass: the change touches no module of the mesh's graph
mesh/repo-check head 98b731d5d1ff merged into trunk 375e77690b8a — pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request

This commit is contained in:
2026-10-17 09:35:37 +00:00
parent 375e77690b
commit 98b731d5d1
3 changed files with 162 additions and 27 deletions
+22 -12
View File
@@ -98,6 +98,9 @@ and repair).
*Not:* ~~tools-sdk~~
- **invokes** — the manifest word for the tools a module calls, `<module>.<tool>` each or `*` for every
one. A grant on the publish side and nothing else; a module that declares none calls nothing.
- **run for** — an assignment, or a start of a module, that serves one agent identity with that identity's machine
account, home and bus password. Only a module whose manifest declares it may be run for an identity; running for
the operator is the default run, as the operator account, with no setting (ADR 0412).
- **upgrade policy** — how a module's new builds reach its nodes: `roll` (one node first, judged, then
the rest), `together`, or `record` (register the build, send it nowhere)
(ADR 0236).
@@ -231,7 +234,7 @@ every other domain has something to run on. **Recorded by** the controller and t
**Purpose.** To decide, send and apply what each node runs, and to say why.
**Recorded by** the controller's `inventory` database. **Upstream of** Provisioning, Connectivity, Data
and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 0252, 0261.
and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 0252, 0261, 0411.
**Uses:** node, machine, module, seat, manifest (Module), config value (Config).
- **assignment** — a module put on a node. Its config values on that node (module-assignment config,
@@ -264,15 +267,15 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02
other things (see [Homonyms](#homonyms)).
- **apply** — the node-engine making its node match its declaration; **reconcile** is doing so again
until nothing differs.
- **operator account** — the login name of the person who works on a node, stated on the node record;
empty for a node nobody logs into. Everything the mesh places under a person's home is resolved
against this account's home and owned by it
(ADR 0181).
- **operator account** — the machine account of the operator's person identity on a node, read from the
identity and no longer stated on the node record; empty for a node nobody logs into. Everything the mesh
places under a person's home is resolved against this account's home and owned by it
(ADR 0181, ADR 0411).
Not a name a manifest carries.
- **agent account** — the login every coding agent on a node runs as, when the node names one of its own;
stated on the node record at the controller's terminal, never by a verb or a config value. Empty means agents
run as the operator account. It cannot become root without a person, and the node-engine judges that on
every look (ADR 0266).
- **agent account** — the machine account of the agent identity the identity seat marks as a node's agent account,
on the operator's Approve, never by an assignment or a config value. Where none is marked, agents run as the
operator account. It cannot
become root without a person, and the node-engine judges that on every look (ADR 0266, ADR 0411).
- **account group** — a group of the machine's group database that a module puts an account in, by
declaring the account with that group and nothing else of it. Several modules may each add one to the
same account; the mesh takes back only an account group it added
@@ -341,7 +344,7 @@ and vault (Identity and access).
**Purpose.** To issue, hold, rotate and check the credentials and grants by which modules, nodes, agents
and the operator act. **Recorded by** the controller's `identity` and `licences` databases and the vault.
**Upstream of** Provisioning, Change and delivery, and Operator and conversation.
**Decided by** ADR 0085, 0113, 0183, 0225, 0234, 0386, 0387, 0388.
**Decided by** ADR 0085, 0113, 0183, 0225, 0234, 0386, 0387, 0388, 0411, 0413, 0414.
**Uses:** module, node, seat, tool (Module), operator, consumer and provision (Provisioning), agent and ask (Operator and conversation).
- **credential** — anything that proves an identity: a password, a key, a token. A **pair credential**
@@ -355,8 +358,13 @@ and the operator act. **Recorded by** the controller's `identity` and `licences`
- **vault** — the module that owns every secret (`mesh-vault`,
[24 — The secrets vault](../03-DESIGN/01-to-be/24-the-secrets-vault.md)).
- **identity** — a person, an agent or a module as the mesh knows it: a name, a kind, a role, and whether it
is switched on. Every identity and role is held by the identity seat, in the bus's key-value store, and
changes only through its verbs (ADR 0386).
is switched on; a person or an agent also has a login name, the machines it is present on and, for a person,
the login kept on a machine where it differs. Every identity and role is held by the identity seat, in the
bus's key-value store, and changes only through its verbs (ADR 0386, ADR 0411). Each person and agent
identity has a bus account of its own, carrying its role (ADR 0413).
- **machine account** — an identity's login on one machine, made by the mesh from the identity: the
controller composes it and the node-engine applies it, adopting a login that exists and never renaming or
deleting one (ADR 0411).
- **role** — what an identity may call, as a set of grants (ADR 0386). Not a seat: a bare *role* is a
homonym (see [Homonyms](#homonyms)).
- **grant** — one line of a role: an effect everywhere, an effect on one seat, or one named tool, and may be
@@ -817,6 +825,8 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical.
| record | a numbered decision | **decision record** | The record |
| | the literal reader of this repository, searched first for a symptom | **the record** (the `records` module) | Operator and conversation |
| | the upgrade policy that sends nowhere | `record` | Module |
| nox | the mesh's one agent identity, its logins and accounts (ADR 0414) | **`nox`, the agent** | Identity and access |
| | the operator's terminal command, `mesh-cli` | **the `nox` command** | Operator and conversation |
| knowledge base | the module holding the decision records and research efforts whole | **knowledge base** | The record |
| | the predecessor's operational memory, in older playbooks (issue 430) | none: it no longer exists | — |
| check | a pull request's two statuses | **merge check**, **merge gate**, **repository check** | Change and delivery |
@@ -2,8 +2,10 @@
layer: to-be
status: in-progress
code: [mesh-catalog modules/claude-code]
updated: 2026-10-13
updated: 2026-10-17
decisions:
- "ADR 0411"
- "ADR 0412"
- "ADR 0343"
- "ADR 0274"
- "ADR 0273"
@@ -306,21 +308,27 @@ operator's word — and, for the operator's own home, only at the terminal or on
## 9. The account the agent runs as
*Added 2026-10-08 by ADR 0266.*
Everywhere above, "the operator's home" and "the operator account" mean **the account the agent runs as**.
That is the operator account, unless the node names an **agent account** of its own. The control node does.
*Added 2026-10-08 by ADR 0266; changed 2026-10-17 by ADR 0411 and ADR 0412.*
Everywhere above, "the operator's home" and "the operator account" mean **the account the agent runs as**:
the machine account of the identity the module runs for (ADR 0412). claude-code declares that it can run for
an agent identity, in its assignment or when a session is started: started for `nox` it runs with the agent's
home; started for `jochen`, the operator, it is the default run, with the operator's configuration. On a
machine where no agent is marked as the agent account, its assignment is the default run, as every module's is.
**The fact.** The operator states the agent account at the controller's terminal. No verb and no setting
writes it. The controller resolves the machine facts `agent-account`, `agent-home` and `agent-root`, and gives
the tool runner the account and its home. Where the node names none, the facts name the operator account and
`agent-root` is empty, so nothing changes there.
**The fact.** The machine accounts come from the identity seat (ADR 0411); the operator no longer states the
agent account at the controller's terminal. A machine's agent account is the machine account of the agent the
identity seat marks as the agent account there, on the operator's Approve: `nox` on novox. There this module's
assignment is run for that agent, and the controller refuses one that is not. The controller resolves the
machine facts `agent-account`, `agent-home` and `agent-root` from it, and gives the tool runner the account and
its home. Where no agent is marked (ace, g14 and shanks), the facts name the operator account and `agent-root`
is empty, so nothing changes there, though a login `nox` exists for the modules run for it.
**What the module declares.**
- A `user` named by `agent-account`, with `root` set from `agent-root`. Where the account is the agent's own,
the mesh creates it (home, own group, no password) and the node-engine judges on every look that it cannot
become root without a person, by the ways ADR 0266 §3 lists. It detects those ways and no others; it
prevents nothing.
- No login. The mesh makes the agent's machine account (home, own group, no password) from the identity, and the
node-engine judges on every look that it cannot become root without a person, by the ways ADR 0266 §3 lists.
It detects those ways and no others; it prevents nothing. The `user` resource named by `agent-account`,
which this module declared until ADR 0411, goes.
- `~/.claude` under that account's home, owned by it.
- `claude-agent`, a command that starts the agent as that account through the operator's own sudo, or
directly when already run as it.
@@ -2,7 +2,7 @@
layer: to-be
status: designed
code: [mesh-catalog, mesh-media-catalog, mesh-sdk, mesh-tools, mesh-controller, mesh-host, mesh-lab]
updated: 2026-10-16
updated: 2026-10-17
decisions:
- "ADR 0383"
- "ADR 0384"
@@ -12,6 +12,10 @@ decisions:
- "ADR 0388"
- "ADR 0389"
- "ADR 0390"
- "ADR 0411"
- "ADR 0412"
- "ADR 0413"
- "ADR 0414"
---
# 58 — Agent work as the mesh's own
@@ -21,8 +25,10 @@ bus by a thread seat; a thread handler on an always-on node runs the agent harne
of its own, with the thread's own branch on the forge as its workspace; the agent works through a workspace toolkit
and named tools, never a general command runner. Every person, agent and module is an identity held by one identity
seat, with a role made of grants; the bus checks each login by its signature, and the tool runner checks each call
against the role, tool by tool, by the effect every tool carries.**
(ADR 0383 to ADR 0390, from research 053.)
against the role, tool by tool, by the effect every tool carries. An identity is also its logins: the mesh makes each
person's and agent's machine account on every machine it is present on, gives each its own bus password, and runs a
module for an identity only where the module is set to; everything else runs as the operator.**
(ADR 0383 to ADR 0390, from research 053; ADR 0411 to ADR 0414, from research 057.)
**Acceptance.** The operator starts a thread from the terminal client, an agent on an always-on node works it in a
sandbox, asks a question the operator answers in place, and the thread moves to another node and carries on with
@@ -106,6 +112,95 @@ agent carries a token the identity seat signed for that agent, and the tool runn
refusal names the missing grant; every call is recorded with its identity and thread. A session on an operator's
machine calls as the operator's person identity or as an agent, never through the machine's tool-runner login.
### 5.1 An identity on the machines (ADR 0411, ADR 0414)
A person or agent identity also holds a **login name**, the **machines** it is present on and, for a person, the
login name kept on a machine where it differs. The seat starts with two: `jochen`, the operator, and `nox`, the one
agent; every piece of agent work is a thread of `nox` (§2), and a second agent identity is made only when a rule needs
another role. The agent is `nox` everywhere: its login, its forge account (the forge account `nox-agent` renamed,
keys and team kept), Keycloak, mail and the bus. The operator is `jochen` where the operator has no account yet;
the logins `jochens`, `jochen` and `ace` and the forge account `jschoubben` are kept as they are. On a machine where agents ran as the
operator's login, that login stays the operator's and `nox` gets a login of its own; nox's bus account is `agent.nox`. `nox` is also the
operator's terminal command (`mesh-cli`), and prose says which is meant.
An identity's login on one machine is its **machine account**. The controller composes the machine account of every
identity present on a machine into that machine's declaration, and the node-engine applies it with its `user`
resource. A login that exists is adopted under its name, uid and home; the mesh never renames or deletes one. An
agent's machine account has its own home and group, no password, no root group and no sudo rule, and the node-engine
judges on every look that it cannot become root without a person (ADR 0266 §3). No module declares a login for a
person or an agent: claude-code's `agent-account` resource goes, and the catalogue's check refuses a manifest that
declares one. The node record's operator account and agent account are read from the identities, no longer stated
at the controller's terminal or in the mesh-config snapshot; the machine facts `account`, `agent-account` and their
homes keep their names. A machine names an agent account only where the identity seat marks an agent as its agent
account: novox, marked `nox`, where the guard and the licence stay as they are. ace, g14 and shanks are marked with
none, so the guard stays off there and the operator's sessions keep the mesh's tools, while the login `nox` serves the
modules run for `nox`. Where a person or an agent is present, its kept logins and the agent account mark change only
through a verb of the identity seat that only the operator calls, on an Approve; an assignment never sets the mark,
because an agent may call the verb that changes an assignment (ADR 0266 §4). The verb, and the controller at composition,
refuse an agent whose login on a machine would be `root`, a person's login there or a well-known service account
(ADR 0266 §5). The self-check judges every agent login,
marked or not. The seed: `jochen` on all four, kept logins `ace` on ace and `jochens` on novox (`jochen` on g14 and
shanks is the identity's own name); `nox` on all four, the agent account on novox.
```
identity seat controller each machine (node-engine)
───────────── ────────── ──────────────────────────
jochen person, its machines, composes, per machine: the operator's login (adopted)
the login kept on each the machine accounts present nox, root: never (adopted on novox,
nox agent, its machines the facts account, agent-account made elsewhere)
each identity's bus password ──► its secret, owned by its login, 0600
```
### 5.2 Run for an identity (ADR 0412)
Every module runs as the operator account of its machine, as today, with no setting; running for the operator is that
default run. A manifest may declare that its module can **run for** an agent identity, at assignment, at start or both: serve one identity with that identity's machine account, home and bus password.
An assignment of such a module may name the identity it runs for, and the module may let the one who starts it
choose: claude-code started for `jochen` is the default run with the operator's configuration, and started for `nox`
it runs for `nox` with the agent's home. A start
goes down only: a module is started for an identity by a process already running as that identity's login, or by the
operator's own login for an agent; an agent never starts one for a person, and the module refuses it, naming who asked
and for whom. A module may be assigned to one machine once per identity it runs for there, each its own process under
its own login, and the controller keys an assignment by machine, module and identity. The first two to declare it are
claude-code and ssh-client. On a machine the identity seat marks with an agent account, claude-code's assignment is
run for that agent (`nox` on novox), so its licence and home scope stay in the agent's home, and the controller refuses
one there that is not. ssh-client keeps its default assignment for
the operator wherever `nox` is present and gains a second one run for `nox`, which makes the agent's forge key in the
agent's home and closes issue 989; gitea's provider registers that key on the forge account `nox`. A module run for an identity calls as that
identity and gets no module identity of its own (this narrows ADR 0386 §4, which holds for every other assignment). A module with an account of its
own (`runs-as`, ADR 0259 §8) cannot declare it, and a run for an identity with no machine account on that machine is
refused at composition and at start. ADR 0266's guard
stands: on novox, a session started for the operator gets the operator's configuration and its tool calls are still
refused.
### 5.3 A bus password per identity (ADR 0413)
Each person and agent identity has a bus account of its own (`person.jochen`, `agent.nox`), whose memberships are made
from its role, and its password is a secret owned by its machine account at mode 0600 on each machine it is present
on, which no other account but root can read. A person's password is placed only on a machine that names an agent
account of its own judged unable to become root, by a verdict at most fifteen minutes old; on ace, g14 and shanks, where agents can still run as the operator,
it is not placed, and the controller says so. A module run for an identity reaches the bus with that password, can do
only what the identity's role allows, and every call is recorded as that identity's. Nox's role never holds an approval
grant, a trusted party's grant or a dangerous tool named in it (ADR 0387 §4 does not apply to it), and the identity seat
refuses one; each dangerous act of nox's is asked one by one. The break-glass agent (§6) keeps its own rules and gets
no login and no bus password from this. This changes ADR 0259 §8, which kept every bus credential out of an agent's account; the rest of §8 stands.
The password lives in today's list of bus accounts and is replaced by a signed login for the same role at the bus
switch (§7, §8).
### 5.4 Traced to GENESIS
Checked on 2026-10-17 (playbook 02, step 1); no conflict was found.
- [Mission](../../00-META/mission.md): agents "hold identity", and there is one kind of participant, some of them
human; persons and agents are held alike, with the same fields, and differ in what their role allows, which the
mission calls modality. "The mesh brokers credentials": the bus password per identity and the service accounts made
from it. "The mesh owns the truth": logins are derived from identities, no longer stated per node. "Dogfood": logins
go through the node-engine's existing resource.
- [Context](../../00-META/context.md): "Identity is mesh-internal", with no directory and no SSO, so the identity seat
holds it and Keycloak only receives accounts; "Nodes are personal" and the mesh is a guest, so existing logins are
adopted, never renamed; human agents are few, often one, so the seat holds two identities and one agent.
- [Effect](../../00-META/effect.md): a human agent's environment is part of the mesh, its login included.
## 6. Effects, asks and break-glass (ADR 0387)
Every seat verb and module tool is one permission and carries one **effect**, set in its module's manifest:
@@ -156,6 +251,28 @@ carry them:
`research/053-signed-bus-logins`, loses nothing and leaves every identity on the new bus.
5. The acceptance sentence at the top, end to end.
From research 057 (ADR 0411 to ADR 0414):
6. The identity seat lists `jochen` and `nox` with their machines, kept logins and novox's agent account mark; a
create or a presence change by any caller but the operator's Approve is refused.
7. On ace, g14 and shanks a login `nox` exists; on novox the login `nox` is adopted with its uid and home unchanged;
on all four the node-engine judges `nox` unable to become root, and the self-check raises `agent-can-become-root`
for it on a machine that marks no agent account too; the operator's logins `ace`, `jochen` and `jochens` are
unchanged.
8. No manifest in the catalogue declares a login for a person or an agent; the catalogue's check refuses one.
9. For every machine, the declaration before and after differs only in the machine accounts' `user` resources (now
the controller's, and `nox` added on ace, g14 and shanks); claude-code on novox, run for `nox`, places the same
files in the same home; on ace, g14 and shanks the guard stays off and the operator's sessions keep the mesh's tools.
10. A session started for `nox` on novox gets the agent's home configuration and one started for `jochen` the
operator's, with no tool call through; a session as `nox` that starts claude-code for `jochen` is refused; with
ssh-client run for `nox`, nox's key is on the forge account `nox` and the session pushes a branch over SSH as `nox`.
11. Nox's bus password is owned by `nox` at mode 0600 on every machine nox is present on; a call with it outside
nox's role is refused; a grant test finds no approval grant, trusted party's grant or dangerous tool in nox's
role; the operator's password is placed only on a machine with an agent account judged root-free within fifteen
minutes, and the controller says so for every other.
12. The forge account `nox-agent` is renamed `nox`, keeps every machine's key, stays in the agents' write team, and
every `forge-account` entry names `nox`.
## 11. Milestones
Each milestone is one feature step (playbook 07), usable as soon as its delivery plan is done, and starts when