hq to-be 38, WP2 — the controller composes one runtime per node. Four commits, each with its tests, in the design's order. Pairs with mesh-tools #29 (WP1); nothing here changes what any live node is sent until the runtime module node-tools is assigned to it (WP3).
A node principal (1f86ed4). Beside one bus principal per module per node, one of kind node-tools where that module is assigned, username <node>.node-tools, minted and delivered through the same path as a module's into node-tools' own broker secret. Serving grants are the union of every assigned module's tool subjects on the node and every held seat's verbs; it may read and follow mesh.assignment.<node>.*; invoking is *; it may emit each carried module's declared events; it consumes nothing. Memberships are composed exactly as before (proven equal with and without the runtime).
Bundle delivery (b1df688). For every module on such a node whose build produced a bundle the runtime loads from, the declaration gains an archive at /var/lib/mesh/bundles/<module>/<bundle>, digest as the build recorded, routed through the artifact store. The resolved manifest now carries bundles (derived; refused in a repo manifest). A bundle says what the runtime loads (subset of its entrypoints; absent means every entrypoint when the module declares tools), so a bundle that also carries a daemon is not started inside the runtime.
The runtime's process (9d4d847). One process per node from node-tools' own bundle: run: ["node", <entrypoint>], MESH_TOOL_MODULES as <module>=<path>,…, MESH_BROKER_FILE, and MESH_OPERATOR_ACCOUNT/MESH_OPERATOR_HOME plus user when the node has an account; restart-on names every bundle archive and the credential. Refused by name when node-tools has other than one bundle or one entrypoint, or no own-secrets.broker.
The gate (8eb6c3e). A manifest declaring tools and a container built on mesh-tools' runtime image is refused at registration once node-tools is in the catalogue, naming ADR 0175 / to-be 38; accepted before.
Also in here, deliberately flagged: the TypeScript toolchain gains --rootDir . so a compiled entrypoint lands at the path the manifest names (a module compiling only tools/index.ts previously got index.js at the bundle root, which the entrypoint tools/index.js never matched). This touches every TypeScript bundle build (showcase, zsh, systemd): verify on the first live build after merge.
Tests:go build, go vet, go test ./... green everywhere except one pre-existing failure in cmd/mesh-controller (TestModuleCheckPassesTheCatalogue: the catalogue's fail2ban manifest does not yet serve the intrusion seat's verbs — hq #295's work, fails identically on main).
Open for WP3: the runtime module's name is one constant (RuntimeModule, held equal across packages by a test). Suggest keeping mesh-tools as the module the 35 manifests build on and adding node-tools as a second module in the same repository rather than renaming. The node-tools manifest needs exactly one typescript bundle with one entrypoint, own-secrets.broker, invokes: ["*"], the loopback listen, and no tools.
**hq to-be 38, WP2 — the controller composes one runtime per node.** Four commits, each with its tests, in the design's order. Pairs with mesh-tools #29 (WP1); nothing here changes what any live node is sent until the runtime module `node-tools` is assigned to it (WP3).
1. **A node principal** (`1f86ed4`). Beside one bus principal per module per node, one of kind `node-tools` where that module is assigned, username `<node>.node-tools`, minted and delivered through the same path as a module's into node-tools' own `broker` secret. Serving grants are the union of every assigned module's tool subjects on the node and every held seat's verbs; it may read and follow `mesh.assignment.<node>.*`; invoking is `*`; it may emit each carried module's declared events; it consumes nothing. Memberships are composed exactly as before (proven equal with and without the runtime).
2. **Bundle delivery** (`b1df688`). For every module on such a node whose build produced a bundle the runtime loads from, the declaration gains an `archive` at `/var/lib/mesh/bundles/<module>/<bundle>`, digest as the build recorded, routed through the artifact store. The resolved manifest now carries `bundles` (derived; refused in a repo manifest). A bundle says what the runtime `loads` (subset of its entrypoints; absent means every entrypoint when the module declares `tools`), so a bundle that also carries a daemon is not started inside the runtime.
3. **The runtime's process** (`9d4d847`). One `process` per node from node-tools' own bundle: `run: ["node", <entrypoint>]`, `MESH_TOOL_MODULES` as `<module>=<path>,…`, `MESH_BROKER_FILE`, and `MESH_OPERATOR_ACCOUNT`/`MESH_OPERATOR_HOME` plus `user` when the node has an account; `restart-on` names every bundle archive and the credential. Refused by name when node-tools has other than one bundle or one entrypoint, or no `own-secrets.broker`.
4. **The gate** (`8eb6c3e`). A manifest declaring `tools` and a container built on mesh-tools' `runtime` image is refused at registration once `node-tools` is in the catalogue, naming ADR 0175 / to-be 38; accepted before.
**Also in here, deliberately flagged:** the TypeScript toolchain gains `--rootDir .` so a compiled entrypoint lands at the path the manifest names (a module compiling only `tools/index.ts` previously got `index.js` at the bundle root, which the entrypoint `tools/index.js` never matched). This touches every TypeScript bundle build (showcase, zsh, systemd): verify on the first live build after merge.
**Tests:** `go build`, `go vet`, `go test ./...` green everywhere except one pre-existing failure in `cmd/mesh-controller` (`TestModuleCheckPassesTheCatalogue`: the catalogue's fail2ban manifest does not yet serve the intrusion seat's verbs — hq #295's work, fails identically on main).
**Open for WP3:** the runtime module's name is one constant (`RuntimeModule`, held equal across packages by a test). Suggest keeping `mesh-tools` as the module the 35 manifests build on and adding `node-tools` as a second module in the same repository rather than renaming. The node-tools manifest needs exactly one typescript `bundle` with one entrypoint, `own-secrets.broker`, `invokes: ["*"]`, the loopback listen, and no `tools`.
Where the node-tools module is assigned, the machine's bus user list gains one principal of kind
node-tools in place of that module's own: it may subscribe every carried module's tool namespace
and every held seat's verbs on its node, read and follow every membership on its node, call any
tool anywhere, answer what it is asked — and consume nothing, because tools are what it runs.
Every other module keeps its own principal, so a module still serving tools from its container
holds its own credential until it moves.
Named exactly as the module it stands for, so `module issue` and `rollout mint` deliver its
credential through the path a module's already takes, into node-tools' own `broker` secret. The
runtime module's name is one constant in each of the broker and catalogue packages, held to one
string by the agreement test, because a rule turns on it.
The resolved manifest now carries what the build compiled — each bundle's source, digest, language
and entrypoints — because a tools bundle is named by no resource of the module's own: the node's
runtime loads it, and until this the mesh held no trace of the one artifact that runtime needs. A
repository manifest that writes `bundles` beside its build is refused: the mesh derives it.
Where the runtime module is in a node's set, every assigned module's bundle with entrypoints is
composed as an archive under the mesh's own directory, routed through the artifact store like any
image or archive the mesh built. A bundle without entrypoints is run rather than loaded and is
delivered by the process that runs it. A node without the runtime is sent exactly what it was.
Where node-tools is in a node's set, the declaration ends with one process: the runtime module's own
bundle, run from its one entrypoint by its language's interpreter, told in MESH_TOOL_MODULES every
<module>=<file> the machine's bundles load, where its credential is (the module's own broker secret
as this node places it), and — on a machine with an operator account — who the operator is, running
as that account so a tool that needs root can escalate as the operator would. Restarted when any
bundle it loads or the credential changes. A machine with no account runs it as root without the two
operator words; a machine without the runtime is sent nothing new.
A bundle says which of its entrypoints the runtime LOADS (`loads`), because one bundle may carry a
daemon beside its tools and importing the daemon into the runtime would start it there; absent, a
module declaring tools has every entrypoint loaded. And the TypeScript toolchain is rooted at the
module, so an entrypoint lands at the path it is named by — the runtime loading bundles by their
declared paths is what made the compiler's common-directory default visible.
A module declaring tools, a container, and a build on mesh-tools' runtime image is a container whose
purpose is serving tools — the pattern the node's tool runtime retires. Once node-tools is in the
catalogue, registering one is refused by name, with the record that says why; before, it is accepted
as it always was, so a mesh converts in the design's order and nothing is refused before there is
anything to move to. This is the mechanism that keeps the old pattern from returning by habit.
Judged from a repository manifest's own build.on, and for a built manifest — which carries no build
— from what its build stood on, now recorded beside the commit as part of a module's provenance.
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.
hq to-be 38, WP2 — the controller composes one runtime per node. Four commits, each with its tests, in the design's order. Pairs with mesh-tools #29 (WP1); nothing here changes what any live node is sent until the runtime module
node-toolsis assigned to it (WP3).1f86ed4). Beside one bus principal per module per node, one of kindnode-toolswhere that module is assigned, username<node>.node-tools, minted and delivered through the same path as a module's into node-tools' ownbrokersecret. Serving grants are the union of every assigned module's tool subjects on the node and every held seat's verbs; it may read and followmesh.assignment.<node>.*; invoking is*; it may emit each carried module's declared events; it consumes nothing. Memberships are composed exactly as before (proven equal with and without the runtime).b1df688). For every module on such a node whose build produced a bundle the runtime loads from, the declaration gains anarchiveat/var/lib/mesh/bundles/<module>/<bundle>, digest as the build recorded, routed through the artifact store. The resolved manifest now carriesbundles(derived; refused in a repo manifest). A bundle says what the runtimeloads(subset of its entrypoints; absent means every entrypoint when the module declarestools), so a bundle that also carries a daemon is not started inside the runtime.9d4d847). Oneprocessper node from node-tools' own bundle:run: ["node", <entrypoint>],MESH_TOOL_MODULESas<module>=<path>,…,MESH_BROKER_FILE, andMESH_OPERATOR_ACCOUNT/MESH_OPERATOR_HOMEplususerwhen the node has an account;restart-onnames every bundle archive and the credential. Refused by name when node-tools has other than one bundle or one entrypoint, or noown-secrets.broker.8eb6c3e). A manifest declaringtoolsand a container built on mesh-tools'runtimeimage is refused at registration oncenode-toolsis in the catalogue, naming ADR 0175 / to-be 38; accepted before.Also in here, deliberately flagged: the TypeScript toolchain gains
--rootDir .so a compiled entrypoint lands at the path the manifest names (a module compiling onlytools/index.tspreviously gotindex.jsat the bundle root, which the entrypointtools/index.jsnever matched). This touches every TypeScript bundle build (showcase, zsh, systemd): verify on the first live build after merge.Tests:
go build,go vet,go test ./...green everywhere except one pre-existing failure incmd/mesh-controller(TestModuleCheckPassesTheCatalogue: the catalogue's fail2ban manifest does not yet serve the intrusion seat's verbs — hq #295's work, fails identically on main).Open for WP3: the runtime module's name is one constant (
RuntimeModule, held equal across packages by a test). Suggest keepingmesh-toolsas the module the 35 manifests build on and addingnode-toolsas a second module in the same repository rather than renaming. The node-tools manifest needs exactly one typescriptbundlewith one entrypoint,own-secrets.broker,invokes: ["*"], the loopback listen, and notools.