|
|
|
@@ -0,0 +1,86 @@
|
|
|
|
|
# What the tool containers are given, measured
|
|
|
|
|
|
|
|
|
|
Counted 2026-10-03 in the catalogue, after the two holders moved.
|
|
|
|
|
|
|
|
|
|
| | |
|
|
|
|
|
|---|---|
|
|
|
|
|
| modules whose tools still run as a container on the runtime's image | 33 |
|
|
|
|
|
| tool containers among them (two modules run two) | 36 |
|
|
|
|
|
| modules whose container's environment carries only the bus credential | 1 (the intrusion prevention, now moved) |
|
|
|
|
|
| modules whose container's environment carries more | 32 — 31 still containers |
|
|
|
|
|
|
|
|
|
|
## What "more" is
|
|
|
|
|
|
|
|
|
|
Every value a container is given is one of five shapes. The reference kinds the composer resolves
|
|
|
|
|
in those values, over the 36 containers: a module directory (`${dir:…}`) in all 36, a mesh-chosen
|
|
|
|
|
port (`${port:…}`) in 12, a seat and an access grant once each.
|
|
|
|
|
|
|
|
|
|
1. **A file the mesh already places on the host, mounted in.** The module's configuration as
|
|
|
|
|
JSON (`…_CONFIG_FILE`), its own secret (`…_TOKEN_FILE`, `…_PASSWORD_FILE`, `MESH_BROKER_FILE`),
|
|
|
|
|
a provision's address and secret written for it. Every one is a path under one of the module's
|
|
|
|
|
directories — its mesh state, its state, its grants, what it has written — mounted at a path of
|
|
|
|
|
the container's choosing and named to the tool through the environment. **The file is on the
|
|
|
|
|
host already; only the name under which the tool finds it is the container's.**
|
|
|
|
|
2. **The service's address, with the port the mesh chose:** `http://127.0.0.1:${port:3000}`. The
|
|
|
|
|
port is the composer's; the rest is the manifest's constant.
|
|
|
|
|
3. **A provision's address as a constant string** (a database's URL on the module's own network
|
|
|
|
|
name), paired with a mounted secret file from shape 1.
|
|
|
|
|
4. **A directory of grants** (`MESH_RECEIVES`): shape 1 again, a directory rather than a file.
|
|
|
|
|
5. **Literals the image needs:** a time zone, a user id, a memory limit. These belong to the
|
|
|
|
|
service's container where one exists; a tool bundle needs none of them.
|
|
|
|
|
|
|
|
|
|
So the whole of what a bundled tool needs is: the paths of its module's directories on this
|
|
|
|
|
machine, the ports the mesh chose for its module here, and the constants its own manifest wrote.
|
|
|
|
|
Nothing a container had that a bundle cannot have; the mesh composes all three for the container
|
|
|
|
|
today, per module per machine.
|
|
|
|
|
|
|
|
|
|
## What the runtime already has for it
|
|
|
|
|
|
|
|
|
|
- The SDK's tool contributor is `(env) => tools`, and `collectTools(env)` takes the environment to
|
|
|
|
|
hand each contributor. The runtime calls it without one, so every contributor reads the process's
|
|
|
|
|
— the four words. The hook for a per-module environment exists and is unused.
|
|
|
|
|
- A launched bundle ([ADR 0188](../../02-DECISIONS/0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md))
|
|
|
|
|
is spawned with the runtime's environment; the launch takes an environment argument.
|
|
|
|
|
- The composer resolves `${dir:…}` and `${port:…}` for a container's `env` and `volumes`; the same
|
|
|
|
|
resolution over a bundle's declaration is the same code.
|
|
|
|
|
|
|
|
|
|
## Options
|
|
|
|
|
|
|
|
|
|
**A. The bundle declares its environment on its artifact, and the mesh composes it as a
|
|
|
|
|
container's.** The manifest's tools artifact gains `env`, resolved with the same references;
|
|
|
|
|
values that were mount targets become the host-side paths directly (`${dir:mesh-state}/config.json`
|
|
|
|
|
rather than `/run/config/config.json`). The controller composes one environment per bundle per
|
|
|
|
|
machine into the runtime's declaration; the runtime hands it to the bundle's contributor and to a
|
|
|
|
|
launched child, and to nothing else. *For:* the tool code does not change — it reads the same
|
|
|
|
|
names; the conversion of the thirty-one is a mechanical move of the container's `env` with the
|
|
|
|
|
mounts folded in; one rule, one place. *Against:* the runtime's process carries thirty-one
|
|
|
|
|
environments in its declaration, and a bundle's environment is visible to the other bundles in the
|
|
|
|
|
process unless the runtime keeps them apart, which it must — a tool that reads `process.env`
|
|
|
|
|
instead of the environment it was handed would see its neighbours' paths.
|
|
|
|
|
|
|
|
|
|
**B. The runtime derives the environment from the module's placed manifest.** No new field: the
|
|
|
|
|
runtime reads, for each module it serves, where that module's directories and ports are, and hands
|
|
|
|
|
a conventional set of words. *For:* nothing to declare. *Against:* a convention the tool code must
|
|
|
|
|
be rewritten to, thirty-one times; the runtime learns the composer's job; a module that names its
|
|
|
|
|
file `config.json` and one that names it `settings.json` need different words anyway.
|
|
|
|
|
|
|
|
|
|
**C. Tools read their module's files through the bus** — ask the controller. *Against:* a tool
|
|
|
|
|
that cannot start without the bus answering a question is a tool that fails in the one case the
|
|
|
|
|
tools exist for, and a secret crossing the bus to reach a file already on the machine is a
|
|
|
|
|
disclosure for nothing.
|
|
|
|
|
|
|
|
|
|
A is the one that keeps the tool code and the composer's vocabulary as they are, and names the one
|
|
|
|
|
thing the runtime must add: an environment per bundle, kept apart. The thing to decide beside it:
|
|
|
|
|
whether a bundle's environment may name a secret file at all, or whether secrets stay mounts in
|
|
|
|
|
spirit — a path the tool reads, never a value in the environment — which is what every container
|
|
|
|
|
does today and what A keeps if the rule says *paths, not values*.
|
|
|
|
|
|
|
|
|
|
## What a decision would have to say
|
|
|
|
|
|
|
|
|
|
- Where a bundle says what it is given (the artifact, option A), and that values are paths and
|
|
|
|
|
constants, never a secret's content.
|
|
|
|
|
- That the composer resolves it with the references it already has, per module per machine.
|
|
|
|
|
- That the runtime hands each bundle its own environment and nothing of another's, and how that is
|
|
|
|
|
checked: a test loading two bundles whose environments differ and asserting each sees only its own.
|
|
|
|
|
- That the thirty-one move in one mechanical change after the rule lands, each proven by its tools
|
|
|
|
|
answering from the runtime, and the registration gate then refuses the container shape for all.
|