claude-code: declare the account agents run as and the command that starts it

The control node is to run its agents under an account that cannot become root
(hq ADR 0266). Declare it as a user the node-engine judges root: never, put the
agent's directory in its home, and place claude-agent so the operator starts a
session there through their own sudo. Where no agent account is named, both
name the operator's account, as before.
This commit is contained in:
jochen
2026-10-09 10:14:25 +02:00
parent c8fb0016f2
commit 17b0ac9f6c
2 changed files with 29 additions and 3 deletions
+14 -1
View File
@@ -8,12 +8,25 @@ configuration, and the consumer side of the Anthropic licence manager (design 39
Two directories, declared, so the mesh refuses a second module owning either:
- `/etc/claude-code`, the agent's machine-wide managed directory, root's, `0755`.
- `~/.claude` under the operator account's home, the operator's, `0700`. The module owns the directory —
- `~/.claude` under the home of the account agents run as (the operator's, unless the machine names an agent
account of its own), that account's, `0700`. The module owns the directory —
that it exists, who owns it, its mode — and of what is inside only what it writes. Everything else
in it (memory, history, projects, local settings, a person's own rules and skills) is the person's
and is never read or written (hq ADR 0182). Unassigned, the module leaves the directory: the host
removes a directory only when it is empty.
And, for where the agent runs as an account of its own (hq ADR 0266):
- **the account agents run as**, a `user` named by the machine fact `agent-account` — the operator's
account where the machine names none, which declares nothing new of it. Where it names one, the mesh
makes the account (its home, its own group, no password, no group of the mesh's) and asks the node-engine
to judge `root: never` on every look: that it is not root, is in no group that grants root, has no sudo
rule and can read no secret the mesh placed for another account. A way found is this module's condition,
and the controller's self-check says it urgently.
- `/usr/local/bin/claude-agent`, root's, `0755`: starts the agent as that account — `claude` itself when run
as it, otherwise `sudo -iu <account> claude` through the operator's own sudo, carrying the guard's
override only when it is set in the operator's shell.
## What it writes
Under the agent's managed directory, `/etc/claude-code`, owned whole by this module and rewritten
+15 -2
View File
@@ -84,12 +84,25 @@
"path": "/etc/claude-code",
"mode": "0755"
},
{
"id": "start",
"type": "file",
"path": "/usr/local/bin/claude-agent",
"mode": "0755",
"content": "#!/bin/sh\n# The mesh's (module claude-code, novox/hq ADR 0266): start the agent as the account agents run as on this\n# machine. Written whole at every push: an edit here is overwritten.\nagent='${machine:agent-account}'\nif [ \"$(id -un)\" = \"$agent\" ]; then\n\texec claude \"$@\"\nfi\n# Another account, the operator's, becomes the agent's through its own sudo: the person is the authority. The\n# operator's override of the guard travels only when it is set in this shell, as it would reach claude.\nif [ -n \"$MESH_GUARD_OVERRIDE\" ]; then\n\texec sudo -iu \"$agent\" env MESH_GUARD_OVERRIDE=\"$MESH_GUARD_OVERRIDE\" claude \"$@\"\nfi\nexec sudo -iu \"$agent\" claude \"$@\"\n"
},
{
"id": "agent-account",
"type": "user",
"name": "${machine:agent-account}",
"root": "${machine:agent-root}"
},
{
"id": "agent-home",
"type": "directory",
"path": "${machine:account-home}/.claude",
"path": "${machine:agent-home}/.claude",
"mode": "0700",
"owner": "${machine:account}"
"owner": "${machine:agent-account}"
},
{
"id": "state",