v2.10.0: memory across runs and learning PRs - #14
Merged
Merged
Conversation
…sions v2.10.0 item 1. Probed the factory's exact claudeArgs flags against a fresh throwaway repo: the CLI's system/init event still reports an active memory_paths.auto path, and the model saw the invoking user's global CLAUDE.md, even with --setting-sources project,local (user excluded) and --no-session-persistence. The path is keyed by a hash of cwd under the operator's own ~/.claude/projects/, so it's per-worktree, machine-local, and invisible to CI or a VPS runner. Confirms the roadmap's design: the factory's own lessons memory must live in the repo (.factory/memory/lessons.md, item 2), never depend on this mechanism. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
v2.10.0 item 2. buildContextPack (src/context.ts) now reads .factory/memory/lessons.md as a "lessons learned" section, right after AGENTS.md. Capped independently at 8 KiB (MAX_LESSONS_BYTES), separate from the pack's own 64 KiB budget, keeping the most recent lines when it grows past that since a newer lesson is more likely to still apply. install.sh scaffolds a starter file and treats it as repo-owned, like charter.md and config.example.json: --update never overwrites accumulated lessons. Works identically on the Mac, a VPS, or in CI, since it is only a file read off the worktree, unlike ~/.claude's operator-local auto-memory (research/agents/claude/memory.md). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Plan v2.10.0 items 3-4. A read-only retro stage (Haiku by default) runs after an issue's final outcome (merged, rejected, or given up on after verify rejections) and proposes at most one lesson or skill edit, or none. `factory learn` batches every pending proposal into one PR on a daily factory/learning-YYYYMMDD branch, exempt from protectedPaths only for .factory/memory/** and .claude/skills/**, checked by diffing the branch before any push. It never auto-merges, and shows in the inbox as its own read-only kind since it has no linked issue to chatops against. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… config Plan v2.10.0 structural test. touchesProtectedPath's build-stage call (src/watch.ts) relied entirely on the repo's own protectedPaths, which defaults to []: with no config, a Bash-made edit to .claude/** or .factory/** would reach a push, even though guard-paths.sh already hardcodes both as unconditionally protected for interactive Edit/Write tool calls. This adds the same ALWAYS_PROTECTED_PATHS to the build-stage diff check so the two enforcement paths agree. `factory learn`'s branch never calls touchesProtectedPath (it uses outsideAllowedPaths instead), so its exemption never weakens this for a normal build. Reverting the merge at the call site reproduces the gap and fails the new scenario test (confirmed manually). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Verification on the prior commit (a874ca0) found a second call site, src/merge-policy.ts's autoEligible, that also uses touchesProtectedPath but was never merged with ALWAYS_PROTECTED_PATHS: a low-risk PR touching .claude/** or .factory/** could still be judged auto-eligible on its own, even though this is currently unreachable in practice (the build-stage push check already blocks it earlier). Rather than patch that one call site too and leave a third future caller exposed to the same mistake, the merge now lives inside touchesProtectedPath itself, so every caller gets it for free. watch.ts's build-stage call drops its now-redundant explicit spread. Reverting the merge back out of touchesProtectedPath reproduces the gap and fails three tests: the two ALWAYS_PROTECTED_PATHS tests in boundary.test.ts and scenario test 12b (confirmed manually, then restored). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Retro stage plus factory learn (plan v2.10.0 items 1-4), and a merge-time follow-up: touchesProtectedPath now bakes ALWAYS_PROTECTED_PATHS in itself rather than at each caller, closing the same gap at a second call site (merge-policy.ts's autoEligible) the first fix missed. The live splitbill-demo run is deferred pending your reset OK, same as v2.7.0's precedent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.factory/memory/lessons.md, capped, injected viabuildContextPack) since headless Claude's own auto-memory is operator-machine-local state the factory can't rely on (research/agents/claude/memory.md).factory learnbatches pending proposals into one PR on a dailyfactory/learning-YYYYMMDDbranch, exempt fromprotectedPathsonly for.factory/memory/**and.claude/skills/**. Never auto-merges; shows in the dashboard inbox as its own read-only kind.touchesProtectedPathnow bakesALWAYS_PROTECTED_PATHS(.claude/**,.factory/**) into itself rather than at each call site, closing the same class of gap at a second call site (merge-policy.ts'sautoEligible) that a caller-side-only fix would have missed.See
CHANGELOG.mdfor the full v2.10.0 entry, including what's deliberately deferred.Test plan
make check(typecheck + full test suite + skills-ref validation) green — see commit history for output.touchesProtectedPathsingle-resolver fix), each confirmed to fail on revert and pass on restore.factory learn's ordering (rows marked learned only after push+PR succeed),runRetro's spend-cap accounting and non-mutation of run status, and the disjointness oftouchesProtectedPath/outsideAllowedPaths— verdict: works as described.check-prose.py) clean on every line this release added.learnwithparam/splitbill-demo: deferred pending your reset OK (same precedent as v2.7.0's live-run deferral) — the installed productionfactorypredates this branch, so a genuine run needs a clean baseline reset first.🤖 Generated with Claude Code