The predecessor's agent module was retired and its six files stayed on both workstations telling every session to use tools that no longer exist. Before a successor module is written, the design needs the decisions it rests on and nothing in the record stated them: - ADR 0169 (reconstructed) records what the controller shipped on 2026-09-27 without a record: the operator account is a node fact stated by the operator, the home is derived unless stated, a resource may be placed under it owned by the account, and a node with no account refuses one. - ADR 0170 generalises to-be 29 §3's found-vs-owned boundary to every directory under a home: the module owns the directory and the files it places, writes into the tool's own files for its few keys, never declares a credential's content, and holds everything else as found — a predecessor's leftovers included, which the operator removes once. - ADR 0171 draws the licence line the operator asked to have drawn rather than assumed: the mesh binds and delivers (to-be 14 and 15 stand), the module alone writes the credential file, refresh stays central (ADR 0050), a switch is the binding changed through a controller seat verb asked for via the console, and the token-carrying shell helper is retired. The controller learns nothing about the agent; that is what "no part" means. To-be 36 is the module's design: the ownership map per path, the fate of the six predecessor files, what the three instruction documents say, the licence tools and skill, the console as a node-scoped provision, the package gap stated honestly, and the order of the build. To-be 14, 29 and 34 carry dated notes; the glossary gains "operator account".
118 lines
9.3 KiB
Markdown
118 lines
9.3 KiB
Markdown
---
|
|
topic: what runs on it
|
|
status: accepted
|
|
date: 2026-10-02
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md
|
|
---
|
|
|
|
# 177. Inside a home, the mesh owns the directory and the files it places, writes into the tool's own files, and holds everything else as found
|
|
|
|
## Context
|
|
|
|
[ADR 0176](0176-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md) lets a module
|
|
place files under a person's home. A home is unlike any directory the mesh has written into so far:
|
|
it is shared with the person, and with every program the person runs. The agent's configuration
|
|
directory on the laptop makes the point. On 2026-10-02 it holds thirty entries. The predecessor placed
|
|
five of them (an instruction file, a conventions rule, a settings file it merged into, two skills); a
|
|
sibling module placed a sixth (the node's identity rule). The agent itself writes the other
|
|
twenty-four: its settings, its credentials, its history, the memory of every project it has worked in,
|
|
its plugins, its session logs. Several of those are what [to-be 15](../03-DESIGN/01-to-be/15-the-agent-session.md)
|
|
calls memory *written by the session itself and declared by nobody*: a mechanism that regenerated the
|
|
directory would erase a season of it, silently, while reporting success.
|
|
|
|
The predecessor's own module recorded the hazard in the other direction. Its settings file was first
|
|
shipped as *replace*, and every `/model` choice a person made inside a session was reverted to the
|
|
template's value on the next synchronisation — on every node, indefinitely, with no indication why. It
|
|
was changed to *merge*, and the comment explaining why is still in its manifest.
|
|
|
|
**And the generator is gone while its output stayed.** The predecessor was retired from the laptop on
|
|
2026-10-01. Its six files are still on both workstations, with their content telling every session to
|
|
use tools that no longer exist. Nothing owns them; nothing will ever rewrite or remove them.
|
|
|
|
[To-be 29 §3](../03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md) drew the line for one directory,
|
|
`~/.ssh`: the mesh owns the directory and the files it places; it holds the person's private keys and
|
|
personal drop-ins as found. That was argued from the lockout `~/.ssh` can cause. The argument here is
|
|
the same shape with a different stake — the person's work rather than the person's way in — and it has
|
|
to hold for every directory the family of home-scoped modules will touch, so it is a rule, not a
|
|
section.
|
|
|
|
## Considered Options
|
|
|
|
1. **The module owns the directory whole**, regenerating it from the definition. Rejected: it destroys
|
|
the memory, history and local settings the agent writes for itself, which is the failure to-be 15
|
|
names and the predecessor's settings file demonstrated at small scale.
|
|
2. **The module owns only the files it names, and nothing about the directory.** Rejected: *owning one
|
|
file beside foreign ones is not owning anything* (to-be 29). The directory must exist, with the right
|
|
owner and mode, before the tool first runs on a fresh machine; and a credentials file in a
|
|
world-readable directory is a credentials file in the wrong directory.
|
|
3. **The module owns the directory and the files it places; a file the tool writes for itself is
|
|
written into, never over; everything else is held as found.** Chosen.
|
|
|
|
## Decision
|
|
|
|
**A home-scoped module owns the directory it declares: its existence, owner and mode.** The host creates
|
|
it if absent, owned by the account, and never removes it while it holds anything
|
|
([ADR 0030](0030-data-outlives-the-mesh-that-declared-it.md)). Inside it, every path the module touches
|
|
is in exactly one of four classes, and **the class is visible in the definition from the shape
|
|
declared**, not inferred from what happened to be on disk:
|
|
|
|
| class | declared as | the host's rule |
|
|
|---|---|---|
|
|
| **owned** | a file with content, or a roster fact | written whole, regenerated, removed when undeclared; a file found there with no record of the mesh making it is kept once before it is written over ([ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md)) |
|
|
| **written into** | a file written *into* a structured document | only the keys the definition names are set, every other key is kept, and each set key is given back when undeclared (ADR 0102). The key list is the module's and is short |
|
|
| **written by the module's own process** | a secret the mesh delivers to the module, and a step that writes the file from it | the file's content is never a declared file's content, because a declaration travels in the clear on the bus and the host records it; the module's process writes it, owned by the account, atomically. [ADR 0178](0178-the-mesh-binds-and-delivers-a-licence-and-the-module-writes-the-tools-credential.md) says how for a credential |
|
|
| **found** | nothing | never read, never rewritten, never removed. The person's memory, history, projects, local settings, their own rules and skills |
|
|
|
|
**A file the tool writes for itself is written into, never over.** The agent's settings file and its
|
|
own state file are the tool's; the mesh has one or two facts to state in each. Setting those keys and
|
|
nothing else is what lets a person's `/model` choice survive a push, and what lets the mesh's keys be
|
|
taken back cleanly when the module goes.
|
|
|
|
**A predecessor's output is found.** A file placed by a generator that no longer exists is, to the
|
|
mesh, a file it has no record of making. Where the successor module keeps the path, declaring it
|
|
*adopts* it: the host keeps the original once and writes the mesh's. Where the successor does not keep
|
|
the path, the mesh does not remove the file, because it removes nothing it did not make; **the operator
|
|
removes it, once**, and the module's definition names those paths in its own documentation so the step
|
|
is not forgotten. This is the first instance of the one-off setup step to-be 29 leaves open, and the
|
|
rule chosen for it is that it is a person's act, listed, not a module's.
|
|
|
|
**The rule is the family's.** An ssh client module, a shell module, an agent module each declare their
|
|
directory and classify their paths this way. A module that cannot say which class a path is in has not
|
|
finished its definition.
|
|
|
|
## Consequences
|
|
|
|
- A person's work under their home survives every push and every unassign. The mesh's own files come
|
|
and go with the module; the mesh's keys in the tool's files come and go with it; the directory stays.
|
|
- **Stale files survive too.** Two workstations keep three predecessor files each until a person removes
|
|
them — a visible cost, accepted over a mesh that deletes under a person's home. A module author who
|
|
renames one of the mesh's own files has the ordinary path: the old resource id is undeclared and the
|
|
host removes what it made ([ADR 0118](0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md)).
|
|
- A module's definition is longer by a classification, and a reviewer has one more question per path.
|
|
That is the point: *which parts are managed must be explicit rather than inferred* (to-be 15).
|
|
- **What got harder:** a module cannot seed a person's preference once and leave it. A seeded file
|
|
([ADR 0087](0087-a-seeded-file-is-created-once.md)) is the shape for that, and it is available to
|
|
this family unchanged; what is refused is a seed the module later wants to change, because what grew
|
|
in it is the person's.
|
|
|
|
## How it is checked
|
|
|
|
| Rule | Checked by |
|
|
|---|---|
|
|
| The directory is created owned by the account and kept when the module goes | host tests of a directory resource with an owner (ADR 0051's and 0118's), and the family's lab check below |
|
|
| An owned file found with no record is kept once, then written | host tests of ADR 0102's kept-original rule |
|
|
| Only the declared keys of a written-into file change, and are given back | host tests of ADR 0102: declared keys set, the rest kept, restored when undeclared |
|
|
| Nothing found is touched | the family's lab check: a machine with a seeded home holding a person's file beside a predecessor's; after apply the person's file is byte-identical, the predecessor's is kept as the original, the mesh's keys are set and the person's keys in the same file remain; after unassign the mesh's files are gone, the keys are restored, the person's files are untouched and the directory stands |
|
|
| Every path a home-scoped module touches is classified | a catalogue review rule for this family: each path is a directory, a file, a file written into, a secret-and-step, or absent — the first module written to it is [to-be 36](../03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md) |
|
|
|
|
## References
|
|
|
|
- [to-be 29 §3](../03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md) — the same boundary drawn for `~/.ssh`
|
|
- [to-be 15](../03-DESIGN/01-to-be/15-the-agent-session.md) — a session's memory is declared by nobody
|
|
- [ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md), [ADR 0087](0087-a-seeded-file-is-created-once.md),
|
|
[ADR 0118](0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md), [ADR 0030](0030-data-outlives-the-mesh-that-declared-it.md) — the mechanics each class rests on
|
|
- [ADR 0051](0051-shared-data-is-the-operators.md) — the third case the host had no word for: what it neither made nor configured
|
|
- the predecessor's `claude-code` module manifest, whose comment on `strategy: merge` records the reverted `/model` choice
|