gaganb.pageResume

CHECKPOINT

Project memory that stays with the code.

View on PyPI
Status
Shipped. v1.2.6 on PyPI.
Runs on
GitHub Actions
Year
2026
Role
Design and code, solo
Built with
PythonGitGitHub ActionsLiteLLMMistralMarkdown

OVERVIEW

Git records what changed. It doesn't tell you why, or what you missed while you were away. Checkpoint reads the history on every push and writes it down as Markdown in the repository: a checkpoint for each commit, a catch-up for whoever was away, a guide for whoever is new, and a summary for each pull request.

WHAT I OWNED

  • Designed and built it alone, in Python.
  • Wrote the GitHub Actions workflow it installs: checkpoints on push, summaries on pull requests, the guide on merge.
  • Cut the first version's DSPy, LangGraph and ChromaDB down to Git and one model call per document.
  • Published it to PyPI as checkpoint-agent. It's at v1.2.6.

OBJECTIVES

Catch up without reading every diff

How might someone back from a week away learn what changed, and why?

Onboard without asking around

How might a new developer find the main decisions without depending on someone's memory?

Keep it next to the code

How might project context live in the repository, reviewed like code, instead of in another tool?

HOW THEY BECAME FEATURES

WHY?

Git keeps the diff, not the reason behind it.

DESIGN DECISIONS

One checkpoint per commit, written on push. Git supplies the diff, author and date; the model writes Context, Changes, Impact and a priority. Anything inferred is marked "Likely". Its own files and bot commits are left out, so it never summarises itself.

TRADEOFF

Every commit costs a model call, and a model can still misread a diff. The files are reviewed like code.

WHY?

Coming back means reading other people's work, not your own.

DESIGN DECISIONS

It starts from your last commit and reads everyone else's checkpoints since then. Critical changes come first, five at most. The prompt forbids inventing names, owners or PR numbers. Your catch-up is deleted when you commit again.

TRADEOFF

A catch-up is only as good as the checkpoints it's built from.

WHY?

Someone new needs the whole picture, not the latest change.

DESIGN DECISIONS

MASTER_CONTEXT.md is rebuilt when a pull request merges, from the file tree, README, dependencies and recent checkpoints. Python projects get architecture diagrams from the syntax tree; other languages get model-drawn ones.

TRADEOFF

The diagrams help you find your way. They aren't a full map of the code.

A WEEK AT SPROUT

An example team, and every sheet is Checkpoint's own output. Cleo and Ben push while Ava is away. On Friday her catch-up is built from their checkpoints, and Darren starts with the project guide.

FRI 02
AvaAva
MON 05
CleoCleo
BenBen
TUE 06
Cleo
Ben
WED 07
Cleo
Ben
THU 08
Cleo
Ben
Cleo
FRI 09
AvaAva
DarrenDarren
FIG. 05 · EXAMPLE · SPROUT
CATCH-UP · AVA · 09 OCT 2026

Commit f15c0ae — 2026-10-02

Context

Ava’s commit starts Sprout, a fictional local plant-watering reminder service. The README says Cleo and Ben maintain it while Ava is away, and Darren is joining the project. The service uses local JSON files and no external services.

Commit b26f83c — 2026-10-05

Context

The watering interval setting is being renamed from reminder_days to watering_interval_days to make its purpose explicit. Existing configuration must be updated before starting the service.

Commit af60d81 — 2026-10-05

Context

The plant-watering reminder service is moving its reminder endpoint into an API route namespace. This is a breaking URL change: clients must switch from GET /reminders to GET /api/reminders. The commit does not describe a data-format change.

Commit 3894c30 — 2026-10-06

Context

Plants whose watering date was the current day were excluded from the due list. The commit fixes that boundary so plants are due on their scheduled day, not only afterward.

Commit 24153c1 — 2026-10-06

Context

The commit adds coverage for the boundary between overdue, due-today, and future watering reminders. It checks how sprout.reminders.due_plants handles those cases across two consecutive dates.

Commit ef1521b — 2026-10-07

Context

The service is moving its settings from JSON to YAML. The commit adds PyYAML as a runtime dependency and updates the default settings loader to use it. The existing watering interval and server port remain unchanged.

Commit b9d8436 — 2026-10-07

Context

Plant storage now uses an explicit schema version and renames watered_at to last_watered. Existing files without a version are treated as v1 by the migration, but the reminder loader requires v2. Operators must migrate existing data before starting the service.

Commit 277188e — 2026-10-08

Context

This change adds tests for migration backup and repeat-run behavior. The migration converts plant data from watered_at to last_watered; the tests check that the original data is backed up before migration and that an existing backup blocks migration.

Commit 33cf8bc — 2026-10-08

Context

The server needs a health endpoint that does not read plant storage. This gives clients a way to check the HTTP server without using the reminders endpoint.

Commit ee814c0 — 2026-10-08

Context

Returning maintainers need a clear path for upgrading existing installations. The commit adds an upgrade pointer to the README alongside the existing setup and run instructions.

While You Were Gone — Since October 02, 2026

You need to upgrade plant data, settings, dependencies, and client URLs before bringing an existing installation back up. The service also has a storage-independent health endpoint, and reminders now include plants due today.

Critical Changes (Must-Read)

  1. Migrate plant data before starting the service. Stop the service and run python -m sprout.migrate once. The reminder loader now requires schema version 2; unversioned and v1 files cannot load until migrated. The migration renames watered_at to last_watered. It refuses to overwrite an existing plants.json.bak, so you must resolve that file before retrying a v1 migration.
  2. Update reminder clients to GET /api/reminders. The old GET /reminders route now returns 404. Matching is exact, so a query string on the new route also prevents a match. Update any client, script, or monitoring configuration that uses the old URL.
  3. Move settings to YAML and install PyYAML. Install dependencies with python -m pip install -r requirements.txt and put your settings in settings.yaml. The default loader no longer reads settings.json, and importing sprout.reminders requires PyYAML even if you do not load settings.
  4. Rename the watering interval key. Use watering_interval_days instead of reminder_days. Settings containing only the old key cause a KeyError when due plants are calculated. The supplied interval remains seven days.
  5. Expect reminders on the scheduled day. The due-date comparison now includes today as well as earlier dates. Plants with future due dates remain excluded.

Master Context

Sprout is a fictional, local plant-watering reminder service. It reads configuration and plant records from files, calculates which plants need water, and exposes the result over HTTP. It has no external services and no production database; the tracked plants.json is sample data. Ava started the project, Cleo and Ben maintain it while Ava is away, and Darren is joining. The main engineering work is keeping the reminder rule, file formats, HTTP interface, and upgrade path aligned. Existing installations need special attention: settings moved from JSON to YAML, the interval key and reminders route changed, and plant records now require a versioned schema.

GIT SUPPLIES THE FACTS

The first version used DSPy, Gemini, LangGraph and ChromaDB. I was exploring the frameworks as much as the problem. Git already knows which files changed, who changed them and exactly how, so I took the frameworks out. Now the model only explains what needs interpretation.

git show --stat b26f83c
Author
Cleo
Date
Subject
refactor: rename watering interval configuration
docs/upgrade.md
+3 −0
settings.json
+1 −1
sprout/reminders.py
+1 −1
@@ -13,6 +13,6 @@ def load_plants(path=Path('plants.json')):1313 1414 1515 def due_plants(plants, today, settings):16− interval = timedelta(days=settings['reminder_days'])16+ interval = timedelta(days=settings['watering_interval_days'])1717 return [plant for plant in plants1818 if date.fromisoformat(plant['watered_at']) + interval < today]
CHECKPOINT-CLEO.MD

The watering interval setting is being renamed from reminder_days to watering_interval_days to make its purpose explicit. Existing configuration must be updated before starting the service.

git show --stat 3894c30
Author
Cleo
Date
Subject
fix: include plants due on the current day
sprout/reminders.py
+1 −1
@@ -15,4 +15,4 @@ def load_plants(path=Path('plants.json')):1515 def due_plants(plants, today, settings):1616 interval = timedelta(days=settings['watering_interval_days'])1717 return [plant for plant in plants18− if date.fromisoformat(plant['watered_at']) + interval < today]18+ if date.fromisoformat(plant['watered_at']) + interval <= today]
CHECKPOINT-CLEO.MD

Plants whose watering date was the current day were excluded from the due list. The commit fixes that boundary so plants are due on their scheduled day, not only afterward.

git show --stat b9d8436
Author
Ben
Date
Subject
fix: migrate plant storage to explicit schema version
docs/upgrade.md
+4 −0
plants.json
+1 −1
sprout/migrate.py
+26 −0
sprout/reminders.py
+5 −2
tests/test_reminders.py
+3 −3
@@ -0,0 +1,26 @@1+"""Upgrade sample plant storage with a backup and an atomic replacement."""2+import json3+from pathlib import Path4+5+6+def migrate(path=Path('plants.json')):7+ original = path.read_bytes()8+ data = json.loads(original)9+ if data.get('schema_version') == 2:
CHECKPOINT-BEN.MD

Plant storage now uses an explicit schema version and renames watered_at to last_watered. Existing files without a version are treated as v1 by the migration, but the reminder loader requires v2. Operators must migrate existing data before starting the service.

ON EVERY PUSH

Checkpoint runs inside your GitHub Actions. Every document it writes goes back into the repository as a commit, so there's no dashboard to sign into.

your pushGitHub Actionscheckpoints, catch-ups, guideyour repository
NO DASHBOARD
Push to any branch
Commit checkpoints and catch-ups for every developer.
Pull request
Checkpoints for its commits and a pull-request summary.
Merge to main
A fresh MASTER_CONTEXT.md.
Model
Any provider LiteLLM supports.
Setup
pip install checkpoint-agent, then checkpoint --init. Add your model's API key as a GitHub secret and push.
Limits
Bot commits and Checkpoint's own files are skipped. Repositories outside GitHub aren't supported yet.
# While You Were Gone — Since October 02, 2026

You need to upgrade plant data, settings, dependencies, and client URLs before bringing an existing installation back up. The service also has a storage-independent health endpoint, and reminders now include plants due today.

## Critical Changes (Must-Read)

Markdown is the memory

Every document Checkpoint writes is a Markdown file in the repository. People review it in pull requests, Git versions it, and models read the same files. There's no dashboard and no database.

Faster runs, not a benchmark

Successful workflow runs averaged 3m02s across 9 earlier runs and 2m08s across 43 later ones, 29.9% less. That's what the run history shows, not a controlled benchmark: the earlier runs came from one day, the later ones from about a month.

Result

Shipped. checkpoint-agent v1.2.6 is on PyPI, and the checkpoint, catch-up, pull-request summary and project guide flows all work. Support for repositories outside GitHub isn't finished.

Reflection

The system got better when Git supplied the facts and models explained the changes. More AI wasn't always the answer.