Redesign evolve-lite: no hooks, no custom modes — native memory + EVOLVE.md#266
Redesign evolve-lite: no hooks, no custom modes — native memory + EVOLVE.md#266illeatmyhat wants to merge 12 commits into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds per-platform EVOLVE docs and audit scripts, deterministic entity IO and adapt/doctor/provenance CLIs, installer managed-pointer/global-script delivery, and wide test updates including end-to-end provenance validation. ChangesEvolve-lite memory, audit, and provenance workflow
Sequence Diagram(s)sequenceDiagram
participant User
participant AdaptScript
participant EntityStore
participant AuditScript
participant Provenance
participant TranscriptStore
User->>AdaptScript: mirror native memory (file path, --type, --trigger)
AdaptScript->>EntityStore: write entity (type/slug + native_path)
User->>AuditScript: record consulted entity ids
Provenance->>AuditScript: read recall events
Provenance->>TranscriptStore: locate transcript for session_id
Provenance->>EntityStore: read entity excerpt
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
af8d706 to
be2fdf9
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py (1)
1-189:⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy liftDoctor script incorrectly copied to Codex platform.
This script is labeled "Claude-only diagnostic" (line 3) and checks Claude-specific paths (
.claudeat line 93) and mechanisms (@importapproval), but it's deployed undercodex/plugins/. Per the PR objectives, Codex uses a different integration approach (pointer in~/.codex/AGENTS.mdrather than@import), so this canary-based diagnostic is not applicable.Either implement a Codex-specific health check or remove the doctor skill from the Codex plugin if no equivalent diagnostic is needed.
# Verify the integration differences between Claude and Codex rg -A 10 "Codex.*pointer|AGENTS\.md" --type md🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py` around lines 1 - 189, This doctor script is Claude-specific (uses CLAUDE.md, .claude transcripts and CLAUDE_IMPORT_LINE) but was copied into a Codex plugin; either drop it from the Codex plugin or rewrite it to perform a Codex-native health check. To fix: either 1) remove the doctor skill from this Codex plugin and any plugin manifest/skill registration that references main()/diagnose(), or 2) implement Codex logic by replacing Claude-specific constants and helpers (CLAUDE_IMPORT_LINE, _transcript_slug, _recent_transcripts, _canary_in_transcripts) and the diagnose() function to instead inspect Codex agent pointers (e.g. the AGENTS.md pointer format) and any Codex-installed evolve artifacts (use _evolve_dir/_evolve_dir logic as appropriate), and update main() to call the new Codex diagnose routine; ensure no references to .claude, CLAUDE.md, or transcript scanning remain if you choose the rewrite option.
🧹 Nitpick comments (16)
tests/platform_integrations/test_end_to_end_claude.py (1)
164-167: ⚡ Quick winAssert exactly one entity id line for test precision.
The test extracts lines containing "Entity id:" and uses the first one, but only checks that the list is non-empty. If the script mistakenly printed multiple entity id lines, the test would silently use the first and might not catch the bug.
🔍 Suggested assertion
id_lines = [ln for ln in adapt.stdout.splitlines() if ln.startswith("Entity id:")] - assert id_lines, f"adapt did not print an entity id:\n{adapt.stdout}" + assert len(id_lines) == 1, f"Expected exactly one entity id line, got {len(id_lines)}:\n{adapt.stdout}" adapted_entity_id = id_lines[0].split("Entity id:", 1)[1].strip()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/platform_integrations/test_end_to_end_claude.py` around lines 164 - 167, Ensure the test asserts there is exactly one "Entity id:" line to avoid silently using the wrong line: replace the loose truthy check on id_lines with an exact length assertion (e.g., assert len(id_lines) == 1) and keep the diagnostic message using adapt.stdout; then continue extracting adapted_entity_id from id_lines[0] as before so the test fails loudly if zero or multiple entity id lines are printed (refer to the id_lines and adapted_entity_id variables in this test).tests/platform_integrations/test_entity_io_core.py (1)
146-150: 💤 Low valueConsider using
pytest.mark.parametrizefor better test isolation.The loop writes multiple entities to the same
tmp_path, causing filename collisions (the second and third writes get-2,-3suffixes). While the test correctly validates that all files land in theguideline/directory, using@pytest.mark.parametrizewould provide better test isolation and clearer pytest output showing which specific invalid type value failed.♻️ Optional parametrize refactor
+ `@pytest.mark.parametrize`("bad_type", ["", " ", "!!!"]) - def test_empty_or_invalid_type_defaults_to_guideline(self, tmp_path): - for bad_type in ("", " ", "!!!"): - entity = {"type": bad_type, "content": "Some content."} - path = entity_io.write_entity_file(tmp_path, entity) - assert path.parent == tmp_path / "guideline" + def test_empty_or_invalid_type_defaults_to_guideline(self, tmp_path, bad_type): + entity = {"type": bad_type, "content": "Some content."} + path = entity_io.write_entity_file(tmp_path, entity) + assert path.parent == tmp_path / "guideline"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/platform_integrations/test_entity_io_core.py` around lines 146 - 150, Replace the manual loop in test_empty_or_invalid_type_defaults_to_guideline with pytest.mark.parametrize so each bad_type value runs as a separate test invocation; call entity_io.write_entity_file(tmp_path, entity) inside the test using the param bad_type and assert path.parent == tmp_path / "guideline" — this avoids filename collisions and gives clearer pytest output for the test function test_empty_or_invalid_type_defaults_to_guideline.tests/platform_integrations/test_doctor.py (1)
50-63: 💤 Low valueConsider renaming
claude_mdparameter for clarity.The parameter name
claude_mdsuggests it controls whether the CLAUDE.md file is created, but it actually controls whether the@.evolve/EVOLVE.mdimport line is included. The file is always created. A name likeinclude_import_lineorhas_import_linewould better communicate the parameter's purpose.📝 Suggested parameter rename
-def _make_project(root, *, claude_md=True, evolve_md=True, canary=True): +def _make_project(root, *, include_import_line=True, evolve_md=True, canary=True): """Build a fake project tree under `root`.""" root.mkdir(parents=True, exist_ok=True) - if claude_md: + if include_import_line: (root / "CLAUDE.md").write_text(f"# Project rules\n\n{_IMPORT_LINE}\n", encoding="utf-8") else: (root / "CLAUDE.md").write_text("# Project rules\n", encoding="utf-8")And update call sites:
- _make_project(root, claude_md=False) + _make_project(root, include_import_line=False)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/platform_integrations/test_doctor.py` around lines 50 - 63, Rename the boolean parameter claude_md on function _make_project to a clearer name (e.g., include_import_line or has_import_line) because the flag controls whether the import line is written into CLAUDE.md/EVOLVE.md rather than whether CLAUDE.md is created; update the function signature in _make_project and every call site that passes claude_md to use the new parameter name, and ensure the internal conditional that writes the import line uses the new parameter name (refer to function _make_project and its callers in tests/platform_integrations/test_doctor.py).platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.py (3)
69-82: ⚖️ Poor tradeoffConsider extracting
_claude_transcript_slugto shared library.The comment explicitly notes this function is duplicated from
doctor.pyand asks maintainers to keep both in sync manually. This is a maintenance burden and a source of potential divergence bugs. Since both scripts already import from a sharedlib/evolve-lite/directory, consider moving this utility toentity_io.pyor a new shared module to eliminate the duplication.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.py` around lines 69 - 82, Extract the duplicated slug logic into a shared utility (e.g., add a function named claude_transcript_slug in the existing lib/evolve-lite/entity_io.py or a new lib/evolve-lite/utils.py), move the docstring and regex implementation from _claude_transcript_slug into that shared function, then replace the local _claude_transcript_slug in provenance.py and the corresponding _transcript_slug in doctor.py to import and call the shared claude_transcript_slug; ensure the new shared function accepts the same parameter (root), preserves behavior and examples in the docstring, and update imports in both scripts accordingly so there is no duplicate implementation.
160-166: ⚡ Quick winImprove resilience: skip malformed lines with logging.
The code silently skips lines that fail JSON parsing. While this prevents crashes, it also hides potential data corruption in the audit log. Consider logging a warning when lines are skipped so that corrupted audit logs can be detected and fixed.
📋 Suggested improvement
for line in audit_log.read_text(encoding="utf-8").splitlines(): if not line.strip(): continue try: event = json.loads(line) except json.JSONDecodeError: + log(f"Skipping malformed audit log line: {line[:100]}") continue🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.py` around lines 160 - 166, The loop that reads audit_log lines currently swallows JSONDecodeError silently; update the except block for json.JSONDecodeError (the one around json.loads(line) inside the for over audit_log.read_text(...).splitlines()) to log a warning containing the problematic line (or its index/preview) and any parse error details using the module logger (or create one if absent) before continuing, so malformed audit lines are recorded for investigation.
125-130: ⚖️ Poor tradeoffHandle potential performance issue with JSON parsing in loop.
The code opens and parses every
trajectory_*.jsonfile (excluding those already matched) to search for a matchingsession_id. For repositories with many trajectory files, this could become slow. Consider whether this fallback pattern is common enough to warrant optimization (e.g., caching or indexing).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.py` around lines 125 - 130, The loop currently calls path.read_text(...) and json.loads for every trajectory_*.json to match session_id, which will be slow at scale; optimize by avoiding full JSON deserialization on each file — either maintain an on-disk index (map session_id -> path) updated when files are written, or perform a cheaper scan before json.loads (e.g., read a small prefix/chunk or use a regex/search for the "session_id" field) and only json.loads when the quick check matches; update the code that references path.read_text and json.loads in this search routine (and any writer that creates trajectory_*.json) to build/refresh the index or implement the quick pre-check.platform-integrations/bob/evolve-lite/EVOLVE.md (1)
26-28: ⚡ Quick winAdd language identifier to code fence.
The code fence should specify
bashorshellas the language identifier to improve rendering and accessibility.📝 Proposed fix
-``` +```bash python3 ~/.bob/evolve-lite/audit_recall.py <file> [<file> ...]</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@platform-integrations/bob/evolve-lite/EVOLVE.mdaround lines 26 - 28, The
fenced code block in EVOLVE.md that shows the command "python3
~/.bob/evolve-lite/audit_recall.py [ ...]" is missing a language
identifier; update that fenced block to use a shell language tag (e.g., "bash"
or "shell") so the fence reads like ```bash and retains the same contents,
ensuring proper rendering and accessibility for the command example.</details> <!-- cr-comment:v1:a6fabe306132b2403a59a760 --> _Source: Linters/SAST tools_ </blockquote></details> <details> <summary>platform-integrations/bob/evolve-lite/scripts/audit_recall.py (1)</summary><blockquote> `53-56`: _⚡ Quick win_ **Consider adding error handling for file operations.** The script writes to the audit log without catching potential `OSError` exceptions. While the directory creation is handled with `exist_ok=True`, write failures (e.g., permission errors, disk full) will cause an unhandled exception. Given that this script is invoked by the agent, surfacing write failures explicitly would make debugging easier. <details> <summary>🛡️ Suggested error handling</summary> ```diff - log = _evolve_dir() / "audit.log" - log.parent.mkdir(parents=True, exist_ok=True) - with log.open("a", encoding="utf-8") as fh: - fh.write(json.dumps(row) + "\n") + try: + log = _evolve_dir() / "audit.log" + log.parent.mkdir(parents=True, exist_ok=True) + with log.open("a", encoding="utf-8") as fh: + fh.write(json.dumps(row) + "\n") + except OSError as exc: + print(f"Error: failed to write audit log: {exc}", file=sys.stderr) + return 1 ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/bob/evolve-lite/scripts/audit_recall.py` around lines 53 - 56, The audit log write currently opens and appends to the file returned by _evolve_dir() without handling file I/O errors; wrap the file open/write block that uses log = _evolve_dir() / "audit.log" and the with log.open("a", ...) as fh: fh.write(json.dumps(row) + "\n") in a try/except that catches OSError (and optionally Exception), log the error (using the module logger or print) with context including the path and the exception, and either re-raise or surface a clear error/return so the caller/agent can detect the failure instead of crashing silently. ``` </details> <!-- cr-comment:v1:604a31a7e5bf3e6a316194bd --> </blockquote></details> <details> <summary>platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/scripts/adapt_memory.py (2)</summary><blockquote> `1-29`: _💤 Low value_ **Consider clarifying the platform-specific comment.** Line 3 states this is a "Claude-only" script, but it's located in the Bob integration directory. While the SKILL.md correctly documents that this feature is a no-op on Bob, the docstring could cause confusion. Consider adding a note that this script is rendered across platforms but only functional on Claude. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/scripts/adapt_memory.py` around lines 1 - 29, Update the module-level docstring in adapt_memory.py to clarify that although the script is labeled "Claude-only" it is present in the Bob integration tree for consistency and is rendered on all platforms but only functional when running against Claude; specifically, edit the opening lines of the docstring (the "Adapt Memory Script (Claude-only)" header and the first paragraph) to add a short note stating the script is included in other integrations (e.g., Bob) for completeness but is a no-op there, and keep the rest of the usage and behavior text intact so readers understand that real functionality applies only to Claude while the file may appear in other integration directories. ``` </details> <!-- cr-comment:v1:3f0b8cd4784d8fdb9e5076d5 --> --- `107-107`: **Refute: relative `native_path` won’t break provenance lookups.** `native_path` is only persisted into entity frontmatter; the evolve-lite provenance flow resolves recalled entities by `entity_id` from `entities/<type>/<name>.md` and locates transcripts via `session_id` (not by reading `native_path` as a filesystem path). Optional improvement: when stamping `native_path` in `adapt_memory.py`, resolve `args.memory_path` to an absolute path for more stable metadata for any external tooling. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/scripts/adapt_memory.py` at line 107, The current assignment memory_path = Path(args.memory_path).expanduser() leaves a relative native_path; update the stamping in adapt_memory.py to produce an absolute, stable path by resolving the expanded path (e.g., call resolve with strict=False) so native_path is an absolute path for external tooling while avoiding errors if the path doesn't exist; change the assignment that uses args.memory_path/Path(...) accordingly. ``` </details> <!-- cr-comment:v1:e7248503714712b8cf237f71 --> </blockquote></details> <details> <summary>plugin-source/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py (1)</summary><blockquote> `107-134`: _⚡ Quick win_ **Consider using the resolved path for consistency.** Line 140 stores `args.memory_path` (the original CLI argument, which might be unexpanded like `~/foo`) in the `native_path` frontmatter field. For consistency, consider using `str(memory_path)` (the resolved and expanded path from line 107) so the stored path is always absolute. <details> <summary>♻️ Proposed change</summary> ```diff entity = { "type": args.type, "trigger": args.trigger, "content": content, "source": "native-memory", - "native_path": args.memory_path, + "native_path": str(memory_path), } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugin-source/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py` around lines 107 - 134, The frontmatter currently stores the original CLI string (args.memory_path) which may be unexpanded; change the code that sets the native_path frontmatter to use the resolved Path created earlier (memory_path) instead (e.g., use str(memory_path) or memory_path.as_posix()) so the saved native_path is always the expanded/resolved path; update the assignment that writes native_path in the frontmatter block (referencing args.memory_path -> memory_path) near where memory_path is created and read (see variables memory_path, args.memory_path and the frontmatter/native_path field). ``` </details> <!-- cr-comment:v1:367ef53dee5757e81648e0b1 --> </blockquote></details> <details> <summary>plugin-source/skills/evolve-lite/provenance/scripts/provenance.py (1)</summary><blockquote> `69-82`: _⚖️ Poor tradeoff_ **Consider extracting `_claude_transcript_slug()` to a shared utility.** This function duplicates logic from `doctor.py` (lines 81-87). The comment acknowledges manual synchronization, but keeping identical logic in sync by hand is fragile—if Claude's slugification algorithm changes or requires adjustment, both copies must be updated independently, risking divergence. While the "independent scripts" constraint is noted, both scripts already share `lib/evolve-lite/entity_io.py`. A shared `transcript_utils.py` module in `lib/evolve-lite/` could centralize this logic without coupling the scripts' top-level flow, eliminating the synchronization risk. Additionally, the `import re` at line 80 inside the function is non-idiomatic; standard practice places imports at module level. <details> <summary>♻️ Refactor option: shared utility module</summary> Create `plugin-source/lib/transcript_utils.py`: ```python """Shared transcript-related utilities.""" import re def claude_transcript_slug(root): """Claude derives a project's transcript dir name by replacing every non-alphanumeric character in the absolute project path with ``-``. e.g. /Users/x/Documents/kaizen -> -Users-x-Documents-kaizen """ return re.sub(r"[^A-Za-z0-9]", "-", str(root)) ``` Then in both `doctor.py` and `provenance.py`: ```python from transcript_utils import claude_transcript_slug as _claude_transcript_slug ``` This eliminates duplication while preserving script independence. </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugin-source/skills/evolve-lite/provenance/scripts/provenance.py` around lines 69 - 82, The _claude_transcript_slug function in provenance.py duplicates logic from doctor.py and does a local import of re; extract this logic to a shared utility module (e.g., plugin-source/lib/transcript_utils.py or lib/evolve-lite/transcript_utils.py) that defines a single claude_transcript_slug (or _claude_transcript_slug) function with the re import at module level, then update provenance.py and doctor.py to import and use that shared function instead of their local copies; ensure the new utility preserves the current regex r"[^A-Za-z0-9]" and string conversion behavior. ``` </details> <!-- cr-comment:v1:bac4770df8f93d1fd93da808 --> </blockquote></details> <details> <summary>platform-integrations/claude/plugins/evolve-lite/EVOLVE.md (1)</summary><blockquote> `21-23`: _⚡ Quick win_ **Add language specifier to fenced code block.** The fenced code block should specify `bash` or `shell` as the language for proper syntax highlighting and to satisfy the markdownlint rule. <details> <summary>✨ Proposed fix</summary> ```diff -``` +```bash python3 ~/.claude/evolve-lite/audit_recall.py <id> [<id> ...] ``` ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@platform-integrations/claude/plugins/evolve-lite/EVOLVE.mdaround lines 21 -
23, Update the fenced code block in EVOLVE.md that shows the python3
audit_recall command to include a language specifier (e.g., change the opening
fence fromtobash or ```shell) so markdownlint and syntax highlighting
recognize it; locate the block containing "python3
~/.claude/evolve-lite/audit_recall.py [ ...]" and add the language
token to the opening fence.</details> <!-- cr-comment:v1:e13faed34e1794c749fbb6a2 --> _Source: Linters/SAST tools_ </blockquote></details> <details> <summary>platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py (1)</summary><blockquote> `107-141`: **Clarify `native_path` semantics: it’s intentionally stamped from the original CLI arg** - `adapt_memory.py` expands `args.memory_path` for the “file exists / can read” checks, but stores `entity["native_path"] = args.memory_path` unchanged; this matches `test_id_is_type_slash_name_and_native_path_stamped`, which asserts the parsed `native_path` equals the exact `str(native)` passed on the CLI. - No other in-repo code references the `native_path` key (only frontmatter serialization/deserialization), so any need for `expanduser()` in provenance/audit can’t be confirmed here. - Optional: if provenance/audit requires a resolvable filesystem path, consider also storing a resolved/expanded field (e.g., `native_path_resolved`) in the entity. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py` around lines 107 - 141, The code currently expands args.memory_path to memory_path for file checks but intentionally preserves the original CLI string in entity["native_path"] (args.memory_path) to satisfy tests like test_id_is_type_slash_name_and_native_path_stamped; keep that behavior in adapt_memory.py (do not replace entity["native_path"] with memory_path), and if you need a resolvable filesystem path for provenance add a separate field (e.g., "native_path_resolved") set to memory_path.as_posix() or str(memory_path) after expansion; locate this logic around the parse_native_memory/name/description/body handling and the entity dict construction where slugify(...) and parse_native_memory(...) are used. ``` </details> <!-- cr-comment:v1:08ccb6f5d1cd3caf16ccc95a --> </blockquote></details> <details> <summary>platform-integrations/codex/plugins/evolve-lite/EVOLVE.md (1)</summary><blockquote> `26-28`: _⚡ Quick win_ **Add language specifier to fenced code block.** The fenced code block at line 26 is missing a language specifier, which reduces syntax highlighting and readability. <details> <summary>📝 Proposed fix</summary> ```diff -``` +```bash python3 ~/.codex/evolve-lite/audit_recall.py <file> [<file> ...] ``` ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@platform-integrations/codex/plugins/evolve-lite/EVOLVE.mdaround lines 26 -
28, The fenced code block containing the commandpython3 ~/.codex/evolve-lite/audit_recall.py <file> [<file> ...]in EVOLVE.md lacks a
language specifier; update the opening fence fromtobash so the block
becomes a bash code block (add the word bash immediately after the opening
backticks) to enable syntax highlighting and improve readability.</details> <!-- cr-comment:v1:72976393a7adb2e6edb3340e --> _Source: Linters/SAST tools_ </blockquote></details> <details> <summary>platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py (1)</summary><blockquote> `69-82`: _⚖️ Poor tradeoff_ **Duplication acknowledged but still a maintenance risk.** The `_claude_transcript_slug` function is manually kept in sync with `doctor.py`. While the comment acknowledges this trade-off, consider extracting the shared logic into a common utility module under `lib/evolve-lite/` so both scripts import it. This would eliminate manual sync risk. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py` around lines 69 - 82, Extract the shared slug logic from _claude_transcript_slug (and the corresponding _transcript_slug in doctor.py) into a single utility function (e.g., slugify_project_path) in a new common module under lib/evolve-lite (or another shared package), update both provenance.py and doctor.py to import and call that utility instead of duplicating re.sub logic, and remove the duplicated implementation and comment about manual sync; keep the same behavior (replace non-alphanumeric chars with "-") and add a small unit test for the new slugify_project_path to prevent regressions. ``` </details> <!-- cr-comment:v1:cb737f9af067267466c701dd --> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.Inline comments:
In
@platform-integrations/claude/plugins/evolve-lite/lib/evolve-lite/entity_io.py:
- Around line 357-386: The write_entity_file function accepts a caller-provided
filename but uses it directly to build the target path, allowing path traversal;
fix write_entity_file by validating/sanitizing the filename parameter (e.g., run
it through slugify or reject inputs containing path separators, leading slashes,
or “..”), then construct the target path and assert it is inside the computed
type_dir (use Path.resolve and compare parents) before writing; update
references to the slug variable (filename/slug) in write_entity_file to use the
sanitized value and raise a clear error if validation fails.In
@platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py:
- Around line 150-151: The docstring for read_recall_rows incorrectly states it
"Yield"s results while the implementation builds and returns a list; update the
docstring to "Return a list of (session_id, [entity_id, ...]) for everyrecall
audit row" (or, if you prefer lazy evaluation, refactor the function to yield
each (session_id, entity_ids) instead); locate the function read_recall_rows and
either replace "Yield" with "Return a list of" in its docstring or convert the
code that appends to a list into yielding each tuple so the implementation and
docstring match.In
@platform-integrations/claw-code/plugins/evolve-lite/EVOLVE.md:
- Around line 26-28: The fenced code block showing the CLI invocation lacks a
language tag; update the opening backticks for that block in EVOLVE.md fromtobash (or ```shell) so the snippet "python3
~/.claw/evolve-lite/audit_recall.py [ ...]" is rendered as a bash
shell block and satisfies the linter.In
@platform-integrations/claw-code/plugins/evolve-lite/lib/evolve-lite/entity_io.py:
- Around line 357-386: The write_entity_file function currently uses the
filename param directly to build the target path; validate/sanitize any provided
filename to prevent path traversal by either: (a) running it through the
existing slugify function (like slug = slugify(filename)) so it becomes a safe
slug, or (b) rejecting filenames containing path separators or parent-segment
patterns ("/", "\", "..") and raising an error; after computing the target path
(type_dir / f"{slug}.md") resolve both type_dir and target path and assert the
target is within type_dir (compare resolved parents) before writing to enforce
confinement; update references to filename/slug logic in write_entity_file and
keep existing overwrite collision behavior intact.In
@platform-integrations/codex/plugins/evolve-lite/lib/evolve-lite/entity_io.py:
- Around line 357-386: The write_entity_file function currently accepts a
caller-provided filename without sanitization allowing path traversal; update
write_entity_file to reject or sanitize the filename parameter (e.g., run
slugify on filename or validate to disallow path separators, "..", and null
bytes) before constructing the target path, and after joining type_dir with the
filename ensure the final path is within type_dir (use a resolved/absolute
compare) to prevent escaping the intended directory; reference the symbols
write_entity_file, entity_type/type_dir, slug and ensure overwrite behavior
remains the same.In
@platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.md:
- Around line 55-58: The SKILL.md text claiming the trajectory locator always
falls back to the native Claude transcript is inaccurate for Codex; update the
paragraph describing the locator (lines referencing.evolve/trajectories/and
~/.claude/projects/<slug>/<session-id>.jsonl) to state that provenance.py
attempts.evolve/trajectories/first and then tries the native Claude
transcript but that for Codex/Bob the native transcript resolution can return
None, so provenance may emit missing fields (e.g.,missing: ["trajectory"])
rather than “working” — mention provenance.py and the trajectory lookup behavior
explicitly and clarify the possible None result for Codex transcripts.
Outside diff comments:
In
@platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py:
- Around line 1-189: This doctor script is Claude-specific (uses CLAUDE.md,
.claude transcripts and CLAUDE_IMPORT_LINE) but was copied into a Codex plugin;
either drop it from the Codex plugin or rewrite it to perform a Codex-native
health check. To fix: either 1) remove the doctor skill from this Codex plugin
and any plugin manifest/skill registration that references main()/diagnose(), or
- implement Codex logic by replacing Claude-specific constants and helpers
(CLAUDE_IMPORT_LINE, _transcript_slug, _recent_transcripts,
_canary_in_transcripts) and the diagnose() function to instead inspect Codex
agent pointers (e.g. the AGENTS.md pointer format) and any Codex-installed
evolve artifacts (use _evolve_dir/_evolve_dir logic as appropriate), and update
main() to call the new Codex diagnose routine; ensure no references to .claude,
CLAUDE.md, or transcript scanning remain if you choose the rewrite option.
Nitpick comments:
In@platform-integrations/bob/evolve-lite/EVOLVE.md:
- Around line 26-28: The fenced code block in EVOLVE.md that shows the command
"python3 ~/.bob/evolve-lite/audit_recall.py [ ...]" is missing a
language identifier; update that fenced block to use a shell language tag (e.g.,
"bash" or "shell") so the fence reads like ```bash and retains the same
contents, ensuring proper rendering and accessibility for the command example.In
@platform-integrations/bob/evolve-lite/scripts/audit_recall.py:
- Around line 53-56: The audit log write currently opens and appends to the file
returned by _evolve_dir() without handling file I/O errors; wrap the file
open/write block that uses log = _evolve_dir() / "audit.log" and the with
log.open("a", ...) as fh: fh.write(json.dumps(row) + "\n") in a try/except that
catches OSError (and optionally Exception), log the error (using the module
logger or print) with context including the path and the exception, and either
re-raise or surface a clear error/return so the caller/agent can detect the
failure instead of crashing silently.In
@platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/scripts/adapt_memory.py:
- Around line 1-29: Update the module-level docstring in adapt_memory.py to
clarify that although the script is labeled "Claude-only" it is present in the
Bob integration tree for consistency and is rendered on all platforms but only
functional when running against Claude; specifically, edit the opening lines of
the docstring (the "Adapt Memory Script (Claude-only)" header and the first
paragraph) to add a short note stating the script is included in other
integrations (e.g., Bob) for completeness but is a no-op there, and keep the
rest of the usage and behavior text intact so readers understand that real
functionality applies only to Claude while the file may appear in other
integration directories.- Line 107: The current assignment memory_path =
Path(args.memory_path).expanduser() leaves a relative native_path; update the
stamping in adapt_memory.py to produce an absolute, stable path by resolving the
expanded path (e.g., call resolve with strict=False) so native_path is an
absolute path for external tooling while avoiding errors if the path doesn't
exist; change the assignment that uses args.memory_path/Path(...) accordingly.In
@platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.py:
- Around line 69-82: Extract the duplicated slug logic into a shared utility
(e.g., add a function named claude_transcript_slug in the existing
lib/evolve-lite/entity_io.py or a new lib/evolve-lite/utils.py), move the
docstring and regex implementation from _claude_transcript_slug into that shared
function, then replace the local _claude_transcript_slug in provenance.py and
the corresponding _transcript_slug in doctor.py to import and call the shared
claude_transcript_slug; ensure the new shared function accepts the same
parameter (root), preserves behavior and examples in the docstring, and update
imports in both scripts accordingly so there is no duplicate implementation.- Around line 160-166: The loop that reads audit_log lines currently swallows
JSONDecodeError silently; update the except block for json.JSONDecodeError (the
one around json.loads(line) inside the for over
audit_log.read_text(...).splitlines()) to log a warning containing the
problematic line (or its index/preview) and any parse error details using the
module logger (or create one if absent) before continuing, so malformed audit
lines are recorded for investigation.- Around line 125-130: The loop currently calls path.read_text(...) and
json.loads for every trajectory_.json to match session_id, which will be slow
at scale; optimize by avoiding full JSON deserialization on each file — either
maintain an on-disk index (map session_id -> path) updated when files are
written, or perform a cheaper scan before json.loads (e.g., read a small
prefix/chunk or use a regex/search for the "session_id" field) and only
json.loads when the quick check matches; update the code that references
path.read_text and json.loads in this search routine (and any writer that
creates trajectory_.json) to build/refresh the index or implement the quick
pre-check.In
@platform-integrations/claude/plugins/evolve-lite/EVOLVE.md:
- Around line 21-23: Update the fenced code block in EVOLVE.md that shows the
python3 audit_recall command to include a language specifier (e.g., change the
opening fence fromtobash or ```shell) so markdownlint and syntax
highlighting recognize it; locate the block containing "python3
~/.claude/evolve-lite/audit_recall.py [ ...]" and add the language
token to the opening fence.In
@platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py:
- Around line 107-141: The code currently expands args.memory_path to
memory_path for file checks but intentionally preserves the original CLI string
in entity["native_path"] (args.memory_path) to satisfy tests like
test_id_is_type_slash_name_and_native_path_stamped; keep that behavior in
adapt_memory.py (do not replace entity["native_path"] with memory_path), and if
you need a resolvable filesystem path for provenance add a separate field (e.g.,
"native_path_resolved") set to memory_path.as_posix() or str(memory_path) after
expansion; locate this logic around the
parse_native_memory/name/description/body handling and the entity dict
construction where slugify(...) and parse_native_memory(...) are used.In
@platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py:
- Around line 69-82: Extract the shared slug logic from _claude_transcript_slug
(and the corresponding _transcript_slug in doctor.py) into a single utility
function (e.g., slugify_project_path) in a new common module under
lib/evolve-lite (or another shared package), update both provenance.py and
doctor.py to import and call that utility instead of duplicating re.sub logic,
and remove the duplicated implementation and comment about manual sync; keep the
same behavior (replace non-alphanumeric chars with "-") and add a small unit
test for the new slugify_project_path to prevent regressions.In
@platform-integrations/codex/plugins/evolve-lite/EVOLVE.md:
- Around line 26-28: The fenced code block containing the command
python3 ~/.codex/evolve-lite/audit_recall.py <file> [<file> ...]in EVOLVE.md lacks a
language specifier; update the opening fence fromtobash so the block
becomes a bash code block (add the word bash immediately after the opening
backticks) to enable syntax highlighting and improve readability.In
@plugin-source/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py:
- Around line 107-134: The frontmatter currently stores the original CLI string
(args.memory_path) which may be unexpanded; change the code that sets the
native_path frontmatter to use the resolved Path created earlier (memory_path)
instead (e.g., use str(memory_path) or memory_path.as_posix()) so the saved
native_path is always the expanded/resolved path; update the assignment that
writes native_path in the frontmatter block (referencing args.memory_path ->
memory_path) near where memory_path is created and read (see variables
memory_path, args.memory_path and the frontmatter/native_path field).In
@plugin-source/skills/evolve-lite/provenance/scripts/provenance.py:
- Around line 69-82: The _claude_transcript_slug function in provenance.py
duplicates logic from doctor.py and does a local import of re; extract this
logic to a shared utility module (e.g., plugin-source/lib/transcript_utils.py or
lib/evolve-lite/transcript_utils.py) that defines a single
claude_transcript_slug (or _claude_transcript_slug) function with the re import
at module level, then update provenance.py and doctor.py to import and use that
shared function instead of their local copies; ensure the new utility preserves
the current regex r"[^A-Za-z0-9]" and string conversion behavior.In
@tests/platform_integrations/test_doctor.py:
- Around line 50-63: Rename the boolean parameter claude_md on function
_make_project to a clearer name (e.g., include_import_line or has_import_line)
because the flag controls whether the import line is written into
CLAUDE.md/EVOLVE.md rather than whether CLAUDE.md is created; update the
function signature in _make_project and every call site that passes claude_md to
use the new parameter name, and ensure the internal conditional that writes the
import line uses the new parameter name (refer to function _make_project and its
callers in tests/platform_integrations/test_doctor.py).In
@tests/platform_integrations/test_end_to_end_claude.py:
- Around line 164-167: Ensure the test asserts there is exactly one "Entity id:"
line to avoid silently using the wrong line: replace the loose truthy check on
id_lines with an exact length assertion (e.g., assert len(id_lines) == 1) and
keep the diagnostic message using adapt.stdout; then continue extracting
adapted_entity_id from id_lines[0] as before so the test fails loudly if zero or
multiple entity id lines are printed (refer to the id_lines and
adapted_entity_id variables in this test).In
@tests/platform_integrations/test_entity_io_core.py:
- Around line 146-150: Replace the manual loop in
test_empty_or_invalid_type_defaults_to_guideline with pytest.mark.parametrize so
each bad_type value runs as a separate test invocation; call
entity_io.write_entity_file(tmp_path, entity) inside the test using the param
bad_type and assert path.parent == tmp_path / "guideline" — this avoids filename
collisions and gives clearer pytest output for the test function
test_empty_or_invalid_type_defaults_to_guideline.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro **Run ID**: `f555117a-f7b7-4088-a6c7-464b84e716e5` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between a8a6fe4c8d422c63c92b018f28d21df3b79c7888 and af8d706e1b359e8567a6dcbf0b44f2db134420f4. </details> <details> <summary>📒 Files selected for processing (64)</summary> * `platform-integrations/bob/evolve-lite/EVOLVE.md` * `platform-integrations/bob/evolve-lite/commands/evolve-lite-adapt-memory.md` * `platform-integrations/bob/evolve-lite/commands/evolve-lite-doctor.md` * `platform-integrations/bob/evolve-lite/lib/evolve-lite/entity_io.py` * `platform-integrations/bob/evolve-lite/scripts/audit_recall.py` * `platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/SKILL.md` * `platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/scripts/adapt_memory.py` * `platform-integrations/bob/evolve-lite/skills/evolve-lite-doctor/SKILL.md` * `platform-integrations/bob/evolve-lite/skills/evolve-lite-doctor/scripts/doctor.py` * `platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/SKILL.md` * `platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.py` * `platform-integrations/claude/plugins/evolve-lite/EVOLVE.md` * `platform-integrations/claude/plugins/evolve-lite/hooks/hooks.json` * `platform-integrations/claude/plugins/evolve-lite/lib/evolve-lite/entity_io.py` * `platform-integrations/claude/plugins/evolve-lite/scripts/audit_recall.py` * `platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.md` * `platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py` * `platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.md` * `platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py` * `platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.md` * `platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py` * `platform-integrations/claw-code/plugins/evolve-lite/EVOLVE.md` * `platform-integrations/claw-code/plugins/evolve-lite/lib/evolve-lite/entity_io.py` * `platform-integrations/claw-code/plugins/evolve-lite/scripts/audit_recall.py` * `platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.md` * `platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py` * `platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.md` * `platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py` * `platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.md` * `platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py` * `platform-integrations/codex/plugins/evolve-lite/EVOLVE.md` * `platform-integrations/codex/plugins/evolve-lite/lib/evolve-lite/entity_io.py` * `platform-integrations/codex/plugins/evolve-lite/scripts/audit_recall.py` * `platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.md` * `platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py` * `platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.md` * `platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py` * `platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.md` * `platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py` * `platform-integrations/install.sh` * `plugin-source/EVOLVE.md.j2` * `plugin-source/_claude/hooks/hooks.json` * `plugin-source/build_plugins.py` * `plugin-source/lib/entity_io.py` * `plugin-source/scripts/audit_recall.py` * `plugin-source/skills/evolve-lite/adapt-memory/SKILL.md.j2` * `plugin-source/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py` * `plugin-source/skills/evolve-lite/doctor/SKILL.md.j2` * `plugin-source/skills/evolve-lite/doctor/scripts/doctor.py` * `plugin-source/skills/evolve-lite/provenance/SKILL.md.j2` * `plugin-source/skills/evolve-lite/provenance/scripts/provenance.py` * `tests/platform_integrations/conftest.py` * `tests/platform_integrations/test_audit_recall.py` * `tests/platform_integrations/test_claude.py` * `tests/platform_integrations/test_codex.py` * `tests/platform_integrations/test_doctor.py` * `tests/platform_integrations/test_dry_run.py` * `tests/platform_integrations/test_end_to_end_claude.py` * `tests/platform_integrations/test_entity_io_core.py` * `tests/platform_integrations/test_idempotency.py` * `tests/platform_integrations/test_marker_line.py` * `tests/platform_integrations/test_plugin_structure.py` * `tests/platform_integrations/test_preservation.py` * `tests/platform_integrations/test_provenance.py` </details> <details> <summary>💤 Files with no reviewable changes (2)</summary> * platform-integrations/claude/plugins/evolve-lite/hooks/hooks.json * plugin-source/_claude/hooks/hooks.json </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
|
No vulnerabilities found. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
tests/platform_integrations/test_entity_io_core.py (1)
13-15: Import isolation concern doesn’t apply hereThe suggested
sys.modulescollision risk is unlikely: withintests/platform_integrations, onlytest_entity_io.pyandtest_entity_io_core.pyimportentity_io, and both add the exact sameplatform-integrations/claude/plugins/evolve-lite/lib/evolve-litedirectory tosys.path, so both imports resolve to the same renderedentity_io.py.
Optional: load viaimportlib.util.spec_from_file_locationinstead of mutating globalsys.pathfor stronger hermeticity.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/platform_integrations/test_entity_io_core.py` around lines 13 - 15, The current sys.path insertion and top-level import of entity_io in test_entity_io_core.py risks global path mutation; replace that pattern by loading the module directly from its file using importlib.util.spec_from_file_location + importlib.util.module_from_spec and spec.loader.exec_module to create a private module object (assign it to the name entity_io in the test), and remove the sys.path.insert(0, ...) and any sys.modules manipulation so the test loads the exact file hermetically; reference the module name entity_io and the importlib utilities spec_from_file_location, module_from_spec, and exec_module when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@platform-integrations/bob/evolve-lite/EVOLVE.md`:
- Around line 26-28: The fenced code block containing the command `python3
~/.bob/evolve-lite/audit_recall.py <file> [<file> ...]` in EVOLVE.md lacks a
language tag; update that fence to include a shell tag (e.g., "bash") so the
block becomes a labeled fenced code block (` ```bash `) to satisfy markdownlint
MD040 and reduce lint noise.
In `@platform-integrations/claude/plugins/evolve-lite/EVOLVE.md`:
- Around line 21-23: The unlabeled fenced code block containing the shell
command "python3 ~/.claude/evolve-lite/audit_recall.py <id> [<id> ...]" should
be marked as a bash (or sh) block to satisfy MD040; update the fenced block in
EVOLVE.md that holds that command by adding the language tag (e.g., "bash")
immediately after the opening backticks so the block is rendered and linted
correctly.
In `@platform-integrations/codex/plugins/evolve-lite/EVOLVE.md`:
- Around line 26-28: Add a language tag to the fenced command block that
currently contains the command "python3 ~/.codex/evolve-lite/audit_recall.py
<file> [<file> ...]": change the opening triple-backtick to include a language
identifier such as bash (```bash) so the block is properly labeled for
linting/MD040 and consistent rendering.
---
Nitpick comments:
In `@tests/platform_integrations/test_entity_io_core.py`:
- Around line 13-15: The current sys.path insertion and top-level import of
entity_io in test_entity_io_core.py risks global path mutation; replace that
pattern by loading the module directly from its file using
importlib.util.spec_from_file_location + importlib.util.module_from_spec and
spec.loader.exec_module to create a private module object (assign it to the name
entity_io in the test), and remove the sys.path.insert(0, ...) and any
sys.modules manipulation so the test loads the exact file hermetically;
reference the module name entity_io and the importlib utilities
spec_from_file_location, module_from_spec, and exec_module when making the
change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bb5a71a0-7c11-43fb-9542-867e158a8e63
📒 Files selected for processing (64)
platform-integrations/bob/evolve-lite/EVOLVE.mdplatform-integrations/bob/evolve-lite/commands/evolve-lite-adapt-memory.mdplatform-integrations/bob/evolve-lite/commands/evolve-lite-doctor.mdplatform-integrations/bob/evolve-lite/lib/evolve-lite/audit_recall.pyplatform-integrations/bob/evolve-lite/lib/evolve-lite/entity_io.pyplatform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/SKILL.mdplatform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/scripts/adapt_memory.pyplatform-integrations/bob/evolve-lite/skills/evolve-lite-doctor/SKILL.mdplatform-integrations/bob/evolve-lite/skills/evolve-lite-doctor/scripts/doctor.pyplatform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/SKILL.mdplatform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.pyplatform-integrations/claude/plugins/evolve-lite/EVOLVE.mdplatform-integrations/claude/plugins/evolve-lite/hooks/hooks.jsonplatform-integrations/claude/plugins/evolve-lite/lib/evolve-lite/audit_recall.pyplatform-integrations/claude/plugins/evolve-lite/lib/evolve-lite/entity_io.pyplatform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.mdplatform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.pyplatform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.mdplatform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.pyplatform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.mdplatform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.pyplatform-integrations/claw-code/plugins/evolve-lite/EVOLVE.mdplatform-integrations/claw-code/plugins/evolve-lite/lib/evolve-lite/audit_recall.pyplatform-integrations/claw-code/plugins/evolve-lite/lib/evolve-lite/entity_io.pyplatform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.mdplatform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.pyplatform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.mdplatform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.pyplatform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.mdplatform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.pyplatform-integrations/codex/plugins/evolve-lite/EVOLVE.mdplatform-integrations/codex/plugins/evolve-lite/lib/evolve-lite/audit_recall.pyplatform-integrations/codex/plugins/evolve-lite/lib/evolve-lite/entity_io.pyplatform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.mdplatform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.pyplatform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.mdplatform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.pyplatform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.mdplatform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.pyplatform-integrations/install.shplugin-source/EVOLVE.md.j2plugin-source/_claude/hooks/hooks.jsonplugin-source/build_plugins.pyplugin-source/lib/audit_recall.pyplugin-source/lib/entity_io.pyplugin-source/skills/evolve-lite/adapt-memory/SKILL.md.j2plugin-source/skills/evolve-lite/adapt-memory/scripts/adapt_memory.pyplugin-source/skills/evolve-lite/doctor/SKILL.md.j2plugin-source/skills/evolve-lite/doctor/scripts/doctor.pyplugin-source/skills/evolve-lite/provenance/SKILL.md.j2plugin-source/skills/evolve-lite/provenance/scripts/provenance.pytests/platform_integrations/conftest.pytests/platform_integrations/test_audit_recall.pytests/platform_integrations/test_claude.pytests/platform_integrations/test_codex.pytests/platform_integrations/test_doctor.pytests/platform_integrations/test_dry_run.pytests/platform_integrations/test_end_to_end_claude.pytests/platform_integrations/test_entity_io_core.pytests/platform_integrations/test_idempotency.pytests/platform_integrations/test_marker_line.pytests/platform_integrations/test_plugin_structure.pytests/platform_integrations/test_preservation.pytests/platform_integrations/test_provenance.py
💤 Files with no reviewable changes (2)
- platform-integrations/claude/plugins/evolve-lite/hooks/hooks.json
- plugin-source/_claude/hooks/hooks.json
✅ Files skipped from review due to trivial changes (14)
- platform-integrations/bob/evolve-lite/skills/evolve-lite-doctor/SKILL.md
- platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/SKILL.md
- platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.md
- platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.md
- platform-integrations/bob/evolve-lite/commands/evolve-lite-doctor.md
- platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.md
- platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.md
- platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/SKILL.md
- platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/doctor/SKILL.md
- platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/SKILL.md
- plugin-source/skills/evolve-lite/adapt-memory/SKILL.md.j2
- platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.md
- platform-integrations/bob/evolve-lite/skills/evolve-lite-adapt-memory/scripts/adapt_memory.py
- platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (37)
- platform-integrations/bob/evolve-lite/commands/evolve-lite-adapt-memory.md
- plugin-source/skills/evolve-lite/doctor/SKILL.md.j2
- plugin-source/build_plugins.py
- plugin-source/skills/evolve-lite/provenance/SKILL.md.j2
- plugin-source/lib/entity_io.py
- tests/platform_integrations/test_dry_run.py
- platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py
- plugin-source/EVOLVE.md.j2
- tests/platform_integrations/test_claude.py
- platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py
- tests/platform_integrations/test_audit_recall.py
- tests/platform_integrations/test_marker_line.py
- tests/platform_integrations/conftest.py
- platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/provenance/SKILL.md
- platform-integrations/claude/plugins/evolve-lite/lib/evolve-lite/entity_io.py
- platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py
- tests/platform_integrations/test_plugin_structure.py
- platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/doctor/scripts/doctor.py
- platform-integrations/bob/evolve-lite/skills/evolve-lite-provenance/scripts/provenance.py
- platform-integrations/bob/evolve-lite/lib/evolve-lite/entity_io.py
- plugin-source/skills/evolve-lite/doctor/scripts/doctor.py
- tests/platform_integrations/test_codex.py
- platform-integrations/claw-code/plugins/evolve-lite/lib/evolve-lite/entity_io.py
- tests/platform_integrations/test_provenance.py
- tests/platform_integrations/test_end_to_end_claude.py
- tests/platform_integrations/test_doctor.py
- platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py
- plugin-source/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py
- plugin-source/skills/evolve-lite/provenance/scripts/provenance.py
- platform-integrations/bob/evolve-lite/skills/evolve-lite-doctor/scripts/doctor.py
- platform-integrations/claw-code/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py
- platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/provenance/scripts/provenance.py
- tests/platform_integrations/test_preservation.py
- platform-integrations/codex/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py
- platform-integrations/claude/plugins/evolve-lite/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py
- platform-integrations/install.sh
- tests/platform_integrations/test_idempotency.py
- entity_io.write_entity_file: sanitize the explicit `filename` arg through slugify() to harden against path traversal (.., /, \ collapse to a safe single segment); slugify is idempotent on already-slugged input so all existing callers/tests stay green. - provenance.read_recall_rows: fix docstring — it returns a list, not a generator, so "Yield ..." becomes "Return a list of ... tuples ...". - EVOLVE.md.j2: add `bash` language to the bare fenced audit_recall command blocks so all rendered platform EVOLVE.md files get a fenced language. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ex/bob plugins doctor's @import-canary diagnostic greps ~/.claude transcripts and is Claude-specific, so it's meaningless on codex/bob (Codex uses an ~/.codex/AGENTS.md pointer); exclude it from those plugins (and bob's auto-generated command), addressing CodeRabbit's Critical on PR #266. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Re: CodeRabbit's Critical — Claude-only Agreed the diagnostic is Claude-specific: it greps
|
…o hooks/modes) Replace evolve-lite's hook- and custom-mode-driven recall/learn with a self-directed memory methodology (EVOLVE.md) installed as an always-on instruction: - Bob: full EVOLVE.md content as a global rules file (~/.bob/rules/00-evolve-lite.md); drop the custom_modes.yaml merge. - Codex: a single always-read pointer line in ~/.codex/AGENTS.md -> ~/.codex/evolve-lite/EVOLVE.md copy; drop the UserPromptSubmit/SessionStart hooks and their generation code. - Recall is native (model reads ./.evolve/memory/MEMORY.md); a self-contained audit_recall.py logs consulted entries for provenance (session id from $CLAUDE_CODE_SESSION_ID / $CODEX_THREAD_ID, self-mint+echo fallback on bob). - FileOps: add sentinel-block and single-line marker injectors. - Installer tests rewritten to the new contract (229 passing). Phase 1 of the redesign; Claude/claw-code to follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…VE.md via CLAUDE.md @import Claude leans on its native self-directed memory; evolve adds only sharing + provenance as a thin EVOLVE.md, delivered through a single CLAUDE.md @import pointer (the import reference doubles as its own sentinel). - entity_io: accept arbitrary entity types (sanitized), not just guideline/preference, so Claude's native types pass straight through - new Claude-only adapt-memory skill: mirrors a just-saved native memory into .evolve/entities/<type>/ with an agent-synthesized trigger - EVOLVE.md.j2: thin Claude variant (native owns recall/save; evolve adds mirror-on-save + audit-on-recall); bob/codex EVOLVE.md unchanged - ClaudeInstaller: copy EVOLVE.md to <repo>/.evolve/, inject single @.evolve/EVOLVE.md line into <repo>/CLAUDE.md, copy audit_recall.py to ~/.claude/evolve-lite/; warn about the one-time external-import approval Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d import Claude's CLAUDE.md @import needs a one-time per-project approval; a declined (or previously-declined) approval silently disables the import with no error, making evolve a no-op on Claude. Reading Claude's internal approval flag is unreliable (undocumented ~/.claude.json key), so detect via a canary: - thin Claude EVOLVE.md carries a unique canary token that expands into the session transcript only when the import actually loads - new import-independent doctor skill greps the latest project transcript for the canary and reports OK / IMPORT_DISABLED (with claude project purge remediation) / NOT_INSTALLED / STALE_EVOLVE_MD / UNKNOWN - doctor extracts the token from the installed EVOLVE.md (no double-hardcode) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ully hookless) The Claude plugin still shipped the old hooks (UserPromptSubmit recall-manifest, SessionStart sync, Stop save-trajectory + learn), which conflict with the new native-memory + CLAUDE.md @import design (double recall/save). Remove the Claude hooks.json entirely so native+import is the sole mechanism; recall is native, save is native, sync/learn/provenance become explicit skills. Skills are unchanged and remain invokable (evolve-lite is not a no-op). Only the hook wiring is removed. bob/codex/claw untouched. Tests updated to assert the Claude plugin ships no hooks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rovenance Closes the correlation-id gap that broke provenance on Claude. The adapter now derives the entity slug from the native memory's name field, so the entity id is a deterministic, derivable <type>/<name> on both the save and recall sides, and re-mirroring overwrites in place (idempotent, no -N suffix). The entity also stamps native_path as a back-reference. - entity_io.write_entity_file: optional filename/overwrite for deterministic in-place writes (default behavior unchanged for existing callers); native_path added to _FRONTMATTER_KEYS - adapt_memory.py: parse native name, write <type>/<name>.md, print the id - Claude EVOLVE.md recall-audit now logs the entity id <type>/<name> (not native paths), which provenance resolves to .evolve/entities/<type>/<name>.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-transcript awareness Provenance was a fully-manual procedure with no deterministic plumbing, so the recall->entity->trajectory loop couldn't be closed or tested. Add provenance.py: - candidates: read audit recall rows, skip already-influenced pairs, resolve each entity id <type>/<name> to its file, locate the session trajectory, and emit JSONL judgment candidates (entities/trajectories that can't be found are emitted with a missing:[...] field, never silently dropped) - record: validate + persist an influence verdict via the existing log_influence writer (no duplicated write logic) - trajectory locator now also reads the NATIVE Claude transcript at ~/.claude/projects/<slug>/<sid>.jsonl (slug logic shared with doctor), so provenance works in the hookless world where no .evolve/trajectories/ is written The semantic verdict (followed/contradicted/not_applicable) stays agent-driven; provenance.py does only the deterministic matching/resolution + recording. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…2e guards in CI Add test_end_to_end_claude.py: drives the REAL rendered Claude scripts as subprocesses in sequence (save->adapt->audit->provenance->record) and asserts the entity id stays identical across adapt_memory, audit_recall, and provenance, that the native-transcript locator resolves, and that record+dedup closes the loop. A second test asserts gaps are surfaced (missing entity/trajectory) not dropped. No production code needed — the chain closes as built. Also drop the e2e marker from test_provenance.py and the new chain test: CI runs pytest with the default '-m not llm and not e2e' filter, so e2e-marked tests never execute in CI. These are sandboxed and fast (no real CLI/network), so they belong in the default suite as guards — matching test_doctor/test_entity_io_core. Default suite: 242 -> 252. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… top-level scripts/ dir
audit_recall.py is a self-contained, model-invoked executable; it lived in a
new top-level plugin-source/scripts/ dir that existed only for this one file.
Move it next to the shared lib (plugin-source/lib/ -> lib/evolve-lite/ on every
host) so it ships alongside entity_io/audit/config instead of carving out a
parallel scripts/ tree.
The installed, model-facing path is UNCHANGED: the installer still drops it at
~/.{claude,codex,bob}/evolve-lite/audit_recall.py (no lib/ segment) and EVOLVE.md
still invokes it there. Only the rendered SOURCE location moved; installer source
paths and three test path constants updated to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- entity_io.write_entity_file: sanitize the explicit `filename` arg through slugify() to harden against path traversal (.., /, \ collapse to a safe single segment); slugify is idempotent on already-slugged input so all existing callers/tests stay green. - provenance.read_recall_rows: fix docstring — it returns a list, not a generator, so "Yield ..." becomes "Return a list of ... tuples ...". - EVOLVE.md.j2: add `bash` language to the bare fenced audit_recall command blocks so all rendered platform EVOLVE.md files get a fenced language. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ex/bob plugins doctor's @import-canary diagnostic greps ~/.claude transcripts and is Claude-specific, so it's meaningless on codex/bob (Codex uses an ~/.codex/AGENTS.md pointer); exclude it from those plugins (and bob's auto-generated command), addressing CodeRabbit's Critical on PR #266. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5196fff to
63176c6
Compare
…gn artifacts uninstall is now migration-aware: it reverses the OLD pre-redesign install artifacts in addition to the new-design ones, so an upgrading user gets a true clean slate. - Codex (GLOBAL ~/.codex/, independent of --dir): strip legacy plugin tables [plugins."evolve-lite@<marketplace>"] from config.toml via line-surgery (new FileOps.remove_toml_tables), then tomllib-validate the result; remove legacy plugin caches plugins/cache/<marketplace>/evolve-lite/ and rmdir the emptied marketplace parent. - Claude: add `claude plugin marketplace remove evolve-marketplace` (best-effort, tolerates non-zero exit / missing CLI, mirrors the existing uninstall call); remove orphan ~/.claude/plugins/data/evolve-lite-* data dirs; remove legacy plugin caches plugins/cache/<marketplace>/evolve-lite/ (the orphaned OLD hooks/ bundle left behind by `claude plugin uninstall`, which could otherwise resurrect the old bundle on reinstall) and rmdir the emptied marketplace parent. - Bob: remove the legacy `install-evolve-lite` bootstrap mode (a bare YAML list item, not a sentinel block) via new FileOps.remove_yaml_custom_mode_by_slug. All new removals are defensive, idempotent, and dry-run-aware (routed through DryRunFileOps), so `uninstall --dry-run` prints the intended legacy removals and changes nothing on disk. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
tests/platform_integrations/test_legacy_migration.py (3)
126-126: 💤 Low valueRemove unused
temp_project_dirparameter.The
temp_project_dirfixture is not used in this test method. Claude legacy migration operates on global~/.claudepaths viasandbox_home, sotemp_project_diris unnecessary here.♻️ Suggested cleanup
- def test_uninstall_removes_orphan_data_dirs(self, sandbox_home, install_runner, temp_project_dir): + def test_uninstall_removes_orphan_data_dirs(self, sandbox_home, install_runner):🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/platform_integrations/test_legacy_migration.py` at line 126, The test method test_uninstall_removes_orphan_data_dirs declares an unused fixture parameter temp_project_dir; remove temp_project_dir from the function signature so the test only accepts sandbox_home and install_runner (e.g., change def test_uninstall_removes_orphan_data_dirs(self, sandbox_home, install_runner):). Ensure no references to temp_project_dir remain in the test and run tests to confirm no fixture ordering or name mismatches occur.
161-161: 💤 Low valueRemove unused
temp_project_dirparameter.The
temp_project_dirfixture is not used in this test method. Claude legacy migration operates on global~/.claudepaths viasandbox_home, sotemp_project_diris unnecessary here.♻️ Suggested cleanup
- def test_uninstall_removes_legacy_plugin_cache(self, sandbox_home, install_runner, temp_project_dir): + def test_uninstall_removes_legacy_plugin_cache(self, sandbox_home, install_runner):🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/platform_integrations/test_legacy_migration.py` at line 161, The test_uninstall_removes_legacy_plugin_cache function declares an unused temp_project_dir fixture parameter; remove temp_project_dir from the test signature so the test only accepts sandbox_home and install_runner (which are actually used) and update any callers or parametrization if present; keep sandbox_home and install_runner intact to preserve the environment for Claude legacy migration testing.
87-88: 💤 Low valueClarify the comment about marketplace parent directory.
The comment states "its now-empty marketplace parent gone too, BUT only because the sibling keeps it alive" — this is self-contradictory. The parent is not "gone too"; it remains because the sibling exists. Consider rephrasing: "the marketplace parent would also be removed if it were empty, BUT the sibling other-plugin keeps it alive."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/platform_integrations/test_legacy_migration.py` around lines 87 - 88, Update the ambiguous inline comment in tests/platform_integrations/test_legacy_migration.py that currently reads "evolve-lite subdir gone; its now-empty marketplace parent gone too, BUT only because the sibling other-plugin keeps it alive here." to a clearer phrasing such as "the marketplace parent would also be removed if it were empty, BUT the sibling other-plugin keeps it alive," so the comment accurately states that the parent is preserved due to the sibling rather than being gone; replace the existing comment text where it appears.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/platform_integrations/test_legacy_migration.py`:
- Line 21: Replace any conditional tomli import with a plain import tomllib
(Python >=3.12 is declared), remove the unused temp_project_dir fixture
parameter from the test methods
TestClaudeLegacyMigration.test_uninstall_removes_orphan_data_dirs and
TestClaudeLegacyMigration.test_uninstall_removes_legacy_plugin_cache, and update
the comment near the TestClaudeLegacyMigration section (the comment around the
marketplace parent assertion) to correctly state that the marketplace parent
directory should remain because a sibling cache exists (so the assertion
expecting the parent to remain is correct).
---
Nitpick comments:
In `@tests/platform_integrations/test_legacy_migration.py`:
- Line 126: The test method test_uninstall_removes_orphan_data_dirs declares an
unused fixture parameter temp_project_dir; remove temp_project_dir from the
function signature so the test only accepts sandbox_home and install_runner
(e.g., change def test_uninstall_removes_orphan_data_dirs(self, sandbox_home,
install_runner):). Ensure no references to temp_project_dir remain in the test
and run tests to confirm no fixture ordering or name mismatches occur.
- Line 161: The test_uninstall_removes_legacy_plugin_cache function declares an
unused temp_project_dir fixture parameter; remove temp_project_dir from the test
signature so the test only accepts sandbox_home and install_runner (which are
actually used) and update any callers or parametrization if present; keep
sandbox_home and install_runner intact to preserve the environment for Claude
legacy migration testing.
- Around line 87-88: Update the ambiguous inline comment in
tests/platform_integrations/test_legacy_migration.py that currently reads
"evolve-lite subdir gone; its now-empty marketplace parent gone too, BUT only
because the sibling other-plugin keeps it alive here." to a clearer phrasing
such as "the marketplace parent would also be removed if it were empty, BUT the
sibling other-plugin keeps it alive," so the comment accurately states that the
parent is preserved due to the sibling rather than being gone; replace the
existing comment text where it appears.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1524bbfc-b795-46ba-958e-c857abce2d78
📒 Files selected for processing (2)
platform-integrations/install.shtests/platform_integrations/test_legacy_migration.py
🚧 Files skipped from review as they are similar to previous changes (1)
- platform-integrations/install.sh
| the install.sh subprocess) so we never touch the developer's real home. | ||
| """ | ||
|
|
||
| import tomllib |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check declared Python version in pyproject.toml
echo "=== Python version requirements in pyproject.toml ==="
rg -A 2 'requires-python|python_requires' pyproject.toml
echo -e "\n=== Checking for tomli in dependencies ==="
rg -i 'tomli' pyproject.toml
echo -e "\n=== Checking if other test files use tomllib or tomli ==="
rg -l 'import toml' tests/Repository: AgentToolkit/altk-evolve
Length of output: 384
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== pyproject.toml requires-python ==="
rg -n '^(requires-python|python_requires)\s*=' pyproject.toml || true
rg -n 'python\s*=\s*"' pyproject.toml || true
echo
echo "=== Dependencies mentioning tomli (backport) ==="
rg -n -i 'tomli' pyproject.toml || true
echo
echo "=== Search tests for tomllib/tomli imports ==="
rg -n 'import\s+tomllib|from\s+tomllib|tomllib\.' tests/ || true
rg -n 'import\s+tomli|from\s+tomli|tomli\.' tests/ || trueRepository: AgentToolkit/altk-evolve
Length of output: 566
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="tests/platform_integrations/test_legacy_migration.py"
echo "=== Show import + top of file (1-110) ==="
nl -ba "$FILE" | sed -n '1,120p'
echo
echo "=== Inspect around pending unused temp_project_dir params (110-190) ==="
nl -ba "$FILE" | sed -n '110,210p'
echo
echo "=== Inspect comment around lines 80-95 ==="
nl -ba "$FILE" | sed -n '80,105p'
echo
echo "=== Search for uses of temp_project_dir within the file ==="
rg -n 'temp_project_dir' "$FILE"
echo
echo "=== Show function signatures around matches (context) ==="
rg -n --context 2 'temp_project_dir' "$FILE"Repository: AgentToolkit/altk-evolve
Length of output: 171
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="tests/platform_integrations/test_legacy_migration.py"
echo "=== Show import + top of file (1-120) ==="
cat -n "$FILE" | sed -n '1,120p'
echo
echo "=== Inspect around pending unused temp_project_dir params (110-240) ==="
cat -n "$FILE" | sed -n '110,240p'
echo
echo "=== Inspect comment around lines 80-105 ==="
cat -n "$FILE" | sed -n '80,105p'
echo
echo "=== Search for uses of temp_project_dir within the file ==="
rg -n 'temp_project_dir' "$FILE"
echo
echo "=== Show function signatures around matches (context) ==="
rg -n --context 2 'temp_project_dir' "$FILE"Repository: AgentToolkit/altk-evolve
Length of output: 15982
tomllib compatibility is OK (Python >=3.12); clean up minor test issues
tests/platform_integrations/test_legacy_migration.pyusesimport tomllib, andpyproject.tomldeclaresrequires-python = ">=3.12", so notomlibackport/conditional import is needed.- Remove unused
temp_project_dirfixture parameters inTestClaudeLegacyMigration.test_uninstall_removes_orphan_data_dirs(line 126) andTestClaudeLegacyMigration.test_uninstall_removes_legacy_plugin_cache(line 161). - Clarify the comment at lines 87-88: it says the marketplace parent is “gone too”, but the assertions expect the parent directory to remain due to the sibling cache.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/platform_integrations/test_legacy_migration.py` at line 21, Replace any
conditional tomli import with a plain import tomllib (Python >=3.12 is
declared), remove the unused temp_project_dir fixture parameter from the test
methods TestClaudeLegacyMigration.test_uninstall_removes_orphan_data_dirs and
TestClaudeLegacyMigration.test_uninstall_removes_legacy_plugin_cache, and update
the comment near the TestClaudeLegacyMigration section (the comment around the
marketplace parent assertion) to correctly state that the marketplace parent
directory should remain because a sibling cache exists (so the assertion
expecting the parent to remain is correct).
…allowlist evolve scripts (no permission prompts)
Claude plugins cannot self-declare tool permissions, env vars are not
expanded in permission rules, and plugin install dirs are version-unstable,
so the adapt-memory skill's Python invocation and its .evolve/ writes
triggered a per-use permission prompt on every run.
Fix (Claude-scoped; adapt-memory is functionally Claude-only — it is a no-op
stub on bob/codex/claw):
1. Ship adapt_memory.py to the version-stable global path
~/.claude/evolve-lite/adapt_memory.py (mirroring the existing
audit_recall.py delivery). Unlike audit_recall.py (self-contained),
adapt_memory.py imports entity_io from the shared lib and resolves it by
walking up its ancestors for lib/evolve-lite/entity_io.py, so the shared
lib is shipped alongside at ~/.claude/evolve-lite/lib/evolve-lite/. The
rendered adapt-memory SKILL.md now invokes that stable path instead of
${CLAUDE_PLUGIN_ROOT}/... (new adapt_memory_script render context +
invoke() path_override).
2. The installer merges five allow-rules (the two stable script paths plus
Read/Edit/Write on .evolve/**) into <repo>/.claude/settings.json on
install and removes exactly those rules on uninstall, preserving any
user-added rules/keys and cleaning up empties (allow key, then
permissions, then file, then .claude dir). New FileOps helpers
merge_json_permission_rules / remove_json_permission_rules with DryRunFileOps
overrides so --dry-run writes nothing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Redesign evolve-lite: no hooks, no custom modes — native memory + EVOLVE.md
This PR replaces evolve-lite's hook- and custom-mode-driven machinery with a self-directed, native-memory methodology. Recall and save are now the agent's own native behavior; evolve adds only the two things native memory lacks — sharing (mirror into a shared
.evolve/store) and provenance (measure whether recalled guidance actually influenced a session) — delivered as an always-onEVOLVE.mdinstruction plus a few explicit skills. No background hooks fire; nothing is a no-op.Per platform:
EVOLVE.mdas a global rules file (~/.bob/rules/00-evolve-lite.md); custom-mode merge dropped.~/.codex/AGENTS.md→~/.codex/evolve-lite/EVOLVE.md; UserPromptSubmit/SessionStart hooks dropped.EVOLVE.mddelivered via a single@.evolve/EVOLVE.mdimport line in the repo'sCLAUDE.md; all auto-firing hooks removed. Native memory owns recall/save; evolve adds mirror-on-save + audit-on-recall.It also closes the provenance loop deterministically (recall → entity → trajectory → recorded verdict), with native-transcript awareness so it works in the hookless world.
For human reviewers — get your agent to test this with you
This change is mostly agent-facing plumbing (install scripts, skills, an always-on instruction file, audit/provenance flow). The fastest way to review it is to hand this PR to your coding agent and have it drive the checks while you watch. Suggested prompt to your agent:
What you (the human) should personally confirm:
@.evolve/EVOLVE.mdline into your repo'sCLAUDE.md, and Bob/Codex write an always-on instruction to your global agent config (~/.bob/rules/,~/.codex/AGENTS.md). Make sure you're comfortable with that before running a real (non-dry-run) install.@importneeds a per-project "allow external imports" approval. If you (or a past session) decline it, the import silently disables and evolve becomes a no-op with no error. The newdoctorskill detects exactly this — run it and confirm it reportsOKafter you approve.Quick manual smoke test (safe, no real config touched):
Per-harness validation scenarios (give the agent a real task)
An empty repo gives the agent nothing to do, so it never discovers anything worth remembering and the evolve cascade never fires. Seed a tiny uv project with a built-in "discovered learning" first:
Then install evolve for the harness under test (Claude/Codex per-repo
--dir .; Bob global--dir "$HOME").The cascade is
save → mirror → audit → provenance, but what counts as a "save" differs per harness:Claude — native auto-memory owns the save, and it only fires on a discovered learning/correction, never on a stated convention (Claude routes "always use uv" to
CLAUDE.mdby design — that's correct, not a bug). So drive a real discovery: tell the agent "Complete TASK.md." It will try barepytest(fails — uv-only), discoveruv run pytest, and save that learning. Verify:~/.claude/projects/<repo-slug>/memory/adapt-memorymirrored it to.evolve/entities/<type>/<name>.md(synthesizedtrigger+native_pathback-ref)doctorskill → expectOK(canary found ⇒ the@importactually loaded)recallrow in.evolve/audit.log; then theprovenanceskill /audit_recall.pycloses the loop.evolve/entities/stays empty → that's the "loaded ≠ obeyed" gap; flag itCodex — no native memory; the evolve skills own the save and the pointer lives in
~/.codex/AGENTS.md. Skills are invoked with$($evolve-lite:recall, not/). Same TASK.md, then: "Complete TASK.md — recall relevant guidance first and save what you learned at the end." Confirm the save wrote.evolve/entities/...and arecallrow hit.evolve/audit.log.Bob — no native memory; the global rules file
~/.bob/rules/00-evolve-lite.md+evolve-lite-*skills own the save (drive interactively or viabob --experimental-acp). Same TASK.md + recall/save instruction; confirm.evolve/entities/...+ the audit row.Reduce prompt noise: the
adapt-memoryand audit steps shell out to Python scripts and write under.evolve/, so a fresh setup prompts on each. Allowlist them once in your Claude settings (~/.claude/settings.jsonfor all repos, or a project.claude/settings.json):{ "permissions": { "allow": [ "Read(.evolve/**)", "Edit(.evolve/**)", "Write(.evolve/**)", "Bash(python3 ~/.claude/evolve-lite/audit_recall.py:*)", "Bash(python3 ${CLAUDE_PLUGIN_ROOT}/skills/evolve-lite/adapt-memory/scripts/adapt_memory.py:*)" ] } }Clean up (uninstall is migration-aware — it also sweeps legacy pre-redesign artifacts: old hook plugin + marketplace, codex
config.tomlplugin tables + caches, bob'sinstall-evolve-litemode):For agents working on this PR
Read this section before editing anything.
Source of truth: edit
plugin-source/, never the rendered treeplatform-integrations/{claude,claw-code,codex,bob}/...is generated output. Do not hand-edit it — your change will be overwritten and the drift gate will fail. Edit the templates/scripts underplugin-source/, then regenerate:*.j2files render through Jinja2 per platform ({{ platform }}+ macros inplugin-source/_macros.j2)..j2scripts (e.g.provenance.py,log_influence.py,adapt_memory.py,doctor.py) are copied verbatim to all four platforms, so one edit fans out to all of them.plugin-source/lib/and renders intolib/evolve-lite/on every host. Scripts resolve it by walking up tolib/evolve-lite/entity_io.py; that resolution only works in the rendered tree, so integration tests run the rendered Claude copy..bob/skills/evolve-lite-<name>/, colon-free on disk).Required gate before any commit
The pre-commit gate runs more than pytest. All of these must pass:
Notes:
mypyexcludesplugin-source/andplatform-integrations/, but nottests/— typed test code is checked.sys.path.insertneeds# noqa: E402.sys.pathshim, scripts import the shared lib (entity_io,audit) by bare name; keep that pattern.Test layout
tests/platform_integrations/and are markedplatform_integrations(+ sometimese2e/llm).-m 'not llm and not e2e'(~252 of 404 collected). Sandboxed, fast tests (doctor, provenance, the end-to-end chain) deliberately ship without thee2emarker so they run as guards in the default suite. Don't re-adde2eto a fast sandboxed test.conftest.pysandboxesHOMEfor every test (so installs never touch real~/.bob,~/.codex,~/.claude). Reusetemp_project_dir,sandbox_home, and the*_audit_script/*_evolve_mdfixtures rather than building paths by hand.~/.claude/projects/<slug>/<sid>.jsonlwhere<slug>slugifies the resolved project root (every non-alphanumeric →-). The same slug logic lives indoctor.py; keep the two in sync.Provenance: keep the verdict agent-driven
provenance.pydoes only deterministic work — read recall rows, skip already-influenced pairs, resolve<type>/<name>entity files, locate the trajectory, emit JSONL candidates (gaps surfaced via amissing:[...]field, never dropped), and persist a verdict via the existinglog_influencewriter. The semantic verdict (followed/contradicted/not_applicable) is an LLM judgment and must stay agent-driven. Do not invent a heuristic verdict. If you can't separate the judgment from the plumbing, stop and flag it rather than faking it.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Chores