A thought experiment inspired and motivated by the concepts of permacomputing, community resilience, and library/gift economies.
Vesta is a federated compute daemon for small, trusted networks of personal
machines. Run vestad on two or more machines and they form a shared resource
pool. CPU-bound and memory-bound workloads route automatically to whichever
node has the most spare capacity. When a node is saturated, work spills to
peers. Large jobs split across multiple nodes and run in parallel.
No container runtime, no root, no cloud account. Three static binaries.
desktop pi4
vestad (8 cores) <-- LAN --> vestad (4 cores)
| |
vesta submit cpu 500 auto-splits across both
Does: route self-contained batch jobs (hashing, memory allocation, shell
commands) to the node with the most spare capacity. When you submit a job, the
daemon measures real /proc/stat CPU load and /proc/meminfo availability
across all peers and places the work accordingly. If the best node is
overwhelmed mid-job, a future submission goes elsewhere; no manual targeting.
Does not: transparently share CPU or RAM between running processes. A
compile running in your shell stays on your machine. Only workloads explicitly
submitted through vesta participate in the pool.
| Binary | Purpose |
|---|---|
vestad |
Daemon: one per machine. Discovers peers, runs jobs, serves the control socket. |
vesta |
CLI: submit jobs, query status, stress-test routing. |
vestatop |
Live monitor: htop-style view of all nodes, real CPU/RAM bars, active flows. |
piwork |
Example workload: Monte Carlo Pi estimator, demonstrates real federated compute. |
# desktop:
./vestad -name desk -key "your-shared-secret-here"
# Pi (over SSH):
./vestad -name pi4 -key "your-shared-secret-here"Defaults: TCP 7777 (peer protocol), UDP 7778 (discovery). Nodes on the same subnet find each other automatically within about 5 seconds.
For cross-subnet or VPN peers, add -seed <other-ip>:7778 on each side.
./vesta peersBoth nodes should appear within a few seconds. If not: same -key? Same
subnet? Check that UDP 7778 is not blocked by a firewall.
./vesta cpu 200 # 200M SHA-256 iterations, routed automatically
./vesta mem 512 5000 # hold 512 MiB for 5 seconds, routed automaticallyThe daemon checks live CPU load and picks the best node. If the local machine is loaded, the job goes to a peer. If two or more nodes are viable and the job is large enough, it splits across them in parallel.
./vestatopYou can see the CPU bars on the receiving node jump when a job arrives, and active flows show which node is lending to which.
# Submit 500M iterations to the whole federation
./vesta cpu 500
# Stress the local machine first so the job spills to a peer
./vesta stress 0 30 # pin all cores for 30 seconds
./vesta cpu 200 # will route to the idle peer
./vesta stop-stress # cancel early if you wantThe piwork binary is a self-contained Monte Carlo Pi estimator that makes
federated routing visible:
./vesta exec -- ./piwork 100The result includes the hostname of the machine that ran it. When the
submitting node is saturated, piwork runs on the peer and the output --
with the peer's hostname; appears in your terminal.
Flags on the command line cover the common case:
vestad -name NAME -key SECRET [-port 7777] [-dport 7778]
[-allow-exec] [-power auto|grid|solar|battery]
[-seed host:port,...] [-advertise-spare MS]
[-config path/to/node.json]For more control, use a JSON config file. See config.example.json for all
fields with explanations.
| Field | Default | Notes |
|---|---|---|
cpu_offer_pct |
75 | Percentage of cores offered for lending |
mem_offer_mb |
1024 | Hard cap on RAM offered in MiB |
reserve_pct |
20 | Kept for local use, never lended |
spill_cpu_pct |
80 | CPU% at which jobs spill to peers |
allow_exec |
false | Permit peers to run shell commands |
exec_allowlist |
[] | If non-empty, only these commands are allowed |
max_borrow_ratio |
5 | Leeching cap: max borrow without contributing |
battery_min_pct |
15 | Stop lending below this battery charge |
Each node tracks what it has lended and borrowed per peer (see vestad-ledger-*.json).
New peers start with a goodwill floor and can borrow freely up to
max_borrow_ratio * goodwill without contributing anything. Once they have
contributed even a little, they're treated as full participants. Nodes that
never lend are eventually capped.
vesta status and vestatop show each node's ledger balance so you can see
whether the exchange is roughly equal over time.
On battery-powered nodes (laptops, Pi with UPS), vestad reads
/sys/class/power_supply and scales back how much it offers:
- Grid/charging: lends at 100% willingness
- Discharging, charge >= 50%: "solar" mode, lends proportionally to charge
- Discharging, charge < 50%: 35% willingness
- Charge <
battery_min_pct(default 15%): stops lending entirely
Override with -power grid|solar|battery to force a specific mode.
Off by default. To allow peers to run arbitrary commands on your node:
vestad -name mynode -key SECRET -allow-execWith an allowlist (recommended if you enable exec):
{
"allow_exec": true,
"exec_allowlist": ["make", "ffmpeg", "python3"]
}The allowlist matches against both the basename and full path of argv[0],
so listing "make" will permit /usr/bin/make as well as ./make.
Warning: nodes that can reach your vestad with the correct key can run any permitted command. Only enable exec in a federation of machines you fully control and trust.
All inter-node traffic is AES-256-GCM encrypted. The federation key is the membership credential. Anyone with the key can submit jobs to any node, so treat it like a password: long, random, and not reused elsewhere.
What the encryption covers:
- All peer-to-peer job traffic (TCP, AES-256-GCM)
- All discovery beacons (UDP, AES-256-GCM)
What it does not cover:
- The lender can see the contents of any job it runs. For a network of your own machines this is expected. For untrusted federations, hardware TEE support (AMD SEV-SNP, Intel TDX) would be required; this is on the roadmap.
- The control socket (
/tmp/vestad-NAME.sock) is restricted to the owner (mode 0600) but trusts any local process running as the same user.
Node identity files (vestad-identity-*.json) are written with mode 0600.
cargo build --release -p vestad -p vesta -p vestatop -p piworkrustup target add aarch64-unknown-linux-gnu
cargo install cargo-zigbuild
sudo dnf install zig # Fedora/RHEL
# or: sudo apt install zig
cargo zigbuild --release --target aarch64-unknown-linux-gnu \
-p vestad -p vesta -p vestatop -p piworkBinaries land in target/aarch64-unknown-linux-gnu/release/. Run ./build.sh
to build all targets (amd64, arm64, armv7) at once.
src/
lib.rs crate root and re-exports
proto.rs wire protocol types (Budget, NodeStatus, Job, JobResult, Msg)
crypto.rs AES-256-GCM cipher derived from the federation key
wire.rs length-prefixed sealed TCP framing
identity.rs Ed25519 keypair and node fingerprint
config.rs Config struct, JSON loading, name sanitization
sysstat.rs Linux /proc and /sys readers (CPU, memory, power, GPU, thermals)
ledger.rs per-peer reciprocity accounting, persistence
peertable.rs in-memory peer discovery table
discovery.rs UDP beacon broadcast and listener
executor.rs job runner (cpu, mem, gpu, exec)
autopilot.rs routing logic and distributed job splitting
daemon.rs daemon core, TCP/Unix accept loops, job dispatch
control.rs CLI-side Unix socket client
vestad/ daemon binary entry point
vesta/ control CLI
vestatop/ live terminal monitor
piwork/ example federated workload (Monte Carlo Pi)
This project is released as-is. I will look at pull requests occasionally and may merge ones that are clearly correct and self-contained, but I have little interest in maintaining this long term.
If you want to take it further, please fork it. The codebase is small and self-contained by design, so a fork is easy to own. It also makes a reasonable exercise if you want to learn Rust systems programming, distributed protocols, or federated network design.
GNU Affero General Public License v3.0 or later. See LICENSE.
The AGPL requires that if you run a modified version of this software on a server and allow others to interact with it over a network, you must make the corresponding source code available to those users.