tx9 — CLI design

The vision for the tx9 Go CLI: one installed binary that creates and manages hermes boxes. Twelve decisions locked 2026-07-04; bash prototypes deleted; this replaces the boxd user guide.

The vision

curl -fsSL https://tx9.davis7.sh/install | bash

tx9 create                 # → "large-cat" + getting-started checklist
tx9 list
tx9 enter large-cat        # (alias: ssh)
tx9 backup large-cat --path ~/Downloads     # (alias: export)
tx9 import large-cat-20260704.tx9
tx9 upgrade                # self-update CLI
tx9 upgrade large-cat      # move box onto current image

No repo checkout, no ./docker/boxd, no compose plugin. The binary embeds all build assets (provision script, guest scripts, Dockerfile); the first create on a machine builds the box image locally (~10 min, cached after). The Docker bits live in the boxes; the CLI is just a clean, fast Go tool for managing them.

The 12 decisions

Settled 2026-07-03 → 04
TopicDecision
Image sourceEmbedded assets, local build on first create. No registry (can be added later).
State home~/.tx9/ (token cache, locks, config). Docker labels are the source of truth; backups default to ~/Downloads.
NamingFriendly generated names (large-cat) by default; tx9 create my_box for explicit.
Create UXEnds with a printed numbered checklist: enter, auth claude/codex, hermes setup, dashboard URL.
Aliasesenter/ssh; backup/export.
Passwords--passwordTX9_PASSWORD → hidden prompt. --no-encrypt escape hatch.
Archive.tx9 extension; tar.gz inside, GPG-compatible when encrypted; embeds box-name metadata; import fails on collision, --name overrides.
ScopeLocal-only v1. Cross-machine = backup → transfer → import.
Docker interfaceEngine API via the Go SDK — no compose dependency (it bit us: siva didn't have the plugin), owned progress/error UX.
RepoThis repo; Go code alongside provision/ and guest/, which it embeds at build time. Open-sourced when ready.
DistributionGitHub Releases + tx9.davis7.sh/install redirect; hosted site later.
Versioningtx9 upgrade self-updates; images tagged tx9-box:<cli-version>; list shows per-box drift; prune cleans old images. Bash prototypes deleted.

Command surface

tx9 commands (v1)
CommandBehavior
create [name]Generate name, build image if missing, create network + volumes + agent/executor pair, mint token, wire MCP, doctor, print checklist
listAll boxes from daemon labels: state, image-version drift vs CLI, dashboard URL
enter <box>Agent-container shell, tmux attach; starts if stopped (alias ssh)
start / stop <box>Both containers together; volumes persist
backup <box>--path (default ~/Downloads), password precedence, --no-encrypt; quiesce → archive → validate → verify → .tx9 (alias export)
import <file.tx9>Validate before creating anything; name from metadata, --name override, collision fails; arrives quiesced + gateway-disabled + fresh token
open <box>Authenticated dashboard URL (?_token=)
doctor <box>In-box hb doctor + host port probe
upgrade [box]No args: CLI self-update. With box: recreate containers on current image + readiness gate
delete <box>Containers + volumes + token, typed-name confirmation
pruneUnused image versions + stale state

Contracts carried from the verified prototype

The compose bash draft was dry-run- and QA-verified before deletion; these survive the port as fixed requirements:

  • Topology: free-rein agent container (no published ports, volume = the box) + executor-only container (one 0.0.0.0 token-gated port for dashboard + MCP) + per-box private network. Cross-box DNS isolation verified.
  • Token: 256-bit per box, injected as BOXD_EXECUTOR_TOKEN which outranks any restored on-disk env (real bug found in dry runs); wiring re-checks token and URL freshness.
  • Archive safety: member-by-member validation (traversal, links, cycles, duplicates, special files) before anything is created on import; stage-then-promote restores; quiesce + gateway-disabled arrival.
  • Single-writer gateway: restores never auto-enable Hermes; hb gateway-enable --confirm-single-writer … stays the only path.
  • Gotchas: disable IPv6 in containers (executor binds localhost → ::1 otherwise); boot-window retry before executor health checks.

Saved for later (explicitly out of v1)

  • Remote/multi-hosttx9 --host nexus list, tx9 move large-cat nexus as one command. Worth it in the future; v1 keeps the Docker interface behind a small Go interface so a remote daemon slots in cleanly.
  • Hosted docs site at tx9.davis7.sh beyond the install redirect.
  • Registry-published images if local build time annoys.
  • Healthchecks, token rotation, slim executor image, executor egress policy, executor-state backup (currently scratch by contract).

Where things stand

Deleted
./box (smolvm), ./docker/boxd + compose.yaml, smolvm tests/fixtures, smolvm-era systemd units — commit 9a030e2
Kept
guest/ (hb, hb-workload, hermes-state), provision/, docker build assets — the box internals tx9 embeds
Spec
docs/tx9-cli-design.md in the repo (all decisions + Go implementation notes)
CI
make check green on the surviving surface
Next session
Scaffold the Go CLI: cli/ module, embed pipeline, create + list first
Experiment status

This is a shape-finding experiment. The runtime architecture underneath (agent/executor split) is verified and stable; the CLI surface above is the current best guess and expected to evolve with use.