claude-code: point the agent at the mesh's tools and guard its shell against ssh to the mesh (hq ADR 0245)

The agent kept running ssh <machine> journalctl while the journal verb existed. The managed
instructions now carry an "instead of" table generated from what each verb says it replaces, and
the plugin carries a PreToolUse guard that refuses ssh to a mesh machine and local work-arounds for a
mesh name, naming the tool or saying one must be created. The operator's override is read from the
session's start environment and recorded.
This commit is contained in:
jochen
2026-10-07 20:27:31 +02:00
parent ba6058abb9
commit 24a3fac2ba
13 changed files with 2033 additions and 14 deletions
@@ -0,0 +1,103 @@
package main
// The "instead of" table in the agent's managed instructions (novox/hq ADR 0244): to do this, call that
// address, not this shell command — generated on every render from what each seat verb and module tool
// says it replaces, so it cannot drift from the tools the mesh has.
//
// Short: a row per seat or module, its top what this machine's agent reached round most — the tools the
// guard named most often in its record.
import (
"fmt"
"sort"
"strings"
)
// InsteadOfRows is how many rows — seats and modules — the table holds; the rest are one search away.
const InsteadOfRows = 16
// insteadOrder is the order rows are taken in: a machine's seat, a module on a machine, the mesh's seat.
func insteadOrder(r Replacement) int {
switch {
case r.Seat && r.NodeScoped:
return 0
case !r.Seat:
return 1
}
return 2
}
func code(s string) string { return "`" + strings.ReplaceAll(s, "`", "'") + "`" }
// insteadGroup is one row: a seat or a module, and its verbs that replace a command.
type insteadGroup struct {
prefix string // `<node>/node-service-manager.` or `mesh-controller.`
verbs []Replacement
refused int
}
// InsteadOf is the section, or "" when the mesh said nothing replaces anything — an older controller,
// or one not yet asked.
//
// One row per seat or module, every verb of it that replaces a command in the row, so a verb is never cut
// for being late in its seat's list; the rows the guard here named most come first, then the machines'
// seats, the modules' tools and the mesh's own seats in the records' order.
func InsteadOf(m *MeshTools) string {
if m == nil || len(m.Replacements) == 0 {
return ""
}
var groups []*insteadGroup
at := map[string]*insteadGroup{}
for order := 0; order <= 2; order++ {
for _, r := range m.Replacements {
if insteadOrder(r) != order {
continue
}
prefix := r.Address[:strings.LastIndex(r.Address, ".")+1]
if r.NodeScoped {
prefix = "<node>/" + prefix
}
g := at[prefix]
if g == nil {
g = &insteadGroup{prefix: prefix}
at[prefix] = g
groups = append(groups, g)
}
g.verbs = append(g.verbs, r)
g.refused += m.Refused[r.Address]
}
}
sort.SliceStable(groups, func(i, j int) bool { return groups[i].refused > groups[j].refused })
for _, g := range groups {
sort.SliceStable(g.verbs, func(i, j int) bool { return m.Refused[g.verbs[i].Address] > m.Refused[g.verbs[j].Address] })
}
more := 0
if len(groups) > InsteadOfRows {
more = len(groups) - InsteadOfRows
groups = groups[:InsteadOfRows]
}
var b strings.Builder
b.WriteString("\n## Instead of a shell command\n\n")
b.WriteString("Generated from what each seat verb and module tool says it replaces (`replaces`, novox/hq ADR 0244),\n")
b.WriteString("rewritten on every render. Call `<address><verb>` through `mesh_call`, `<node>` being the machine;\n")
b.WriteString("`mesh_search` with the command you would have typed finds it too.\n\n")
b.WriteString("| call | the verb — instead of |\n|---|---|\n")
for _, g := range groups {
var cells []string
for _, r := range g.verbs {
var not []string
for _, c := range r.Replaces {
not = append(not, code(c))
}
cells = append(cells, code(r.Address[strings.LastIndex(r.Address, ".")+1:])+" — "+strings.Join(not, ", "))
}
fmt.Fprintf(&b, "| %s | %s |\n", code(g.prefix), strings.ReplaceAll(strings.Join(cells, " · "), "|", "/"))
}
if more > 0 {
fmt.Fprintf(&b, "\n%d more seats and modules: `mesh_search` with the command finds the tool for it.\n", more)
}
b.WriteString("\n- **Never `ssh` to a mesh machine**, and never edit `/etc/hosts` or set `HOSTALIASES` for a mesh\n" +
" name: the guard on this session's shell refuses it and names the tool. Where no tool covers what you\n" +
" need, none is worked around: say so, and the tool is created in the module that owns it, on its seat.\n")
return b.String()
}