Skip to content

[AI Fix] [BOUNTY $100] 🐜 The Memanto + mattpocock Developer Skills C#724

Closed
duongynhi000005-oss wants to merge 1 commit into
moorcheh-ai:mainfrom
duongynhi000005-oss:fix/bounty-10
Closed

[AI Fix] [BOUNTY $100] 🐜 The Memanto + mattpocock Developer Skills C#724
duongynhi000005-oss wants to merge 1 commit into
moorcheh-ai:mainfrom
duongynhi000005-oss:fix/bounty-10

Conversation

@duongynhi000005-oss

@duongynhi000005-oss duongynhi000005-oss commented Jun 11, 2026

Copy link
Copy Markdown

Automated Fix

This PR was automatically generated by an AI coding agent.

Bounty: [BOUNTY $100] 🐜 The Memanto + mattpocock Developer Skills Challenge
Issue: #508
Tool: codex


Please review the changes carefully before merging.

Summary by CodeRabbit

Release Notes

  • Documentation

    • Added comprehensive guide for integrating Memanto with Claude Code skills, including setup instructions and usage examples.
  • New Features

    • Introduced automatic memory hooks that recall relevant context before skill execution and extract engineering insights after completion.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a complete Memanto integration example for Claude Code skills. It consists of documentation describing the integration, a Python hook script implementing pre/post lifecycle handlers for memory recall and extraction, and a Bash wrapper orchestrating the flow. The hooks store durable engineering signals extracted from skill transcripts and inject recalled memories as system context before skill execution.

Changes

Claude Code + Memanto Integration Example

Layer / File(s) Summary
Documentation and setup guide
examples/claudecode-skills-memanto/README.md
README documenting the integration purpose, Memanto agent setup, hook installation via .claude/settings.json, end-to-end usage examples, environment variable controls, cross-skill memory reuse patterns, and implementation notes about memory storage and agent management.
Memanto hook script implementation
examples/claudecode-skills-memanto/scripts/memanto_skill_hook.py
Python CLI with pre, post, and sync modes: pre-hook derives skill name and constructs a recall query from prompt and working directory, then calls memanto recall and formats memories in a skill-specific context block; post-hook loads transcript excerpts, extracts durable engineering signals via regex and sentence splitting, and stores compact memory summaries via memanto remember with metadata; includes subprocess execution with timeouts, error handling, signal deduplication and truncation, and utility functions for text normalization and environment configuration.
Bash orchestration wrapper
examples/claudecode-skills-memanto/scripts/run_skill_with_memanto.sh
Bash wrapper validating skill arguments, exporting environment variables, generating JSON payloads containing prompt and working directory, calling the pre-hook to derive optional recall context, conditionally passing context to claude --append-system-prompt, running the skill, and invoking the post-hook to extract and store execution summaries.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A rabbit hops through memories keen,
Storing signals in between,
Claude's slash-commands now recall
The wisdom gathered through it all! 🐰✨
Durable decisions, fresh and bright—
Cross-skill learning, pure delight!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague, uses generic markers like [AI Fix] and [BOUNTY $100], includes an emoji, and is truncated mid-word ending with just 'C'. It fails to clearly describe the actual changes being made. Revise the title to be clear and descriptive of the main change, e.g., 'Add Claude Code skill lifecycle hook integration with Memanto for memory recall and engineering signal extraction' without decorative markers or emojis.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

@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: 4

🧹 Nitpick comments (1)
examples/claudecode-skills-memanto/scripts/memanto_skill_hook.py (1)

214-217: ⚡ Quick win

Avoid loading the entire transcript file when only tail lines are used.

Line 214 reads the full file into memory, but Line 216 only processes the last MAX_TRANSCRIPT_LINES. Use a bounded tail read (e.g., collections.deque) to reduce memory and I/O overhead for large transcripts.

🤖 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/scripts/memanto_skill_hook.py` around
lines 214 - 217, The code currently calls path.read_text(...) to load the entire
transcript into lines then slices the last MAX_TRANSCRIPT_LINES, which wastes
memory for large files; change the logic in the block that builds texts (around
path.read_text, lines, and the for loop using MAX_TRANSCRIPT_LINES) to stream
the file and keep only the tail using a bounded buffer such as
collections.deque(maxlen=MAX_TRANSCRIPT_LINES) while iterating over
path.open(encoding="utf-8", errors="replace"), then convert the deque to a list
and proceed with the existing loop so only the last MAX_TRANSCRIPT_LINES are
ever held in memory.
🤖 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/scripts/memanto_skill_hook.py`:
- Around line 108-130: The code currently persists raw content from
_build_memory (using prompt/transcript_text) directly via _run_memanto; instead,
perform a redaction pass on the memory string after calling _build_memory and
before calling _truncate/_run_memanto to strip/mask credentials, tokens, emails,
credit-cards and other PII. Implement or call a function like
redact_secrets(memory) (used on the variable returned by _build_memory) and use
the redacted text for the length check, the _truncate call and the value passed
into _run_memanto; keep existing symbols _build_memory, _truncate, _run_memanto,
MAX_MEMORY_CHARS and tags but ensure redaction is applied and tested so no raw
secrets are sent to Memanto.
- Around line 44-50: The CLI currently allows negative integers for "--limit"
and "--timeout" (set via parser.add_argument and _int_env), which breaks later
logic; add validation by replacing the type for these arguments with a validator
(e.g., a positive_int function used as the type in parser.add_argument for
"--limit" and "--timeout") that converts to int and raises
argparse.ArgumentTypeError if the value is <= 0, and also validate the parsed
values immediately after parsing (where DEFAULT_LIMIT / DEFAULT_TIMEOUT_SECONDS
and variables from _int_env are used) to ensure any env-derived values are
rejected or replaced with a safe default.
- Around line 92-97: The recall output from _run_memanto (variable recall) can
be arbitrarily large and is passed directly into _format_recall_context/print,
which causes CLI argument bloat in wrapper mode; before calling
_format_recall_context(skill_name, recall) truncate recall to a reasonable max
length (e.g., max_chars constant), preserving the start (or end) and appending
an ellipsis, and optionally log or annotate that the recall was truncated;
implement this trimming where recall is returned (after the _run_memanto call
and before the empty-check) so all downstream uses (including
_format_recall_context and print) receive the bounded string.

In `@examples/claudecode-skills-memanto/scripts/run_skill_with_memanto.sh`:
- Around line 29-35: set -e causes a failing claude invocation (the two branches
that call the claude command) to abort the script before the post-hook runs;
change the flow so you capture claude's exit status (run claude in both the
context and non-context branches, save its exit code into a variable, e.g.
claude_status), then unconditionally invoke the post-hook (python3
memanto_skill_hook.py post with payload), and finally exit/return with the saved
claude_status so the original exit code is preserved.

---

Nitpick comments:
In `@examples/claudecode-skills-memanto/scripts/memanto_skill_hook.py`:
- Around line 214-217: The code currently calls path.read_text(...) to load the
entire transcript into lines then slices the last MAX_TRANSCRIPT_LINES, which
wastes memory for large files; change the logic in the block that builds texts
(around path.read_text, lines, and the for loop using MAX_TRANSCRIPT_LINES) to
stream the file and keep only the tail using a bounded buffer such as
collections.deque(maxlen=MAX_TRANSCRIPT_LINES) while iterating over
path.open(encoding="utf-8", errors="replace"), then convert the deque to a list
and proceed with the existing loop so only the last MAX_TRANSCRIPT_LINES are
ever held in memory.
🪄 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: 0a75466c-af27-4122-8963-3ee077a4e835

📥 Commits

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

📒 Files selected for processing (3)
  • examples/claudecode-skills-memanto/README.md
  • examples/claudecode-skills-memanto/scripts/memanto_skill_hook.py
  • examples/claudecode-skills-memanto/scripts/run_skill_with_memanto.sh

Comment on lines +44 to +50
"--limit", type=int, default=_int_env("MEMANTO_SKILL_LIMIT", DEFAULT_LIMIT)
)
parser.add_argument(
"--timeout",
type=int,
default=_int_env("MEMANTO_SKILL_TIMEOUT", DEFAULT_TIMEOUT_SECONDS),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate --limit and --timeout as positive integers.

Lines 44-50 accept negative values from CLI/env. A negative timeout later causes subprocess errors and silently disables behavior due global exception handling.

🤖 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/scripts/memanto_skill_hook.py` around
lines 44 - 50, The CLI currently allows negative integers for "--limit" and
"--timeout" (set via parser.add_argument and _int_env), which breaks later
logic; add validation by replacing the type for these arguments with a validator
(e.g., a positive_int function used as the type in parser.add_argument for
"--limit" and "--timeout") that converts to int and raises
argparse.ArgumentTypeError if the value is <= 0, and also validate the parsed
values immediately after parsing (where DEFAULT_LIMIT / DEFAULT_TIMEOUT_SECONDS
and variables from _int_env are used) to ensure any env-derived values are
rejected or replaced with a safe default.

Comment on lines +92 to +97
recall = _run_memanto(["recall", query, "--limit", str(limit)], timeout)
if not recall.strip():
return

print(_format_recall_context(skill_name, recall))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Bound recalled context size before printing it.

Line 92 can return arbitrarily large recall output, and Line 96 emits it directly. In wrapper mode this becomes a CLI argument to claude, which can fail with argument-size limits and prompt bloat. Cap/truncate recall text before formatting.

Proposed fix
 def _pre_skill(event: dict[str, Any], limit: int, timeout: int) -> None:
@@
-    recall = _run_memanto(["recall", query, "--limit", str(limit)], timeout)
+    recall = _run_memanto(["recall", query, "--limit", str(limit)], timeout)
     if not recall.strip():
         return
 
-    print(_format_recall_context(skill_name, recall))
+    bounded_recall = _truncate(recall.strip(), MAX_MEMORY_CHARS)
+    print(_format_recall_context(skill_name, bounded_recall))
🤖 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/scripts/memanto_skill_hook.py` around
lines 92 - 97, The recall output from _run_memanto (variable recall) can be
arbitrarily large and is passed directly into _format_recall_context/print,
which causes CLI argument bloat in wrapper mode; before calling
_format_recall_context(skill_name, recall) truncate recall to a reasonable max
length (e.g., max_chars constant), preserving the start (or end) and appending
an ellipsis, and optionally log or annotate that the recall was truncated;
implement this trimming where recall is returned (after the _run_memanto call
and before the empty-check) so all downstream uses (including
_format_recall_context and print) receive the bounded string.

Comment on lines +108 to +130
memory = _build_memory(skill_name, prompt, signals, transcript_text)
if len(memory) < 80:
return

tags = ["claude-code", "skills-memanto"]
if skill_name:
tags.append(_tagify(skill_name))

_run_memanto(
[
"remember",
_truncate(memory, MAX_MEMORY_CHARS),
"--type",
"context",
"--confidence",
"0.85",
"--provenance",
"observed",
"--source",
"claude_code_skills",
"--tags",
",".join(tags),
],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Redact secrets before persisting memory content to Memanto.

Lines 108-130 store prompt/transcript-derived content externally. Without redaction, credentials/tokens/PII from user prompts or transcript snippets can be persisted.

🤖 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/scripts/memanto_skill_hook.py` around
lines 108 - 130, The code currently persists raw content from _build_memory
(using prompt/transcript_text) directly via _run_memanto; instead, perform a
redaction pass on the memory string after calling _build_memory and before
calling _truncate/_run_memanto to strip/mask credentials, tokens, emails,
credit-cards and other PII. Implement or call a function like
redact_secrets(memory) (used on the variable returned by _build_memory) and use
the redacted text for the length check, the _truncate call and the value passed
into _run_memanto; keep existing symbols _build_memory, _truncate, _run_memanto,
MAX_MEMORY_CHARS and tags but ensure redaction is applied and tested so no raw
secrets are sent to Memanto.

Comment on lines +29 to +35
if [[ -n "${context// }" ]]; then
claude "$skill_name" "$@" --append-system-prompt "$context"
else
claude "$skill_name" "$@"
fi

printf '%s' "$payload" | python3 "$script_dir/memanto_skill_hook.py" post || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Ensure post-hook runs even when claude exits non-zero.

With set -e (Line 2), a failing claude command on Lines 30/32 exits the script before Line 35, so post-processing is skipped. Capture claude exit status, run post-hook unconditionally, then return the original status.

Proposed fix
 if [[ -n "${context// }" ]]; then
-  claude "$skill_name" "$@" --append-system-prompt "$context"
+  claude_rc=0
+  claude "$skill_name" "$@" --append-system-prompt "$context" || claude_rc=$?
 else
-  claude "$skill_name" "$@"
+  claude_rc=0
+  claude "$skill_name" "$@" || claude_rc=$?
 fi
 
 printf '%s' "$payload" | python3 "$script_dir/memanto_skill_hook.py" post || true
+exit "$claude_rc"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ -n "${context// }" ]]; then
claude "$skill_name" "$@" --append-system-prompt "$context"
else
claude "$skill_name" "$@"
fi
printf '%s' "$payload" | python3 "$script_dir/memanto_skill_hook.py" post || true
if [[ -n "${context// }" ]]; then
claude_rc=0
claude "$skill_name" "$@" --append-system-prompt "$context" || claude_rc=$?
else
claude_rc=0
claude "$skill_name" "$@" || claude_rc=$?
fi
printf '%s' "$payload" | python3 "$script_dir/memanto_skill_hook.py" post || true
exit "$claude_rc"
🤖 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/scripts/run_skill_with_memanto.sh` around
lines 29 - 35, set -e causes a failing claude invocation (the two branches that
call the claude command) to abort the script before the post-hook runs; change
the flow so you capture claude's exit status (run claude in both the context and
non-context branches, save its exit code into a variable, e.g. claude_status),
then unconditionally invoke the post-hook (python3 memanto_skill_hook.py post
with payload), and finally exit/return with the saved claude_status so the
original exit code is preserved.

@Xenogents

Copy link
Copy Markdown
Collaborator

We were blown away by the community's creativity and the sheer volume of high-quality submissions! After reviewing all the pull requests against the bounty's success matrix, we have decided to move forward with merging PR #692, which implemented a highly portable prompt-injection architecture via CLAUDE.md.

We are closing this PR because it falls into one of the architectural approaches that we ultimately decided against for the ecosystem:

  • High Friction (CLI Wrappers): Many submissions used Python or Bash wrappers (e.g., forcing the user to type memanto-wrap /tdd instead of the native claude /tdd). While effective at passing context, managing child PTY processes introduces terminal overhead and breaks the developer's native muscle memory
  • Incomplete Lifecycle (Manual Scripts): Some submissions successfully implemented the context extraction logic but failed to automate it, requiring the user to manually run pre and post scripts around every skill session.

We deeply appreciate the time and engineering effort you put into this submission. The codebase was fantastic to review, and we hope to see you in future Moorcheh bounties!

@Xenogents Xenogents closed this Jun 16, 2026
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.

2 participants