Skip to content

feat(examples): add claudecode-skills-memanto — cross-session engineering memory for mattpocock/skills#725

Open
Suraj-kumar00 wants to merge 1 commit into
moorcheh-ai:mainfrom
Suraj-kumar00:feat/claudecode-skills-memanto
Open

feat(examples): add claudecode-skills-memanto — cross-session engineering memory for mattpocock/skills#725
Suraj-kumar00 wants to merge 1 commit into
moorcheh-ai:mainfrom
Suraj-kumar00:feat/claudecode-skills-memanto

Conversation

@Suraj-kumar00

@Suraj-kumar00 Suraj-kumar00 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

What this PR is about

This PR adds a new example, examples/claudecode-skills-memanto/, that makes Memanto a global, active memory companion across mattpocock/skills executions 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 /handoff starts cold architectural decisions, codebase conventions, and stated preferences vanish the moment a session ends.

This integration makes that memory survive:

  • An architectural decision made during /grill-with-docs in one terminal is
    recalled by /tdd in a completely fresh process, zero repeated
    instructions
    .
  • The engineering profile grows monotonically across every skill execution.
  • No forks of the mattpocock skills, no copy-paste workflow, no manual step
    before each prompt.

How it works; the three implementation guidelines

Guideline Where What it does
Global Memory Hook install.py.claude/settings.json One command registers SessionStart, UserPromptSubmit, and Stop hooks. Idempotent, backs up your settings, and preserves any hooks you already had, even when merged into shared entries.
Active Extraction hooks/on_stop.pySkillMemory.distill_and_store Hands the transcript to Memanto's backend LLM (SdkClient.answer), which distills the durable engineering signals, decisions, rules, preferences, into typed memories. Guarded by stop_hook_active so a session is never double-distilled.
Dynamic Injection hooks/on_prompt.pySkillMemory.recall_for_skill Detects the invoked skill (path-safe, /usr/local/bin is 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.

LLM-powered extraction, not regex. answer() is the primary path. A
conservative heuristic only fires if the LLM yields nothing parseable, so a
hook never silently no-ops.

Architecture

How it works, three real lifecycle hooks:

how-it-works-three-real-lifecycle-hooks

Component architecture:

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

    • Claude Code ↔ Memanto integration for cross-session engineering memory, lifecycle hooks (SessionStart/UserPromptSubmit/Stop), CLI, installer, demo scripts, and a skill companion.
  • Documentation

    • Comprehensive README and SKILL guide with quick start, configuration, CLI usage, and design notes.
  • Tests

    • Extensive tests covering memory client, extractor, hooks, installer, profile rendering, and skill routing.
  • Chores

    • Packaging config, example env, and .gitignore updates.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds 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.

Changes

Cross-Session Engineering Memory for Claude Code Skills

Layer / File(s) Summary
Configuration, profile, and routing contracts
examples/claudecode-skills-memanto/memanto_skills/config.py, examples/claudecode-skills-memanto/memanto_skills/profile.py, examples/claudecode-skills-memanto/memanto_skills/skill_map.py, examples/claudecode-skills-memanto/memanto_skills/__init__.py, examples/claudecode-skills-memanto/tests/test_profile.py, examples/claudecode-skills-memanto/tests/test_skill_map.py
SkillsConfig loads env-driven settings (MOORCHEH_API_KEY, agent id, recall limits, optional similarity floor). MemoryProfile formats recalled memories into deterministic <engineering-profile> blocks with grouping and tentative marking. SkillRoute maps skills to natural-language recall queries and tags.
Extraction pipeline & SkillMemory client
examples/claudecode-skills-memanto/memanto_skills/extractor.py, examples/claudecode-skills-memanto/memanto_skills/client.py, examples/claudecode-skills-memanto/tests/conftest.py, examples/claudecode-skills-memanto/tests/test_extractor.py, examples/claudecode-skills-memanto/tests/test_client.py
build_extraction_question(), parse_llm_memories(), and heuristic_memories() implement LLM-based structured extraction with robust JSON parsing and a keyword-driven heuristic fallback. SkillMemory orchestrates setup, recall, profile rendering, LLM extraction fallback, tag enrichment, and batch→per-item persistence with tests and fake SDK fixtures.
Hook shared utilities & lifecycle hooks
examples/claudecode-skills-memanto/hooks/_common.py, examples/claudecode-skills-memanto/hooks/session_start.py, examples/claudecode-skills-memanto/hooks/on_prompt.py, examples/claudecode-skills-memanto/hooks/on_stop.py, examples/claudecode-skills-memanto/tests/test_hooks.py
Shared hook helpers enforce a non-failing hook contract (run()), parse hook stdin/transcripts, detect skills, emit additionalContext, construct SkillMemory when available, and provide transcript flattening/truncation logic. Hooks: SessionStart emits profile, UserPromptSubmit injects skill-scoped context, Stop distills+stores.
Installer and CLI tooling
examples/claudecode-skills-memanto/memanto_skills/installer.py, examples/claudecode-skills-memanto/install.py, examples/claudecode-skills-memanto/memanto_skills/cli.py, examples/claudecode-skills-memanto/tests/test_installer.py
Idempotent install/uninstall of lifecycle hooks into .claude/settings.json (project or global), backups, marker-based managed-entry detection/removal, preservation of user hooks, and CLI (memanto-skills) for recall/store/profile/doctor/install/uninstall with diagnostic doctor. Tests cover robustness and malformed settings.json recovery.
Examples, demos, packaging & docs
examples/claudecode-skills-memanto/pyproject.toml, examples/claudecode-skills-memanto/.claude-plugin/plugin.json, examples/claudecode-skills-memanto/.env.example, examples/claudecode-skills-memanto/.gitignore, examples/claudecode-skills-memanto/README.md, examples/claudecode-skills-memanto/skills/memanto-companion/SKILL.md, examples/claudecode-skills-memanto/demo_session_1.py, examples/claudecode-skills-memanto/demo_session_2.py, examples/claudecode-skills-memanto/demo_session_3.py
Packaging metadata, plugin manifest, env template, gitignore, README and skill docs, plus demo scripts showing cross-process/session memory store and recall.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • Xenogents
  • Neelpatel1604

🐰 "Across sessions your memories softly creep,
Hooks hum and store what developers keep,
CLI and demos show the context they weave,
Profiles and recalls let reasoning breathe,
A rabbit cheers: persistence takes a leap!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and accurately summarizes the main change: adding a claudecode-skills-memanto example that integrates Memanto for cross-session engineering memory with mattpocock/skills.
Linked Issues check ✅ Passed All key requirements from issue #508 are met: Memanto integration as a global memory companion, lightweight lifecycle hooks (SessionStart, UserPromptSubmit, Stop), active extraction via backend-LLM distillation (SkillMemory.distill_and_store), dynamic injection via skill-scoped recall (SkillMemory.recall_for_skill), Moorcheh API credential handling, complete example at /examples/claudecode-skills-memanto with installable package, CLI, three cross-process demos, and idempotent hook registration via install.py.
Out of Scope Changes check ✅ Passed All changes are scoped to the new /examples/claudecode-skills-memanto example directory. No modifications to core codebase, other examples, or unrelated functionality are present.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Suraj-kumar00 Suraj-kumar00 changed the title feat(examples): add claudecode-skills-memanto — cross-session enginee… feat(examples): add claudecode-skills-memanto — cross-session engineering memory for mattpocock/skills Jun 11, 2026
@Suraj-kumar00 Suraj-kumar00 force-pushed the feat/claudecode-skills-memanto branch from 7d12b41 to 4d9e047 Compare June 11, 2026 18:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
examples/claudecode-skills-memanto/tests/test_client.py (1)

58-113: ⚡ Quick win

Add 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 contain skill: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 win

Add a malformed-hooks shape regression test.

Please add a case where settings.json contains "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

📥 Commits

Reviewing files that changed from the base of the PR and between 39d92d0 and 7d12b41.

⛔ Files ignored due to path filters (2)
  • examples/claudecode-skills-memanto/assets/component-architecture.png is excluded by !**/*.png
  • examples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.png is excluded by !**/*.png
📒 Files selected for processing (31)
  • examples/claudecode-skills-memanto/.claude-plugin/plugin.json
  • examples/claudecode-skills-memanto/.env.example
  • examples/claudecode-skills-memanto/.gitignore
  • examples/claudecode-skills-memanto/README.md
  • examples/claudecode-skills-memanto/demo_session_1.py
  • examples/claudecode-skills-memanto/demo_session_2.py
  • examples/claudecode-skills-memanto/demo_session_3.py
  • examples/claudecode-skills-memanto/hooks/__init__.py
  • examples/claudecode-skills-memanto/hooks/_common.py
  • examples/claudecode-skills-memanto/hooks/on_prompt.py
  • examples/claudecode-skills-memanto/hooks/on_stop.py
  • examples/claudecode-skills-memanto/hooks/session_start.py
  • examples/claudecode-skills-memanto/install.py
  • examples/claudecode-skills-memanto/memanto_skills/__init__.py
  • examples/claudecode-skills-memanto/memanto_skills/cli.py
  • examples/claudecode-skills-memanto/memanto_skills/client.py
  • examples/claudecode-skills-memanto/memanto_skills/config.py
  • examples/claudecode-skills-memanto/memanto_skills/extractor.py
  • examples/claudecode-skills-memanto/memanto_skills/installer.py
  • examples/claudecode-skills-memanto/memanto_skills/profile.py
  • examples/claudecode-skills-memanto/memanto_skills/skill_map.py
  • examples/claudecode-skills-memanto/pyproject.toml
  • examples/claudecode-skills-memanto/skills/memanto-companion/SKILL.md
  • examples/claudecode-skills-memanto/tests/__init__.py
  • examples/claudecode-skills-memanto/tests/conftest.py
  • examples/claudecode-skills-memanto/tests/test_client.py
  • examples/claudecode-skills-memanto/tests/test_extractor.py
  • examples/claudecode-skills-memanto/tests/test_hooks.py
  • examples/claudecode-skills-memanto/tests/test_installer.py
  • examples/claudecode-skills-memanto/tests/test_profile.py
  • examples/claudecode-skills-memanto/tests/test_skill_map.py

Comment thread examples/claudecode-skills-memanto/memanto_skills/cli.py
Comment thread examples/claudecode-skills-memanto/memanto_skills/client.py
Comment thread examples/claudecode-skills-memanto/memanto_skills/client.py
Comment thread examples/claudecode-skills-memanto/memanto_skills/installer.py Outdated
Comment thread examples/claudecode-skills-memanto/memanto_skills/profile.py Outdated
Comment thread examples/claudecode-skills-memanto/README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
examples/claudecode-skills-memanto/README.md (1)

92-107: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add 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 win

Guard hooks type 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 with AttributeError.

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 0

Also 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 win

Add a regression test for malformed hooks shape.

Please add a case where settings.json has "hooks": [] (or string) and assert install_hooks() / uninstall_hooks() return 0 without 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

📥 Commits

Reviewing files that changed from the base of the PR and between 7d12b41 and 4d9e047.

⛔ Files ignored due to path filters (2)
  • examples/claudecode-skills-memanto/assets/component-architecture.png is excluded by !**/*.png
  • examples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.png is excluded by !**/*.png
📒 Files selected for processing (31)
  • examples/claudecode-skills-memanto/.claude-plugin/plugin.json
  • examples/claudecode-skills-memanto/.env.example
  • examples/claudecode-skills-memanto/.gitignore
  • examples/claudecode-skills-memanto/README.md
  • examples/claudecode-skills-memanto/demo_session_1.py
  • examples/claudecode-skills-memanto/demo_session_2.py
  • examples/claudecode-skills-memanto/demo_session_3.py
  • examples/claudecode-skills-memanto/hooks/__init__.py
  • examples/claudecode-skills-memanto/hooks/_common.py
  • examples/claudecode-skills-memanto/hooks/on_prompt.py
  • examples/claudecode-skills-memanto/hooks/on_stop.py
  • examples/claudecode-skills-memanto/hooks/session_start.py
  • examples/claudecode-skills-memanto/install.py
  • examples/claudecode-skills-memanto/memanto_skills/__init__.py
  • examples/claudecode-skills-memanto/memanto_skills/cli.py
  • examples/claudecode-skills-memanto/memanto_skills/client.py
  • examples/claudecode-skills-memanto/memanto_skills/config.py
  • examples/claudecode-skills-memanto/memanto_skills/extractor.py
  • examples/claudecode-skills-memanto/memanto_skills/installer.py
  • examples/claudecode-skills-memanto/memanto_skills/profile.py
  • examples/claudecode-skills-memanto/memanto_skills/skill_map.py
  • examples/claudecode-skills-memanto/pyproject.toml
  • examples/claudecode-skills-memanto/skills/memanto-companion/SKILL.md
  • examples/claudecode-skills-memanto/tests/__init__.py
  • examples/claudecode-skills-memanto/tests/conftest.py
  • examples/claudecode-skills-memanto/tests/test_client.py
  • examples/claudecode-skills-memanto/tests/test_extractor.py
  • examples/claudecode-skills-memanto/tests/test_hooks.py
  • examples/claudecode-skills-memanto/tests/test_installer.py
  • examples/claudecode-skills-memanto/tests/test_profile.py
  • examples/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

@Suraj-kumar00 Suraj-kumar00 force-pushed the feat/claudecode-skills-memanto branch from 4d9e047 to 739f78d Compare June 11, 2026 19:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4d9e047 and 739f78d.

⛔ Files ignored due to path filters (2)
  • examples/claudecode-skills-memanto/assets/component-architecture.png is excluded by !**/*.png
  • examples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.png is excluded by !**/*.png
📒 Files selected for processing (31)
  • examples/claudecode-skills-memanto/.claude-plugin/plugin.json
  • examples/claudecode-skills-memanto/.env.example
  • examples/claudecode-skills-memanto/.gitignore
  • examples/claudecode-skills-memanto/README.md
  • examples/claudecode-skills-memanto/demo_session_1.py
  • examples/claudecode-skills-memanto/demo_session_2.py
  • examples/claudecode-skills-memanto/demo_session_3.py
  • examples/claudecode-skills-memanto/hooks/__init__.py
  • examples/claudecode-skills-memanto/hooks/_common.py
  • examples/claudecode-skills-memanto/hooks/on_prompt.py
  • examples/claudecode-skills-memanto/hooks/on_stop.py
  • examples/claudecode-skills-memanto/hooks/session_start.py
  • examples/claudecode-skills-memanto/install.py
  • examples/claudecode-skills-memanto/memanto_skills/__init__.py
  • examples/claudecode-skills-memanto/memanto_skills/cli.py
  • examples/claudecode-skills-memanto/memanto_skills/client.py
  • examples/claudecode-skills-memanto/memanto_skills/config.py
  • examples/claudecode-skills-memanto/memanto_skills/extractor.py
  • examples/claudecode-skills-memanto/memanto_skills/installer.py
  • examples/claudecode-skills-memanto/memanto_skills/profile.py
  • examples/claudecode-skills-memanto/memanto_skills/skill_map.py
  • examples/claudecode-skills-memanto/pyproject.toml
  • examples/claudecode-skills-memanto/skills/memanto-companion/SKILL.md
  • examples/claudecode-skills-memanto/tests/__init__.py
  • examples/claudecode-skills-memanto/tests/conftest.py
  • examples/claudecode-skills-memanto/tests/test_client.py
  • examples/claudecode-skills-memanto/tests/test_extractor.py
  • examples/claudecode-skills-memanto/tests/test_hooks.py
  • examples/claudecode-skills-memanto/tests/test_installer.py
  • examples/claudecode-skills-memanto/tests/test_profile.py
  • examples/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

Comment thread examples/claudecode-skills-memanto/README.md Outdated
@Suraj-kumar00 Suraj-kumar00 force-pushed the feat/claudecode-skills-memanto branch 2 times, most recently from adcf061 to 1028e33 Compare June 12, 2026 06:35

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between adcf061 and 1028e33.

⛔ Files ignored due to path filters (2)
  • examples/claudecode-skills-memanto/assets/component-architecture.png is excluded by !**/*.png
  • examples/claudecode-skills-memanto/assets/how-it-works-three-real-lifecycle-hooks.png is excluded by !**/*.png
📒 Files selected for processing (31)
  • examples/claudecode-skills-memanto/.claude-plugin/plugin.json
  • examples/claudecode-skills-memanto/.env.example
  • examples/claudecode-skills-memanto/.gitignore
  • examples/claudecode-skills-memanto/README.md
  • examples/claudecode-skills-memanto/demo_session_1.py
  • examples/claudecode-skills-memanto/demo_session_2.py
  • examples/claudecode-skills-memanto/demo_session_3.py
  • examples/claudecode-skills-memanto/hooks/__init__.py
  • examples/claudecode-skills-memanto/hooks/_common.py
  • examples/claudecode-skills-memanto/hooks/on_prompt.py
  • examples/claudecode-skills-memanto/hooks/on_stop.py
  • examples/claudecode-skills-memanto/hooks/session_start.py
  • examples/claudecode-skills-memanto/install.py
  • examples/claudecode-skills-memanto/memanto_skills/__init__.py
  • examples/claudecode-skills-memanto/memanto_skills/cli.py
  • examples/claudecode-skills-memanto/memanto_skills/client.py
  • examples/claudecode-skills-memanto/memanto_skills/config.py
  • examples/claudecode-skills-memanto/memanto_skills/extractor.py
  • examples/claudecode-skills-memanto/memanto_skills/installer.py
  • examples/claudecode-skills-memanto/memanto_skills/profile.py
  • examples/claudecode-skills-memanto/memanto_skills/skill_map.py
  • examples/claudecode-skills-memanto/pyproject.toml
  • examples/claudecode-skills-memanto/skills/memanto-companion/SKILL.md
  • examples/claudecode-skills-memanto/tests/__init__.py
  • examples/claudecode-skills-memanto/tests/conftest.py
  • examples/claudecode-skills-memanto/tests/test_client.py
  • examples/claudecode-skills-memanto/tests/test_extractor.py
  • examples/claudecode-skills-memanto/tests/test_hooks.py
  • examples/claudecode-skills-memanto/tests/test_installer.py
  • examples/claudecode-skills-memanto/tests/test_profile.py
  • examples/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

Comment thread examples/claudecode-skills-memanto/hooks/_common.py Outdated
@Suraj-kumar00 Suraj-kumar00 force-pushed the feat/claudecode-skills-memanto branch from 1028e33 to e9911c9 Compare June 12, 2026 06:49
@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

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

@Suraj-kumar00

Copy link
Copy Markdown
Contributor Author

Hi @Xenogents, let me know the feedback once you get the time to review it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOUNTY $100] 🐜 The Memanto + mattpocock Developer Skills Challenge

1 participant