The work order's group-3 question answered: an ordinary module the mesh assigns to the machine a person sits at, holding a minted credential, calling tools under a manifest grant (invokes), serving MCP on loopback. Design 34; pointers in 33, 25 and 0095; module check designed into 12 (issue 148); README stops claiming an indexing nothing provides (issue 006).
117 lines
7.2 KiB
Markdown
117 lines
7.2 KiB
Markdown
---
|
|
layer: to-be
|
|
status: in-progress
|
|
code: [mesh-catalog, mesh-tools, mesh-controller]
|
|
updated: 2026-09-30
|
|
decisions:
|
|
- 02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md
|
|
- 02-DECISIONS/0132-a-seat-carries-the-tools-its-holder-must-serve.md
|
|
- 02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md
|
|
- 02-DECISIONS/0035-one-implementation-several-surfaces.md
|
|
- 02-DECISIONS/0034-the-local-account-owns-the-mesh.md
|
|
---
|
|
|
|
# 34 — The console
|
|
|
|
**The mesh's tools, on the machine a person sits at, served by a module the mesh assigned there.**
|
|
An agent reaches them over MCP on the machine's loopback; a person reaches the same endpoint. Nothing is
|
|
installed by hand, nothing is configured with an address, and the mesh knows the surface exists because
|
|
it put it there ([ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md)).
|
|
|
|
## 1. What it is
|
|
|
|
A module, `mesh-console`, in the catalogue. Its image is the tool runtime's own — the client that
|
|
already speaks the bus as a command line and as an MCP server — started in a mode that reads the
|
|
module's credential and listens on loopback. It has no state, no provision, no seat. What it needs is
|
|
the bus, which it gets the way every module does: a credential the mesh minted for `<node>.mesh-console`,
|
|
sealed to the machine, delivered as the module's own secret.
|
|
|
|
Its manifest says three things nothing else in the catalogue says together:
|
|
|
|
- `invokes: ["*"]` — it calls every tool on the mesh, and the bus grants exactly that publish side;
|
|
- `listens` on a port `from: machine` — the filter opens nothing for it, because loopback is not outside;
|
|
- no `emits`, no `consumes`, no `tools` — it answers nothing on the bus and nobody can address it there.
|
|
|
|
## 2. What it serves, and to whom
|
|
|
|
**One endpoint, `POST /mcp` on the machine's loopback**, speaking MCP over HTTP: `initialize`,
|
|
`tools/list`, `tools/call`. An agent on the machine is pointed at it once — the address is the machine's
|
|
own and never changes — and sees every tool the mesh can say it has. A person at a terminal uses the
|
|
same endpoint through the `mesh` client, or through anything that can make an HTTP request; the client
|
|
needs no credential, because the console holds it.
|
|
|
|
**The endpoint is the machine's login.** It binds `127.0.0.1` and nothing else. Whoever can connect is
|
|
on the machine, and whoever is on the machine is the account that owns the mesh there
|
|
([ADR 0034](../../02-DECISIONS/0034-the-local-account-owns-the-mesh.md),
|
|
[ADR 0144](../../02-DECISIONS/0144-anything-on-a-machine-may-call-anything-on-it.md)). There is no
|
|
token, no login page and no second identity, on purpose: a credential a person had to carry to reach
|
|
their own machine's console would be the arrangement this replaces, moved one hop.
|
|
|
|
## 3. How it knows what the mesh can do
|
|
|
|
Design [33](33-the-tools-the-mesh-answers.md) §5 splits discovery in two: a role's tools are read from
|
|
the mesh's records, a module's own are asked of the module. The console builds the second half now and
|
|
reads the first when it exists.
|
|
|
|
**Every tool runtime answers `tools`.** The runtime that serves a module's tools also serves one verb of
|
|
its own under that module's name, `mesh.mod.<module>.tool.tools`, answering the module's tool names,
|
|
descriptions and argument schemas — the definitions from the code that answers them, and from nowhere
|
|
else. A module may not name a tool of its own `tools`; the runtime refuses the collision at load.
|
|
|
|
**The console asks the catalogue which modules the mesh holds, then asks each.** `catalog_modules`
|
|
answers the roster; one `tools` request per module, in parallel, answers the list. The bus refuses at
|
|
once a request nothing serves, so a module that is not running costs nothing and is named in the answer
|
|
as not answering, rather than silently absent — *silence and success must never look alike*. The list is
|
|
kept for a short while and refreshed, so an agent asking on every turn does not fan out on every turn.
|
|
|
|
**A tool that was not listed can still be called.** Listing is discovery; calling is the grant. An agent
|
|
that knows a tool's name asks for it by `<module>.<tool>` and the module answers or the bus says why not.
|
|
|
|
**What is missing from the list, and until when.** A role's tools and the mesh's own verbs — `status`,
|
|
`push`, `assign` — are the `mesh-controller` seat's under ADR 0132 and are not served yet; their three
|
|
prerequisites are listed in that record. When the seat serves them, the console lists them beside the
|
|
modules' own, and the person stops opening a shell for the mesh's own questions. Until then the console
|
|
says so in its handshake.
|
|
|
|
## 4. Where it runs
|
|
|
|
On whichever machines an operator sits at, by assignment. It is not on the control node by default and
|
|
does not need to be: it reaches the bus like any module, from anywhere in the mesh. A machine that is
|
|
not a node cannot have it, which is the right refusal — the mesh reaches what it declares, and a
|
|
workstation that wants the console joins first.
|
|
|
|
The person's credential and the `mesh` client (design [25](25-the-bus-on-nats.md) §7) remain the path
|
|
for a machine that is not a node, and the path to a mesh not yet far enough along to assign anything.
|
|
|
|
## 5. Removing it
|
|
|
|
Unassigning the console from a machine revokes its bus account at the next composition and stops the
|
|
container; nothing is left on the machine that could still connect. An agent pointed at the loopback
|
|
address gets a refused connection, which is the truthful answer.
|
|
|
|
## How it is checked
|
|
|
|
| Check | Defends |
|
|
|---|---|
|
|
| a module invoking one tool may publish that subject and no other tool's; `*` may publish every one; neither may publish an event or subscribe what it did not consume | ADR 0152, the grant |
|
|
| a module registering two tools answers three names to `tools`, with schemas; a module naming its own `tools` is refused at load | ADR 0152, discovery |
|
|
| against a real bus: two modules up, a third held and not running — the console lists the two and names the third as not answering | ADR 0152, silence is not success |
|
|
| a call through the console's endpoint reaches a module over the bus and the answer is the module's own, unshaped | ADR 0035, a surface decides nothing |
|
|
| on the live mesh: the console assigned to a workstation answers `tools/list` on loopback and a call to the forge returns repositories | the exit of work-order step 3 |
|
|
| the composed filter for a machine carrying the console opens no port for it | ADR 0144 |
|
|
|
|
## What this does not settle
|
|
|
|
- Narrowing a console's grant per assignment. ADR 0046 makes it a setting; nothing reads one yet.
|
|
- The mesh's own verbs on the bus. Design 33's third family; this document only says where they appear
|
|
once they exist.
|
|
- A person's identity behind the console. The mesh sees the console's account; design 15 keeps the
|
|
question open.
|
|
|
|
## References
|
|
|
|
- [ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md) — the decision
|
|
- [33 — The tools the mesh answers](33-the-tools-the-mesh-answers.md) — what the console lists
|
|
- [25 — The bus on NATS](25-the-bus-on-nats.md) §7 — the person's client this makes a module of
|
|
- [issue 147](../../04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md) — the symptom
|