Improve CLI and daemon lifecycle usability
This commit is contained in:
parent
afec7063db
commit
f61cb44dad
14 changed files with 1028 additions and 204 deletions
|
|
@ -6,8 +6,15 @@ Accepted.
|
|||
|
||||
## Decision
|
||||
|
||||
Geth provides `geth daemon service ...` commands to install, uninstall, start,
|
||||
stop, inspect, and print daemon service definitions.
|
||||
Geth provides direct `geth daemon install|start|stop|status|uninstall` commands
|
||||
for the common lifecycle. `daemon install` initializes the selected geth home,
|
||||
installs and enables the user service, and starts it immediately. The existing
|
||||
`geth daemon service ...` commands remain available for compatibility, explicit
|
||||
manager selection, definition previews, and install-without-start behavior.
|
||||
Status probes return a normalized state. An inactive or missing service is a
|
||||
successful inspection result, while a service-manager access problem is
|
||||
reported as `unknown` with the manager's diagnostic rather than mislabeled as a
|
||||
stopped daemon.
|
||||
|
||||
The service is always installed as a user service:
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ accept and live-sync tasks, releases native docs/gossip/blob handles, calls
|
|||
`Endpoint::close().await`, and removes the local control socket. The same
|
||||
cleanup path runs when the serving loop returns an error, preventing stale
|
||||
socket files and unclosed endpoint clones from becoming restart behavior.
|
||||
Foreground daemons handle Ctrl-C, and Unix daemons also handle the SIGTERM used
|
||||
by user service managers, through this same graceful shutdown path.
|
||||
|
||||
The local metadata store is SQLite product state. `geth-store` tracks a numeric
|
||||
`schema_version` in the `meta` table and applies ordered migrations up to the
|
||||
|
|
@ -44,6 +46,14 @@ daemon. The initial backends are systemd user units on Linux, launchd user agent
|
|||
on macOS, and per-user scheduled tasks on Windows. Geth does not install itself
|
||||
as a privileged system service.
|
||||
|
||||
The common service lifecycle is available directly as `geth daemon
|
||||
install|start|stop|status|uninstall`; the nested service commands remain the
|
||||
advanced and compatibility surface. `geth daemon run --ephemeral` creates a
|
||||
temporary home, reports how another CLI process can select it with `--home`, and
|
||||
removes it after a normal foreground shutdown. Ephemeral mode still starts the
|
||||
same daemon-owned Iroh endpoint and local control stack; it is not a second
|
||||
runtime or transport path.
|
||||
|
||||
## Iroh-Only Remote Communication
|
||||
|
||||
Remote geth node-to-node communication is Iroh-only. The daemon will own one
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@ export GETH_HOME="${GETH_HOME:-$HOME/.local/share/geth/geth}"
|
|||
geth init
|
||||
geth daemon run >"$GETH_HOME/daemon.log" 2>&1 &
|
||||
daemon_pid=$!
|
||||
trap 'kill "$daemon_pid" 2>/dev/null || true' EXIT
|
||||
|
||||
geth wait daemon --timeout-ms 30000
|
||||
geth doctor --json
|
||||
geth status --json
|
||||
|
||||
trap 'kill "$daemon_pid" 2>/dev/null || true' EXIT
|
||||
```
|
||||
|
||||
Create a backup into a separate directory and validate that it can restore to a
|
||||
|
|
@ -106,13 +105,17 @@ manager mutation:
|
|||
|
||||
```sh
|
||||
geth daemon service print
|
||||
geth daemon service install --start
|
||||
geth daemon install
|
||||
geth wait daemon --timeout-ms 30000
|
||||
geth daemon service status
|
||||
geth daemon service stop
|
||||
geth daemon service uninstall
|
||||
geth daemon status
|
||||
geth daemon stop
|
||||
geth daemon uninstall
|
||||
```
|
||||
|
||||
For a disposable interactive test, `geth daemon run --ephemeral` creates and
|
||||
prints a temporary home. Other commands can target it explicitly with `geth
|
||||
--home <printed-path> ...`; normal Ctrl-C shutdown removes the state.
|
||||
|
||||
Admin SSH keys remain outside geth state. Automation should pass public admin
|
||||
keys with `--admin-key` and use the matching private key only as an argument to
|
||||
the explicit signing command when an admin operation is intended:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ to stable commands after the first deployment tag.
|
|||
The following command families are intended to be stable automation surfaces:
|
||||
|
||||
- `geth init`
|
||||
- `geth daemon run`
|
||||
- `geth --home <dir> ...`
|
||||
- `geth daemon run [--ephemeral]`
|
||||
- `geth daemon install|start|stop|status|uninstall`
|
||||
- `geth daemon service install|uninstall|start|stop|status|print`
|
||||
- `geth status`
|
||||
- `geth doctor`
|
||||
|
|
|
|||
|
|
@ -49,8 +49,9 @@ On Machine A:
|
|||
|
||||
```sh
|
||||
geth init --admin-key ~/.ssh/id_ed25519.pub --signing-key ~/.ssh/id_ed25519 --node-name owner
|
||||
geth daemon service install --start
|
||||
geth daemon install
|
||||
geth wait daemon --timeout-ms 30000
|
||||
geth daemon status
|
||||
geth status --json
|
||||
geth doctor --json
|
||||
geth peer export --out /tmp/owner.peer.json
|
||||
|
|
@ -191,8 +192,8 @@ On Machine A:
|
|||
|
||||
```sh
|
||||
geth backup create --out /tmp/geth-backup
|
||||
geth daemon service stop
|
||||
geth daemon service start
|
||||
geth daemon stop
|
||||
geth daemon start
|
||||
geth wait daemon --timeout-ms 30000
|
||||
geth doctor --json
|
||||
```
|
||||
|
|
|
|||
|
|
@ -15,6 +15,53 @@ Status markers:
|
|||
For deployment-readiness work that cuts across feature areas, see
|
||||
[`docs/production-readiness-roadmap.md`](production-readiness-roadmap.md).
|
||||
|
||||
## Operator Usability
|
||||
|
||||
- `[x]` Make startup modes and the daemon lifecycle discoverable.
|
||||
Acceptance criteria:
|
||||
- `[x]` Base and nested CLI help explain every command family instead of
|
||||
showing unlabeled command names.
|
||||
- `[x]` `geth daemon install` initializes, installs, enables, and starts a
|
||||
background service for the current user.
|
||||
- `[x]` Common start, stop, status, and uninstall operations do not require
|
||||
the nested compatibility command path.
|
||||
- `[x]` Service status reports running, inactive/not-installed, and unknown
|
||||
manager states without treating every nonzero status probe as an action
|
||||
failure.
|
||||
- `[x]` `geth daemon run --ephemeral` creates disposable state and prints the
|
||||
exact `--home` selector needed by another terminal.
|
||||
- `[x]` Unix user-service shutdown handles SIGTERM through the daemon's
|
||||
graceful Iroh/task/socket cleanup path.
|
||||
- `[x]` Tests cover lifecycle parsing, help discoverability, and explicit
|
||||
home selection without mutating a real user service manager.
|
||||
|
||||
- `[x]` Document task-oriented user stories.
|
||||
Acceptance criteria:
|
||||
- `[x]` Workflows cover disposable evaluation, persistent background use,
|
||||
owner setup, enrollment, CAS transfer, synchronized application state,
|
||||
automation, diagnosis, backup, and recovery.
|
||||
- `[x]` Each workflow identifies its success signal and relevant trust or
|
||||
durability boundary.
|
||||
- `[x]` Documentation distinguishes automated coverage from real-machine,
|
||||
hardware-key, relay, and privileged-interface dogfooding.
|
||||
|
||||
- `[ ]` Add unified service-log inspection.
|
||||
Acceptance criteria:
|
||||
- `[ ]` One CLI command gives the platform-appropriate user-service log view
|
||||
or an exact recovery command on Linux, macOS, and Windows.
|
||||
- `[ ]` Log access remains user-scoped and does not require a system service.
|
||||
- `[ ]` Human and JSON output distinguish unavailable logs, an uninstalled
|
||||
service, and an installed service with no log entries.
|
||||
|
||||
- `[ ]` Publish copy-paste installation entrypoints for release artifacts.
|
||||
Acceptance criteria:
|
||||
- `[ ]` Linux, macOS, and Windows installation instructions verify artifact
|
||||
checksums and put the single `geth` executable on `PATH`.
|
||||
- `[ ]` Installation stays separate from explicit `geth daemon install` so
|
||||
downloading a binary never silently creates trust state or starts a service.
|
||||
- `[ ]` Upgrade and uninstall instructions preserve or explicitly remove the
|
||||
selected geth home.
|
||||
|
||||
## Long-Term Goal: Distributed Homelab Overlay
|
||||
|
||||
Goal: evolve geth into a distributed, fault-tolerant homelab overlay runtime in
|
||||
|
|
|
|||
233
docs/user-workflows.md
Normal file
233
docs/user-workflows.md
Normal 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`.
|
||||
Loading…
Reference in a new issue