feat(claude-memory): add stateless skill - #775
Conversation
Add /claude-memory:stateless for inspecting and disabling Claude Code auto memory — the notes Claude writes for itself per repo under ~/.claude/projects/<project>/memory/ (relocatable via autoMemoryDirectory). Actions: status (default, read-only — effective on/off state and store contents across all settings scopes), disable (autoMemoryEnabled:false + CLAUDE_CODE_DISABLE_AUTO_MEMORY via a deterministic jq merge in a confirmed scope, with a dotfile-manager backfill flag), and purge (destructive — reads autoMemoryDirectory at every scope, captures an explicit deletion manifest, flags any dir outside ~/.claude/projects/, and deletes the exact captured paths only after explicit confirmation). Scope is auto-memory only; the instruction layer stays with the audit skill, and transcripts/history are out of scope. Per the env-vars doc, CLAUDE_CODE_DISABLE_AUTO_MEMORY overrides autoMemoryEnabled, so status treats a set env var as authoritative and disable writes both levers. scope-report.sh reuses the plugin's single-source resolve-memory-dir.sh. Bumps claude-memory 0.2.3 -> 0.3.0; updates README, CHANGELOG, marketplace tags, and regenerates the root catalog. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 3m 38s —— View job PR Review: feat(claude-memory): add stateless skillTodo:
Overall AssessmentStrong, security-conscious addition. The three-action design (status / disable / purge) is well-scoped, the TOCTOU avoidance in Finding 1 — Test isolation gap in Case 4 (minor)File: OUT=$(cd "$REPO" && HOME="$ISO_HOME" bash "$SCRIPT")Cases 2 and 3 correctly control The fix is a one-word addition: prepend Finding 2 — Multi-scope
|
|
Claude finished @kyle-sexton's task in 3m 22s —— View job Security Review
Two security issues found. No CRITICAL issues. IMPORTANT · HIGH confidence — Path traversal bypass in purge relocation checkFile: The PR specifically adds a case-statement guard to flag directories outside case "$dir" in
"$HOME/.claude/projects/"*) : ;; # expected default tree
*) echo "UNEXPECTED RELOCATION: $dir is outside ~/.claude/projects/ ..." ;;
esacThis check uses string prefix matching, not canonicalized path comparison. A project's { "autoMemoryDirectory": "~/.claude/projects/../../sensitive-docs/" }expands (after the model does the That string starts with The safety guard that the PR description cites as a security improvement is the exact control that fails. The confirmation gate partially mitigates this, but:
Fix: canonicalize with real_dir=$(realpath -m "$dir" 2>/dev/null || echo "$dir")
case "$real_dir" in
"$HOME/.claude/projects/"*) : ;;
*) echo "UNEXPECTED RELOCATION: $real_dir ..." ;;
esac
find "$real_dir" ... # also find on the resolved pathSUGGESTION · MEDIUM confidence — Terminal escape injection via env var echoFile: echo "CLAUDE_CODE_DISABLE_AUTO_MEMORY=${CLAUDE_CODE_DISABLE_AUTO_MEMORY} (set in OS environment)"The raw value of Expected values are printf 'CLAUDE_CODE_DISABLE_AUTO_MEMORY=%q (set in OS environment)\n' \
"${CLAUDE_CODE_DISABLE_AUTO_MEMORY}"
No other security issues found. The TOCTOU mitigation (exact-manifest capture in |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f38d0d37d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Address two review findings on the stateless skill.
1. CLAUDE_CONFIG_DIR relocation. Per the official .claude-directory doc, setting
CLAUDE_CONFIG_DIR relocates every ~/.claude path — the user settings.json AND
the projects/<project>/memory/ tree — under that directory. Resolution now uses
${CLAUDE_CONFIG_DIR:-$HOME/.claude} wherever scopes/dirs are enumerated:
scope-report.sh (user scope + reports the resolved root), the shared
resolve-memory-dir.sh (root-cause fix — both audit and stateless benefit),
and the disable/purge workflows (including purge's relocation-flag check, so a
CLAUDE_CONFIG_DIR-relocated tree is expected, not flagged).
2. Create the settings parent directory before writing. The disable jq-merge
recipe now runs mkdir -p "$(dirname "$settings")" before the write, so a
project/local scope whose .claude/ does not exist yet no longer fails the mv.
Adds a CLAUDE_CONFIG_DIR regression case to scope-report.test.sh (16 checks) and
a sourced quote to the reference doc.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Claude finished @kyle-sexton's task in 2m 28s —— View job Security Review: feat(claude-memory): add stateless skillTodo:
Two security issues found. Both were flagged in the initial security review on commit IMPORTANT · HIGH confidence — Path traversal bypass in purge relocation checkFile: case "$dir" in
"$config_root/projects/"*) : ;; # expected default (or CLAUDE_CONFIG_DIR-relocated) tree
*) echo "UNEXPECTED RELOCATION: $dir is outside $config_root/projects/ ..." ;;
esac
find "$dir" -maxdepth 1 -type f -name '*.md' 2>/dev/nullThe relocation safety check uses string prefix matching on an unresolved path. A { "autoMemoryDirectory": "~/.claude/projects/../../sensitive-docs/" }After Step 1's This starts with The security control the PR description cites is the exact control that fails. Fix: canonicalize real_dir=$(realpath -m "$dir" 2>/dev/null || readlink -f "$dir" 2>/dev/null || echo "$dir")
case "$real_dir" in
"$config_root/projects/"*) : ;;
*) echo "UNEXPECTED RELOCATION: $real_dir ..." ;;
esac
find "$real_dir" -maxdepth 1 -type f -name '*.md' 2>/dev/nullPresent SUGGESTION · MEDIUM confidence — Terminal escape injection via unquoted env var echoFile: echo "CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR} (config root relocated — ...)"
...
echo "CLAUDE_CODE_DISABLE_AUTO_MEMORY=${CLAUDE_CODE_DISABLE_AUTO_MEMORY} (set in OS environment)"Raw env var values are emitted directly to stdout. Bash's built-in Expected values for printf 'CLAUDE_CONFIG_DIR=%q (config root relocated — ...)\n' "${CLAUDE_CONFIG_DIR}"
printf 'CLAUDE_CODE_DISABLE_AUTO_MEMORY=%q (set in OS environment)\n' "${CLAUDE_CODE_DISABLE_AUTO_MEMORY}"
No other security issues found. The TOCTOU avoidance (exact-manifest capture in Step 2), |
|
Claude finished @kyle-sexton's task in 3m 43s —— View job PR Review: feat(claude-memory): add stateless skillTodo:
Overall AssessmentThe two-commit PR is well-designed: the first commit delivers the What the Fix Commit (705208d) AddressedBoth Codex findings are confirmed resolved: 1. CLAUDE_CONFIG_DIR honored — 2. Outstanding Findings (from prior reviews — not yet addressed)1 — Path traversal bypass in purge relocation check · HIGHFile: The fix commit updated An Fix: canonicalize before the case check: real_dir=$(realpath -m "$dir" 2>/dev/null || readlink -f "$dir" 2>/dev/null || echo "$dir")
case "$real_dir" in
"$config_root/projects/"*) : ;;
*) echo "UNEXPECTED RELOCATION: $real_dir is outside $config_root/projects/ (from autoMemoryDirectory)" ;;
esac
find "$real_dir" -maxdepth 1 -type f -name '*.md' 2>/dev/null2 — Test isolation gap in Case 4 · minorFile: OUT=$(cd "$REPO" && HOME="$ISO_HOME" bash "$SCRIPT")Case 2 and the new Case 6 both correctly unset OUT=$(cd "$REPO" && env -u CLAUDE_CODE_DISABLE_AUTO_MEMORY HOME="$ISO_HOME" bash "$SCRIPT")3 — Multi-scope
|
Summary
Adds a second skill to the
claude-memoryplugin:/claude-memory:stateless— inspect, disable, and (destructively) purge Claude Code auto memory, the notes Claude writes for itself per repo under~/.claude/projects/<project>/memory/(relocatable viaautoMemoryDirectory). Sibling to the existingauditskill (instruction-layer axis); no overlap.Actions:
status(default, read-only): effective on/off state and store contents resolved across all settings scopes.disable: setsautoMemoryEnabled: false+CLAUDE_CODE_DISABLE_AUTO_MEMORYvia a deterministicjqmerge in a scope you confirm, and flags a dotfile-manager backfill when the targetsettings.jsonis tracked.purge(destructive): readsautoMemoryDirectoryat every scope, captures an explicit deletion manifest, flags any candidate dir outside~/.claude/projects/, and deletes the exact captured paths only after an explicit confirmation gate.Scope is auto-memory only — the instruction layer (
CLAUDE.md/.claude/rules/) stays withaudit; transcripts/history are out of scope (auto-cleaned bycleanupPeriodDays). Claude Desktop / claude.ai account memory is server-side, so the skill gives direction-only steps rather than deleting it locally.No linked issue — planned skill (ledger "Skill K") built as part of the parallel plugin-build batch; not tracked as a GitHub issue.
Precedence (verified this session)
The design ledger flagged env-var-vs-setting precedence as UNVERIFIED. The
/en/env-varsdoc does document it:CLAUDE_CODE_DISABLE_AUTO_MEMORY"Set to0to force auto memory on even when …autoMemoryEnabled: falsewould otherwise disable it." So the env var overrides the setting — the skill treats a set env var as authoritative instatusand writes both levers ondisable.Design notes
${CLAUDE_PLUGIN_ROOT}refs only.scope-report.shreuses the plugin's single-sourceresolve-memory-dir.sh(point-don't-copy) rather than re-deriving the slug.claude-memory0.2.3 → 0.3.0; updates README, CHANGELOG, marketplace tags; regenerates the root catalog.Verification
~/.claude/projects/) + independent code/design review.skill-quality:checkPASS (0/0), evals schema (check-jsonschema) OK,scope-report.test.sh13/13, shellcheck + shfmt clean, markdownlint 0 errors,validate-plugins,generate-catalog --check,check-changelog-parity, unique leaf name, portability.Do not merge — orchestrator merges lanes sequentially.
Related
plugins/claude-memory/skills/audit— sibling skill (instruction-layer axis);statelesscovers the auto-memory state/lifecycle axis.🤖 Generated with Claude Code