// ZWIRE-HOST — UNIVERSAL LOCAL HOST

single static Rust binary (~500 KB) · sysinfo · fs · exec · pty · kv · jobs · bus · peer · 59 commands · two transports, one dispatcher · also a library

Report GitHub
// Color scheme

>_ZWIRE-HOST

One pipe. One binary. The whole machine — reachable from anywhere. zwire-host is a single self-contained Rust binary (~500 KB, no Python, no psutil) that exposes the local machine to any app over one JSON message protocol. It began as the Chrome native-messaging host for zwire's HUD; it is now a universal local endpoint reachable from a browser extension and from tmux, emacs, desktop apps, plugins, shell scripts, and any language — because it also runs as a local-socket daemon speaking newline-delimited JSON, the one protocol every tool already has.

Two transports, one dispatcher

Both transports feed the same capability router (src/session.rs), so every command works over either one. A request may carry an id that is echoed on the matching reply, so a client can multiplex many in-flight requests, streams and terminals over one connection.

Native messaging (default)Chrome / browser extensions — little-endian u32 length + JSON body on stdin/stdout
Local-socket daemon (serve)tmux, emacs, desktop apps, plugins, any language — newline-delimited JSON, one object per line, over a Unix domain socket (macOS/Linux) or a named pipe (Windows)

The socket is created 0600 under a 0700 dir — owner-only, since it exposes exec/fs/pty. Inbound TCP peers are gated by a shared --token; local Unix-socket clients are trusted.

Capabilities

System statssysinfo_once / sysinfo_start / sysinfo_stop — stream cpu · mem · swap · disk · net rate · load · uptime · battery · temp · host · LAN/WAN ip
Filesystemfs_read / fs_write / fs_append / fs_list / fs_walk (recursive crawl) / fs_stat / fs_mkdir / fs_rm; leading ~ accepted
Watch & tailfs_watch streams create/modify/remove events; fs_tail streams appended lines (tail -f, survives rotation); watch_stop / watch_list
Exec & OSexec (run to completion, base64 stdout/stderr), open, clipboard_get / clipboard_set, notify
Background jobsjob_start spawns a job that survives the connection and fires a desktop notification on completion; job_list / job_result / job_poll
Process toolsps (by memory), kill (signal), which (resolve on $PATH)
Pub/sub bussub / unsub / pub — the host as a coordination hub; it publishes on scheme/ui for live theme sync without polling
Host-to-host peeringpeers / peer_connect / remote — a mesh of TCP-peered daemons that federates the bus across machines and runs a request on another host
PTY terminalspty_spawn / pty_write / pty_resize / pty_kill, multiplexed by id
Key/value storekv_set / kv_get / kv_merge / kv_del / kv_keys — a per-app JSON store under ~/.<app>/kv/
Discoveryhello (feature-test caps), hostinfo (os, arch, kernel, hostname, user, cpus, mem, LAN ip)

CLI

zwire-host call is the portable path — one request, one reply, from any tool that can write a line. Add --stream to keep printing frames from a streaming command.

zwire-host serve &                                   # run the socket daemon
zwire-host call '{"cmd":"hostinfo"}'                 # one request, one reply
zwire-host call '{"cmd":"fs_walk","path":"~/src","ext":"rs"}'
echo '{"cmd":"exec","program":"git","args":["status"]}' | zwire-host call
zwire-host call --stream '{"cmd":"sysinfo_start"}'   # keep printing frames

Or talk to the endpoint directly with no client library — e.g. printf '{"cmd":"sysinfo_once"}\n' | nc -U ~/.zwire/host.sock on macOS/Linux.

Library use (embed as a dependency)

The crate is a library too (zwire_host), so sibling hosts (e.g. zpwrchrome-host) can pull it in to crawl and exec without re-implementing anything. Embedders that only need the light capabilities can set default-features = false to drop the heavy sysinfo and portable-pty dependencies.

use zwire_host::api;

// crawl the filesystem
for e in api::walk("~/src", Some("rs")) {
    println!("{}", e.path.display());
}

// run a command, get bytes back
let out = api::exec("git", ["status", "--porcelain"]).unwrap();
println!("exit {:?}: {}", out.code, out.stdout_str());

Or drive the whole dispatcher yourself over any transport with zwire_host::{Peer, Session}, or delegate main to zwire_host::run(std::env::args().skip(1).collect()).

Chrome install

Point a native-messaging host manifest's path at the binary and list the allowed extension origins, then drop it in the browser's NativeMessagingHosts/ directory:

{ "name": "com.zwire.hud", "type": "stdio",
  "path": "/abs/path/to/zwire-host",
  "allowed_origins": ["chrome-extension://<id>/"] }

zwire's scripts/localinstall.sh builds this binary and wires the manifest automatically when packaging the .app.

Build & test

cargo build --release      # -> target/release/zwire-host (~500 KB)
cargo test                 # exercises the protocol over both transports
cargo fmt --all --check
cargo clippy --all-targets -- -D warnings

sysinfo and portable-pty abstract the OS, so the same source builds for macOS · Linux · Windows; CI runs the four polish gates on all three. Battery reporting is macOS-only (via pmset) until a native reader lands for other platforms.

Source layout

src/session.rsthe capability router shared by every transport — per-connection state (PTYs, sysinfo stream, bus/peer links) and the command dispatch
src/transport.rsthe three ways to reach the dispatcher: stdio native messaging, the serve daemon, and the call client
src/proto.rs / src/peer.rsframing + reply plumbing; the peer/mesh link and TCP federation
src/fsops.rs / src/watch.rsfilesystem read/write/crawl; streaming watch + tail observers
src/exec.rs / src/jobs.rs / src/procs.rsrun-to-completion exec; background jobs; ps/kill/which
src/sysmon.rs / src/osops.rsthe sysinfo stream monitor; open/clipboard/notify/hostinfo
src/pty.rs / src/bus.rs / src/store.rsmultiplexed PTY sessions; pub/sub bus; per-app kv store
src/api.rsthe light library surface (walk, exec, …) for embedders with default-features = false

The zwire stack

zwire-host is the local endpoint behind the zwire HUD and its siblings. Browse the rest via the MenkeTechnologiesMeta umbrella repo:

  • zwire — the browser HUD this host was born to feed
  • zpwrchrome — sibling Chrome extension; zpwrchrome-host embeds this crate
  • strykelang — the scripting language across the stack