geth/README.md

9.8 KiB

geth

geth is a personal, local-first mesh runtime for scripts, devices, databases, documents, blobs, pipes, and future multi-user collaboration.

This project is not the Ethereum geth client. The project and executable are still named geth.

One Binary

There is one executable: geth.

It has daemon mode and control mode:

geth init
geth daemon run
geth daemon service install
geth status
geth node id
geth resource list
geth cas add ./file

The daemon owns local identity, the Iroh endpoint, trust state, resource registry, module router, local metadata store, and synchronized data structures. Most non-daemon commands talk to the daemon through a local Unix socket at $GETH_HOME/run/geth.sock.

The daemon can also install itself as a user service:

geth daemon service install
geth daemon service status
geth daemon service uninstall

The bootstrap service managers are systemd user units on Linux, launchd user agents on macOS, and per-user scheduled tasks on Windows. These are user-level services, not system services.

Transport And SSH

All remote node-to-node geth communication is designed to happen over Iroh only. SSH is not a geth transport backend, and there is no SSH fallback transport. The default node config uses Iroh's default relay policy for practical connectivity; set [iroh].relay_mode = "disabled" for local-only/offline development. Named custom relay maps can be selected with relay_mode = "custom" and relay_map = "<name>". Iroh local-network discovery is enabled by default with [iroh].local_discovery = true.

SSH keys are used as admin trust anchors and ecosystem integration points. OpenSSH, FIDO, and YubiKey-backed keys can sign geth trust objects through canonical geth envelopes with explicit namespaces such as geth.keychain.v1@geth.local. Future SSH proxying may carry SSH protocol bytes over authorized Iroh streams, but the geth transport remains Iroh.

SSH certificate request and renewal flows are managed as geth metadata. A node can create a certificate request, another machine can approve it and receive an explicit ssh-keygen -s ... command suitable for a CA key or YubiKey-backed CA, and the resulting -cert.pub can be imported for distribution. Certificate and key revocation entries are tracked locally and can be exported as JSONL or as an OpenSSH KRL specification file or a binary OpenSSH KRL generated through ssh-keygen -k. geth ssh cert sync <node-id> and geth ssh revocation sync <node-id> pull certificate-flow and revocation metadata from an authorized peer over Iroh.

MVP Features

The bootstrap implementation provides:

  • geth init
  • geth daemon run
  • geth daemon service install|uninstall|start|stop|status|print
  • geth status
  • geth node id
  • geth peer export [--out <path>]
  • geth peer import <path>
  • geth peer list
  • geth peer ping <node-id>
  • geth peer auth-check <node-id> <resource> <capability>
  • geth resource list
  • geth resource create <kind> <name>
  • geth keychain init [--admin-key <path>]
  • geth keychain status
  • geth secret status
  • geth secret create <resource>
  • geth secret rotate <resource>
  • geth secret bearer create <resource> --capability <capability>
  • geth secret bearer list
  • geth secret bearer revoke <resource> <secret>
  • geth auth explain <subject> <resource> <capability>
  • geth auth grant <subject> <resource> <capability> [--grant-id <id>]
  • geth auth revoke <resource> <grant-id>
  • local filesystem CAS commands: add, get, fetch, hash, has, pin, unpin, cleanup, list
  • local CAS tree objects describe file trees and are stored as CAS blobs
  • local file-root commands: geth cas root add/list/scan
  • local file conflict metadata commands: geth cas conflict record/list/resolve
  • local DB resource registration: geth db add <name> <path> and geth db status <name> with schema and crsql_changes metadata; the DB crate and daemon can extract typed local crsql_changes batches through geth db changes <name> for future sync
  • local SQLite-backed KV commands: geth kv create/set/get; kv set accepts --subject <principal> to exercise local capability checks for non-local callers; geth kv sync <node-id> <name> pulls authorized remote updates
  • local JSON document commands: geth document create/status/set/get
  • local daemon-lifetime pubsub snapshots: geth pubsub pub/sub; geth pubsub pub <topic> <message> --node <node-id> publishes to an authorized peer
  • SSH certificate flow metadata:
    • geth ssh cert request --public-key <path> --principal <name>
    • geth ssh cert requests
    • geth ssh cert approve <request-id> --ca-key <path>
    • geth ssh cert import <request-id> --cert <path>
    • geth ssh cert list
    • geth ssh cert sync <node-id>
    • geth ssh revocation add <kind> <target>
    • geth ssh revocation list
    • geth ssh revocation export --out <path> [--format jsonl|openssh-krl-spec|openssh-krl]
    • geth ssh revocation import <path> [--format jsonl|openssh-krl-spec]
    • geth ssh revocation sync <node-id>
  • pipe registry/connect commands: geth pipe listen <name> and geth pipe connect <name> [--node <node-id>]

geth peer export/import/list is for untrusted peer-card exchange. Peer cards include the Iroh EndpointID plus currently known relay/direct addresses. geth peer ping <node-id> uses the local daemon's Iroh endpoint to dial an imported peer card and exchange a signed candidate-only peer-card ping. geth peer auth-check <node-id> <resource> <capability> sends a protected Iroh control request: the remote daemon verifies that the caller's signed peer card binds the actual Iroh EndpointID before reducing resource-local auth ops. geth cas fetch <node-id> <hash> uses the same protected Iroh control path to request a blob from a peer. The remote daemon only returns bytes when the caller has cas.fetch on resource:cas:local, and the caller verifies that the bytes hash to the requested BLAKE3 CAS hash before storing them locally. This is the bootstrap transfer path; future work will move provider/fetch behavior to iroh-blobs. geth ssh cert sync <node-id> requires ssh_cert.sync on resource:ssh:certs at the peer. geth ssh revocation sync <node-id> requires ssh_revocation.sync on resource:ssh:revocations. Both commands merge authorized peer metadata into the local store for offline listing and later approval/signing workflows. While the daemon is running, it also performs a background live-sync tick for known peers every 30 seconds. Live-sync stores per-peer high-water cursors in local metadata so repeated ticks request only newer SSH certificate-flow and revocation records. Named KV stores participate in the same live-sync loop once they exist locally: manual geth kv sync <node-id> <name> and background ticks require kv.read on the remote resource:kv:<name> and import only remote entries that are not older than the local value. Remote pubsub publish uses the protected Iroh control path too. The remote peer requires pubsub.publish on resource:pubsub:<topic> before recording the message in its local daemon-lifetime ring buffer. Pubsub remains lossy and is not durable storage. Remote pipe connect uses the same protected Iroh control path and requires pipe.connect on resource:pipe:<name>. The current prototype records a remote connection attempt and whether a listener exists; byte streaming and forwarding are still future work. Importing or pinging a peer card never grants capabilities by itself. When [iroh].local_discovery = true, the daemon also advertises and discovers signed peer cards on LAN using a geth-specific mDNS TXT payload. That payload is candidate metadata only; all geth node-to-node requests still run over Iroh.

Other command groups exist as explicit stubs: ssh proxy.

Resource Modules

Everything meaningful is modeled as a resource. Planned resource kinds are:

  • db: SQLite/cr-sqlite synchronization
  • kv: Iroh Documents backed key-value stores
  • pipe: dumbpipe-like byte streams over Iroh; the bootstrap has a local daemon registry only
  • document: Automerge documents over Iroh streams
  • pubsub: lossy notifications, not authoritative storage; the bootstrap keeps only an in-memory daemon-lifetime ring buffer
  • cas: content-addressed blob storage and distribution
  • ssh-proxy: authorized SSH proxy/admin access over Iroh

Authorization is resource-scoped and capability-based. Bearer secrets may grant specific resource capabilities but do not create trusted node identity. The auth evaluator supports scoped KV write grants such as kv.write_prefix:apps/foo/ for kv.write_key:apps/foo/config explain checks. geth kv set --subject <principal> enforces those local grants for test callers; the local node/agent still has owner access for local administration.

Local State

If GETH_HOME is set, geth uses it. Otherwise it uses an OS-specific data directory. The bootstrap layout is:

$GETH_HOME/
  geth.sqlite
  config.toml
  identity/agent.ed25519
  identity/iroh.ed25519
  cas/blobs/
  run/geth.sock

Quick Start

In one shell:

export GETH_HOME="$(mktemp -d)"
cargo run -p geth -- init
cargo run -p geth -- daemon run

In another shell:

export GETH_HOME="<same dir>"
cargo run -p geth -- status
cargo run -p geth -- node id
echo "hello geth" > /tmp/hello-geth.txt
cargo run -p geth -- cas add /tmp/hello-geth.txt
cargo run -p geth -- cas list

Authorization Direction

The MVP defines the split between:

  • keychain: SSH-rooted users, devices, nodes, agents, and endpoint bindings
  • auth: resource-local signed authorization operations and capability grants
  • secrets: resource master secrets, epochs, envelopes, and bearer access

The current code does not implement Keyhive, BeeKEM, strong forward secrecy, or post-compromise security. It leaves room for future local-first, replicated auth logs and BeeKEM/CGKA-style group key evolution.