Forking is the only time travel
agit fork exp#4 -b alt # branch off turn 4
agit fork alice/photo@exp -b repro --resume
You never “check out an old state” — history only grows. Forking from any ref
(branch tip, old commit, tag, exp#12, someone else’s line) mints a new
session identity and inherits the tree byte-for-byte. If the point you name
has no session (a file-line point on main), fork refuses: agit new starts a
fresh session instead.
agit resume alt— continue a session: native resume when the runtime matches (full fidelity), materialized resume across runtimes (loss list confirmed up front), or--forcepast an active sibling instance.agit new -b fresh— a brand-new session that inherits the shared files (memory/, skills/) from main, empty transcript.
The merge protocol
agit merge alt --into exp # start: recon (fork point, new turns each side)
# a merge agent is resumed — or drive it yourself:
agit merge alt --into exp --manual
agit merge pick alt#5..#6 # select turns
agit merge drop alt#7.2 # unselect
agit merge summary -m "keep only the ratelimit conclusion"
agit merge --continue # CAS + two-parent commit
agit merge --abort # walk away; the target ref never moved
--status shows the open transaction, --dry-run recon only.
--continue validates the summary exists and the target ref still matches
(compare-and-swap), then lands a two-parent commit. The VIEW gains marker
envelopes (__merge_start__/__merge_end__) plus the merge summary — the next
session inherits not just the merged content but what the reconciliation
concluded.
Conflicts in this system are rarely text conflicts — they’re intent
collisions (one side rate-limits by user_id, the other renamed it to
uid; both compile, together they’re wrong). That’s why a merge agent reads
the transcripts instead of git guessing byte ranges.
Cherry-pick and revert
agit cherry-pick alt#5..#6 --into exp # lift turns without a merge agent
agit revert exp#12.3 # drop an event from the VIEW
Both touch the VIEW only. The log — the evidence — never changes.
Pull requests
# contributor side (merge agent's work happened *before* this point)
agit pr create alice/photo@exp -b repro -m "fix for repro table 3"
# author side — review the proposed turns, then:
agit pr fetch <id> && agit show pr/<id> && agit pr merge <id>
pr merge is approve-and-land; the server never starts an agent. The server
decides the landing shape:
- fast-forward — contributor branched off the current tip;
- mechanical merge — the contributor already landed a two-parent commit whose first parent is the target tip (a pre-run merge, replayed);
- adopt — the whole incoming line is adopted as a new branch.
Two honest refusals: stale (your branch moved while the PR was open → 409, the PR is void rather than silently merging an old state) and genuinely diverged with no pre-run merge (→ 409 with the exact commands to fix it).