Skip to content

feat: GoalRun loop engine — durable act→verify→continue loops with maker-checker + deterministic PR finalization#517

Merged
alari76 merged 6 commits into
mainfrom
feat/goal-runs
Jun 14, 2026
Merged

feat: GoalRun loop engine — durable act→verify→continue loops with maker-checker + deterministic PR finalization#517
alari76 merged 6 commits into
mainfrom
feat/goal-runs

Conversation

@alari76

@alari76 alari76 commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduces the GoalRun primitive: a durable, auditable act→verify→continue loop around a coding agent, delivered across five incremental cuts on this branch.

  • Cut 1 — Loop primitive: goal_runs/goal_run_turns SQLite store, deterministic verifier (run cmds → exit code → pass/fail), and the controller state machine with turn/cost budget enforcement and readonly-glob constraint enforcement.
  • Cut 2 — Maker–checker: an optional second-provider review pass. Maker writes → deterministic gate → a different provider checker judges scope-creep / test-gaming / goal-met with a strict parseable verdict {approve | request_changes | escalate}.
  • Cut 3 — Loop templates: ci-autorepair, coverage-increase, dependency-upgrade (.codekin/loops/*.md, YAML frontmatter + markdown goal).
  • Cut 4 — API + UI: /api/goal-runs router (templates, runs list, per-run evidence ledger, start, abort) behind the master token; a Loop Runs panel (runs list + evidence ledger + start-loop form) with sidebar nav.
  • Cut 5 — Deterministic finalization / PR write-back: on success Codekin (not the agent) commits the verified tree, pushes, and opens a PR via gh, capturing the URL. Push/PR failures keep the run succeeded (verification passed) with the reason in the evidence ledger, surfaced in the UI.

Default completionPolicy is prnever auto-merges to main.

Test plan

  • tsc -b + vite build clean
  • Full suite green (2431 passing, 98 files)
  • New unit coverage: finalizer (commit/push/PR per policy + graceful failure + already-open-PR recovery), controller finalize (deterministic + prUrl capture + failure-still-succeeds), store pr_url round-trip
  • eslint clean on new/changed files
  • Manual smoke: start a ci-autorepair run from the Loop Runs panel against a repo, confirm evidence ledger + PR link populate

🤖 Generated with Claude Code

alari76 and others added 6 commits June 14, 2026 20:30
Introduces the Cut-1 foundation for Loop-driven development: a durable,
auditable act→verify→continue loop that wraps a coding session.

- goal-run-store: better-sqlite3 persistence for runs + per-turn evidence
  ledger (~/.codekin/goal-runs.db, WAL, 0600)
- verifier-runner: deterministic gate that runs the loop's verify commands,
  captures exit codes/output tails, plus git diff helpers for debounce and
  readonly enforcement
- glob-match: dependency-free matcher for readonly path constraints
- goal-run-controller: drives the loop off onSessionResult with turn/cost
  budgets, readonly strikes→escalation, no-change nudge, debounced verify,
  and a finalize (push+PR) step; leaves an onVerifyPassed seam for Cut-2
  maker-checker

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
When a goal run's spec sets a `checker` provider, a passing deterministic
verifier now hands off to a second-provider review pass instead of
finalizing directly — a different model reviews the diff so it isn't
grading its own work.

- verifier-runner: getDiff returns the full `git diff HEAD` patch, which
  travels in the checker prompt (the maker's edits are uncommitted, so a
  sibling worktree can't see them)
- controller: onVerifyPassed spawns the checker on its own review branch
  off the maker's branch (git forbids two worktrees on one branch), routes
  the parsed verdict — approve → finalize, request_changes → feed notes
  back to the maker and resume, escalate/unparseable → awaiting_human —
  and folds checker cost into the run budget
- parseCheckerVerdict: last `VERDICT:` line wins (tolerates echoed
  instructions); a missing marker escalates rather than silently passing

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Make Goal Runs authorable as markdown recipes instead of raw API specs.
A loop template is a `.md` file with YAML frontmatter describing the
GoalRunSpec (maker/checker providers, verify commands, readonly globs,
budgets, completion policy) plus a body that becomes the default goal.

- loop-loader: parses + validates templates (closed kind/provider/policy
  sets, positive budgets, non-empty verify/goal) using the `yaml` lib;
  loads built-ins from server/loops/ and per-repo overrides from
  {repo}/.codekin/loops/ (same kind wins), and maps a template into a
  CreateGoalRunInput with runtime repo/branch + optional goal override
- built-in templates: ci-autorepair, coverage-increase, dependency-upgrade
  (all default to a second-provider checker and completionPolicy: pr)
- ship server/loops/ in the published package

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Wire the GoalRun loop primitive to an HTTP API and frontend panel:
- server/goal-run-routes.ts: /api/goal-runs router (templates, runs
  list, per-run evidence ledger, start, abort) behind master token
- GoalRunController.abortRun: stop maker, mark aborted, record ledger
- ws-server: mount router, construct store+controller, close on shutdown
- LoopRunsView + goalRunApi: runs list, evidence ledger, start-loop form
- Left sidebar "Loop Runs" nav + /loops route

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Stop trusting the maker agent's prose to land a verified run. On success
Codekin now commits the verified tree, pushes the branch, and opens a PR
deterministically, capturing the URL:
- goal-run-finalizer.ts: commit-if-dirty → push → gh pr create per policy,
  recovering an already-open PR; push/PR failures are reported, never thrown
- controller: finalizeSucceeded stops the maker, runs the finalizer, persists
  prUrl; failures keep status 'succeeded' (verification passed) with the note
  in the evidence ledger
- store: pr_url column (+ idempotent migration), prUrl on GoalRun/patch
- UI: PR link in LoopRunsView, with a visible "finalization failed" notice
  when a succeeded run has no PR

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
@alari76
alari76 merged commit 982300c into main Jun 14, 2026
2 checks passed
@alari76
alari76 deleted the feat/goal-runs branch June 14, 2026 21:39
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.

1 participant