2026-05-15 15:08:20 +02:00
|
|
|
# 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:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
geth init
|
|
|
|
|
geth daemon run
|
2026-05-16 00:17:08 +02:00
|
|
|
geth daemon service install
|
2026-05-15 15:08:20 +02:00
|
|
|
geth status
|
|
|
|
|
geth node id
|
|
|
|
|
geth resource list
|
|
|
|
|
geth cas add ./file
|
|
|
|
|
```
|
|
|
|
|
|
2026-05-16 03:17:45 +02:00
|
|
|
The daemon owns local identity, the Iroh endpoint, trust state, resource
|
2026-05-15 15:08:20 +02:00
|
|
|
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`.
|
|
|
|
|
|
2026-05-16 00:17:08 +02:00
|
|
|
The daemon can also install itself as a user service:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
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.
|
|
|
|
|
|
2026-05-15 15:08:20 +02:00
|
|
|
## 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.
|
2026-05-16 03:17:45 +02:00
|
|
|
The default node config uses Iroh's default relay policy for practical
|
|
|
|
|
connectivity; set `[iroh].relay_mode = "disabled"` for local-only/offline
|
2026-05-16 14:28:38 +02:00
|
|
|
development. Named custom relay maps can be selected with
|
2026-05-16 14:33:45 +02:00
|
|
|
`relay_mode = "custom"` and `relay_map = "<name>"`. Iroh local-network
|
|
|
|
|
discovery is enabled by default with `[iroh].local_discovery = true`.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
|
|
|
|
SSH keys are used as admin trust anchors and ecosystem integration points.
|
|
|
|
|
OpenSSH, FIDO, and YubiKey-backed keys can sign geth trust objects through
|
2026-05-16 14:37:16 +02:00
|
|
|
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.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
2026-05-16 00:17:08 +02:00
|
|
|
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
|
2026-05-17 18:29:47 +02:00
|
|
|
key revocation entries are tracked locally and can be exported as JSONL or as an
|
2026-05-18 11:51:12 +02:00
|
|
|
OpenSSH KRL specification file or a binary OpenSSH KRL generated through
|
2026-05-18 17:24:10 +02:00
|
|
|
`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.
|
2026-05-16 00:17:08 +02:00
|
|
|
|
2026-05-15 15:08:20 +02:00
|
|
|
## MVP Features
|
|
|
|
|
|
|
|
|
|
The bootstrap implementation provides:
|
|
|
|
|
|
|
|
|
|
- `geth init`
|
|
|
|
|
- `geth daemon run`
|
2026-05-16 00:17:08 +02:00
|
|
|
- `geth daemon service install|uninstall|start|stop|status|print`
|
2026-05-15 15:08:20 +02:00
|
|
|
- `geth status`
|
|
|
|
|
- `geth node id`
|
2026-05-18 04:03:52 +02:00
|
|
|
- `geth peer export [--out <path>]`
|
|
|
|
|
- `geth peer import <path>`
|
|
|
|
|
- `geth peer list`
|
2026-05-18 12:09:50 +02:00
|
|
|
- `geth peer ping <node-id>`
|
2026-05-18 17:01:50 +02:00
|
|
|
- `geth peer auth-check <node-id> <resource> <capability>`
|
2026-05-15 15:08:20 +02:00
|
|
|
- `geth resource list`
|
|
|
|
|
- `geth resource create <kind> <name>`
|
2026-05-16 16:34:20 +02:00
|
|
|
- `geth keychain init [--admin-key <path>]`
|
2026-05-15 15:08:20 +02:00
|
|
|
- `geth keychain status`
|
2026-05-16 22:18:49 +02:00
|
|
|
- `geth secret status`
|
|
|
|
|
- `geth secret create <resource>`
|
|
|
|
|
- `geth secret rotate <resource>`
|
2026-05-17 02:58:58 +02:00
|
|
|
- `geth secret bearer create <resource> --capability <capability>`
|
|
|
|
|
- `geth secret bearer list`
|
|
|
|
|
- `geth secret bearer revoke <resource> <secret>`
|
2026-05-15 15:08:20 +02:00
|
|
|
- `geth auth explain <subject> <resource> <capability>`
|
2026-05-16 16:32:03 +02:00
|
|
|
- `geth auth grant <subject> <resource> <capability> [--grant-id <id>]`
|
|
|
|
|
- `geth auth revoke <resource> <grant-id>`
|
2026-05-18 17:18:25 +02:00
|
|
|
- local filesystem CAS commands: `add`, `get`, `fetch`, `hash`, `has`, `pin`,
|
|
|
|
|
`unpin`, `cleanup`, `list`
|
2026-05-17 21:20:24 +02:00
|
|
|
- local CAS tree objects describe file trees and are stored as CAS blobs
|
2026-05-18 03:50:09 +02:00
|
|
|
- local file-root commands: `geth cas root add/list/scan`
|
2026-05-18 03:57:26 +02:00
|
|
|
- local file conflict metadata commands:
|
|
|
|
|
`geth cas conflict record/list/resolve`
|
2026-05-16 21:13:33 +02:00
|
|
|
- local DB resource registration: `geth db add <name> <path>` and
|
2026-05-17 20:22:50 +02:00
|
|
|
`geth db status <name>` with schema and `crsql_changes` metadata; the DB
|
2026-05-17 20:32:36 +02:00
|
|
|
crate and daemon can extract typed local `crsql_changes` batches through
|
|
|
|
|
`geth db changes <name>` for future sync
|
2026-05-18 04:06:41 +02:00
|
|
|
- local SQLite-backed KV commands: `geth kv create/set/get`; `kv set` accepts
|
|
|
|
|
`--subject <principal>` to exercise local capability checks for non-local
|
|
|
|
|
callers
|
2026-05-17 19:59:03 +02:00
|
|
|
- local JSON document commands: `geth document create/status/set/get`
|
2026-05-17 18:23:51 +02:00
|
|
|
- local daemon-lifetime pubsub snapshots: `geth pubsub pub/sub`
|
2026-05-16 00:17:08 +02:00
|
|
|
- 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`
|
2026-05-18 17:24:10 +02:00
|
|
|
- `geth ssh cert sync <node-id>`
|
2026-05-16 00:17:08 +02:00
|
|
|
- `geth ssh revocation add <kind> <target>`
|
|
|
|
|
- `geth ssh revocation list`
|
2026-05-18 11:51:12 +02:00
|
|
|
- `geth ssh revocation export --out <path> [--format jsonl|openssh-krl-spec|openssh-krl]`
|
2026-05-18 11:56:42 +02:00
|
|
|
- `geth ssh revocation import <path> [--format jsonl|openssh-krl-spec]`
|
2026-05-18 17:24:10 +02:00
|
|
|
- `geth ssh revocation sync <node-id>`
|
2026-05-17 20:17:26 +02:00
|
|
|
- local pipe registry commands: `geth pipe listen/connect`
|
2026-05-15 15:08:20 +02:00
|
|
|
|
2026-05-18 12:09:50 +02:00
|
|
|
`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.
|
2026-05-18 17:01:50 +02:00
|
|
|
`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.
|
2026-05-18 17:18:25 +02:00
|
|
|
`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`.
|
2026-05-18 17:24:10 +02:00
|
|
|
`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.
|
2026-05-18 12:09:50 +02:00
|
|
|
Importing or pinging a peer card never grants capabilities by itself.
|
2026-05-18 17:05:43 +02:00
|
|
|
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.
|
2026-05-18 04:03:52 +02:00
|
|
|
|
|
|
|
|
Other command groups exist as explicit stubs: `ssh proxy`.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
|
|
|
|
## 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
|
2026-05-17 20:17:26 +02:00
|
|
|
- `pipe`: dumbpipe-like byte streams over Iroh; the bootstrap has a local
|
|
|
|
|
daemon registry only
|
2026-05-15 15:08:20 +02:00
|
|
|
- `document`: Automerge documents over Iroh streams
|
2026-05-17 18:23:51 +02:00
|
|
|
- `pubsub`: lossy notifications, not authoritative storage; the bootstrap
|
|
|
|
|
keeps only an in-memory daemon-lifetime ring buffer
|
2026-05-15 15:08:20 +02:00
|
|
|
- `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
|
2026-05-17 18:26:30 +02:00
|
|
|
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/`
|
2026-05-18 04:06:41 +02:00
|
|
|
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.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
|
|
|
|
## Local State
|
|
|
|
|
|
|
|
|
|
If `GETH_HOME` is set, geth uses it. Otherwise it uses an OS-specific data
|
|
|
|
|
directory. The bootstrap layout is:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
$GETH_HOME/
|
|
|
|
|
geth.sqlite
|
|
|
|
|
config.toml
|
|
|
|
|
identity/agent.ed25519
|
2026-05-16 03:17:45 +02:00
|
|
|
identity/iroh.ed25519
|
2026-05-15 15:08:20 +02:00
|
|
|
cas/blobs/
|
|
|
|
|
run/geth.sock
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Quick Start
|
|
|
|
|
|
|
|
|
|
In one shell:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
export GETH_HOME="$(mktemp -d)"
|
|
|
|
|
cargo run -p geth -- init
|
|
|
|
|
cargo run -p geth -- daemon run
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In another shell:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
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.
|