Enable Checkpoint Backend Selection Flag

ok, I want to work on a simple path to enable the ref backend on an existing repo but also during initial enable, can you give me a few suggestions?
Here's the lay of the land, then concrete suggestions.
The key insight
The git-refs backend is already fully wired and runnable — registry, store, ULID minting, read-routing for mixed repos, backend-aware push/fetch all exist. The only thing missing is a config writer. Today it's turned on only via ENTIRE_CHECKPOINTS_PRIMARY=git-refs or hand-editing .entire/settings.json.
So "enable the ref backend" reduces to: write checkpoints.primary.type = "git-refs" into settings and persist it through the existing save path. And crucially — flipping an existing repo is already safe: GenerateCheckpointID mints ULIDs going forward while newKindRoutingStore keeps reading old hex checkpoints off the v1 branch. There's no data migration to write. That's what makes a "simple path" realistic.
Suggestions
Option 1 — One shared flag on enable + configure (recommended)
entire enable --checkpoint-backend refshandles the initial case (setEnableOptions.CheckpointBackend, writesettings.CheckpointsinrunEnableInteractiveright where other settings mutate, beforesaveSettingsToTarget).entire configure --checkpoint-backend refshandles the existing-repo case. This matches the documented layout exactly —configureis the canonical home for non-agent settings (telemetry, hook mode, strategy options), and backend selection is precisely that.- Both call one tiny helper: validate the value against the checkpoint registry (must exist + be
gitBackedto be primary), set the field, save to the right target file. - Why this is the simplest:
enablealready has an "already set up" re-run branch that applies strategy flags, so evenenable --checkpoint-backend refsalone works on an existing repo —configurejust gives it a conventional home.
Option 2 — A dedicated subcommand under the checkpoint group
entire checkpoint backend show(prints current + effective source: file vs env vs default) andentire checkpoint backend set refs.- Best discoverability and it gives you a read path for free (useful for
doctor/support). Natural fit under the existingcheckpointnoun group. - Slightly more surface than Option 1. Good candidate to advertise via
entire labswhile the backend is still rolling out, rather than exposing it in root help.
Option 3 — Interactive prompt in the enable wizard
- Add a Select to the wizard. Lowest-ceremony for humans, but per the agent-safe-fallbacks rule it's only sugar on top of a flag — you'd still need Option 1's flag for non-interactive/agent use. Probably premature to prompt everyone while this is experimental; I'd skip it for now.
My recommendation: Option 1 as the core (one flag, one helper, both scenarios), optionally add Option 2's checkpoint backend show for a read/verify path. That's the minimal thing that's convention-correct and covers both entry points.
Watch-outs to bake in
- Value naming: expose friendly
branch/refs(or accept the rawgit-branch/git-refs) and map to the registry type — don't invent a third vocabulary. - Validate as primary: reject non-git-backed types as primary (they're mirror-only); reject unknown types with a message listing valid ones.
- Target file: reuse
saveSettingsToTargetsosettings.local.jsonvssettings.jsonis respected —LoadCheckpointsConfigtreats.local.jsonas a wholesale replacement. - Forward-compat:
LoadCheckpointsConfigusesDisallowUnknownFields, so only write fields current readers understand. - Downgrade isn't symmetric yet: refs→branch mirror-push for downgrade safety is noted as "a later step." Enabling refs forward is safe; if you want a safety net, allow an optional
git-branchmirror alongside the refs primary (the one-of-each-type rule permits it).
Want me to turn Option 1 into a concrete implementation plan (flag + helper + where it slots into setup.go/configure), or explore any option further?
do option 1, and then we should maybe option 3 with branch being default but ref backend selectable
Both options are implemented, verified end-to-end against the real binary, and the full unit suite (7613 tests) plus lint pass.
What I built
The git-refs backend was already fully wired to run — the only missing piece was a config writer. I added that as a single --checkpoint-backend flag plus a first-run selector.
Option 1 — shared flag on enable + configure (covers both scenarios):
entire configure --checkpoint-backend refs— the existing-repo path (canonical home for non-agent settings).entire enable --checkpoint-backend refs— works on both fresh repos and already-set-up repos (the already-set-up branch now behaves likeconfigure), and on the--agentnon-interactive path.- Accepts friendly
branch/refsand canonicalgit-branch/git-refs(trimmed, case-insensitive).
Option 3 — interactive selector, branch as default:
- On the first interactive setup,
runEnableInteractiveprompts with Branch (default) / Refs (experimental). An explicit flag skips the prompt; non-interactive /--yes/ not-first-run keep the default silently. UsesNewAccessibleForm(ACCESSIBLE-mode safe), and choosing the default writes nothing (keepssettings.jsonclean).
Verified behavior:
- Invalid value fails fast before any repo bootstrap/hook install:
invalid --checkpoint-backend: unknown checkpoint backend type "bogus" (registered: git-branch, git-refs). - Writes/round-trips correctly through
settings.jsonand--local→settings.local.json; switching back tobranchoverrides cleanly. - Fresh enable without the flag writes no
checkpointsblock.
Key design choices baked in:
- Only git-backed backends can be primary — enforced via a new exported
checkpoint.ValidatePrimaryBackend, so the error list stays in sync with the registry. applyCheckpointBackendpreserves existing mirrors but drops one that would collide with the new primary (the one-of-each-type rule).- Switching primary on an existing repo is safe — old checkpoints stay readable via the existing kind-routing; no migration needed.
Files: checkpoint/registry.go (+validator/test), checkpoint_backend.go (new helpers), checkpoint_backend_test.go (new), setup.go (flag, wiring, extracted runEnableOnConfiguredRepo to keep complexity in check).
Two follow-ups I deliberately left out of scope (say the word if you want them):
- Downgrade safety: refs→branch mirror-push isn't implemented upstream yet, so switching back off refs after pushing refs-format checkpoints has the known remote-visibility caveat.
- Docs: I didn't touch
docs/architecture/sessions-and-checkpoints.mdsince this is the experiments tree — happy to add a short "selecting a backend" note if you want it.
/simplify → 4 cleanup agents in parallel → apply the fixes
You are improving the quality of the changed code, not hunting for bugs. Review
it for reuse, simplification, efficiency, and altitude issues, then fix what you
find. Do not look for correctness bugs — that is what /code-review is for.
Phase 0 — Gather the diff
Run git diff @{upstream}...HEAD (or git diff main...HEAD / git diff HEAD~1
if there's no upstream) to get the unified diff under review. If there are
uncommitted changes, or the range diff is empty, also run git diff HEAD and
include the working-tree changes in scope — the review often runs before the
commit. If a PR number, branch name, or file path was passed as an argument,
review that target instead. Treat this diff as the review scope.
Phase 1 — Review (4 cleanup agents in parallel)
Launch 4 independent review agents via the Agent tool, all in a
single message so they run concurrently. Pass each agent the diff and one of
the four angles below. Each returns its findings with file, line, a
one-line summary, and the concrete cost (what is duplicated, wasted, or
harder to maintain).
Reuse
Flag new code that re-implements something the codebase already has — Grep shared/utility modules and files adjacent to the change, and name the existing helper to call instead.
Simplification
Flag unnecessary complexity the diff adds: redundant or derivable state, copy-paste with slight variation, deep nesting, dead code left behind. Name the simpler form that does the same job.
Efficiency
Flag wasted work the diff introduces: redundant computation or repeated I/O, independent operations run sequentially, blocking work added to startup or hot paths. Also flag long-lived objects built from closures or captured environments — they keep the entire enclosing scope alive for the object's lifetime (a memory leak when that scope holds large values); prefer a class/struct that copies only the fields it needs. Name the cheaper alternative.
Altitude
Check that each change is implemented at the right depth, not as a fragile bandaid. Special cases layered on shared infrastructure are a sign the fix isn't deep enough — prefer generalizing the underlying mechanism over adding special cases.
Phase 2 — Apply the fixes
Wait for all four agents to complete, dedup findings that point at the same line or mechanism, and fix each remaining one directly. Skip any finding whose fix would change intended behavior, require changes well outside the reviewed diff, or that you judge to be a false positive — note the skip rather than arguing with it. Finish with a brief summary of what was fixed and what was skipped (or confirm the code was already clean).
Build, lint, and tests all pass. Here's the /simplify result.
Applied (3 fixes)
-
De-duplicated the "primary must be git-backed" rule (
checkpoint/open.go) — flagged by both the reuse and altitude agents.buildPrimarynow delegates to the newValidatePrimaryBackendinstead of re-implementing thelookupBackend+!gitBackedcheck. This single-sources the rule, drops a redundant registry lookup, and fixes an already-diverged error message (the two copies listed different example backends). Updated the doc comment to reflect it's now the source of truth. -
Simplified the mirror-drop loop (
checkpoint_backend.go) — simplification agent. Replaced the 9-line guardedmake/append/reassign with oneslices.DeleteFunc. Behavior-identical (nil stays nil;mirrorsisomitemptyanyway;sis never aliased at the call sites). -
Dropped the redundant
backend stringparam fromupdateCheckpointBackend(checkpoint_backend.go) — simplification agent. It now readsopts.CheckpointBackenddirectly, matching its siblingupdateStrategyOptions(ctx, w, opts)and removing a param that could silently diverge fromopts. Updated 2 call sites + 3 test calls.
Skipped (noted)
- Efficiency — nothing. The double validation (fail-fast before bootstrap, then at apply) is intentional and pure/cheap; the per-flag-group load+save is the established
update*pattern, not a regression. - Vocabulary seam (altitude, low-priority) — flag/prompt say
branch/refsbut a typo's error lists canonicalgit-branch/git-refs. The agent confirmed the alias mapping belongs in the CLI layer (not the registry), and the error is still actionable. Left as-is to keep the change tight. loadTargetSettingshelper across all 5update*functions (reuse) — a real DRY opportunity, but it's a pre-existing pattern spanning code outside this diff.- Prompt-default-writes-nothing vs flag-writes-explicit-block asymmetry (altitude) — principled (keeps fresh settings pristine; explicit downgrade must write a block), not an accidental special case.
The layering (resolve → apply → applyFlag/updateCheckpointBackend) was confirmed by two agents to map to genuinely distinct call sites — not collapsed.
Done. Branch pushed and PR opened.
PR #1661 — https://github.com/entireio/cli/pull/1661
- Branch:
soph/enable-ref-backend→main(onentireio/cli) - Commit:
e79baf663—feat: select checkpoint backend via --checkpoint-backend on enable/configure - Files: 6 (
checkpoint_backend.go+ test new;open.go,registry.go,registry_test.go,setup.gomodified)
Pre-push gate was clean: mise run check passed in full — fmt, lint (0 issues), and unit + 59 integration + 4 e2e canary tests. The push also pushed 1 checkpoint ref to the checkpoint remote (Entire is enabled on this repo).
The PR body summarizes the feature (Option 1 flag + Option 3 selector), the simplify-pass cleanups (single-sourced primary-backend rule), verification, and the two noted follow-ups (downgrade data-safety caveat, optional docs).
Looked at the PR comments and addressed them. Here's the summary.
PR #1661 review — 2 bot findings, no human comments yet
1. Cursor Bugbot (Medium) — promptCheckpointBackend used form.Run() + fmt.Errorf, so Ctrl+C / a cancelled command context wouldn't abort cleanly and cancellation surfaced a generic wrapped error.
- ✅ Fixed. Verified this is a real team convention (a "learned rule" plus sibling
setup_import.go,resume_*,doctor). Switched toform.RunWithContext(ctx)+handleFormCancellation. Cancellation now prints a clean "cancelled" line and keeps the default backend so enable continues — matching how the other optional setup prompts behave.
2. Copilot — the ValidatePrimaryBackend doc said unknown types are rejected "with a message that names the valid types," but for an unknown type the message actually lists all registered backends (which can include mirror-only ones).
- ✅ Fixed (doc-only). Reworded to distinguish the two cases: unknown type → error lists the registered types; registered-but-non-git-backed → rejected separately.
Both build, lint clean (0 issues), and the affected unit tests pass. Pushed as 48a450215 — the PR is updated (the bots should re-review on the new commit).
Nothing else needed action: no human reviewers have commented, and Copilot's overall summary was just an overview. Want me to reply to the bot threads on GitHub marking them resolved, or leave them for the re-review?