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.envfiles, two index states. Context cost: high. (Heddle's answer isheddle start <name> --path ../<name>, which makes a checkout with no.gitof its own — drive it with Heddle commands, not by shelling out togitinside it.--hydratesymlinks 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
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
heddle start: make a new thread from a capture (--from <state>).heddle thread: list, switch, and inspect threads (including forks).heddle capture: every capture is a potential fork point.
Next: annotation that survives refactor (the other primitive nothing else has), or captures and states if you want the foundational layer first.