diff --git a/00-META/glossary.md b/00-META/glossary.md index 8363b63d..75575e35 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -98,6 +98,9 @@ and repair). *Not:* ~~tools-sdk~~ - **invokes** — the manifest word for the tools a module calls, `.` 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 @@ -618,8 +626,8 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0259, 0272, 0383, 03 line as the **controller's terminal** or as an ordinary call (ADR 0272). - **nox** — `mesh-cli`'s alias, in interactive zsh only. A script, `sudo` and a document meant to work everywhere - say `mesh-cli`. The operator also calls the mesh itself *nox mesh*; on this page and in the records *nox* is the - alias alone. It is the one command the operator types: every line the mesh addresses to the operator — a + say `mesh-cli`. The operator also calls the mesh itself *nox mesh*. *nox* is also the agent (ADR 0414 §7): see + [Homonyms](#homonyms), and say which is meant. It is the one command the operator types: every line the mesh addresses to the operator — a condition's words, a verb's answer, a README, a design — names a `nox` line, never a daemon's (the controller's or the node-engine's binary followed by a command), which `words.py` and the catalogue's check refuse (ADR 0272, @@ -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 | diff --git a/03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md b/03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md index a37710b8..02dd8e36 100644 --- a/03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md +++ b/03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md @@ -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 §12 to §17 list. + 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. diff --git a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md index f5e63aab..66fa86f3 100644 --- a/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md +++ b/03-DESIGN/01-to-be/58-agent-work-as-the-meshs-own.md @@ -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, by the ways ADR 0266 §12 to §17 list. 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,29 @@ 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; a login `nox` given a sudo rule in a test is left + unaltered 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, for the modules not set to run for an identity, 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