HEDDLE

Concept

Fork from capture

The primitive nothing else has. At any capture, you can branch the working state into a second thread. The original keeps running. The fork is fully attributed and addressable. Both paths persist. The abandoned one stays browseable from the same repo it came from. This is the operation that replaces stash, duplicate worktrees, and restart-the-agent in one move.

The wound

Halfway through a refactor you hit a fork in the road. Two approaches are defensible; you don't know which will pay off until you try one. Today, in Git, you have bad options:

  • Stash the working tree, try approach B, hope you can come back to A. Stash drops on a typo. Stash forgets which agent was driving. Stash has no notion of attribution.
  • Duplicate the worktree with git worktree add, run a second agent against it. Now you have two directories, two terminals, two sets of .env files, two index states. Context cost: high. (Heddle's answer is heddle start <name> --path ../<name>, which makes a checkout with no .git of its own — drive it with Heddle commands, not by shelling out to git inside it. --hydrate symlinks the origin's ignored dependency directories in so it builds immediately, at the cost of sharing them: installing a dependency there mutates the origin's copy too.)
  • Restart the agent from scratch in a fresh session. Lose every minute of warmup, every cached embedding, every piece of working context the model built up.

All three options leak context. Most engineers stash + worktree + pray, and roughly half of the abandoned paths are lost within a week because the stash got dropped, the worktree got nuked, or the agent session timed out.

What fork does

heddle start <thread> --from <state> creates a second thread that starts from the chosen capture (defaulting to HEAD if --from is omitted). Both threads now exist as first-class objects. The original keeps its name, its agent identity, its event log. The fork gets its own name, its own agent identity, and its own event log starting from the fork point.

Fork a thread at the audit-middleware-scopes capture

bash# the team is unsure whether to keep a JWT compat layer$ heddle start task/biscuit-authz.shim --from hd-5xtkhq8m2pfStarted task/biscuit-authz.shim from hd-5xtkhq8m2pf · attached to gpt · 5.4  parent task/biscuit-authz continues with claude · opus 4.7

The forked thread inherits the working tree at the fork capture: every file, every uncommitted change up to that point. Both agents now operate from a known shared state and diverge from there.

Both paths persist

If the fork doesn't pay off, the abandoned thread doesn't vanish. Its captures stay browseable, its event log stays intact, the abandonment itself is recorded as an event:

An abandoned fork is still browseable

bash$ heddle thread show task/biscuit-authz.shimtask/biscuit-authz.shim   ·  gpt · 5.4 · started from hd-5xtkhq8m2pf  3 captures · 1 abort (cost outweighs migration)  state: abandoned · still addressable

This matters for two reasons. First, you can come back to an abandoned path months later when conditions change. The capture record is the closest thing to a working time machine for code. Second, the abandoned path's attribution survives: the agent that tried it, the captures it produced, the reason given for abandoning are all part of the audit trail.

Recovery

Every capture in an abandoned fork is still a state, and states stay addressable. To pick one back up, branch a new thread off it: heddle start <name> --from <state>. Read it first with heddle show <state> or heddle thread show <name>.

There is no verb that checks an arbitrary state out in place. heddle thread switch attaches the checkout to an existing thread ref, and there is no top-level heddle switch at all — ADR 0046 rules it out as a competing verb. Recovery in Heddle is a branch, not a seek: the state you came from stays where it was.

For unwinding rather than revisiting, heddle undo is the command — and it is thread-local, so run it from the checkout you want rewound.

When to fork, when not

Fork when the next step is genuinely uncertain: when two approaches are both defensible and you don't know which will pay off until you've tried. Fork when a second agent will explore in parallel. Fork when you want to keep the not-yet-resolved path as evidence of what was considered.

Don't fork for every disagreement in the model. Threads can hold retries, aborts, and conflicts inline. Those don't warrant a fork. Fork is for paths that meaningfully diverge, not for "I changed my mind about a variable name."

Compared to Git

GitHeddle
git stash heddle start --from <state>

Stash is volatile, and drops on a typo. A forked thread is durable: the abandoned path stays attributed and addressable, and you rejoin it by branching off the capture rather than seeking back to it.

git worktree add heddle start

Worktrees give you a second directory; starting a thread gives you a second thread that the worktree concept doesn't even need to exist for. Both can coexist.

git branch (for experimentation) heddle start

Branches forget. Forked threads remember the moment of divergence, the agent that took each path, and the reason for abandoning if one is abandoned.

The commands

Next: annotation that survives refactor (the other primitive nothing else has), or captures and states if you want the foundational layer first.