>_EXECUTIVE SUMMARY
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 the zwire HUD and became a universal local endpoint: it also runs as a local-socket daemon speaking newline-delimited JSON, so browser extensions, tmux, emacs, desktop apps, plugins, shell scripts and any language reach the same capabilities.
Two transports feed one dispatcher (src/session.rs): a native-messaging stdio framing and a local-socket daemon (Unix domain socket on macOS/Linux, named pipe on Windows). Every capability — sysinfo, filesystem crawl/watch/tail, exec, background jobs, process tools, a pub/sub bus that federates across TCP-peered hosts, PTY terminals and a per-app kv store — is reachable over either transport, and the crate is also a zwire_host library so sibling hosts can embed it.
~ARCHITECTURE
One dispatcher, many transports. A per-connection Session holds the connection's PTYs, sysinfo stream and bus/peer links; dropping it tears every one down, so a client disconnect never leaks a shell, a thread, a subscriber or a stale link. Requests carry an optional id echoed on the reply so one connection multiplexes many in-flight requests, streams and terminals.
| Layer | Implementation |
|---|---|
| Native messaging | little-endian u32 length + JSON body on stdin/stdout; the default when the browser launches the binary |
| Local-socket daemon | serve speaks newline-delimited JSON over a Unix domain socket (0600 under a 0700 dir) on macOS/Linux, or a per-user named pipe on Windows (via interprocess) |
| Dispatcher | Session::handle routes one decoded request to the capability modules and either replies (RPC) or sets up a background stream; both transports drive it identically |
| Streams | sysinfo, fs_watch, fs_tail, PTY output and bus pub frames are pushed asynchronously, keyed by the request id |
| Peering | TCP-peered daemons federate the bus single-hop (star and full-mesh without loops); inbound TCP is gated by a shared --token, local Unix clients are trusted |
| Library | the crate is zwire_host too; default-features = false drops sysinfo + portable-pty for embedders that only need fs/exec/kv/bus/jobs/watch |
&COMMAND SURFACE
66 host commands, all reachable over both transports — the surface SURFACE_VERBS advertises on App::open("zwire")->verbs(), alongside the 100 browser.* verbs the Chromium HUD executes. The hello reply advertises which capability tags were compiled in so a client can feature-test.
Every verb declares a reversibility class, published as rev: inverse (a compensation exists), pure (reads only — runs but is not journaled), or irreversible (the default). While a transaction is open every reversible call is journaled; txn_abort compensates the journal in reverse order and fires the txn-aborted hook event, and calling an irreversible verb is refused at call time with verb not reversible: <id> so a chain fails fast instead of stranding itself half-undone. Compensation for browser.* verbs is replayed by the HUD service worker, which captured each step's pre-state; the host contributes the order.
The bus is scriptable everywhere and transactional only where a compensation genuinely exists — most of the surface is irreversible, deliberately. No host command is ever inverse: the journal records a step's verb and args, never its pre-state, so fs_write, kv_set, clipboard_set, the hooks_* writers and exec have nothing to restore from. A browser.* verb qualifies only when the HUD journal can observe all of its effects — it watches tab created / removed / moved / detached / pinned / muted / url / activated / zoomed and window created, and replays a matching set of inverse ops. Verbs outside that vocabulary (window state and bounds, tab groups, downloads, bookmarks, the reading list, browsing data, extension management) journal nothing, so classing one inverse would produce an abort reporting a clean revert having restored nothing. Every deliberately irreversible verb is listed with its reason in tests/rev_coverage.rs, whose coverage gate fails when a verb reaches the surface unclassified.
| Group | Commands |
|---|---|
| Discovery, log & kv | hello, ping, hostinfo, hostlog, kv_set, kv_get, kv_merge, kv_del, kv_keys |
| System stats | sysinfo_once, sysinfo_start, sysinfo_stop, meter_stream |
| Filesystem | fs_read, fs_write, fs_append, fs_list, fs_walk, fs_stat, fs_mkdir, fs_rm |
| Watch & tail | fs_watch, fs_tail, watch_stop, watch_list |
| Exec & OS | exec, open, clipboard_get, clipboard_set, notify |
| Background jobs | job_start, job_list, job_result, job_poll |
| Process tools | ps, kill, which |
| Pub/sub bus | sub, unsub, pub |
| Host-to-host peering | peers, peer, peer_connect, remote |
| PTY terminals | pty_spawn, pty_write, pty_resize, pty_kill |
| Lifecycle hooks | hooks_list, hooks_events, hooks_save, hooks_delete, hooks_set_enabled, hooks_get_script, hooks_set_script, hooks_script_path, hooks_test_run, hook_fire |
| stryke scripting & LSP | stryke_run, stryke_lsp_start, stryke_lsp_send, stryke_lsp_stop |
| Transactions | txn_begin, txn_commit, txn_abort |
| Legacy zwire bridge | get + scheme/ui keys over ~/.zwire/hud-scheme and ~/.zwire/hud-ui.json |
/SECURITY MODEL
The Unix-socket daemon is created 0600 under a 0700 directory, so only the owning user can reach exec/fs/pty. Socket location resolves from $ZWIRE_HOST_SOCK, else $XDG_RUNTIME_DIR/zwire-host.sock, else ~/.zwire/host.sock. Local Unix-socket clients are trusted and never authenticate. Inbound TCP peers must auth/peer_hello with a shared --token (or $ZWIRE_HOST_TOKEN) before anything privileged runs, and federation is single-hop so a forwarded event is delivered locally but not re-forwarded — no loops across star or fully-meshed topologies.
$CI GATES
| Gate | Command |
|---|---|
| fmt | cargo fmt --all --check |
| clippy | cargo clippy --all-targets -- -D warnings |
| doc | RUSTDOCFLAGS=-D warnings cargo doc --no-deps |
| test | cargo test (exercises the protocol over both transports) |
CI runs the four canonical polish gates on Ubuntu + macOS + Windows. The umbrella MenkeTechnologiesMeta repo additionally pins this crate's metadata across its gate suite — LICENSE present + canonical MIT text, authors/repository/homepage fields, and these docs pages.
#PROJECT METADATA
| Item | Value |
|---|---|
| Version | 0.3.21 |
| License | MIT |
| Binary size | ~500 KB (release: opt-level = "z", LTO, stripped, panic = "abort") |
| Dependencies | serde, serde_json, toml, base64, sysinfo (optional), portable-pty (optional), tauri (optional), interprocess (Windows only) |
| Features | sysinfo-caps (live stats + ps/kill), pty (terminals); both default-on, both droppable for a light embed |
| Platforms | macOS · Linux · Windows (all three in CI; battery reporting macOS-only via pmset) |
| Consumers | zwire (native-messaging), zpwrchrome-host (library embed) |
| Author | MenkeTechnologies |
| Repository | github.com/MenkeTechnologies/zwire-host |
| Meta umbrella | MenkeTechnologiesMeta |