feat(examples): add claudecode-skills-memanto — cross-session engineering memory for mattpocock/skills#725
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 a complete example that integrates Memanto with Claude Code skills: env-driven config, LLM+heuristic extraction, SkillMemory (recall/store/profile), lifecycle hooks (SessionStart/UserPromptSubmit/Stop) with an idempotent installer, a CLI, demo scripts, packaging, docs, and tests. ChangesCross-Session Engineering Memory for Claude Code Skills
Sequence Diagram(s)sequenceDiagram
participant SkillMemory
participant Extractor as extractor
participant Memanto as SdkClient
SkillMemory->>Extractor: build_extraction_question(skill, summary)
SkillMemory->>Memanto: answer(agent_id, question, temperature=0.0)
Memanto-->>SkillMemory: answer_text
SkillMemory->>Extractor: parse_llm_memories(answer_text)
alt parsed non-empty
SkillMemory->>Memanto: batch_remember(agent_id, memories)
else parsed empty
SkillMemory->>Extractor: heuristic_memories(summary)
SkillMemory->>Memanto: batch_remember(agent_id, memories)
end
alt batch_remember fails
SkillMemory->>Memanto: remember(agent_id, memory) per-item
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
7d12b41 to
4d9e047
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
examples/claudecode-skills-memanto/tests/test_client.py (1)
58-113: ⚡ Quick winAdd a regression test for canonical
skill:*tag persistence.Current store-path tests use normalized skill input only. Add one case with
"/TDD"(or spaced/uppercase input) and assert persisted tags containskill:tdd.🤖 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 `@examples/claudecode-skills-memanto/tests/test_client.py` around lines 58 - 113, Add a regression test that ensures skill tags are canonicalized to lowercase with "skill:" prefix when persisted: create a new test method on TestDistillAndStore (e.g., test_skill_tag_canonicalization) that uses FakeSdkClient and calls mem.distill_and_store with a mixed-case/leading-slash skill like "/TDD" (via the existing mem.distill_and_store helper), then assert that persisted items (inspect fake.batch_calls[0] or the returned stored list) include the tag "skill:tdd" (and similarly check individual fallback via fake.remembered if relevant); reuse SOURCE_TAG and existing assertions style to verify normalization to "skill:tdd".examples/claudecode-skills-memanto/tests/test_installer.py (1)
103-110: ⚡ Quick winAdd a malformed-
hooksshape regression test.Please add a case where
settings.jsoncontains"hooks": [](or string) and assert install/uninstall do not crash. This closes the current robustness gap.🤖 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 `@examples/claudecode-skills-memanto/tests/test_installer.py` around lines 103 - 110, Add a regression test that ensures malformed "hooks" shapes (e.g., "hooks": [] and "hooks": "some string") don't crash install/uninstall: create settings JSON with those malformed hooks into settings_path (using the same pattern as test_uninstall_when_nothing_installed_is_a_noop), call installer.install_hooks() and installer.uninstall_hooks(), assert they return expected success codes (or at least don't raise) and that settings_path.read_text() remains equal to the original content (no rewrite/backup churn); reference the existing test name and use settings_path and installer.uninstall_hooks()/installer.install_hooks() to locate where to add the new cases.
🤖 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 `@examples/claudecode-skills-memanto/memanto_skills/cli.py`:
- Around line 100-102: The loop printing stored memories assumes every item has
'type' and 'title' and can raise KeyError; update the printing logic that
iterates over the stored list (variable name stored) to safely access keys using
.get() with sensible defaults (e.g., 'unknown' for type and '(untitled)' for
title) or by falling back to str(m) when keys are missing, so printing never
raises and the command returns 0; locate the loop in cli.py where for m in
stored: print(...) and replace direct indexing with guarded lookups.
In `@examples/claudecode-skills-memanto/memanto_skills/client.py`:
- Around line 135-140: distill_and_store currently returns the full memories
list regardless of persistence outcome because _persist swallows failures;
change _persist to surface which items were successfully written (e.g., return
list of persisted memories or raise on total failure) and update
distill_and_store to use that return value (or propagate errors) so it only
returns memories that were actually persisted (or fails the call). Specifically,
modify the _persist function referenced in distill_and_store to stop suppressing
exceptions and instead return a list of successful writes (or raise an exception
on complete failure), then have distill_and_store replace its unconditional
"return memories" with the persisted-result and propagate errors to callers.
- Around line 156-160: route_for already returns a normalized skill identifier,
but the code builds skill_tag from raw skill_name; update the skill_tag
construction to use the normalized value returned by route_for (e.g., route.name
or route.normalized_name) and only fall back to a normalized version of
skill_name (lowercased and stripped of leading slashes) if the route object
lacks that attribute, then assign mem["tags"] = sorted({*route.tags, skill_tag,
SOURCE_TAG}) as before so persisted tags stay consistent.
In `@examples/claudecode-skills-memanto/memanto_skills/installer.py`:
- Around line 137-143: install_hooks() and uninstall_hooks() assume
settings["hooks"] is a dict and call .get on it, which raises AttributeError if
hooks is a list/string; update both functions to validate/coerce
settings.get("hooks") into a dict before using it: fetch hooks_section =
settings.get("hooks") and if not isinstance(hooks_section, dict) then replace it
with settings.setdefault("hooks", {}) (or assign a new {} and set it back into
settings) so subsequent calls to hooks_section.get(...) and hooks_section[event]
are safe; ensure this validation uses the same helper logic in both
install_hooks and uninstall_hooks and retains use of _managed_hooks() and
_strip_managed() when merging entries.
In `@examples/claudecode-skills-memanto/memanto_skills/profile.py`:
- Around line 94-99: Escape the skill_name before injecting it into the XML-like
context to prevent attribute/structure breakage: sanitize skill_name using an
XML/HTML escape function (e.g., html.escape or xml.sax.saxutils.escape) and
apply it where header_skill is built and where _skill_attr(skill_name) is used
so the generated strings (header_skill and the attribute output from
_skill_attr) contain a safely-escaped value; update the _skill_attr
implementation or call the escape function before passing skill_name to it and
at the header_skill construction site to ensure all injections of skill_name are
escaped.
In `@examples/claudecode-skills-memanto/README.md`:
- Line 92: The README has two fenced code blocks without language identifiers;
add appropriate fence languages to those blocks so Markdown linter MD040 passes:
for the XML snippet that starts with "<engineering-profile source="memanto"
skill="tdd">" add ```xml before it (and close accordingly), and for the
directory tree block starting with "claudecode-skills-memanto/" add ```text (or
```bash) before it; update the fences surrounding those exact blocks in
README.md to include the language labels.
---
Nitpick comments:
In `@examples/claudecode-skills-memanto/tests/test_client.py`:
- Around line 58-113: Add a regression test that ensures skill tags are
canonicalized to lowercase with "skill:" prefix when persisted: create a new
test method on TestDistillAndStore (e.g., test_skill_tag_canonicalization) that
uses FakeSdkClient and calls mem.distill_and_store with a
mixed-case/leading-slash skill like "/TDD" (via the existing
mem.distill_and_store helper), then assert that persisted items (inspect
fake.batch_calls[0] or the returned stored list) include the tag "skill:tdd"
(and similarly check individual fallback via fake.remembered if relevant); reuse
SOURCE_TAG and existing assertions style to verify normalization to "skill:tdd".
In `@examples/claudecode-skills-memanto/tests/test_installer.py`:
- Around line 103-110: Add a regression test that ensures malformed "hooks"
shapes (e.g., "hooks": [] and "hooks": "some string") don't crash
install/uninstall: create settings JSON with those malformed hooks into
settings_path (using the same pattern as
test_uninstall_when_nothing_installed_is_a_noop), call installer.install_hooks()
and installer.uninstall_hooks(), assert they return expected success codes (or
at least don't raise) and that settings_path.read_text() remains equal to the
original content (no rewrite/backup churn); reference the existing test name and
use settings_path and installer.uninstall_hooks()/installer.install_hooks() to
locate where to add the new cases.
🪄 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 Plus
Run ID: 6f8d3992-30c8-42fe-b1e5-243c3527cc82
⛔ Files ignored due to path filters (2)
examples/claudecode-skills-memanto/assets/component-architecture.pngis excluded by!**/*.pngexamples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.pngis excluded by!**/*.png
📒 Files selected for processing (31)
examples/claudecode-skills-memanto/.claude-plugin/plugin.jsonexamples/claudecode-skills-memanto/.env.exampleexamples/claudecode-skills-memanto/.gitignoreexamples/claudecode-skills-memanto/README.mdexamples/claudecode-skills-memanto/demo_session_1.pyexamples/claudecode-skills-memanto/demo_session_2.pyexamples/claudecode-skills-memanto/demo_session_3.pyexamples/claudecode-skills-memanto/hooks/__init__.pyexamples/claudecode-skills-memanto/hooks/_common.pyexamples/claudecode-skills-memanto/hooks/on_prompt.pyexamples/claudecode-skills-memanto/hooks/on_stop.pyexamples/claudecode-skills-memanto/hooks/session_start.pyexamples/claudecode-skills-memanto/install.pyexamples/claudecode-skills-memanto/memanto_skills/__init__.pyexamples/claudecode-skills-memanto/memanto_skills/cli.pyexamples/claudecode-skills-memanto/memanto_skills/client.pyexamples/claudecode-skills-memanto/memanto_skills/config.pyexamples/claudecode-skills-memanto/memanto_skills/extractor.pyexamples/claudecode-skills-memanto/memanto_skills/installer.pyexamples/claudecode-skills-memanto/memanto_skills/profile.pyexamples/claudecode-skills-memanto/memanto_skills/skill_map.pyexamples/claudecode-skills-memanto/pyproject.tomlexamples/claudecode-skills-memanto/skills/memanto-companion/SKILL.mdexamples/claudecode-skills-memanto/tests/__init__.pyexamples/claudecode-skills-memanto/tests/conftest.pyexamples/claudecode-skills-memanto/tests/test_client.pyexamples/claudecode-skills-memanto/tests/test_extractor.pyexamples/claudecode-skills-memanto/tests/test_hooks.pyexamples/claudecode-skills-memanto/tests/test_installer.pyexamples/claudecode-skills-memanto/tests/test_profile.pyexamples/claudecode-skills-memanto/tests/test_skill_map.py
There was a problem hiding this comment.
♻️ Duplicate comments (2)
examples/claudecode-skills-memanto/README.md (1)
92-107:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd language identifiers to fenced code blocks (MD040).
Line 92 and Line 140 use unlabeled fenced code blocks; markdownlint will keep flagging these.
Proposed fix
-``` +```xml <engineering-profile source="memanto" skill="tdd"> @@ </engineering-profile>-
+text
claudecode-skills-memanto/
@@
└── tests/ # 56 unit tests, fully mocked (no network, no key)Also applies to: 140-162
🤖 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 `@examples/claudecode-skills-memanto/README.md` around lines 92 - 107, Add language identifiers to the unlabeled fenced code blocks in README.md: for the XML-style engineering profile block that starts with "<engineering-profile source=\"memanto\" skill=\"tdd\">" add an appropriate language tag such as "xml", and for the project tree block that begins with "claudecode-skills-memanto/" add a tag such as "text" (or "bash") so both fenced code blocks are labeled and satisfy markdownlint MD040; update the two occurrences mentioned (the engineering-profile block and the directory tree block).Source: Linters/SAST tools
examples/claudecode-skills-memanto/memanto_skills/installer.py (1)
137-140:⚠️ Potential issue | 🟠 Major | ⚡ Quick winGuard
hookstype before using.get()to prevent installer crashes.Line 137 and Line 162 assume
settings["hooks"]is a dict; if user config contains a list/string, both flows can crash withAttributeError.Proposed fix
def install_hooks(global_scope: bool = False) -> int: @@ - hooks_section: dict[str, Any] = settings.setdefault("hooks", {}) + hooks_section_raw = settings.get("hooks") + if not isinstance(hooks_section_raw, dict): + hooks_section_raw = {} + settings["hooks"] = hooks_section_raw + hooks_section: dict[str, Any] = hooks_section_raw @@ def uninstall_hooks(global_scope: bool = False) -> int: @@ - hooks_section = settings.get("hooks", {}) + hooks_section = settings.get("hooks", {}) + if not isinstance(hooks_section, dict): + print(f"No valid hooks section found in {path}; nothing to remove.") + return 0Also applies to: 162-166
🤖 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 `@examples/claudecode-skills-memanto/memanto_skills/installer.py` around lines 137 - 140, The code assumes settings["hooks"] is a dict and will raise AttributeError if it's a list/string; before calling settings.setdefault("hooks", {}) or using hooks_section.get(), ensure hooks_section is a dict (e.g., val = settings.get("hooks"); if not isinstance(val, dict): set settings["hooks"] = {} and proceed) and apply the same guard in the second flow that manipulates hooks (the block that iterates _managed_hooks()); update references to hooks_section so both merge loops use the validated/normalized dict instead of calling .get() on a non-dict.
🧹 Nitpick comments (1)
examples/claudecode-skills-memanto/tests/test_installer.py (1)
103-110: ⚡ Quick winAdd a regression test for malformed
hooksshape.Please add a case where
settings.jsonhas"hooks": [](or string) and assertinstall_hooks()/uninstall_hooks()return0without exceptions.🤖 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 `@examples/claudecode-skills-memanto/tests/test_installer.py` around lines 103 - 110, Add a regression test variant in test_uninstall_when_nothing_installed_is_a_noop that writes malformed "hooks" shapes (e.g., set settings_path to JSON with "hooks": [] and another case with "hooks": "string") and assert installer.install_hooks() and installer.uninstall_hooks() each return 0 and raise no exceptions; also assert settings_path.read_text() remains equal to the original content to ensure no rewrite or backup churn. Use the existing settings_path fixture and the installer.install_hooks / installer.uninstall_hooks symbols to locate the code to test.
🤖 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.
Duplicate comments:
In `@examples/claudecode-skills-memanto/memanto_skills/installer.py`:
- Around line 137-140: The code assumes settings["hooks"] is a dict and will
raise AttributeError if it's a list/string; before calling
settings.setdefault("hooks", {}) or using hooks_section.get(), ensure
hooks_section is a dict (e.g., val = settings.get("hooks"); if not
isinstance(val, dict): set settings["hooks"] = {} and proceed) and apply the
same guard in the second flow that manipulates hooks (the block that iterates
_managed_hooks()); update references to hooks_section so both merge loops use
the validated/normalized dict instead of calling .get() on a non-dict.
In `@examples/claudecode-skills-memanto/README.md`:
- Around line 92-107: Add language identifiers to the unlabeled fenced code
blocks in README.md: for the XML-style engineering profile block that starts
with "<engineering-profile source=\"memanto\" skill=\"tdd\">" add an appropriate
language tag such as "xml", and for the project tree block that begins with
"claudecode-skills-memanto/" add a tag such as "text" (or "bash") so both fenced
code blocks are labeled and satisfy markdownlint MD040; update the two
occurrences mentioned (the engineering-profile block and the directory tree
block).
---
Nitpick comments:
In `@examples/claudecode-skills-memanto/tests/test_installer.py`:
- Around line 103-110: Add a regression test variant in
test_uninstall_when_nothing_installed_is_a_noop that writes malformed "hooks"
shapes (e.g., set settings_path to JSON with "hooks": [] and another case with
"hooks": "string") and assert installer.install_hooks() and
installer.uninstall_hooks() each return 0 and raise no exceptions; also assert
settings_path.read_text() remains equal to the original content to ensure no
rewrite or backup churn. Use the existing settings_path fixture and the
installer.install_hooks / installer.uninstall_hooks symbols to locate the code
to test.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1bb8ebf1-29dd-4359-8516-03a5b902160e
⛔ Files ignored due to path filters (2)
examples/claudecode-skills-memanto/assets/component-architecture.pngis excluded by!**/*.pngexamples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.pngis excluded by!**/*.png
📒 Files selected for processing (31)
examples/claudecode-skills-memanto/.claude-plugin/plugin.jsonexamples/claudecode-skills-memanto/.env.exampleexamples/claudecode-skills-memanto/.gitignoreexamples/claudecode-skills-memanto/README.mdexamples/claudecode-skills-memanto/demo_session_1.pyexamples/claudecode-skills-memanto/demo_session_2.pyexamples/claudecode-skills-memanto/demo_session_3.pyexamples/claudecode-skills-memanto/hooks/__init__.pyexamples/claudecode-skills-memanto/hooks/_common.pyexamples/claudecode-skills-memanto/hooks/on_prompt.pyexamples/claudecode-skills-memanto/hooks/on_stop.pyexamples/claudecode-skills-memanto/hooks/session_start.pyexamples/claudecode-skills-memanto/install.pyexamples/claudecode-skills-memanto/memanto_skills/__init__.pyexamples/claudecode-skills-memanto/memanto_skills/cli.pyexamples/claudecode-skills-memanto/memanto_skills/client.pyexamples/claudecode-skills-memanto/memanto_skills/config.pyexamples/claudecode-skills-memanto/memanto_skills/extractor.pyexamples/claudecode-skills-memanto/memanto_skills/installer.pyexamples/claudecode-skills-memanto/memanto_skills/profile.pyexamples/claudecode-skills-memanto/memanto_skills/skill_map.pyexamples/claudecode-skills-memanto/pyproject.tomlexamples/claudecode-skills-memanto/skills/memanto-companion/SKILL.mdexamples/claudecode-skills-memanto/tests/__init__.pyexamples/claudecode-skills-memanto/tests/conftest.pyexamples/claudecode-skills-memanto/tests/test_client.pyexamples/claudecode-skills-memanto/tests/test_extractor.pyexamples/claudecode-skills-memanto/tests/test_hooks.pyexamples/claudecode-skills-memanto/tests/test_installer.pyexamples/claudecode-skills-memanto/tests/test_profile.pyexamples/claudecode-skills-memanto/tests/test_skill_map.py
✅ Files skipped from review due to trivial changes (5)
- examples/claudecode-skills-memanto/hooks/init.py
- examples/claudecode-skills-memanto/.gitignore
- examples/claudecode-skills-memanto/pyproject.toml
- examples/claudecode-skills-memanto/.env.example
- examples/claudecode-skills-memanto/memanto_skills/init.py
🚧 Files skipped from review as they are similar to previous changes (18)
- examples/claudecode-skills-memanto/.claude-plugin/plugin.json
- examples/claudecode-skills-memanto/demo_session_2.py
- examples/claudecode-skills-memanto/install.py
- examples/claudecode-skills-memanto/memanto_skills/skill_map.py
- examples/claudecode-skills-memanto/tests/test_skill_map.py
- examples/claudecode-skills-memanto/tests/test_client.py
- examples/claudecode-skills-memanto/hooks/on_stop.py
- examples/claudecode-skills-memanto/memanto_skills/config.py
- examples/claudecode-skills-memanto/tests/test_extractor.py
- examples/claudecode-skills-memanto/hooks/on_prompt.py
- examples/claudecode-skills-memanto/demo_session_3.py
- examples/claudecode-skills-memanto/hooks/session_start.py
- examples/claudecode-skills-memanto/hooks/_common.py
- examples/claudecode-skills-memanto/tests/test_profile.py
- examples/claudecode-skills-memanto/memanto_skills/profile.py
- examples/claudecode-skills-memanto/memanto_skills/client.py
- examples/claudecode-skills-memanto/memanto_skills/cli.py
- examples/claudecode-skills-memanto/memanto_skills/extractor.py
4d9e047 to
739f78d
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@examples/claudecode-skills-memanto/README.md`:
- Around line 92-107: The README has two fenced code blocks missing language
identifiers; add explicit fence languages so linting passes: mark the first
engineering-profile block with ```xml (the block containing <engineering-profile
source="memanto" skill="tdd">) and mark the directory tree block (the ASCII
project tree starting with "claudecode-skills-memanto/") with ```text; update
the opening and closing fences around those two blocks accordingly so both
blocks include their language identifiers.
🪄 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 Plus
Run ID: 209eedb7-c4ef-415d-a539-136294ed7243
⛔ Files ignored due to path filters (2)
examples/claudecode-skills-memanto/assets/component-architecture.pngis excluded by!**/*.pngexamples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.pngis excluded by!**/*.png
📒 Files selected for processing (31)
examples/claudecode-skills-memanto/.claude-plugin/plugin.jsonexamples/claudecode-skills-memanto/.env.exampleexamples/claudecode-skills-memanto/.gitignoreexamples/claudecode-skills-memanto/README.mdexamples/claudecode-skills-memanto/demo_session_1.pyexamples/claudecode-skills-memanto/demo_session_2.pyexamples/claudecode-skills-memanto/demo_session_3.pyexamples/claudecode-skills-memanto/hooks/__init__.pyexamples/claudecode-skills-memanto/hooks/_common.pyexamples/claudecode-skills-memanto/hooks/on_prompt.pyexamples/claudecode-skills-memanto/hooks/on_stop.pyexamples/claudecode-skills-memanto/hooks/session_start.pyexamples/claudecode-skills-memanto/install.pyexamples/claudecode-skills-memanto/memanto_skills/__init__.pyexamples/claudecode-skills-memanto/memanto_skills/cli.pyexamples/claudecode-skills-memanto/memanto_skills/client.pyexamples/claudecode-skills-memanto/memanto_skills/config.pyexamples/claudecode-skills-memanto/memanto_skills/extractor.pyexamples/claudecode-skills-memanto/memanto_skills/installer.pyexamples/claudecode-skills-memanto/memanto_skills/profile.pyexamples/claudecode-skills-memanto/memanto_skills/skill_map.pyexamples/claudecode-skills-memanto/pyproject.tomlexamples/claudecode-skills-memanto/skills/memanto-companion/SKILL.mdexamples/claudecode-skills-memanto/tests/__init__.pyexamples/claudecode-skills-memanto/tests/conftest.pyexamples/claudecode-skills-memanto/tests/test_client.pyexamples/claudecode-skills-memanto/tests/test_extractor.pyexamples/claudecode-skills-memanto/tests/test_hooks.pyexamples/claudecode-skills-memanto/tests/test_installer.pyexamples/claudecode-skills-memanto/tests/test_profile.pyexamples/claudecode-skills-memanto/tests/test_skill_map.py
✅ Files skipped from review due to trivial changes (2)
- examples/claudecode-skills-memanto/hooks/init.py
- examples/claudecode-skills-memanto/.gitignore
🚧 Files skipped from review as they are similar to previous changes (20)
- examples/claudecode-skills-memanto/.env.example
- examples/claudecode-skills-memanto/pyproject.toml
- examples/claudecode-skills-memanto/hooks/session_start.py
- examples/claudecode-skills-memanto/tests/test_profile.py
- examples/claudecode-skills-memanto/hooks/on_prompt.py
- examples/claudecode-skills-memanto/memanto_skills/init.py
- examples/claudecode-skills-memanto/hooks/on_stop.py
- examples/claudecode-skills-memanto/demo_session_3.py
- examples/claudecode-skills-memanto/demo_session_1.py
- examples/claudecode-skills-memanto/memanto_skills/skill_map.py
- examples/claudecode-skills-memanto/install.py
- examples/claudecode-skills-memanto/tests/test_extractor.py
- examples/claudecode-skills-memanto/demo_session_2.py
- examples/claudecode-skills-memanto/memanto_skills/config.py
- examples/claudecode-skills-memanto/tests/test_client.py
- examples/claudecode-skills-memanto/memanto_skills/extractor.py
- examples/claudecode-skills-memanto/hooks/_common.py
- examples/claudecode-skills-memanto/memanto_skills/cli.py
- examples/claudecode-skills-memanto/memanto_skills/profile.py
- examples/claudecode-skills-memanto/memanto_skills/client.py
adcf061 to
1028e33
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@examples/claudecode-skills-memanto/hooks/_common.py`:
- Around line 146-159: read_transcript_text() currently tail-truncates the
transcript and can drop the initial /skill token so hooks/on_stop.py
misidentifies the skill before SkillMemory.distill_and_store() tags memories;
modify read_transcript_text() to first scan the full un-truncated lines for the
earliest line containing a skill token (e.g., starting with "/") and preserve
that line (or extract and prepend the detected token) before performing the
tail-truncation logic, then ensure the returned string still respects
max_messages and max_chars; add a regression test that builds a long transcript
whose opening skill line falls before the truncation window and assert the
detected skill from hooks/on_stop.py (or the preserved token) matches the
original opening token.
🪄 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 Plus
Run ID: 300ca95c-bbe2-4d0d-9803-ab914e19c438
⛔ Files ignored due to path filters (2)
examples/claudecode-skills-memanto/assets/component-architecture.pngis excluded by!**/*.pngexamples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.pngis excluded by!**/*.png
📒 Files selected for processing (31)
examples/claudecode-skills-memanto/.claude-plugin/plugin.jsonexamples/claudecode-skills-memanto/.env.exampleexamples/claudecode-skills-memanto/.gitignoreexamples/claudecode-skills-memanto/README.mdexamples/claudecode-skills-memanto/demo_session_1.pyexamples/claudecode-skills-memanto/demo_session_2.pyexamples/claudecode-skills-memanto/demo_session_3.pyexamples/claudecode-skills-memanto/hooks/__init__.pyexamples/claudecode-skills-memanto/hooks/_common.pyexamples/claudecode-skills-memanto/hooks/on_prompt.pyexamples/claudecode-skills-memanto/hooks/on_stop.pyexamples/claudecode-skills-memanto/hooks/session_start.pyexamples/claudecode-skills-memanto/install.pyexamples/claudecode-skills-memanto/memanto_skills/__init__.pyexamples/claudecode-skills-memanto/memanto_skills/cli.pyexamples/claudecode-skills-memanto/memanto_skills/client.pyexamples/claudecode-skills-memanto/memanto_skills/config.pyexamples/claudecode-skills-memanto/memanto_skills/extractor.pyexamples/claudecode-skills-memanto/memanto_skills/installer.pyexamples/claudecode-skills-memanto/memanto_skills/profile.pyexamples/claudecode-skills-memanto/memanto_skills/skill_map.pyexamples/claudecode-skills-memanto/pyproject.tomlexamples/claudecode-skills-memanto/skills/memanto-companion/SKILL.mdexamples/claudecode-skills-memanto/tests/__init__.pyexamples/claudecode-skills-memanto/tests/conftest.pyexamples/claudecode-skills-memanto/tests/test_client.pyexamples/claudecode-skills-memanto/tests/test_extractor.pyexamples/claudecode-skills-memanto/tests/test_hooks.pyexamples/claudecode-skills-memanto/tests/test_installer.pyexamples/claudecode-skills-memanto/tests/test_profile.pyexamples/claudecode-skills-memanto/tests/test_skill_map.py
✅ Files skipped from review due to trivial changes (4)
- examples/claudecode-skills-memanto/.claude-plugin/plugin.json
- examples/claudecode-skills-memanto/hooks/init.py
- examples/claudecode-skills-memanto/.gitignore
- examples/claudecode-skills-memanto/.env.example
🚧 Files skipped from review as they are similar to previous changes (18)
- examples/claudecode-skills-memanto/pyproject.toml
- examples/claudecode-skills-memanto/memanto_skills/init.py
- examples/claudecode-skills-memanto/demo_session_2.py
- examples/claudecode-skills-memanto/memanto_skills/cli.py
- examples/claudecode-skills-memanto/tests/test_profile.py
- examples/claudecode-skills-memanto/hooks/on_stop.py
- examples/claudecode-skills-memanto/install.py
- examples/claudecode-skills-memanto/demo_session_3.py
- examples/claudecode-skills-memanto/hooks/on_prompt.py
- examples/claudecode-skills-memanto/hooks/session_start.py
- examples/claudecode-skills-memanto/memanto_skills/extractor.py
- examples/claudecode-skills-memanto/demo_session_1.py
- examples/claudecode-skills-memanto/memanto_skills/config.py
- examples/claudecode-skills-memanto/memanto_skills/skill_map.py
- examples/claudecode-skills-memanto/memanto_skills/profile.py
- examples/claudecode-skills-memanto/tests/test_skill_map.py
- examples/claudecode-skills-memanto/tests/test_client.py
- examples/claudecode-skills-memanto/memanto_skills/client.py
…ring memory for mattpocock/skills
1028e33 to
e9911c9
Compare
|
Hello @Xenogents, Could you please review the PR, Pardon for the late PR. Actually I got into somethings so wasn't able to do the e-2-e testing. But from my end i have verified things. Let me know your feedback and any changes required to proceed further. Thanks! cc: @mjfekri |
|
Hi @Xenogents, let me know the feedback once you get the time to review it. |
What this PR is about
This PR adds a new example,
examples/claudecode-skills-memanto/, that makes Memanto a global, active memory companion acrossmattpocock/skillsexecutions in Claude Code. It is a complete, drop-in integration: three real Claude Code lifecycle hooks, an installable Python package, a companion skill, a CLI, and three live cross-process demos.Closes #508
What it solves
mattpocock's skills are sharp and single-purpose. But each invocation of
/tdd,/diagnose,/grill-with-docs, or/handoffstarts cold architectural decisions, codebase conventions, and stated preferences vanish the moment a session ends.This integration makes that memory survive:
/grill-with-docsin one terminal isrecalled by
/tddin a completely fresh process, zero repeatedinstructions.
before each prompt.
How it works; the three implementation guidelines
install.py→.claude/settings.jsonSessionStart,UserPromptSubmit, andStophooks. Idempotent, backs up your settings, and preserves any hooks you already had, even when merged into shared entries.hooks/on_stop.py→SkillMemory.distill_and_storeSdkClient.answer), which distills the durable engineering signals, decisions, rules, preferences, into typed memories. Guarded bystop_hook_activeso a session is never double-distilled.hooks/on_prompt.py→SkillMemory.recall_for_skill/usr/local/binis not mistaken for a skill), recalls the most relevant memories via semantic search, and injects them as a concise<engineering-profile>block before Claude reads the prompt.Architecture
How it works, three real lifecycle hooks:
Component architecture:
Live demo, three separate processes, one growing Engineering Profile
The-Memanto-mattpocock-Developer-Skills.mp4
Social Posts
X thread: https://x.com/surajk_umar01/status/2065336625891348830
Raddit post: https://www.reddit.com/user/Basic_Pie_1537/comments/1u3op6p/gave_claude_code_skills_crosssession_memory_using/
Summary by CodeRabbit
New Features
Documentation
Tests
Chores