Replace JWT/refresh tokens with Biscuit capabilities
reviewable- agent
- claude opus 4.7
- delegated by
- anan@heddle.sh
- merge
- signed · ed25519:a8f3c1d7 ✓
VERSION CONTROL FOR AGENT WORK
Heddle turns every agent task — captures, retries, aborts, conflicts, one merge — into one named, reviewable, recoverable thread. Drop in beside Git.
Each of these is a workflow you run multiple times a day. Each one exists because Git can't hold the shape of agent work. Heddle holds it natively.
You stash, you forget, the stash disappears in a clean checkout. Heddle threads a fork from any capture — the abandoned path stays attributed and addressable forever.
Both paths persist. The abandoned one is still browseable
from heddle thread show task/biscuit-authz.a.
You cherry-pick five commits, miss the sixth, push, fail review. Heddle merges by task — the task carries every capture it needs, no manual selection.
bash
$ heddle merge --sign task/biscuit-authz
merged to main · hd-d01a8b4e
every capture from the task carried into the merge
ed25519:a8f3c1d7 ✓Force-push, lose two days of agent work, no recovery. Heddle never overwrites; rebase creates a new state, the prior one stays reachable from whatever ref held it.
hd-c4f3a201 hd-d01a8b4e Both states are reachable from the refs that held them. Force-push has no analog.
Blame stops at the author email. Heddle attributes every line by agent, model, delegated-by, and confidence — at the object level, recorded at write time.
verifier.rs:24ed25519:a8f3c1d7 ✓The unit is the task — and the task carries everything Git made you reconstruct by hand.
Replace JWT/refresh tokens with Biscuit capabilities
reviewableWhen an agent pushes a task, the diff isn't the whole answer. You also need to see who delegated, what tests passed, and what's still open. Heddle composes those into one review surface.
src/server/auth/biscuit.rs +312 −47src/proto/auth.proto +18 −34tests/auth/biscuit_spec.rs new +78 −03 files · 2 new symbols · 1 retired type · 1 structural rewrite
Local today: heddle review show. Hosted surface in alpha.
What git stash + git worktree add should have been.
Today this is stash, duplicate worktrees, messy branches, or restarting the agent. Heddle lets you fork at any capture: a second agent picks up the same working state and tries a different approach. Both paths persist. The abandoned one is attributed, addressable, still here when you want it.
Still attributed. Still addressable. Browseable from heddle thread show task/biscuit-authz.a.
Signed merge on main. → merges to state hd-d01a8b4e.
You have lost this exact rationale in a chat log. The constraint that forced a two-phase write. The invariant a single line of code is protecting. The reason this loop exists. Heddle attaches that reasoning to the symbol — not the line — so when the function moves, the reason moves with it. The next agent reads it before it edits.
invariant · production must abort on missing env
configured_minting_keypair line 1
Production startup MUST call require_minting_keypair instead. Option<KeyPair> here is for verifier-only deploys and dev fixtures — a missing env var on a minting node should abort the process at boot, never lazy-fail at the first authenticated request.
pub fn configured_minting_keypair() -> Option<KeyPair> { let raw = std::env::var(PRIVATE_KEY_ENV).ok()?; let raw = raw.trim(); if raw.is_empty() { return None; }rationale · Option, not panic, on malformed input
hex::decode line 6
Returns None on missing OR malformed env vars rather than panicking, so callers can distinguish 'not configured' (verifier-only deploy) from 'configured but broken' (logged + treated as not configured). Both surface the same way to the auth layer; only the deploy operator cares about the difference.
let bytes = match hex::decode(raw) { Ok(b) => b, Err(err) => { tracing::error!("not valid hex"); return None; } }; match PrivateKey::from_bytes(&bytes, Algorithm::Ed25519) { Ok(priv_key) => Some(KeyPair::from(&priv_key)), Err(err) => { tracing::error!("not a valid Ed25519 key"); None } }}Three clients we've tested end-to-end — Claude Code, Cursor, Codex — each writing into the same Heddle repo. Any CLI that shells out captures cleanly via env-var detection; the full adapter list ships with the README. Attribution at the object level: client, model, delegated-by, signed.
shell$ heddle capture -m "wire datalog scope rules"
Captured state hd-9a2f (b3a8…e201) Client, agent, and delegator are read from env vars the shell already sets. Each capture writes into its own thread; the merge happens at the task.
hd-9a1c scaffold biscuit verifierhd-9a2f wire datalog scope ruleshd-9a18 add Capability + Scope typeshd-9a3a drop shim · pure biscuit pathhd-9a24 fix import pathhd-9a44 extract biscuit issuerEach capture knows its client. The CLI runs wherever your agent does.
Names, not noise.
One task. One resolved state. Every change permanent, attributed, and inspectable.
Get in if agents are already changing production code. Heddle is onboarding teams with real agentic workflows: parallel agents, review bottlenecks, provenance requirements, or recovery pain.