[AI Fix] [BOUNTY $100] 🐜 The Memanto + mattpocock Developer Skills C#724
[AI Fix] [BOUNTY $100] 🐜 The Memanto + mattpocock Developer Skills C#724duongynhi000005-oss wants to merge 1 commit into
Conversation
Automated fix by AI agent (codex).
📝 WalkthroughWalkthroughThis 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. ChangesClaude Code + Memanto Integration Example
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 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 |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
examples/claudecode-skills-memanto/scripts/memanto_skill_hook.py (1)
214-217: ⚡ Quick winAvoid 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
📒 Files selected for processing (3)
examples/claudecode-skills-memanto/README.mdexamples/claudecode-skills-memanto/scripts/memanto_skill_hook.pyexamples/claudecode-skills-memanto/scripts/run_skill_with_memanto.sh
| "--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), | ||
| ) |
There was a problem hiding this comment.
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.
| recall = _run_memanto(["recall", query, "--limit", str(limit)], timeout) | ||
| if not recall.strip(): | ||
| return | ||
|
|
||
| print(_format_recall_context(skill_name, recall)) | ||
|
|
There was a problem hiding this comment.
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.
| 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), | ||
| ], |
There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
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.
| 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.
|
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:
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! |
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
New Features