From f291d113c8daed9b1d189dd4e14fda87dcdb4d02 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 5 Oct 2026 10:10:28 +0200 Subject: [PATCH] ADR 0216: the agent's configuration is registered through its module, at three scopes, and served as one plugin Graduates research 029 and amends design 36 (section 8): skills, subagents, commands, hooks and output styles in one nox-mesh plugin; servers, settings and instructions in the managed files; mesh, node and home scopes. --- .../00-overview.md | 6 +- ...t-three-scopes-and-served-as-one-plugin.md | 167 ++++++++++++++++++ 02-DECISIONS/README.md | 1 + .../36-the-operators-agent-on-a-machine.md | 63 ++++++- 4 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 02-DECISIONS/0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md diff --git a/01-RESEARCH/029-the-agent-configured-through-its-module/00-overview.md b/01-RESEARCH/029-the-agent-configured-through-its-module/00-overview.md index be4515f..8c9de10 100644 --- a/01-RESEARCH/029-the-agent-configured-through-its-module/00-overview.md +++ b/01-RESEARCH/029-the-agent-configured-through-its-module/00-overview.md @@ -1,5 +1,5 @@ --- -status: active +status: graduated initiated: 2026-10-04 touches: - 03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md @@ -8,7 +8,9 @@ touches: - 02-DECISIONS/0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md - 02-DECISIONS/0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md - 02-DECISIONS/0213-the-operator-sets-the-agents-managed-settings-through-the-agent-module.md -became: [] +became: + - 02-DECISIONS/0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md + - 03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md --- # 029 — The agent configured through its module diff --git a/02-DECISIONS/0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md b/02-DECISIONS/0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md new file mode 100644 index 0000000..99a9490 --- /dev/null +++ b/02-DECISIONS/0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md @@ -0,0 +1,167 @@ +--- +topic: what runs on it +status: accepted +date: 2026-10-05 +deciders: jochen +reconstructed: false +extends: 02-DECISIONS/0213-the-operator-sets-the-agents-managed-settings-through-the-agent-module.md +--- + +# 216. The agent's configuration is registered through its module, at three scopes, and served as one plugin + +## Context + +The operator wants everything about the coding agent that can be configured to be configured through +the agent module's tools ([research 029](../01-RESEARCH/029-the-agent-configured-through-its-module/00-overview.md)). +That covers subagents, skills, slash commands, hooks, output styles, settings, permissions, +instructions and tool servers. Each is registered once, from any machine, for one machine, several or +all of them. + +The agent module already manages three files in the agent's machine-wide managed directory: the +settings, the tool servers and one instruction file ([to-be 36](../03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md)). +Tool servers registered through its tools are kept in its state on the bus and reach every machine +they apply to. The vendor has **no machine-wide place for skills, subagents, commands or hooks**; they +live only in a home or a project. Measured on four machines +([029/01](../01-RESEARCH/029-the-agent-configured-through-its-module/01-what-is-configured-today.md)), +what was copied there by hand had drifted and gone stale: + +- two skills of a retired system were on all four machines; +- one rule file existed in three versions; +- two contradicting instruction sets were loaded into the same session; +- a subagent existed on one machine only. + +The vendor's **plugin** carries skills, subagents, commands, hooks and output styles. A machine-wide +setting can name a marketplace and enable a plugin from it +([029/02](../01-RESEARCH/029-the-agent-configured-through-its-module/02-what-the-vendor-allows.md)). +Tried on one workstation ([029/04](../01-RESEARCH/029-the-agent-configured-through-its-module/04-what-was-confirmed.md)): + +- a plugin in a directory marketplace, enabled by the managed settings, loads in every session with no + prompt, read in place, and an edit reaches the next session with no version change; +- its items are offered under the plugin's name; +- its hooks run; +- its tool servers are blocked by the exclusive managed tool-server file. + +A plugin cannot carry settings, permission rules or instructions. + +The operator also set the scopes. A skill may be meant for: + +- every machine; +- one machine; +- one machine's own account, as if written there by hand. + +The instruction file the same: the mesh's piece, the node's piece, and further customisation per machine. + +## Considered Options + +1. **Copy everything into each home**, owned by the mesh path by path. Rejected as the *only* place: + the home is the person's ([ADR 0182](0182-inside-a-home-the-mesh-owns-what-it-places-and-holds-the-rest-as-found.md)), + a mesh item there is indistinguishable from the person's by name, and it fills the directory where + the drift was measured. Kept as one scope of three (below). +2. **A plugin per source:** one for the operator's registrations, one for what other modules + contribute. Rejected: two prefixes to remember for one agent. Where an item came from belongs in + the module's list, not in its name. +3. **Registrations in a repository on the forge**, the plugin built from it. Rejected for now: + registering would be a commit, and the forge would sit on the path to every machine. Configuration + would enter the code review cycle, which it does not need. +4. **One plugin, `nox-mesh`, plus the managed files the module already writes, at three scopes, all + registered through the module's tools and kept in its state on the bus.** Chosen. + +## Decision + +Option 4. + +**1. What goes where.** Each kind of item goes to the one place the vendor honours for it: + +| kind | place | +|---|---| +| skills, subagents, slash commands, hooks, output styles | the plugin `nox-mesh` | +| tool servers | the managed tool-server file, as today: the exclusive file blocks a plugin's servers | +| settings and permission rules | the managed settings file: a plugin's settings are dropped | +| instructions | the managed instruction file, in sections: a plugin's instruction file is not loaded | + +The plugin is named `nox-mesh` (the operator's choice): the name its items carry in every session, and +not one a person's own plugin is likely to take. It lives in a marketplace directory inside the module's +managed directory, written whole by the module's code. The managed settings name that marketplace and enable the plugin. Those two keys +are the mesh's, laid last like the attribution key (ADR 0213), and no setting replaces them. + +**2. Three scopes.** Every registration names one: + +- **mesh:** every machine running the agent, including one that joins later. +- **node:** one machine, or a list of them. Rendered into the same plugin and managed files, on those + machines only. +- **home:** the operator account's own agent directory on one machine. The item is placed where the + person's own items live, without the plugin's prefix. + +Settings and permission rules take the mesh and node scopes only. The home's settings file stays the +person's. + +**3. Instructions follow the scopes.** The managed instruction file holds, in order: + +1. the mesh's piece, the same everywhere; +2. the node's piece: its role, and the sections registered for it. + +Further customisation per machine is a rule file placed at the home scope. The vendor concatenates +these and does not override, so the module's status tool names any section that contradicts another, +or that calls a tool the mesh no longer serves. + +**4. Registered through tools, kept on the bus.** For each kind, the module serves `list`, `register` +and `unregister` tools; for settings, tools that read and set them at a scope. Each registration is a +key in the module's state ([ADR 0201](0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md)): + +- an item and its files are one value, refused above **256 KiB**, well under the bus's message limit; +- every instance watches the state and renders what applies to its machine. + +The settings registered this way are laid over the `managed_settings` layer of ADR 0213. In order: +ADR 0213's setting, then the mesh scope, then the node scope, then the mesh's own keys. + +**5. The home scope owns only what it placed.** The module records each home path it placed, in its +state. It writes, changes and removes only those. It refuses to register a name the person already +uses there, rather than overwrite it. + +**6. What the module did not place, it reports and can import.** + +- A status tool lists the home's items and says which the mesh placed. It also names any that + duplicate a mesh item or call tools no longer served. +- An import tool registers an item found in one machine's home at a scope the operator chooses. +- Removing the original stays the person's act. +- Whether home items load at all stays the operator's choice, through a vendor setting in the managed + settings. + +**7. Changing the agent's own settings is the operator's act.** The vendor's guard refuses an agent that +loosens its own settings. A settings or permission tool is called on the operator's word, and the +module does not try to get around that refusal. + +## Consequences + +- One registration puts a skill, a subagent or a rule on every machine, on some, or in one account. A + machine that joins takes the mesh and node items at its first start. Nothing is copied by hand. +- The plugin's items are named `nox-mesh:`, and a person's own items keep their names. Nothing the + mesh adds can shadow them. +- A change reaches the next session on each machine, or a running one at its next plugin reload. +- **What got harder:** + - an item larger than 256 KiB cannot be registered until the state can hold files in pieces; + - the module's state now holds file content, not only small records; + - the stale files already in the homes stay until the person removes them. The module names them; + it does not remove them. +- **Not decided here:** another module contributing a skill or a subagent to the agent through a seat + ([ADR 0210](0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md)). + The agent module holds no seat yet. When one is decided, contributions land in the same plugin. + +## How it is checked + +| Rule | Checked by | +|---|---| +| each kind lands in its one place | the module's render test: a registered skill, subagent, command, hook and output style appear in the plugin; a tool server in the managed tool-server file; a setting in the managed settings file; an instruction section in the managed instruction file | +| scopes | the same test, for one machine of two: a mesh item on both, a node item on one, a home item only in that machine's home | +| the marketplace keys are the mesh's | the render test: a setting naming either key is overridden | +| the home scope owns only what it placed | the module's test: a name the person already uses is refused; unregistering removes only the placed path | +| the size limit | the module's test: an item above 256 KiB is refused at registration | +| live | a skill registered at the mesh scope is offered as `nox-mesh:` in a new session on each machine | + +## References + +- [Research 029](../01-RESEARCH/029-the-agent-configured-through-its-module/00-overview.md) — the evidence, the vendor's rules, and what was confirmed +- [ADR 0213](0213-the-operator-sets-the-agents-managed-settings-through-the-agent-module.md) — the managed settings setting this lays over +- [ADR 0182](0182-inside-a-home-the-mesh-owns-what-it-places-and-holds-the-rest-as-found.md) — what the mesh may do inside a home +- [ADR 0201](0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md) — module state on the bus +- [to-be 36](../03-DESIGN/01-to-be/36-the-operators-agent-on-a-machine.md) — the design this amends diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 4e6ea34..50d53bc 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -315,6 +315,7 @@ python3 00-META/checks/index.py fail if stale - **0213** — [The operator sets the agent's managed settings through the agent module, under the mesh's own keys](0213-the-operator-sets-the-agents-managed-settings-through-the-agent-module.md) - **0214** — [Backups guard against mistakes, stay on the machine, and are declared by the module that owns the data](0214-backups-guard-against-mistakes-and-stay-on-the-machine.md) - **0215** — [The machine's message bus is a node seat, and it is never restarted live](0215-the-machines-message-bus-is-a-node-seat-and-is-never-restarted-live.md) +- **0216** — [The agent's configuration is registered through its module, at three scopes, and served as one plugin](0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md) ### How it is built 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 3a9ff59..8efec9b 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,9 @@ layer: to-be status: in-progress code: [mesh-catalog modules/claude-code] -updated: 2026-10-04 +updated: 2026-10-05 decisions: + - 02-DECISIONS/0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md - 02-DECISIONS/0213-the-operator-sets-the-agents-managed-settings-through-the-agent-module.md - 02-DECISIONS/0209-a-login-on-a-node-moves-that-node-to-its-account-and-an-api-key-is-added-from-any-node-sealed.md - 02-DECISIONS/0206-a-node-reports-the-anthropic-grant-it-holds-and-the-licence-manager-adopts-a-licence-by-refreshing-it.md @@ -41,7 +42,8 @@ The agent reads a machine-wide, administrator-owned configuration directory unde by the vendor: a managed settings file that outranks every user and project setting; a key in it that adds HTTP tool servers *beside* a person's own without blocking them; and a managed instruction file every session reads before the user's and the project's. The agent has **no** machine-wide directory for -rules, skills, slash commands or hooks; those exist only under a home or a project. +rules, skills, slash commands or hooks; those exist only under a home or a project — or in a **plugin** +the managed settings enable, which is how the mesh puts them on every machine (§8). So the mesh's part of the agent's configuration lives there, **owned whole by the module**, and the home is left alone. What the predecessor shipped as two rule files and two skills folds into the managed @@ -205,6 +207,60 @@ answer is a package repository for this ecosystem as a seat and trusted by every node's package manager; not built, and not this module's to build. The vendor's own installer is rejected: it puts a self-updating binary under the person's home, invisible to the mesh. +## 8. The agent's configuration, registered at three scopes + +Everything about the agent that can be configured is registered through this module's tools, once, from +any machine, and kept in the module's state on the bus +([ADR 0216](../../02-DECISIONS/0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md)). Every instance watches that state and writes what applies to its +machine. A machine that joins later takes it at its first start. + +**What goes where.** The vendor honours each kind of item in one place only, so the module writes four: + +- skills, subagents, slash commands, hooks and output styles go into **one plugin named `nox-mesh`**. It + sits in a marketplace directory inside the managed directory, written whole by the module and read in + place by the agent. Its items are offered as `nox-mesh:`, so nothing the mesh adds shadows a + person's own item; +- tool servers go into the managed tool-server file, as in §4. The exclusive file would block a + plugin's servers; +- settings and permission rules go into the managed settings file, as in §2; +- instructions go into the managed instruction file, as sections (§3). + +The managed settings name the marketplace and enable the plugin. Those two keys are the mesh's, laid +last with the attribution key, and no setting replaces them. + +**Three scopes.** Every registration names one: + +- **mesh:** every machine running the agent; +- **node:** one machine or a list of them, rendered into the same plugin and files there only; +- **home:** the operator account's own agent directory on one machine, where the item sits as if + written there by hand. + +Settings take the first two scopes only. In the managed settings file they are laid in this order: +the operator's `managed_settings` setting (§2), then the mesh scope, then the node scope, then the +mesh's own keys. + +**Instructions follow the scopes.** The managed instruction file holds the mesh's piece, then the node's +piece: its role, and the sections registered for it. Further customisation per machine is a rule file +placed at the home scope. The agent concatenates these and does not override, so the status tool names +a section that contradicts another, or that calls a tool the mesh no longer serves. + +**The home scope owns only what it placed.** The module records each home path it placed and touches +only those (ADR 0182). It refuses to register a name the person already uses there. + +**The tools.** + +- For each kind: list, register and unregister. Each register takes a scope, and a list says where + each item came from. +- For settings and permission rules: read, and set at a scope. +- A **status tool** lists the home's own items beside the mesh's and names the stale ones. +- An **import tool** registers an item found in one machine's home at a scope the operator chooses. + +An item and its files are one value in the state, refused above 256 KiB. + +**Changing the agent's own settings is the operator's act.** The vendor refuses an agent that loosens its +own settings, and the module does not route around that refusal. A settings tool is called on the +operator's word. + ## How it is checked | Check | Defends | @@ -215,6 +271,9 @@ installer is rejected: it puts a self-updating binary under the person's home, i | a switch asked of the seat through the console changes the licence and the token on the node; no tool answer and no log line holds a token | ADR 0183 | | the API-key binding writes nothing under the home and the agent authenticates through the helper | ADR 0183 | | the module's test: keys set in `managed_settings` (an auto-mode allow list, a permissions list) appear in the rendered managed settings file, a setting naming the attribution, the connectors key or a key-helper is overridden, and a key-helper appears only for an API-key binding | ADR 0213 | +| the module's render test: a registered skill, subagent, command, hook and output style land in the `nox-mesh` plugin; a tool server, a setting and an instruction section in their managed files; for one machine of two, a mesh item on both, a node item on one, a home item only in that home; a setting naming the marketplace keys is overridden | ADR 0216 | +| the module's test: a home name the person already uses is refused, unregistering removes only the placed path, and an item above 256 KiB is refused | ADR 0216, ADR 0182 | +| live: a skill registered at the mesh scope is offered as `nox-mesh:` in a new session on each machine | ADR 0216 | | the console's provision resolves by co-location; a machine without the console refuses the module by name | ADR 0027, ADR 0152 | | a new session on the assigned workstation lists the console's five tools under `mesh` ([ADR 0195](../../02-DECISIONS/0195-the-meshs-tools-are-found-by-address-not-announced-whole.md)) and answers "which node am I" from the instruction file | the exit of the build |