Skip to content

feat(agents): git checkpoints after each feature-agent step (spec 138) - #931

Merged
arielshad merged 24 commits into
mainfrom
feat/138-git-checkpoints
Oct 11, 2026
Merged

arielshad merged 24 commits into
mainfrom
feat/138-git-checkpoints

Conversation

@arielshad

Copy link
Copy Markdown
Contributor

What

After every feature-agent step that can change files, Shep now snapshots the feature's worktree into a hidden ref, refs/shep/checkpoints/<featureId>/<seq>-<node>, and records it in SQLite. Users can then:

  • see what each step changed,
  • diff any two steps,
  • roll the worktree back to a step, from the CLI or from a new Checkpoints tab in the feature drawer.

Why

Implements specs/138-git-checkpoints/: workstream T4 of the T3 Code review (docs/competitors/t3code.md, "What Shep Should Take" §3).

Until now a run kept only its end state, the branch. Nobody could answer "what did implement change, and what did repair change after it?", or undo one bad step without editing git by hand.

Capture

Capture follows T3's approach and never touches the user's branch, HEAD, index or files:

  1. Seed a temporary GIT_INDEX_FILE.
  2. add -A, then write-tree.
  3. commit-tree with a fixed identity and no signing, then update-ref.

All writes run with core.fsync=objects,reference.

  • Where it hooks in. A withCheckpoint wrapper covers every file-changing node of the full, fast and exploration graphs.
  • Baseline. A baseline is captured before the first step.
  • Unchanged steps. A step that changed nothing records nothing.
  • Failures. A capture failure is logged and never fails the run.

Diff

Diffs run git diff between two checkpoint commits and are cached in-process. The unified-diff parser previously in GitPrService (with a hand copy in the GitHub review service) is now one shared module.

Restore

Restore first captures a pre-restore checkpoint, so a restore can itself be undone. It then runs clean -fd, read-tree --reset -u and reset -q. The working tree matches the checkpoint, ignored files are kept, and the branch is not moved, so nothing already pushed is rewritten.

A single CheckpointRestorePolicy gates restore, and the list exposes its answer as a typed CheckpointRestoreBlocker. It refuses unless all three hold:

  • the feature has its own worktree, distinct from the repository path;
  • git confirms the directory is a linked worktree;
  • the latest agent run is not pending or running.

Cleanup

Refs and rows are deleted when the worktree is removed (post-merge cleanup, delete) or the feature is archived (manual or auto-archive).

Data model

Screenshots / Recording

Storybook (Features/Checkpoints/*) with fixture data. Light and dark.

Light Dark
Per-step diff
Compare two steps
Restore blocked (agent running)
Restore confirmation

Testing

Real git (global/system config isolated, signing off, worktree path with a space): tests/integration/infrastructure/services/git/git-checkpoint.service.test.ts

  • Capture leaves git status, HEAD, branch and index unchanged.
  • Untracked files are captured; ignored files are not.
  • The ref is visible from the main checkout.
  • Diff and stat work, and the cache returns the same object.
  • Restore equals the checkpoint, keeps ignored files and leaves the branch alone.
  • Linked worktree vs main checkout is detected.
  • Ref deletion removes only the feature's refs.
  • The unborn-branch case works.
  • A directory that is not the top of its own work tree is refused, e.g. a leftover worktree directory inside another repository after post-merge cleanup, so the parent checkout is never snapshotted.
  • A mutation check passed: without GIT_INDEX_FILE the "index untouched" test goes red.

Repository: tests/integration/infrastructure/repositories/sqlite-git-checkpoint.repository.test.ts (non-default round-trip, UNIQUE per feature, delete, idempotent migration).

Use cases (tests/unit/application/use-cases/features/checkpoints/)

  • Baseline and step numbering; unchanged tree skipped.
  • Per-step and two-step diffs.
  • Every restore refusal; Windows-spelled repository path treated as the same checkout.
  • Best-effort delete.

Pipeline: with-checkpoint.test.ts and checkpoint-capture.test.ts, plus graph-level tests asserting which nodes capture in the full, fast and exploration graphs (validate nodes never capture).

Cleanup hooks: archive, auto-archive watcher, worktree cleanup, delete.

CLI: checkpoints.command.test.ts.

Web: checkpoints-tab.test.tsx (per-step, baseline, compare, restore confirm/refusal, blocker, empty, error), plus drawer tab visibility.

DI: the bootstrap test resolves every new token and goes red without the registration.

Storybook: CheckpointList (Default / RestoreDisabled / WithPreRestore / WithoutRestore), CheckpointCompareBar, CheckpointRestoreDialog (Default / Pending / Closed), CheckpointsTab.

Local results, on the tree merged with main:

  • lint, format:check, typecheck, check:stories and generate (no drift) all pass.
  • test:unit: 15,043 passed.
  • test:int: 2,160 passed. The first run had 7 failures in dependency-path-traversal, caused by the unpatched extract-zip I had installed into the sandbox as a stand-in; with the repo patch applied, all pass.
  • build, build:web and build:storybook pass.

Checklist

  • pnpm lint passes
  • pnpm format:check passes
  • pnpm typecheck passes
  • pnpm test:unit and pnpm test:int pass
  • pnpm build succeeds
  • (UI only) pnpm build:storybook and pnpm build:web succeed; every new component has a colocated .stories.tsx
  • (Domain changes) pnpm generate ran and output.ts plus apis/json-schema/ are committed
  • (New use case) Tests landed RED-first per the TDD guide
  • No domain/ or application/ file imports anything from infrastructure/
  • Commit messages follow Conventional Commits
  • Updated LESSONS.md

🤖 Generated with Claude Code

https://claude.ai/code/session_01V37fpj6cexvgoExiG9SHKj


Generated by Claude Code

claude and others added 24 commits October 11, 2026 10:54
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
…elpers

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
…ervices

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
… cases

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
… node

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
…t is archived

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
…tore policy

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
…e imports

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
@arielshad
arielshad merged commit 26265ed into main Oct 11, 2026
23 checks passed
@arielshad
arielshad deleted the feat/138-git-checkpoints branch October 11, 2026 13:12
arielshad pushed a commit that referenced this pull request Oct 11, 2026
<p align="center">
  <a href="https://github.com/shep-ai/shep">
    <img src="https://raw.githubusercontent.com/shep-ai/shep/main/docs/screenshots/shep-card.jpg" alt="Shep — run multiple AI agents in parallel" width="720" />
  </a>
</p>

# 🚀 Shep [v1.241.0](/compare/v1.240.0...v1.241.0) · _2026-10-11_

> Your organization does not have access to Claude. Please login again or contact your administrator.

### ✨ Features

* **agents:** emit decision.answered and decision.defaulted telemetry (spec 136) ([#929](#929)) ([1e1f859](1e1f859)), closes [#922](#922) [#925](#925)

  ![default](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/134-unified-decisions/evidence/decision-panel-default.png)
  ![dark](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/134-unified-decisions/evidence/decision-panel-dark.png)
  ![gate](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/134-unified-decisions/evidence/decision-panel-approval-gate.png)
  ![not resumable](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/134-unified-decisions/evidence/decision-panel-not-resumable.png)
* **agents:** git checkpoints after each feature-agent step (spec 138) ([#931](#931)) ([26265ed](26265ed)), closes [#925](#925)

  ![checkpoints tab light](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/138-git-checkpoints/evidence/checkpoints-tab-light.png)
  ![checkpoints tab dark](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/138-git-checkpoints/evidence/checkpoints-tab-dark.png)
  ![checkpoints tab compare light](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/138-git-checkpoints/evidence/checkpoints-tab-compare-light.png)
  ![checkpoints tab compare dark](https://raw.githubusercontent.com/shep-ai/shep/v1.241.0/specs/138-git-checkpoints/evidence/checkpoints-tab-compare-dark.png)
* **web:** put the SDLC board behind a feature flag, off by default ([#932](#932)) ([e71f138](e71f138)), closes [#925](#925)

### 🐛 Bug Fixes

* **cli:** wait for the conpty host to exit when a terminal closes ([#928](#928)) ([94a846d](94a846d)), closes [#925](#925) [#925](#925)

## 📦 Install or update

```bash
# upgrade an existing install
npm i -g @shepai/cli@1.241.0

# or run instantly without installing
npx @shepai/cli@latest
```

## 💬 Join the community

[💬 **Discord**](https://discord.gg/ES6tdVFfur) · [📖 **Docs**](https://github.com/shep-ai/shep#readme) · [⭐ **Star on GitHub**](https://github.com/shep-ai/shep) · [🐛 **Report an issue**](https://github.com/shep-ai/shep/issues)

---

<sub>🤖 Released autonomously by Shep — built by parallel AI agents working in isolated git worktrees. Try it: `npx @shepai/cli`</sub>

Co-Authored-By: Shep Bot <shep-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants