55 lines
3.8 KiB
Markdown
55 lines
3.8 KiB
Markdown
---
|
|
id: fleet/register-ssh-servers-for-terminal-and-agent-awareness
|
|
title: 'Let a systems admin register SSH-reachable servers, for the terminal and for agent awareness'
|
|
theme: fleet
|
|
status: open
|
|
created: 2026-08-25
|
|
date_source: stated
|
|
order: 6
|
|
---
|
|
|
|
**Give a systems admin a way to register SSH-reachable servers.** Wanted 2026-08-25. Two consumers of
|
|
one registry: the **terminal** can SSH into a registered machine directly, and **every agent session**
|
|
is told which servers exist and how to reach each one, so a mid-conversation request naming a server
|
|
("check disk on alpha") doesn't need the agent to guess an address or be taught one by hand — which is
|
|
exactly what this session has been doing ad hoc all week.
|
|
|
|
**Nothing like this exists today — it is entirely informal.** `docs/servers.md` (written 2026-08-21) is
|
|
the closest thing, and it is a hand-maintained markdown file I built by SSHing around and writing down
|
|
what I found — not a registry, not admin-editable, not something an agent's preamble reads, and its own
|
|
opening line says why access works at all: "no `~/.ssh/config`, no passwords" — every machine is
|
|
reachable purely because the owner's key is already trusted there via Tailscale MagicDNS names. There is
|
|
no naming layer between "a machine on the tailnet" and "something Officer knows about."
|
|
|
|
**This is the mechanism two already-filed items assume exists and don't build:**
|
|
`fleet/an-orchestrator-that-acts-on-every-server-at-once` wants to fan out across every server and
|
|
needs a machine-readable list to fan out over — today it reads `docs/servers.md` by hand, which is
|
|
exactly the gap this closes. `fleet/settings-to-choose-which-server-each-feature` wants to route one
|
|
feature (ReClip) to one server by name — the same registry is the thing a dropdown there would be
|
|
populated from. Build this once and both get a real backing store instead of a markdown file and a
|
|
hard-coded env var respectively.
|
|
|
|
**Two things to settle deliberately rather than default into, both real product decisions:**
|
|
|
|
- **Metadata only, or credentials too?** Every server this session reached was already trusted via the
|
|
owner's existing SSH key — nothing here needed a password or a stored secret. The cheap, low-risk
|
|
version of this registry is pure naming: host, tailnet address, login user, a label — an alias table
|
|
over trust that already exists. The moment it needs to hold a private key or a password for a NEW
|
|
identity, it becomes a secret-store problem (`todo/settings/`'s credential question applies
|
|
identically) and should be scoped that way explicitly rather than discovered halfway through building
|
|
the UI.
|
|
- **Who is "a systems admin" here, permission-wise, and it changes what "the terminal can SSH in"
|
|
means.** `terminal` is registered as `kind: 'confined'`
|
|
(`permissions/registry.ts:275`) — grantable, but only meaningful for an account with its own Linux
|
|
user (`authorize.ts` drops a confined grant otherwise). So if this is meant for an `Admin` role
|
|
member rather than only the owner, that account's terminal runs as **their own** OS user, not the
|
|
owner's — and the owner's existing "every host already trusts my key" story does NOT extend to them
|
|
for free. A granted admin registering a server they cannot yet actually SSH into (their own key isn't
|
|
on that box) is the failure mode to design against, not discover afterward.
|
|
|
|
**The agent-awareness half is an affordance**, same delivery mechanism as gitea/image-rendering
|
|
(`capabilities/affordances/`, loaded per turn, no restart): the registry's contents rendered as a short
|
|
block naming each server and how to reach it, so a chat session already knows rather than needing the
|
|
owner to paste an address mid-conversation — which is the exact tax this session has been paying
|
|
manually every time a fleet question came up.
|