zwire-host 0.3.1

Universal local host: system stats, filesystem, exec, PTY & kv store, reachable from Chrome native-messaging or a Unix-socket JSON daemon
Documentation
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="color-scheme" content="dark light">
  <meta name="description" content="zwire-host — a single self-contained Rust binary that exposes the whole local machine (system stats, filesystem, exec, PTY, background jobs, pub/sub bus, kv store) over one JSON message protocol, reachable from Chrome native-messaging or a local-socket JSON daemon, and embeddable as a library.">
  <title>zwire-host — Documentation</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;900&amp;family=Share+Tech+Mono&amp;display=swap" rel="stylesheet">
  <link rel="stylesheet" href="hud-static.css">
  <link rel="stylesheet" href="tutorial.css">
  <style>
    .tutorial-main { max-width: 68rem; }
    .docs-build-line {
      margin: 0.35rem 0 0;
      font-family: 'Share Tech Mono', ui-monospace, monospace;
      font-size: 11px;
      color: var(--text-dim);
      letter-spacing: 0.03em;
      max-width: 46rem;
      opacity: 0.75;
    }
    .hub-scheme-strip {
      border-bottom: 1px dashed var(--border);
      background: color-mix(in srgb, var(--bg-secondary) 85%, transparent);
      padding: 0.55rem 1.5rem 0.65rem;
      position: relative;
    }
    .hub-scheme-strip-inner {
      max-width: 68rem;
      margin: 0 auto;
      display: flex;
      align-items: center;
      gap: 0.85rem;
    }
    .hub-scheme-strip .hud-scheme-label {
      flex: 0 0 auto;
      font-family: 'Orbitron', sans-serif;
      font-size: 9px;
      font-weight: 700;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: var(--accent);
      text-align: left;
    }
    .hub-scheme-strip .scheme-grid {
      flex: 1 1 auto;
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      gap: 6px;
    }
    @media (max-width: 720px) {
      .hub-scheme-strip-inner { flex-direction: column; align-items: stretch; }
      .hub-scheme-strip .scheme-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }
    .example-tbl { width: 100%; border-collapse: collapse; margin: 0.6rem 0; font-size: 12.5px; }
    .example-tbl td {
      padding: 6px 10px;
      border: 1px solid var(--border);
      vertical-align: top;
      color: var(--text-dim);
    }
    .example-tbl td:first-child { width: 40%; color: var(--cyan); font-family: 'Share Tech Mono', monospace; }
    .example-tbl td code { color: var(--accent-light); background: var(--bg); padding: 1px 5px; font-size: 12px; }
  </style>
</head>
<body>
  <div class="app tutorial-app" id="docsApp">
    <div class="crt-scanline" id="crtH" aria-hidden="true"></div>
    <div class="crt-scanline-v" id="crtV" aria-hidden="true"></div>

    <header class="tutorial-header">
      <div class="tutorial-header-inner">
        <div>
          <h1 class="tutorial-brand">// ZWIRE-HOST &mdash; UNIVERSAL LOCAL HOST</h1>
          <nav class="tutorial-crumbs" aria-label="Breadcrumb">
            <span class="current">Docs</span>
            <span class="sep">/</span>
            <a href="report.html">Engineering report</a>
            <span class="sep">/</span>
            <a href="https://github.com/MenkeTechnologies/zwire-host" target="_blank" rel="noopener noreferrer">GitHub</a>
            <span class="sep">/</span>
            <a href="https://github.com/MenkeTechnologies/MenkeTechnologiesMeta" target="_blank" rel="noopener noreferrer">Meta</a>
          </nav>
          <p class="docs-build-line">single static Rust binary (~500 KB) &middot; sysinfo &middot; fs &middot; exec &middot; pty &middot; kv &middot; jobs &middot; bus &middot; peer &middot; 45 commands &middot; two transports, one dispatcher &middot; also a library</p>
        </div>
        <div class="tutorial-toolbar">
          <button type="button" class="btn btn-secondary" id="btnTheme" title="Toggle light/dark">Theme</button>
          <button type="button" class="btn btn-secondary active" id="btnCrt" title="CRT scanline overlay">CRT</button>
          <button type="button" class="btn btn-secondary active" id="btnNeon" title="Neon border pulse">Neon</button>
          <a class="btn btn-secondary" href="report.html">Report</a>
          <a class="btn btn-secondary" href="https://github.com/MenkeTechnologies/zwire-host" target="_blank" rel="noopener noreferrer">GitHub</a>
        </div>
      </div>
    </header>

    <div class="hub-scheme-strip">
      <div class="hub-scheme-strip-inner">
        <span class="hud-scheme-label">// Color scheme</span>
        <div class="scheme-grid" id="hudSchemeGrid"></div>
      </div>
    </div>

    <main class="tutorial-main">
      <h2 class="tutorial-title"><span class="step-hash">&gt;_</span>ZWIRE-HOST</h2>
      <p class="tutorial-subtitle"><strong>One pipe. One binary. The whole machine &mdash; reachable from anywhere.</strong> <code>zwire-host</code> is a single self-contained Rust binary (~500&nbsp;KB, no Python, no <code>psutil</code>) that exposes the local machine to <strong>any app</strong> over one JSON message protocol. It began as the Chrome <strong>native-messaging host</strong> for <a href="https://github.com/MenkeTechnologies/zwire" target="_blank" rel="noopener noreferrer">zwire</a>'s HUD; it is now a <strong>universal local endpoint</strong> reachable from a browser extension <em>and</em> from tmux, emacs, desktop apps, plugins, shell scripts, and any language &mdash; because it also runs as a <strong>local-socket daemon speaking newline-delimited JSON</strong>, the one protocol every tool already has.</p>

      <section class="tutorial-section">
        <h2>Two transports, one dispatcher</h2>
        <p>Both transports feed the <strong>same capability router</strong> (<code>src/session.rs</code>), so every command works over either one. A request may carry an <code>id</code> that is echoed on the matching reply, so a client can multiplex many in-flight requests, streams and terminals over one connection.</p>
        <table class="example-tbl">
          <tbody>
            <tr><td>Native messaging (default)</td><td>Chrome / browser extensions &mdash; little-endian <code>u32</code> length + JSON body on <code>stdin</code>/<code>stdout</code></td></tr>
            <tr><td>Local-socket daemon (<code>serve</code>)</td><td>tmux, emacs, desktop apps, plugins, any language &mdash; newline-delimited JSON, one object per line, over a Unix domain socket (macOS/Linux) or a named pipe (Windows)</td></tr>
          </tbody>
        </table>
        <p>The socket is created <code>0600</code> under a <code>0700</code> dir &mdash; owner-only, since it exposes <code>exec</code>/<code>fs</code>/<code>pty</code>. Inbound TCP peers are gated by a shared <code>--token</code>; local Unix-socket clients are trusted.</p>
      </section>

      <section class="tutorial-section">
        <h2>Capabilities</h2>
        <table class="example-tbl">
          <tbody>
            <tr><td>System stats</td><td><code>sysinfo_once</code> / <code>sysinfo_start</code> / <code>sysinfo_stop</code> &mdash; stream cpu · mem · swap · disk · net rate · load · uptime · battery · temp · host · LAN/WAN ip</td></tr>
            <tr><td>Filesystem</td><td><code>fs_read</code> / <code>fs_write</code> / <code>fs_append</code> / <code>fs_list</code> / <code>fs_walk</code> (recursive crawl) / <code>fs_stat</code> / <code>fs_mkdir</code> / <code>fs_rm</code>; leading <code>~</code> accepted</td></tr>
            <tr><td>Watch &amp; tail</td><td><code>fs_watch</code> streams create/modify/remove events; <code>fs_tail</code> streams appended lines (<code>tail -f</code>, survives rotation); <code>watch_stop</code> / <code>watch_list</code></td></tr>
            <tr><td>Exec &amp; OS</td><td><code>exec</code> (run to completion, base64 stdout/stderr), <code>open</code>, <code>clipboard_get</code> / <code>clipboard_set</code>, <code>notify</code></td></tr>
            <tr><td>Background jobs</td><td><code>job_start</code> spawns a job that survives the connection and fires a desktop notification on completion; <code>job_list</code> / <code>job_result</code> / <code>job_poll</code></td></tr>
            <tr><td>Process tools</td><td><code>ps</code> (by memory), <code>kill</code> (signal), <code>which</code> (resolve on <code>$PATH</code>)</td></tr>
            <tr><td>Pub/sub bus</td><td><code>sub</code> / <code>unsub</code> / <code>pub</code> &mdash; the host as a coordination hub; it publishes on <code>scheme</code>/<code>ui</code> for live theme sync without polling</td></tr>
            <tr><td>Host-to-host peering</td><td><code>peers</code> / <code>peer_connect</code> / <code>remote</code> &mdash; a mesh of TCP-peered daemons that federates the bus across machines and runs a request on another host</td></tr>
            <tr><td>PTY terminals</td><td><code>pty_spawn</code> / <code>pty_write</code> / <code>pty_resize</code> / <code>pty_kill</code>, multiplexed by <code>id</code></td></tr>
            <tr><td>Key/value store</td><td><code>kv_set</code> / <code>kv_get</code> / <code>kv_merge</code> / <code>kv_del</code> / <code>kv_keys</code> &mdash; a per-app JSON store under <code>~/.&lt;app&gt;/kv/</code></td></tr>
            <tr><td>Discovery</td><td><code>hello</code> (feature-test <code>caps</code>), <code>hostinfo</code> (os, arch, kernel, hostname, user, cpus, mem, LAN ip)</td></tr>
          </tbody>
        </table>
      </section>

      <section class="tutorial-section">
        <h2>CLI</h2>
        <p><code>zwire-host call</code> is the portable path &mdash; one request, one reply, from any tool that can write a line. Add <code>--stream</code> to keep printing frames from a streaming command.</p>
<pre>zwire-host serve &amp;                                   # 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</pre>
        <p>Or talk to the endpoint directly with no client library &mdash; e.g. <code>printf '{"cmd":"sysinfo_once"}\n' | nc -U ~/.zwire/host.sock</code> on macOS/Linux.</p>
      </section>

      <section class="tutorial-section">
        <h2>Library use (embed as a dependency)</h2>
        <p>The crate is a library too (<code>zwire_host</code>), so sibling hosts (e.g. <code>zpwrchrome-host</code>) can pull it in to crawl and exec without re-implementing anything. Embedders that only need the light capabilities can set <code>default-features = false</code> to drop the heavy <code>sysinfo</code> and <code>portable-pty</code> dependencies.</p>
<pre>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());</pre>
        <p>Or drive the whole dispatcher yourself over any transport with <code>zwire_host::{Peer, Session}</code>, or delegate <code>main</code> to <code>zwire_host::run(std::env::args().skip(1).collect())</code>.</p>
      </section>

      <section class="tutorial-section">
        <h2>Chrome install</h2>
        <p>Point a native-messaging host manifest's <code>path</code> at the binary and list the allowed extension origins, then drop it in the browser's <code>NativeMessagingHosts/</code> directory:</p>
<pre>{ "name": "com.zwire.hud", "type": "stdio",
  "path": "/abs/path/to/zwire-host",
  "allowed_origins": ["chrome-extension://&lt;id&gt;/"] }</pre>
        <p><a href="https://github.com/MenkeTechnologies/zwire" target="_blank" rel="noopener noreferrer">zwire</a>'s <code>scripts/localinstall.sh</code> builds this binary and wires the manifest automatically when packaging the <code>.app</code>.</p>
      </section>

      <section class="tutorial-section">
        <h2>Build &amp; test</h2>
<pre>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</pre>
        <p><code>sysinfo</code> and <code>portable-pty</code> abstract the OS, so the same source builds for <strong>macOS · Linux · Windows</strong>; CI runs the four polish gates on all three. Battery reporting is macOS-only (via <code>pmset</code>) until a native reader lands for other platforms.</p>
      </section>

      <section class="tutorial-section">
        <h2>Source layout</h2>
        <table class="example-tbl">
          <tbody>
            <tr><td><code>src/session.rs</code></td><td>the capability router shared by every transport &mdash; per-connection state (PTYs, sysinfo stream, bus/peer links) and the command dispatch</td></tr>
            <tr><td><code>src/transport.rs</code></td><td>the three ways to reach the dispatcher: stdio native messaging, the <code>serve</code> daemon, and the <code>call</code> client</td></tr>
            <tr><td><code>src/proto.rs</code> / <code>src/peer.rs</code></td><td>framing + reply plumbing; the peer/mesh link and TCP federation</td></tr>
            <tr><td><code>src/fsops.rs</code> / <code>src/watch.rs</code></td><td>filesystem read/write/crawl; streaming watch + tail observers</td></tr>
            <tr><td><code>src/exec.rs</code> / <code>src/jobs.rs</code> / <code>src/procs.rs</code></td><td>run-to-completion exec; background jobs; <code>ps</code>/<code>kill</code>/<code>which</code></td></tr>
            <tr><td><code>src/sysmon.rs</code> / <code>src/osops.rs</code></td><td>the sysinfo stream monitor; open/clipboard/notify/hostinfo</td></tr>
            <tr><td><code>src/pty.rs</code> / <code>src/bus.rs</code> / <code>src/store.rs</code></td><td>multiplexed PTY sessions; pub/sub bus; per-app kv store</td></tr>
            <tr><td><code>src/api.rs</code></td><td>the light library surface (<code>walk</code>, <code>exec</code>, …) for embedders with <code>default-features = false</code></td></tr>
          </tbody>
        </table>
      </section>

      <section class="tutorial-section">
        <h2>The zwire stack</h2>
        <p>zwire-host is the local endpoint behind the zwire HUD and its siblings. Browse the rest via the <a href="https://github.com/MenkeTechnologies/MenkeTechnologiesMeta" target="_blank" rel="noopener noreferrer">MenkeTechnologiesMeta</a> umbrella repo:</p>
        <ul>
          <li><a href="https://github.com/MenkeTechnologies/zwire" target="_blank" rel="noopener noreferrer">zwire</a> &mdash; the browser HUD this host was born to feed</li>
          <li><a href="https://github.com/MenkeTechnologies/zpwrchrome" target="_blank" rel="noopener noreferrer">zpwrchrome</a> &mdash; sibling Chrome extension; <code>zpwrchrome-host</code> embeds this crate</li>
          <li><a href="https://github.com/MenkeTechnologies/strykelang" target="_blank" rel="noopener noreferrer">strykelang</a> &mdash; the scripting language across the stack</li>
        </ul>
      </section>

    </main>
  </div>
  <script src="hud-theme.js"></script>
</body>
</html>