VERSION CONTROL FOR AGENT WORK

Agents don't work in commits.
Why version their work like humans?

Heddle turns every agent task — captures, retries, aborts, conflicts, one merge — into one named, reviewable, recoverable thread. Drop in beside Git.

01 Workload

Five Git rituals you can stop doing.

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.

  1. 01 git stash

    Stop hiding work you might want back.

    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.

    scaffold biscuit verifier wire datalog scope rules audit middleware scopes · fork point
    abandoned JWT compat shim · 4 fails
    merged pure biscuit · signed ✓

    Both paths persist. The abandoned one is still browseable from heddle thread show task/biscuit-authz.a.

  2. 02 git cherry-pick

    Stop hand-picking commits between branches.

    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 ✓
  3. 03 git push --force

    Stop rewriting history.

    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.

    before rebase hd-c4f3a201 still addressable
    after rebase hd-d01a8b4e on main

    Both states are reachable from the refs that held them. Force-push has no analog.

  4. 04 git blame

    Stop guessing who wrote what.

    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.

    line verifier.rs:24
    agent claude opus 4.7
    delegated by anan@heddle.sh
    confidence 0.94
    signed ed25519:a8f3c1d7 ✓
  5. 05 The Heddle way

    Five commands replaced. One concept.

    The unit is the task — and the task carries everything Git made you reconstruct by hand.

    TASK task/biscuit-authz hd-d01a8b4e

    Replace JWT/refresh tokens with Biscuit capabilities

    reviewable
    agent
    claude opus 4.7
    delegated by
    anan@heddle.sh
    merge
    signed · ed25519:a8f3c1d7 ✓

WORKS WITH GIT

Keep Git. Add the missing control layer for agent work.

Drop into an existing Git repo. heddle init and start. No migration. No GitHub abandonment. Heddle is a repo layer, not a tool layer — multiple agents from any client (Cursor, Claude Code, Codex) converge on one Heddle repo.

bash$ cd my-repo$ heddle initinitialized · git-overlay mode · adopted main$ heddle start "replace-jwt"created task/biscuit-authz · state hd-d01a8b4e
02 Review

Review the task,
through the noise.

When 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.

DIFF structural
  1. src/server/auth/biscuit.rs +312 −47
    • fn verify_capability — new symbol
    • fn attenuate_token — new symbol
    • fn authorize — rewritten signature
  2. src/proto/auth.proto +18 −34
    • message AuthRequest — field rename
    • message JwtClaims — removed
  3. tests/auth/biscuit_spec.rs new +78 −0
    • 12 new tests · 0 ignored

3 files · 2 new symbols · 1 retired type · 1 structural rewrite

Local today: heddle review show. Hosted surface in alpha.

03 Fork

What git stash + git worktree add should have been.

Get a fresh start
without starting over.

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.

  1. pkka73 scaffold biscuit verifier
  2. hxe72g wire datalog scope rules
  3. 5xtkhq audit middleware scopes — fork point
task/biscuit-authz.a abandoned gpt
  1. 9fbcqm keep JWT compat layer
  2. 3jmtnk two auth lanes drift · 4 tests fail
  3. x9r2qm abandoned · cost outweighs the migration window

Still attributed. Still addressable. Browseable from heddle thread show task/biscuit-authz.a.

task/biscuit-authz active claude
  1. vknq84 drop shim · pure biscuit path
  2. 2qpsr7 all tests green
  3. mrgd14 merge · ed25519

Signed merge on main. merges to state hd-d01a8b4e.

04 Context

The next agent
inherits the reason.

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.

crates/server/src/biscuit/keys.rs 2 annotations · attached at object
  1. 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.

    tagged enforces:bootstrap.spec area:auth-bootstrap · since hd-d01a8b4e

  2. 1 pub fn configured_minting_keypair() -> Option<KeyPair> {
  3. 2 let raw = std::env::var(PRIVATE_KEY_ENV).ok()?;
  4. 3 let raw = raw.trim();
  5. 4 if raw.is_empty() { return None; }
  6. 5
  7. 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.

    tagged pattern:fail-soft pairs:require_minting_keypair · since hd-d01a8b4e

  8. 6 let bytes = match hex::decode(raw) {
  9. 7 Ok(b) => b,
  10. 8 Err(err) => {
  11. 9 tracing::error!("not valid hex");
  12. 10 return None;
  13. 11 }
  14. 12 };
  15. 13
  16. 14 match PrivateKey::from_bytes(&bytes, Algorithm::Ed25519) {
  17. 15 Ok(priv_key) => Some(KeyPair::from(&priv_key)),
  18. 16 Err(err) => {
  19. 17 tracing::error!("not a valid Ed25519 key");
  20. 18 None
  21. 19 }
  22. 20 }
  23. 21 }
05 Convergence

Your agents.
Working together.

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.

Claude Code claude opus 4.7
  • hd-9a1c scaffold biscuit verifier
  • hd-9a2f wire datalog scope rules
Cursor gpt 5.4
  • hd-9a18 add Capability + Scope types
  • hd-9a3a drop shim · pure biscuit path
Codex gpt 5.4
  • hd-9a24 fix import path
  • hd-9a44 extract biscuit issuer

Each 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.

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.