ADR 0195: the mesh's tools are found by address, not announced whole; research 021; to-be 34 §3a
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
---
|
||||
topic: what runs on it
|
||||
status: accepted
|
||||
date: 2026-10-03
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md
|
||||
---
|
||||
|
||||
# 195. The mesh's tools are found by address, not announced whole
|
||||
|
||||
## Context
|
||||
|
||||
The console answers MCP on a machine's loopback ([ADR 0152](0152-the-operators-surface-is-a-module-the-console.md),
|
||||
[to-be 34](../03-DESIGN/01-to-be/34-the-console.md)) and announces, at a session's start, every tool
|
||||
the mesh can say it has: 228 on 2026-10-03, 110 KB, taken once. Three things are wrong with that,
|
||||
measured in research [021](../01-RESEARCH/021-finding-a-tool-in-the-mesh/00-overview.md):
|
||||
|
||||
- **Size.** Only one client's habit of deferring long lists keeps them out of the model's context.
|
||||
- **Ambiguity.** A module on two machines is listed once, `node` optional, *whichever answers* — for
|
||||
postgres and mssql, whose instances hold different data, a call that names no machine asks an
|
||||
arbitrary one.
|
||||
- **Staleness.** A tool that arrives after the session started is not listed until it reconnects.
|
||||
|
||||
The mesh already has the structure a caller needs: seats held once for the mesh, seats held once per
|
||||
machine ([ADR 0159](0159-a-tool-call-names-the-machine-and-a-holder-serves-its-seats-verbs.md)), and
|
||||
modules assigned to machines, each assignment issued its own subjects
|
||||
([ADR 0160](0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md)).
|
||||
The operator's direction: *tools are discoverable, in layers, and asking novox's postgres is not asking
|
||||
ace's.*
|
||||
|
||||
## Considered Options
|
||||
|
||||
1. Keep the flat list and rely on the client. Rejected: the ambiguity and the staleness stay, and it
|
||||
is one client's behaviour.
|
||||
2. One tool per assignment, the machine in the name. Rejected: the list multiplies, and an address in
|
||||
a tool's name meets the API's limit — letters, digits, `_` and `-`, at most 64 characters.
|
||||
3. **A fixed handful of tools that walk the mesh's structure, the address an argument.** Chosen.
|
||||
4. MCP resources or prompts. Rejected: unevenly supported, and an agent acts through tools.
|
||||
|
||||
## Decision
|
||||
|
||||
**1. Everything the mesh answers has one address, by the layer it lives in:**
|
||||
|
||||
| layer | address | answered by |
|
||||
|---|---|---|
|
||||
| a seat held once for the mesh | `<seat>.<verb>` | that seat's holder |
|
||||
| a seat held once per machine | `<node>/<seat>.<verb>` | that machine's holder |
|
||||
| a module assigned to a machine | `<node>/<module>.<tool>` | that assignment |
|
||||
| a module whose instances are interchangeable (ADR 0160) | `<module>.<tool>` as well | any of them |
|
||||
|
||||
**A call to a module that is not interchangeable names its machine, or is refused** naming the machines
|
||||
it runs on. "Whichever answers" is no longer an answer for state a machine holds.
|
||||
|
||||
**2. The console announces a fixed set of tools, not the catalogue:**
|
||||
|
||||
- **`mesh_overview`** — the mesh's seats with their verbs, and its machines;
|
||||
- **`mesh_machine`** — one machine: the node seats it holds and the modules assigned to it, each with
|
||||
its tools by name;
|
||||
- **`mesh_search`** — words in, matching addresses out with one line each, across every layer;
|
||||
- **`mesh_describe`** — one address in, its description and argument schema out;
|
||||
- **`mesh_call`** — an address and its arguments in, the answer out, with the machine that gave it.
|
||||
|
||||
Each is answered from the mesh when it is asked, so a tool that arrived a minute ago is found without
|
||||
the client reconnecting. The names are the API's kind of name; addresses never have to be.
|
||||
|
||||
**3. The flat catalogue stays reachable, not announced:** the `mesh` client and a console setting can
|
||||
still list it whole, for a person reading it or a client that wants it. An agent pointed at the console
|
||||
sees the five.
|
||||
|
||||
## Consequences
|
||||
|
||||
- An agent spends a call or two finding a tool it does not know, and none on one it does; the context
|
||||
no longer carries 110 KB it mostly never uses.
|
||||
- The ambiguity is closed by the address, not by a description asking the agent to remember `node`.
|
||||
- What got harder: an agent that once saw a tool's schema up front now asks for it. `mesh_describe` and
|
||||
`mesh_search` answering with the schema of a close match keep that to one call.
|
||||
- The discovery verbs are the console's; the mesh's own records — seats, machines, assignments — are
|
||||
the controller's, and the console asks it rather than keeping a copy.
|
||||
|
||||
## How it is checked
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| The console announces five tools | the console's test: `tools/list` answers exactly the five |
|
||||
| An address resolves to one subject per layer | the console's tests: a mesh seat, a node seat, an assignment, an interchangeable module, each called by address over a real bus |
|
||||
| A non-interchangeable module without a machine is refused, naming its machines | the same tests |
|
||||
| A tool that arrives after the session started is found | a test registering a module after the console's first answer and finding it by `mesh_search` |
|
||||
| Live | from a fresh session, *which databases does novox's postgres hold* is answered by novox's postgres, found through the five |
|
||||
|
||||
## References
|
||||
|
||||
- [ADR 0152](0152-the-operators-surface-is-a-module-the-console.md),
|
||||
[ADR 0159](0159-a-tool-call-names-the-machine-and-a-holder-serves-its-seats-verbs.md),
|
||||
[ADR 0160](0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md)
|
||||
- Research [021](../01-RESEARCH/021-finding-a-tool-in-the-mesh/00-overview.md)
|
||||
- [to-be 34](../03-DESIGN/01-to-be/34-the-console.md)
|
||||
@@ -293,6 +293,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0188** — [A module's own code is bundles in any language, and a tools bundle speaks MCP to the runtime](0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md)
|
||||
- **0192** — [A tools bundle declares what it is given, and the runtime hands it to that bundle alone](0192-a-tools-bundle-declares-what-it-is-given-and-the-runtime-hands-it-to-that-bundle-alone.md)
|
||||
- **0193** — [Every bundle the runtime serves is launched, and the runtime knows no language](0193-every-bundle-the-runtime-serves-is-launched-and-the-runtime-knows-no-language.md)
|
||||
- **0195** — [The mesh's tools are found by address, not announced whole](0195-the-meshs-tools-are-found-by-address-not-announced-whole.md)
|
||||
|
||||
### How it is built
|
||||
|
||||
|
||||
Reference in New Issue
Block a user