PAF becomes saf/device (history kept), STATE.md dissolves into saf/state.md with the dated era archived, the substrate SAF moves up from souveraine, and every agreement points at saf/INDEX.md and nowhere else. one map, nothing to remember
17 KiB
Agent principals
An agent is not a process borrowing the human's account. She has a logical identity that can cross machines and, on every admitted machine, a local Unix principal that lets the kernel tell her work from the human's and from another agent's.
This distinction is not implemented yet. Today the server, its agents, and
their tools normally run as the logged-in human. The per-agent SeedID exists,
but a signature cannot repair a shared UID: SO_PEERCRED still sees the same
caller and ordinary file permissions still collapse every agent into the same
authority.
Three identities that must not be collapsed
| Identity | Meaning | Lifetime |
|---|---|---|
| agent ID + agent SeedID | which being this is | stable across renames and admitted nodes |
| node commission | which admitted body is speaking for her | local to one commissioned device |
| Unix account | which local processes and files the kernel attributes to her | local to one device |
The numeric UID is not federated. An agent can be UID 1003 on one admitted
body and UID 991 on another while remaining herself, because both node-local
account mappings point to the same admitted agent identity. Copying
/etc/passwd, a UID number, or a private key is not commissioning.
There is a fourth identity already on the machines: the souveraine system
account. It belongs to the machine tier and runs souveraine-machined. It is
not Souvie, not a default agent, and not a convenient shared account for all
agents. The name is reserved.
The starting set, by role
A human's devices retain that human's own account. Agents do not borrow it.
| Role | Required local account |
|---|---|
| the default Souveraine agent on a fresh system | souvie |
| the human's primary personal agent, if she is admitted | her own name |
| any further named resident agent | its own name |
Only the first is shipped. souvie is what a fresh Souveraine install admits,
because a Souveraine system running its own agent as the human is the state
this chapter exists to end. Every other admission is a deliberate act by the
human on the body in question — including the primary personal agent, whose
name and cadence are that human's to choose. This chapter describes the
mechanism; which beings a particular deployment admits is that deployment's
record to keep.
"Each node" includes a development laptop. The laptop is not a development exception, and a phone is not a special appliance case. When a resident agent runs on either body, her turn, subconscious pass, memory access, and tools must cross the worker boundary under the mapped account.
The display name is editable. The agent ID, SeedID, and admitted account mapping are not derived again when the display name changes. Account names are chosen once, checked against the local account database and reserved names, then stored in a root-owned node-local mapping. A collision is shown to the administrator; creation must not silently attach an agent to an existing human or daemon account or invent a suffix that nobody noticed.
Souvie is the default, not the only possible agent. Restoring an existing Souvie must join her existing logical identity rather than minting another Souvie because the display name matches. A further agent is admitted onto each body where she is meant to act. Her local Unix account is new on that body; her being is not.
Primary and subconscious are processing positions inside an agent today. Creating an agent therefore does not automatically create a second Unix user for her second cadence. The cadences share her principal unless the human and the system later admit one as an independently authorized agent. The account boundary follows authority, not the number of internal thought streams.
Resident agents and borrowed-user modes
Not every named mode needs a Unix account. A hosted or borrowed-user mode runs
under the human's account rather than claiming a fully admitted resident
identity. That is a deliberate posture, not the same failure as a dedicated
agent accidentally running as the human.
The durable agent record therefore carries a principal intent, not one vague boolean:
| Intent | Expected runtime | Meaning |
|---|---|---|
dedicated |
the named agent account | full node admission and kernel-backed identity |
borrowed-user |
the invoking human account | a hosted mode using authority the human process can already reach |
Promoting a borrowed mode to a resident agent is an admission ceremony; changing a UI label or model does not do it. Which agents in a given deployment hold which intent is that deployment's record, not this chapter's.
A borrowed-user mode must know, in every model request, that readable does not mean owned or shareable. Its operating posture is stricter:
- the human's files, groups, sockets, credentials, and decrypted home are borrowed reach, not the mode's personal territory;
- do not widen mode bits, ACLs, group membership, links, remotes, publication, or sharing outside the explicit task without the human's confirmation;
- prefer the named workspace or a narrow temporary copy over exploring the rest of the human home;
- never read or disclose a resident agent's private memory merely because the shared human UID permits it;
- attribute actions to a borrowed mode acting through the human's principal, not to an independently admitted agent.
This caution is context and policy, not a substitute for containment. A borrowed process still has the human's kernel permissions; sensitive verbs must remain behind the same capability and consent gates.
The live principal fact
The intent in agent.json is durable. The live posture is observed afresh from
the selected agent or mode, node mapping, process credentials, and worker unit.
The trigger may expose a convenient operating_as_user boolean, but that
boolean is only a projection of the facts and is never an authorization input.
The runtime projection contains at least:
agent_id, display_name, principal_intent
expected_account, effective_account, effective_uid
node_id, worker_pid, trigger, observed_at
posture = isolated | borrowed-user | acting-as-human | drift
It is injected as a fresh system block into every model request, including primary and subconscious passes, subagents, resumed conversations, and later tool rounds after a mode switch. It is not ordinary conversation history and cannot be microcompacted, replayed from an old session, or taught back as assistant speech.
A machine-generated cache may be exposed as
/run/souveraine/agent-principals/{agent_id}.json and a Markdown rendering for
inspection. It does not belong in the agent-writable, Git-backed
system/dynamic/ memory tree: an awareness file the agent can edit cannot be
the source of who the kernel says she is. The prompt projection rechecks the
effective credentials when it reads the cache. Authorization always checks
the actual peer and process credentials again at the verb boundary.
Creation is logical creation followed by admission
The current creation path makes a UUID, an agent seed, memory directories, an
agent.json, and a paired subconscious tree under the human's
~/.souveraine. It has no privileged account step. The complete operation is
two related but separately observable transitions:
- Create the logical agent. Establish or import the agent ID and SeedID, initialize her memory, and record the requested local account name. Import must verify identity before it mutates local authority.
- Admit her to this node. A narrow system-tier executor creates or adopts the approved Unix account, writes the agent-to-principal mapping, installs the node commission, gives only her data to that account, and starts her worker as that UID.
The split makes failure honest. An agent can exist while admission is pending,
but the UI and API call that state unadmitted; they do not show a green agent
whose turns still run as the human. Personal- and step-up-tier verbs remain
closed until admission and execution checks pass.
Agent creation should ask for the authority shape, not merely a name and model:
- create a new identity or admit an existing one;
- principal intent and, for a resident, the required local account name;
- which node and role are being admitted;
- whether the privileged admission completed;
- which operating skill was projected from the admitted capabilities.
Fresh installation proposes Souvie and souvie. It must not confuse that
with the package-created souveraine machine account. Adding any further
agent uses the same path; there is no hand-written exceptional setup for a
particular deployment's names.
The privileged edge
QML, the TUI, and the ordinary server must not run useradd, rewrite
/etc/passwd, or recursively chown a human home. They submit one exact
admission request to one package-owned system executor. That executor owns:
- account creation and collision refusal;
- a locked password and non-login shell unless interactive login is later admitted deliberately;
- a stable home/state root tied to the agent ID, not the display name;
- the root-owned agent-ID, SeedID, node-ID, account-name, UID mapping;
- precise ownership changes inside that agent's root only;
- install, start, stop, and inspection of the per-agent worker unit;
- idempotent repair when the requested mapping already exists and agrees.
The low-level account primitive may be systemd-sysusers or an equally narrow
account API. That implementation choice does not create a second authority:
the admission executor remains the only writer and reports the resulting NSS
facts rather than assuming its command worked.
Admission is a ceremony
The executor is not the interface. A binary reachable only by someone who
already knows its name is not a way for a human to grant anything, and sudo
in a terminal that already trusts the caller is not a decision — it is a
formality. Admission is a highly user-directed act and has to be asked for as
one.
It has two occasions:
- initial setup, where a fresh install admits the default Souveraine agent
as
souvie, because that is the shipped default state and the only admission the product makes on its own; and - on the human's request, under specific conditions, for any further agent.
Both cross the same gate. The grant is a polkit action carrying a written reason that names the agent and the account, and it requires step-up authentication at the moment of the grant — including from a caller who could already reach root by other means. The cost is the point: giving an agent her own UID on this body is a deliberate authentication, never an inherited one.
Removing an agent record, removing a node admission, deleting a Unix account, and destroying memory are four different operations. None implies another. Decommission stops the worker and revokes the node commission first. Account and data deletion require explicit, separately named confirmation; archival is the normal default.
One UID requires one execution boundary
A single server process cannot truthfully execute three admitted agents as three UIDs. Per-agent accounts therefore require a process boundary:
- a controller may inventory agents and route requests;
- each admitted agent has a worker process running as her mapped UID;
- her memory, seed interface, conversation state, and tool execution are reached inside that worker's boundary;
- controller-to-worker IPC identifies the peer with
SO_PEERCREDand binds the logical agent ID to the admitted UID; - cross-agent consultation is a signed and policy-visible request, not direct filesystem access through a shared process.
The controller is not allowed to become a universal memory reader merely because it launches workers. Filesystem ownership, service sandboxing, and capability tokens should leave it only the routing and lifecycle access it actually needs.
Existing data under a human's ~/.souveraine is a compatibility layout. The
admission migration must stop the agent, copy or move only that agent's UUID
root, preserve and verify the Git repository, install ownership atomically,
then start the worker under the admitted UID. Never apply a broad recursive
ownership change to ~/.souveraine or a human home. Until migrated, health
labels the agent acting-as-human.
Account and authority health
Agent Health answers two separate questions: does she have an admitted
principal? and is the live work actually running as it? A directory and a
row in /etc/passwd are not runtime proof.
The inspection result is structured and available to setup, the agent manager,
the TUI, the Panel, and describe. At minimum it reports:
- logical agent ID, SeedID fingerprint, and node commission;
- expected account name and UID from the root-owned mapping;
- NSS account existence, home/state root, shell, password-lock state, and narrowly allowed groups;
- owner and mode of the memory, seed, conversation, socket, and runtime roots;
- worker unit, PID, effective UID/GID, cgroup, and executable;
- whether live peer credentials match the logical-agent mapping;
- whether any process handling the turn or its tools is the human,
souveraine, another agent, or an unknown UID; - capability-token subject and expiry when an authority verb is exercised;
- operating-skill presence and whether it matches the current capability description.
The top-level states are deliberately blunt:
| State | Meaning |
|---|---|
isolated |
account, ownership, worker, commission, and peer identity agree |
borrowed-user |
hosted mode intentionally uses the invoking human's account and receives the cautious borrowed-permission posture |
unadmitted |
logical agent exists; this node has no completed admission |
acting-as-human |
a dedicated agent's turn or tool is unexpectedly executing as the human or another human UID |
principal-drift |
mapping exists but NSS, ownership, unit, or peer facts disagree |
identity-drift |
account is healthy but agent key or node commission does not match |
stopped |
admission is sound and no worker is currently expected/running |
acting-as-human, principal-drift, and identity-drift are not yellow
decorations. They refuse personal and step-up authority. Ambient conversation
may remain available in a visibly degraded compatibility mode while migration
is unfinished. borrowed-user is intentional and may use only the human-granted
capability surface; it never becomes isolated merely because the human's UID
can read something.
The audit trail records both logical and kernel-backed subjects: agent ID, node ID, account name, UID, PID, operation, human requestor or consent grant, and result. "The agent asked" and "the human authorized this one action" are different fields. Running as the agent does not silently inherit the human's consent; running as the human does not make a model response the agent's.
The operating skill
Admission also projects an agent-local operating skill when it is missing or stale. It teaches the agent the boundary she actually has on this node:
- her logical and local principal names;
- her owned paths and worker/service inspection verbs;
- the ambient, personal, and step-up capabilities returned by
describe; - how to request a narrow user grant instead of impersonating the user;
- how to interpret and surface health refusals;
- how to ask for repair when the node mapping has drifted.
The skill is generated from the root-owned mapping and the authority's live capability description. It is not a credential and grants nothing. Editing a Markdown skill cannot change a UID, group, token, or verb. Health compares the projection to its sources and can offer an idempotent regeneration. An agent may keep her own prose and procedures around it, but machine claims remain a generated, marked section.
This is why account creation and skill creation belong in one experience but not one trust boundary: admission gives the kernel-backed principal; the skill gives the newly admitted agent an accurate way to use and explain it.
What is true now
- Per-agent SeedIDs and the first-run agent creation path exist.
- The setup wizard defaults inconsistently between
Souverainestate and anAniform field; neither creates a Unix account. - the packaged
souveraineaccount exists only for the machine tier; - on the laptop, NSS currently has no
souvie,annie, orvanguardaccounts, and all seven agent records live below Casey's home; - the Agent settings diagnostics check IDs and paths, not principal or process identity;
- the server hosts multiple agents inside the human's process and home;
- the admission executor exists and is packaged: one writer, the root-owned account mapping, and the runtime principal projection injected per model request. It has never run as root on a real system — every refusal has been proven only against scratch trees;
- there is no ceremony around it. No polkit action, no step-up, no first-run admission, and no surface anywhere that shows a human the choice. Reaching it requires already knowing its name;
- no per-agent worker boundary, account health surface, or generated operating
skill exists yet. Without the worker, every admitted agent still honestly
reads
acting-as-humanandisolatedis unreachable.
Until those pieces land, the system must say logical identity present, kernel principal absent. That is the live gap this chapter owns.