Improve CLI and daemon lifecycle usability

This commit is contained in:
Eric Wendland 2026-07-18 15:23:20 +02:00
commit f61cb44dad
14 changed files with 1028 additions and 204 deletions

233
docs/user-workflows.md Normal file
View file

@ -0,0 +1,233 @@
# User Workflows
This document describes geth from the operator's point of view. Each workflow
states the intended outcome, the shortest supported command path, the success
signal, and important trust or durability boundaries.
## Choose A Startup Mode
### Try geth without keeping state
User story: as a curious user or test author, I want an isolated daemon without
choosing a directory or cleaning it up afterward.
```sh
geth daemon run --ephemeral
```
The command initializes a temporary home, prints its path and a ready-to-copy
control command, and runs in the foreground. In another terminal:
```sh
geth --home <printed-path> status
geth --home <printed-path> node id
```
Success means `geth status` reports `geth daemon: running`. Ctrl-C performs a
graceful shutdown and removes the temporary home. An abrupt process kill may
leave temporary files for the operating system's normal temp cleanup.
### Keep a persistent background node
User story: as a workstation user, I want geth to start now and at future
logins without learning my platform's service-manager syntax.
```sh
geth daemon install
geth wait daemon
geth status
```
`daemon install` initializes the selected home if needed, installs and enables
a service for the current user, and starts it. It never installs a system
service. Common lifecycle operations are direct:
```sh
geth daemon status
geth daemon stop
geth daemon start
geth daemon uninstall
```
The older `geth daemon service ...` family remains supported for scripts and
advanced options. In particular, `geth daemon service install` installs without
starting unless `--start` is supplied.
### Keep state but run in the foreground
User story: as a developer, I want persistent state and logs attached to my
terminal.
```sh
geth init
geth daemon run
```
Set `RUST_LOG=geth_node=debug` when more daemon diagnostics are useful. Use
`geth --home <dir> ...` to operate an isolated home without exporting an
environment variable.
## Establish An Owner Trust Root
User story: as the mesh owner, I want my first node rooted in an existing SSH
or hardware-backed OpenSSH admin key without copying that private key into
geth.
```sh
geth init \
--admin-key ~/.ssh/id_ed25519_sk.pub \
--signing-key ~/.ssh/id_ed25519_sk \
--owner eric \
--node-name owner-laptop
geth daemon install
geth keychain status
geth node list
```
The public key becomes an admin trust anchor. The private key or FIDO/YubiKey
stub is passed to `ssh-keygen -Y sign`; geth does not copy it into local state.
Success means `keychain status` reports accepted signed operations and `node
list` includes the named owner node.
## Enroll A Second Node
User story: as the owner, I want to approve a new device without treating
discovery or a peer card as proof of trust.
1. Export and transfer the owner's signed peer card:
```sh
geth peer export --out owner.peer.json
```
2. On the new node, initialize, import the card, and submit a request:
```sh
geth init
geth daemon install
geth peer import owner.peer.json
geth node enroll request --node-name workstation --out workstation.enroll.json
geth node enroll submit owner-laptop --path workstation.enroll.json
```
3. On the owner node, review and approve with the admin key:
```sh
geth node enroll list --status pending
geth node enroll approve <request-id> --signing-key ~/.ssh/id_ed25519_sk
```
4. On the new node, pull and inspect the approved state:
```sh
geth sync now owner-laptop
geth wait sync owner-laptop
geth node list
```
Peer-card import only supplies signed endpoint metadata. The owner-signed
keychain and authorization operations are what create trust and capabilities.
## Move A Blob Between Nodes
User story: as a mesh user, I want to address content by hash and let an
authorized node fetch it over Iroh.
On the provider:
```sh
geth cas add ./archive.tar
geth node grant workstation resource:cas:local cas.fetch \
--signing-key ~/.ssh/id_ed25519_sk
```
On the consumer, after peer cards and grants have synchronized:
```sh
geth cas fetch owner-laptop <blob-hash>
geth cas providers <blob-hash>
geth cas get <blob-hash> --out ./archive.tar
```
Success means the fetch reports the provider, `cas providers` records it, and
the output hashes to the requested CAS hash. Remote fetch is Iroh-only and is
checked against `cas.fetch` on `resource:cas:local`.
## Synchronize Application State
User story: as a script author, I want small durable state primitives without
building transport, peer authentication, and retry handling myself.
Start locally with one of:
```sh
geth kv create preferences
geth kv set preferences theme dark
geth document create settings
geth document set settings '{"theme":"dark"}'
geth db add inventory ./inventory.sqlite
geth cas root add notes ./notes
geth cas root scan notes
```
Grant the matching resource capability to a node, then use the module's `sync`
command or `geth sync now <node>`. Check `geth sync status --json` for
per-peer/per-stream cursors and retry state. File-root application is
conservative: it does not overwrite local edits, and ambiguous changes become
durable conflicts for `geth cas conflict list`.
## Automate Reliably
User story: as an automation author, I want explicit homes, readiness checks,
machine-readable output, and stable errors.
```sh
geth --home "$job_home" init
geth --home "$job_home" daemon run >"$job_home/daemon.log" 2>&1 &
daemon_pid=$!
geth --home "$job_home" wait daemon --timeout-ms 30000 --json
geth --home "$job_home" status --json
```
Use `--json` for single responses and `--jsonl` for streaming responses. A
missing daemon returns the stable error code `daemon_unavailable` plus a startup
hint. See `automation-examples.md` and `command-stability.md` before depending
on experimental command families.
## Diagnose, Back Up, And Recover
User story: as an operator, I want actionable local diagnostics and a backup
that does not accidentally collect private trust anchors.
```sh
geth doctor
geth status
geth sync status
geth backup create --out ./geth-backup
```
`doctor` works even when the daemon is unavailable. Backups exclude daemon
runtime files, private geth identity keys, and external private SSH admin keys.
Restore always targets a separate empty home:
```sh
geth backup restore ./geth-backup --target-home ./restored-geth
geth --home ./restored-geth daemon run
```
## Workflow Verification Coverage
- CLI tests cover help discoverability, `--home` selection, initialization,
daemon control, stable JSON errors, wait behavior, service-definition
generation, and the owner/enrollment/sync path.
- Two-daemon integration tests cover peer-card exchange, authorization denials,
signed log import, CAS/KV/document/DB/file-root sync, pipe/pubsub, and restart
behavior where practical.
- Real user-service managers, hardware keys, real relays, TUN/Wintun privileges,
and the full two-machine experience remain dogfood checks because automated
tests must not mutate host services or require privileged hardware.
The real-machine acceptance checklist is in `dogfood-checklist.md`.