gage 0.3.4

Hand context between agents — files, prompts and decisions — with a trust boundary that survives the hop.
<!doctype html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>gage — hand context between agents</title>
<meta name="description" content="Hand context between agents — files, prompts and decisions — with a trust boundary that survives the hop.">
<style>
  :root{
    --bg:#fbfaf8; --sheet:#ffffff; --sunk:#f3f1ec; --line:#e7e3dc;
    --fg:#191815; --dim:#5b5751; --faint:#8b867d;
    --accent:#2c5a4d; --accent-soft:#e6eee9;
    --sans:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
    --mono:ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,monospace;
    --shadow:0 1px 2px rgba(25,24,21,.04), 0 10px 28px -20px rgba(25,24,21,.30);
  }
  @media (prefers-color-scheme:dark){
    :root:not([data-theme="light"]){
      --bg:#121316; --sheet:#1b1d21; --sunk:#232529; --line:#2b2e34;
      --fg:#edebe7; --dim:#a8a49d; --faint:#7a766f;
      --accent:#86c7b1; --accent-soft:#1f2f2a;
      --shadow:0 1px 2px rgba(0,0,0,.45), 0 12px 32px -22px rgba(0,0,0,.9);
    }
  }
  *{box-sizing:border-box}
  body{
    margin:0; background:var(--bg); color:var(--fg);
    font-family:var(--sans); line-height:1.6;
    -webkit-text-size-adjust:100%;
  }
  .wrap{max-width:46rem; margin:0 auto; padding:4rem 16px 5rem}
  h1{font-size:2.6rem; line-height:1.1; margin:0 0 .4rem; letter-spacing:-.02em}
  .tag{font-size:1.15rem; color:var(--dim); margin:0 0 2.5rem}
  h2{font-size:1.1rem; margin:2.75rem 0 .6rem; letter-spacing:.02em; text-transform:uppercase; color:var(--faint)}
  h3{font-size:1rem; margin:1.6rem 0 .4rem; color:var(--fg)}
  p{margin:0 0 1rem}
  a{color:var(--accent); text-decoration-thickness:1px; text-underline-offset:2px}
  code,pre{font-family:var(--mono)}
  pre{
    background:var(--sunk); border:1px solid var(--line); border-radius:8px;
    padding:.9rem 1rem; overflow-x:auto; font-size:.9rem; margin:0 0 1rem;
  }
  code:not(pre code){
    background:var(--sunk); border:1px solid var(--line); border-radius:4px;
    padding:.1em .35em; font-size:.88em;
  }
  .words{
    background:var(--accent-soft); border-left:3px solid var(--accent);
    border-radius:0 6px 6px 0; padding:.85rem 1rem; margin:0 0 1rem;
    font-family:var(--mono); font-size:.9rem;
  }
  figure{margin:1.25rem 0 0}
  img{
    width:100%; height:auto; display:block;
    border:1px solid var(--line); border-radius:10px; box-shadow:var(--shadow);
  }
  figcaption{font-size:.85rem; color:var(--faint); margin-top:.55rem}
  ul{margin:0 0 1rem; padding-left:1.2rem}
  li{margin:.3rem 0}
  .links{display:flex; flex-wrap:wrap; gap:.6rem; margin:.25rem 0 1rem; padding:0; list-style:none}
  .links a{
    display:inline-block; padding:.45rem .9rem; border:1px solid var(--line);
    border-radius:999px; background:var(--sheet); text-decoration:none;
    font-size:.92rem; box-shadow:var(--shadow);
  }
  footer{
    margin-top:3.5rem; padding-top:1.25rem; border-top:1px solid var(--line);
    font-size:.86rem; color:var(--faint);
  }
  .note{font-size:.9rem; color:var(--dim)}
</style>

<div class="wrap">
  <h1>gage</h1>
  <p class="tag">Hand context between agents — files, prompts and decisions — with a trust boundary that survives the hop.</p>

  <p>Your Claude hands a task to Codex. A colleague's agent sends you their project state.
  Normally nothing on the receiving side says who wrote it, or whether it can be trusted.
  gage wraps that handoff so the agent reading it is told who signed it, whether you have
  ever confirmed that person, and that nothing inside carries any authority.</p>

  <p>It works across vendors because it is not a protocol. A bundle is a signed directory,
  so it moves over a shared folder, git, email, your own network, or a relay — anything you
  already have.</p>

  <h2>Get going</h2>
  <pre>curl -fsSL https://gage.sh/install.sh | sh</pre>
  <p class="note">Piping a script into a shell is a thing worth being asked to
  trust. <a href="https://gage.sh/install.sh">Read it first</a> if you would
  rather — it is about a hundred lines of POSIX <code>sh</code>: it works out
  your OS and architecture, downloads the matching binary and its
  <code>SHA256SUMS</code> from the latest release, <strong>checks the
  checksum before installing anything</strong>, and puts one file in
  <code>~/.local/bin</code>. No sudo, ever. <code>cargo install gage</code>
  works too, anywhere Rust does.</p>

  <p>Then three beats. The middle one is the only part that needs a human.</p>

  <h3>1 · Who you are</h3>
  <pre>gage init alice          # or just `gage quickstart` and answer four questions</pre>
  <p class="note">Makes a keypair on this machine. <code>gage whoami</code>
  prints the one public line you send a colleague, and the four word-pairs
  that line's key derives.</p>

  <h3>2 · Who you trust</h3>
  <pre>gage add bob &lt;their-key&gt;</pre>
  <p class="note">Then <strong>read the four word-pairs to each other out
  loud</strong> — on a call, in person, not in the channel you sent the key
  through. If one word differs, it is not their key. This is the step nothing
  can do for you, and skipping it is what makes <code>SENDER VERIFIED</code>
  mean only "this is the key I was handed".</p>

  <h3>3 · One handoff</h3>
  <pre>gage send --to bob --subject "spec review" \
     --prompt ask.md --file spec.md --out ./pkg</pre>
  <p class="note">A bundle is a signed directory, so get it to them however
  you already can — a shared folder, git, email, <code>gage push</code>
  through a relay, or <code>gage send --lan</code> on the same network. On
  their side, <code>gage open ./pkg</code>, and what they see is the screen
  below.</p>

  <p>The full tour is in the
  <a href="https://github.com/warewithall2/gage#readme">README</a>. Driving it
  with no human at the keyboard — the command table, the exit codes, how to
  read a verdict, and a complete worked script — is in
  <a href="https://github.com/warewithall2/gage/blob/master/docs/agents.md">docs/agents.md</a>.</p>

  <h2>Keys, said out loud</h2>
  <p>A gage is a pledge, and historically the glove thrown down to open a challenge.
  Two people compare four word-pairs over a channel neither machine controls — a phone
  call, in person — and everything downstream rests on that one human moment. The words
  are derived from the signing key, so nobody picks their own, and two machines showing
  the same words are holding the same key.</p>
  <div class="words">this key says : humble pillar · ruddy lobster · marine armour · eastern dovecote</div>
  <p class="note">Four pairs is 64 bits, and is what a person confirms. The single pair
  shown as a label is 16 bits — enough to tell two machines apart in a list, never enough
  to confirm anything against.</p>

  <h2>Other ways to install</h2>
  <pre>cargo install gage</pre>
  <p class="note">Works anywhere Rust does, and is the route for any platform
  without a prebuilt binary. The binaries and their checksums are attached to
  the <a href="https://github.com/warewithall2/gage/releases/latest">latest
  release</a> if you would rather fetch one by hand and check it yourself —
  <strong>linux-x86_64</strong> and <strong>darwin-arm64</strong>, with one
  <code>SHA256SUMS</code> over both.</p>

  <h2>What it looks like</h2>
  <figure>
    <img src="screenshots/inbox.png" alt="The gage viewer: conversations on the left, a received bundle on the right with its trust verdict stated above the contents.">
    <figcaption><code>gage ui</code> serves a local viewer on 127.0.0.1 — loopback only,
    nothing leaves the machine. The verdict is the headline, not a caption.</figcaption>
  </figure>

  <h2>Where it is</h2>
  <p>v0.3.0. 130 unit tests and 871 adversarial checks pass, along with the
  identity restore drill and the viewer end-to-end suite. It is early
  software, and the honest way to try it is the twenty-minute packet in the
  repository.</p>

  <p><strong>0.3.0 adds two front doors.</strong> <code>gage mcp</code> serves
  the Model Context Protocol over stdio, so an agent calls nine gage tools
  instead of shelling out and parsing prose — a front door, not a second
  implementation, running the same functions the CLI runs. And the local
  viewer no longer dead-ends someone with no identity: a first-run wizard
  walks from nothing to a first verified handoff in the page, with the
  word-pair comparison still a thing two people do and the pair button
  disabled until it is confirmed. Passphrases stay in the terminal. An
  installed 0.2.0 keeps working — nothing about the bundle format or the
  relay protocol changed.</p>

  <p><strong>0.2.0 fixed a security defect in <code>gage open</code></strong>,
  the one part of gage that is a security control: a sender could get a line
  of their own into the trust frame — including a forged authorisation line
  carrying the frame's real marker. <strong>0.1.0 is affected and upgrading is
  recommended.</strong> What it was, who could do it and how it is fixed are
  in the
  <a href="https://github.com/warewithall2/gage/blob/master/CHANGELOG.md">changelog</a>.
  It was found by self-review rather than by an outside reporter, which is
  worth knowing in both directions.</p>

  <p>If you lose the key, that is no longer the end of the identity —
  <code>gage export-identity</code> writes a passphrase-encrypted copy you
  keep yourself. It is opt-in, and it is a trade rather than a free
  improvement: it converts "lose the key, lose everything" into "your security
  is your passphrase's strength", so the file belongs somewhere other than the
  machine it came from.</p>

  <p>Two documents say what this actually is rather than what it hopes to be. The
  <a href="https://github.com/warewithall2/gage/blob/master/docs/spec.md">spec</a> is the
  wire reality, derived from the code. The
  <a href="https://github.com/warewithall2/gage/blob/master/docs/threat-model.md">threat
  model</a> lists the adversaries, the mitigation for each, and the non-goals — including
  that nothing here can make a language model obey the frame, and that the security review
  so far has been self-review.</p>

  <ul class="links">
    <li><a href="https://github.com/warewithall2/gage/blob/master/docs/spec.md">Spec</a></li>
    <li><a href="https://github.com/warewithall2/gage/blob/master/docs/threat-model.md">Threat model</a></li>
    <li><a href="https://github.com/warewithall2/gage">GitHub</a></li>
    <li><a href="https://crates.io/crates/gage">crates.io</a></li>
    <li><a href="https://docs.rs/gage">docs.rs</a></li>
  </ul>

  <footer>
    gage 0.3.0 · dual-licensed MIT or Apache-2.0 · no trackers and no scripts on this page
  </footer>
</div>