The operator decided on 2026-10-08 that agents on the control node run under an account of their own, without sudo, and that the operator's account keeps its sudo. This is that decision written down, with the parts the operator left open filled in. Merging this accepts those parts too.
ADR 0266:
A node may name an agent account. The operator states it at the controller's terminal; no verb or setting can change it.
The claude-code module declares the account as a user with root: never.
The node-engine judges on every look that the account has no uid 0, no group that grants root, no sudo rule, and no readable secret placed for another account. That covers the tool runner's credential.
The self-check raises agent-can-become-root when the judgement fails or is missing. ADR 0259 §8 rule 2 reads the same judgement.
The agent's files are written as the agent through a helper.
The guard refuses any session not running as the agent account.
claude-agent starts a session through the operator's own sudo.
The tool runner stays on the operator's account, and the record says why.
Issue 333: the measured symptom. On the control node, the operator account has two passwordless sudo grants (the mesh's drop-in and a line set by hand) and is in the docker group.
To-be 36 §9: the design amendment, including the operator's day afterwards and the steps on the control node in order. The operator's own sudo is never touched.
Glossary: agent account.
The code pull requests:
mesh-host #61: the node-engine judges root: never.
mesh-controller: the node fact, the machine facts, the self-check invariant (pull request to follow, linked in a comment).
ADR 0259 is still on pull request 211, so it is named without a link. All four checks in merge-check.sh pass locally.
The operator decided on 2026-10-08 that agents on the control node run under an account of their own, without sudo, and that the operator's account keeps its sudo. This is that decision written down, with the parts the operator left open filled in. **Merging this accepts those parts too.**
- **ADR 0266**:
- A node may name an **agent account**. The operator states it at the controller's terminal; no verb or setting can change it.
- The `claude-code` module declares the account as a `user` with `root: never`.
- The node-engine judges on every look that the account has no uid 0, no group that grants root, no sudo rule, and no readable secret placed for another account. That covers the tool runner's credential.
- The self-check raises `agent-can-become-root` when the judgement fails or is missing. ADR 0259 §8 rule 2 reads the same judgement.
- The agent's files are written as the agent through a helper.
- The guard refuses any session not running as the agent account.
- `claude-agent` starts a session through the operator's own sudo.
- The tool runner stays on the operator's account, and the record says why.
- **Issue 333**: the measured symptom. On the control node, the operator account has two passwordless sudo grants (the mesh's drop-in and a line set by hand) and is in the `docker` group.
- **To-be 36 §9**: the design amendment, including the operator's day afterwards and the steps on the control node in order. The operator's own sudo is never touched.
- **Glossary**: *agent account*.
The code pull requests:
- mesh-host #61: the node-engine judges `root: never`.
- mesh-controller: the node fact, the machine facts, the self-check invariant (pull request to follow, linked in a comment).
- mesh-catalog #140: the module's code.
- mesh-catalog (to follow): the manifest.
ADR 0259 is still on pull request 211, so it is named without a link. All four checks in `merge-check.sh` pass locally.
Deliverynovox/hq@cb907d5810a2 — delivered since 2026-10-09T10:56:38Z
Delivery plan — builds nothing: the change touches no module of the mesh's graph
Transitions
2026-10-09 10:27 (new) → proposed (announced): novox/hq#225's head announced
2026-10-09 10:28 proposed → checked (checked): the verdict names this commit
2026-10-09 10:28 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-09 10:56 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-09 10:56 published → delivered (done): nothing for a walk to move
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/hq@cb907d5810a2` — **delivered** since 2026-10-09T10:56:38Z
**Delivery plan** — builds nothing: the change touches no module of the mesh's graph
**Transitions**
- 2026-10-09 10:27 (new) → proposed (announced): novox/hq#225's head announced
- 2026-10-09 10:28 proposed → checked (checked): the verdict names this commit
- 2026-10-09 10:28 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-09 10:56 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-09 10:56 published → delivered (done): nothing for a walk to move
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
The operator chose this remedy for ADR 0259 section 8: an agent there could
become root through the operator account's sudo and docker group, and read the
tool runner's credential. Record the node fact, the node-engine's judgement
the self-check reads, the guard, and how a session starts; issue 333 holds
the measured symptom and to-be 36 the design.
The review found ways round the record: a verb that set the accounts, root
following a link below a home, a tool reading any path as the operator, a
restore written beside the agent's files, a stale verdict passing. Record each
bound, the exact ways judged and not judged, the guard on every tool and its
record's limits, and a rollout order the guard does not block.
The re-review closed the command verb to reads, moved enrolment to the
controller's terminal, widened what the node-engine judges, and found the
store's reader able to read every secret; say each, and that the boundary is
not in force until the store is fixed.
The routes found around the agent account since the record was written are
closed on main (the store's reader, places and served keys, what every session
obeys, execute withheld on the control node); the record names them, drops the
store gap it said kept the boundary from holding, and says plainly what still
remains, first the login shell's execute on the other nodes. To-be 36 §9 gains
the prerequisites and the order the parts go out in.
Rebased and brought up to date on 2026-10-09 (head ee314a2).
ADR 0266 §7 now says where the boundary stands. The store gap paragraph is replaced. The routes closed on main are named: the store's reader (issue 337), places, accesses and served keys at the terminal (issue 339), what every session obeys (issue 340), and execute withheld on the control node (ADR 0268).
What still remains, said plainly:
execute on the other nodes, the desk's terminal open and rofi_run all run a caller's command as that node's operator, who has passwordless sudo there.
**Rebased and brought up to date on 2026-10-09 (head ee314a2).**
**ADR 0266 §7 now says where the boundary stands.** The store gap paragraph is replaced. The routes closed on main are named: the store's reader (issue 337), places, accesses and served keys at the terminal (issue 339), what every session obeys (issue 340), and `execute` withheld on the control node (ADR 0268).
**What still remains, said plainly:**
- `execute` on the other nodes, the desk's terminal `open` and `rofi_run` all run a caller's command as that node's operator, who has passwordless sudo there.
- Tool servers already on the bus.
- The tool runner still runs as the operator.
- The duplicate root probe in mesh-controller #154.
**Smaller changes:**
- §7 records the engine's own agent-home refusal and `plans retry`.
- The checked-by table names the engine test.
- To-be 36 §9 gains step 0 (the prerequisites) and the order the parts go out in.
Code heads: mesh-host #61 b28d7bb, mesh-controller #164 926dbd7, mesh-catalog #140 c8fb001, #141 eacda6e.
Item 10 said two minutes; the engine's bound is 15, with a two-minute limit
inside it still to settle. What still remains now names a build from another
repository registering a module (mesh-controller 174), the forge's tools
changing its protection (mesh-catalog 153), and the urgent condition every
engine restart raises (mesh-controller 175).
The record said a merge needs a person; the forge requires no approval and
the merge tool merges once the checks pass, so nothing enforces the
operator's yes. What still remains now says so, and that the restart fix
counts from when the controller first saw the search pending. Item 10 and
routes A and B describe the follow-ups of the review of 2026-10-09.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The operator decided on 2026-10-08 that agents on the control node run under an account of their own, without sudo, and that the operator's account keeps its sudo. This is that decision written down, with the parts the operator left open filled in. Merging this accepts those parts too.
claude-codemodule declares the account as auserwithroot: never.agent-can-become-rootwhen the judgement fails or is missing. ADR 0259 §8 rule 2 reads the same judgement.claude-agentstarts a session through the operator's own sudo.dockergroup.The code pull requests:
root: never.ADR 0259 is still on pull request 211, so it is named without a link. All four checks in
merge-check.shpass locally.Delivery
novox/hq@cb907d5810a2— delivered since 2026-10-09T10:56:38ZDelivery plan — builds nothing: the change touches no module of the mesh's graph
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.cfa06b68bctoee314a26caRebased and brought up to date on 2026-10-09 (head
ee314a2).ADR 0266 §7 now says where the boundary stands. The store gap paragraph is replaced. The routes closed on main are named: the store's reader (issue 337), places, accesses and served keys at the terminal (issue 339), what every session obeys (issue 340), and
executewithheld on the control node (ADR 0268).What still remains, said plainly:
executeon the other nodes, the desk's terminalopenandrofi_runall run a caller's command as that node's operator, who has passwordless sudo there.Smaller changes:
plans retry.Code heads: mesh-host #61 b28d7bb, mesh-controller #164 926dbd7, mesh-catalog #140 c8fb001, #141 eacda6e.