Let claude-code read its tools and machines from the bus, not the controller

The controller is not placed (ADR 0590), so its tools, modules, nodes and
node verbs answer nothing. claude-code now reads the seats' verbs from the
seats' contract, the placed modules' replaces from the indexer's manifests,
and the machines and where modules run from mesh-placement's placement; the
rendered instructions name the seats that own each job (issue 1126 B13).

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 12:29:56 +01:00
parent b44e600e87
commit f723d4372f
8 changed files with 311 additions and 226 deletions
@@ -8,22 +8,26 @@ import (
"strconv"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// meshForTheGuard is a mesh of two machines and the verbs that replace what an agent runs over ssh, as the
// controller's records say them.
// seats' contract and the modules' manifests say them.
func meshForTheGuard() GuardData {
tools := json.RawMessage(`{"seats":[
{"seat":"mesh-controller","scope":"mesh","tools":[{"name":"node","description":"What one machine reported it can do.","replaces":["hostnamectl","uptime"]}]},
{"seat":"node-service-manager","scope":"node","tools":[
{"name":"status","description":"One unit as the service manager sees it now: its states.","replaces":["systemctl status","systemctl is-active"]},
{"name":"restart","description":"Restart one unit.","replaces":["systemctl restart"]},
{"name":"journal","description":"The last lines of one unit's journal.","replaces":["journalctl"]}]},
{"seat":"node-hostname","scope":"node","tools":[
{"name":"add","description":"Add one address and its names to the operator's lines of /etc/hosts.","replaces":["edit /etc/hosts","HOSTALIASES"]}]}]}`)
modules := json.RawMessage(`[{"module":"docker","on":["anchor"],"replaces":{"docker_logs":["docker logs"],"docker_list":["docker ps"]}},
{"module":"systemd","on":["anchor","laptop"]}]`)
return GuardData{Node: "laptop", Replacements: ReplacementsOf(tools, modules), Machines: []Machine{
seats := []catalogue.Seat{
{Name: "mesh-placement", Scope: catalogue.ScopeMesh, Serves: []catalogue.Verb{
{Name: "placement", Description: "Read placement: one node's key.", Replaces: []string{"hostnamectl", "uptime"}}}},
{Name: "node-service-manager", Scope: catalogue.ScopeNode, Serves: []catalogue.Verb{
{Name: "status", Description: "One unit as the service manager sees it now: its states.", Replaces: []string{"systemctl status", "systemctl is-active"}},
{Name: "restart", Description: "Restart one unit.", Replaces: []string{"systemctl restart"}},
{Name: "journal", Description: "The last lines of one unit's journal.", Replaces: []string{"journalctl"}}}},
{Name: "node-hostname", Scope: catalogue.ScopeNode, Serves: []catalogue.Verb{
{Name: "add", Description: "Add one address and its names to the operator's lines of /etc/hosts.", Replaces: []string{"edit /etc/hosts", "HOSTALIASES"}}}},
}
modules := []ModuleTools{{Module: "docker", On: []string{"anchor"}, Replaces: map[string][]string{"docker_logs": {"docker logs"}, "docker_list": {"docker ps"}}},
{Module: "systemd", On: []string{"anchor", "laptop"}}}
return GuardData{Node: "laptop", Replacements: ReplacementsOf(seats, modules), Machines: []Machine{
{Name: "anchor", Domains: []string{"anchor" + InternalSuffix, "anchor.example"}, Addresses: []string{"192.0.2.10", "10.10.0.1"}},
{Name: "laptop", Domains: []string{"laptop" + InternalSuffix}, Addresses: []string{"10.10.0.4"}},
}}
@@ -69,21 +73,21 @@ func bash(command string) HookInput {
func TestSSHToAMeshMachineIsRefusedNamingTheTool(t *testing.T) {
g := guard()
for command, want := range map[string]string{
"ssh anchor journalctl -u mesh-controller -n 50": "anchor/node-service-manager.journal",
"ssh anchor journalctl -u mesh-config -n 50": "anchor/node-service-manager.journal",
"ssh anchor 'sudo journalctl -fu sshd'": "anchor/node-service-manager.journal",
"ssh -p 22 root@anchor.example systemctl status nats": "anchor/node-service-manager.status",
"ssh anchor.internal systemctl restart nats": "anchor/node-service-manager.restart",
"ssh -o StrictHostKeyChecking=no 10.10.0.1 docker ps -a": "anchor/docker.docker_list",
"ssh anchor docker logs --tail 100 nats": "anchor/docker.docker_logs",
"ssh laptop docker logs x": "anchor/docker.docker_logs",
"ssh a uptime": "mesh-controller.node",
"ssh a uptime": "mesh-placement.placement",
"cd /tmp && ssh anchor journalctl": "anchor/node-service-manager.journal",
"sudo -u root ssh anchor journalctl": "anchor/node-service-manager.journal",
"timeout 10 ssh anchor journalctl": "anchor/node-service-manager.journal",
"env LANG=C ssh anchor journalctl": "anchor/node-service-manager.journal",
"bash -c 'ssh anchor journalctl -u x'": "anchor/node-service-manager.journal",
`echo "$(ssh anchor journalctl -n 5)" | tail`: "anchor/node-service-manager.journal",
"for n in anchor laptop; do ssh $n uptime; done; ssh anchor uptime": "mesh-controller.node",
"for n in anchor laptop; do ssh $n uptime; done; ssh anchor uptime": "mesh-placement.placement",
"ssh -J anchor 203.0.113.9 journalctl": "anchor/node-service-manager.journal",
"ssh via-anchor journalctl": "anchor/node-service-manager.journal",
"ssh nas.lan journalctl": "anchor/node-service-manager.journal",