Checkpoints & review gates
Autonomy is only comfortable if it is reversible and inspectable. LatchAI’s answer is two mechanisms that share one diff surface: checkpoints, which make every run reviewable after the fact, and review gates, which make a run stop and ask.
Checkpoints
Section titled “Checkpoints”A shadow git repository (<home>/runs/checkpoints.git, with the workspace as its
work-tree) snapshots around every run: pre-run before it starts, run <id> after it
finishes. Two consequences follow from the “shadow” part — your own repositories are never
touched by LatchAI’s undo history, and the workspace doesn’t have to be a git repository at
all for this to work.
Nothing about this is opt-in. Every workflow run and every chat turn begins with a
pre-run commit of whatever was outstanding and ends with a run <id> commit of what
changed, so “what did that do?” always has an answer.
Run diffs surface as checkpoint.created events carrying a short sha, a --stat summary
and the diff itself (capped at 100,000 characters), and the Runs sidebar grows a ± per
run that opens it.

Every run has a before and after.
A few boundaries are deliberate:
- Workspace only. Mounted project folders are not in the shadow repo — they usually
have their own git, and the git panel is the surface for
those. What gets checkpointed is what agents write into
workspace/: drafts, briefs, chat notes, dashboard and atlas exports, and agent memory. - Dependency trees and symlinked project roots are excluded —
node_modules/,*.log,.DS_Storeandworkspace/projects— because a diff drowning in ten thousand vendored files is not a review, and git’s output buffer agrees. - A run that changed nothing produces no checkpoint and no event, so the sidebar’s
±simply doesn’t appear.
Reverting
Section titled “Reverting”The overlay’s ⟲ Revert changes button applies an inverse commit in the shadow repo
(git revert --no-edit <sha>), which undoes that run’s file changes without rewriting
history. Today it is wired to chat turns — the ± Review changes affordance in the
chat panel — while run diffs opened from
the Runs sidebar are read-only. The endpoint itself is not chat-specific: POST /api/checkpoints/revert with {"sha": "…"} reverts any checkpoint.
Review gates
Section titled “Review gates”The review_gate node type pauses a run where you put it. It snapshots the mid-run diff,
emits a gate.waiting event, and blocks until the gate is resolved. The workbench
auto-opens a modal review overlay — a colored unified diff, an optional note, and
Approve/Reject.
Approving continues the run, and the note becomes the node’s output, so downstream nodes can read what the reviewer said. Rejecting fails the run.

The run is blocked until someone decides.
Placing one
Section titled “Placing one”A gate is an ordinary node with no config — everything it needs it gets from where you put it in the graph:
{ "nodes": [ { "id": "draft", "type": "agent", "position": { "x": 320, "y": 160 }, "config": { "agent": "release-writer", "prompt": "Draft the notes into out/notes.md." } }, { "id": "review", "type": "review_gate", "position": { "x": 580, "y": 160 }, "config": {} }, { "id": "publish", "type": "agent", "position": { "x": 840, "y": 160 }, "config": { "agent": "publisher", "prompt": "Publish out/notes.md. The reviewer said: {{review}}" } } ], "edges": [ { "from": "draft", "to": "review" }, { "from": "review", "to": "publish" } ]}The diff the reviewer sees is everything the run has changed so far — from the run’s starting commit to the working tree at this instant — not just the immediately preceding node. That is usually what you want: the question a gate asks is “is this run’s work acceptable”, not “did that one step behave”.
What the reviewer’s note is for
Section titled “What the reviewer’s note is for”{{review}} resolves to approved when the note is empty, and approved: <your note>
when it isn’t. That makes the note a real input rather than an audit comment: “approved:
tighten the headline before publishing” is something the next agent can act on.
Rejecting fails the node with review rejected: <note>, which fails the run — the
run.failed event carries the reason, so the log records why a nightly job stopped.
Resolving without the UI
Section titled “Resolving without the UI”Gates are resolved over HTTP, which is what the overlay calls:
curl -X POST http://127.0.0.1:7777/api/gates/resolve \ -H 'content-type: application/json' \ -d '{"runId":"run-1748…-3","nodeId":"review","approved":true,"note":"ship it"}'GET /api/gates lists the pending gate keys (<runId>:<nodeId>). A key that no longer
exists comes back 404, so a double-approve is a clear error rather than a silent no-op.
The same surface everywhere
Section titled “The same surface everywhere”Chat turns are checkpointed too, and working-changes review points the identical overlay at your git diff. Whether the change came from a scheduled run, a chat turn, or your own uncommitted work, “show me the diff” looks the same.