feat(examples): self-improvement flow v1 — read runs, propose prompt+structure edits, open PR

Merged
KH
6d ago
+2376-0

What

examples/self-improvement/ is v1 of the self-improvement agent flow. It is meant to run on a schedule (flows schedule, or flows run from cron or CI). Each pass:

  1. Observe (deterministic): listCloudRuns scans the newest runs, filters them to the target flow's name and to terminal status (completed/failed), and takes the last N. getCloudRunSteps is then called for each run. It authenticates with the workspace workflow token (FLOWS_CLOUD_TOKEN). digest.mjs ranks steps by leverage across four signals: failing ×2.0, weak ×1.0, cost share ×0.5 and latency share ×0.4.
  2. Analyse (agent, readonly): picks the highest-leverage step and writes proposal.json, which holds a diagnosis, evidence from cited runs, prompt edits, structure edits, and a hypothesis (before / after / metric / expected / falsified_if).
  3. Edit (agent, cwd = target checkout): applies the proposal to the target .flow.yaml.
  4. Gate (deterministic, one repair pass each): the proposal must name real steps and cite only collected runs. The edit must change exactly the flow file and pass flows check. The compiled canonical spec, diffed before vs after, must show at least one prompt change and at least one structural change.
  5. PR: one open self-improve/<flow>/… PR per flow, with no stacking. The flow pushes using GH_TOKEN (the App token on Cloud) and runs gh pr create. The PR body carries the before/after hypothesis and the evidence table.

It uses only primitives that exist today. It does not replay, evaluate, merge or deploy, and the README lists the gaps that keep it stopped at the PR.

Verified

  • npm --prefix examples/self-improvement test: 7/7 pass. Covers ranking, filtering of terminal runs and other flows, fail-closed behaviour with no runs, prompt-vs-structure classification in the spec diff, and both check-proposal stages.
  • Typecheck: running tsc -p examples/tsconfig.json shows no errors in self-improvement/. The other errors are pre-existing missing deps in a bare worktree.
  • End to end, locally, with real agents: flows run examples/self-improvement/self-improvement.flow.ts --local-agent --input examples/self-improvement/example/input.json completed 11 steps with completionReason: success. Against the fixture runs it picked classify (failing in 2 of 6 runs). It rewrote the instruction to a closed label enum with an exact final-line contract. It also added maxIterations: 2 and tightened the gate to regex_match, giving 1 prompt edit and 4 structural edits in the compiled spec.
  • Not exercised: the live Cloud read and the real gh pr create path. That needs a workspace token, plus a target repo I was not authorised to open PRs against.

Found along the way (not fixed here)

flows build refuses any YAML flow that has a named gate (regex_match, …), reporting gate_command_missing: command "node" does not resolve. The cause: build's probes defer commands by throwing, and probeNamedGate (packages/sdk/src/preflight.ts) treats the throw as a missing command. This flow therefore compiles with the SDK's compileYamlToCanonicalJson instead (see compile-spec.mjs). The SDK bug deserves its own fix.

Not in scope (documented gaps)

There is no replay-as-gate and no headless deploy auth. Memory writes are also missing, since f.memory.learn throws. Cloud has no first-class way to inject a workspace read token into a hosted run, so for now this flow runs wherever FLOWS_CLOUD_TOKEN is available.

Do not merge without human review.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


[!NOTE]
Medium Risk
Example-only, but agents can use inherited GH/Cloud credentials and push PR branches; misconfiguration or weak repo scoping could publish unwanted changes despite the deterministic gates.

Overview
Adds examples/self-improvement/, a new scheduled-style example that improves a target YAML flow from Cloud run history and stops at an opened PR (no replay, merge, or deploy).

The main self-improvement.flow.ts pipeline clones or copies the target, compiles a before spec, collects terminal runs (Cloud or fixture), ranks steps by leverage, then runs analyst and editor agents. Deterministic .mjs helpers (collect, digest, compile-spec, spec-diff, check-proposal, seal) are base64-embedded via bundle.mjs so hosted runs stay self-contained and gates are re-materialized before each check.

Safety and publication: evidence is sha256-sealed; edits must match proposal.json against the compiled spec (prompt text exact, structure by step/field); git commit/push/PR steps are idempotent on branch self-improve/<flow>. Includes an offline issue-triage fixture, README, node:test suite, and ignores scratch dir /improve/. examples/tsconfig.json includes the new flow for typecheck.

Reviewed by Cursor Bugbot for commit 80e0a039d48cd165f823b36039667c9a09b4d804. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds examples/self-improvement/, a scheduled agent flow that reads a target YAML flow's terminal runs, ranks steps by leverage, proposes both prompt and structure edits with a falsifiable hypothesis, gates the edits deterministically, and opens one PR per flow. It stops at the PR: no replay, eval, merge, or deploy.

  • Helper scripts are embedded in the flow source (bundle.mjs --write; the test fails on drift) because Cloud replays one self-contained source, and they are re-materialized before every check so agents can't edit the gates that judge them.
  • Evidence (runs, digest, before spec, before authored ids, proposal.json) is sha256-sealed and verified from journaled command text; the target checkout must stay at its base commit, and the published blob is byte-compared against the sealed file. compile-spec runs before flows check in both checks so a symlink escaping the checkout is refused before check reads through it.
  • The edit gate requires the compiled-spec diff to be exactly the proposal: prompt edits carry the exact new text, structure edits are matched by compiled-spec (step, field) both ways, and a newly added agent/llm step counts as a prompt change. A step is compiler-generated only if neither the before nor the after YAML declares its id, so a re-authored step under a previously lowered gate's id is never exempt; only lowered gates absent from both declared-id sets and bound to a restructured producer's output are covered.
  • Runs from same-named flows are dropped when their executed steps are mostly not the target's; publication is an idempotent commit/push/PR-reuse sequence on one fixed branch self-improve/<flow>, so a concurrent run's non-force push fails closed. An orphaned branch is taken over with --force-with-lease only when its tip is older than an hour and no PR exists, re-checked right before the push and failing closed if the PR listing errors. A flowName that breaks git ref rules is refused.
  • Scheduling is cron/CI, not flows schedule — a hosted fire can't read other runs — and the README documents that agent steps inherit GH/Cloud credentials.

Not exercised

  • The live Cloud read path and real gh pr create weren't run; they need a workspace token and a repo authorized for PRs.
  • A local end-to-end run with real agents against the fixture data succeeded, and the deterministic helpers have 7 passing tests.

Found along the way

  • flows build rejects YAML flows with named gates like regex_match because the named-gate probe misreads a deferred command as missing; the flow compiles with the SDK's compileYamlToCanonicalJson instead, and the bug warrants its own fix.

Agent Relay sessions

  • claude session 05d0eca0 · opened via gh pr create · last active 2026-10-10
  • claude session a75f94c9 · contributor · ran gh pr commands · last active 2026-10-10
  • claude session 5863fddb · contributor · ran gh pr commands · last active 2026-10-10