Install the memory automation into the current project (${CLAUDE_PROJECT_DIR}), so ./memory/ keeps growing on its own instead of relying on anyone remembering to update it by hand.
What this does
Three scripts, two hooks:
memory-filter.sh (Stop hook) — fires after every response. Reads
transcript_path/cwd from stdin and immediately forks
memory-filter-worker.sh as a detached background process, then exits.
This must stay near-instant: Stop is synchronous (Claude Code waits for
it), so the actual work cannot happen here.
memory-filter-worker.sh (background only, never registered as a
hook) — does the real work. Pulls the last real user message plus every
bit of assistant narration since then out of the transcript, sends it to
a cheap/fast model (Haiku) with a rubric asking "is this a decision /
feedback / progress update / pattern worth remembering?", and if YES,
writes a one-line summary to .claude/hooks/.memory-pending.json. A NO
writes nothing — costs nothing, leaves no trace anywhere.
memory-pending-check.sh (UserPromptSubmit hook) — fires when the
user submits their next message. Reads .memory-pending.json if it
exists, surfaces it as additionalContext for that prompt, then deletes
it (read-once). At that point the main agent (not Haiku) decides what
to actually write and where, following memory/mentoring_rules.md's
SESSION UPDATE PROTOCOL — the filter never writes memory itself.
Why split into three instead of one hook doing everything: measured
latency for a real headless claude -p call is ~5-35s (mostly CLI/network
overhead, not the model). A single synchronous Stop hook would add that
delay after every single response, which defeats the point of a "cheap"
background check. Splitting the slow part into a detached background
process means Stop returns in single-digit milliseconds — the check
still happens, it just surfaces on the next turn instead of blocking this
one. Best-effort, not guaranteed-immediate: if the user replies faster than
the worker finishes, that one reminder is skipped and the next turn's
worker run catches up instead.
Steps
Check dependencies. Run command -v jq and command -v claude. If
either is missing, stop and tell the user which one — everything here
fails open (never breaks a session) but is a no-op without them.
Copy the hook scripts.
mkdir -p ${CLAUDE_PROJECT_DIR}/.claude/hooks
- Copy this skill's
memory-filter.sh, memory-filter-worker.sh, and
memory-pending-check.sh (all co-located next to this SKILL.md) to
${CLAUDE_PROJECT_DIR}/.claude/hooks/.
chmod +x all three copies.
- If files already exist at the destination, diff each against its
source first — if identical, skip; if different, ask the user before
overwriting (they may have customized it).
Register both hooks in .claude/settings.json.
- Read the file if it exists; otherwise start from
{}.
- This is a merge, never a blind overwrite — preserve every existing
key. Add (or extend, if either array already has entries) this block:
{
"hooks": {
"Stop": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/memory-filter.sh",
"timeout": 10,
"suppressOutput": true
}
],
"UserPromptSubmit": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/memory-pending-check.sh",
"timeout": 5,
"suppressOutput": true
}
]
}
}
Both timeouts are short on purpose — memory-filter.sh only forks a
background process, and memory-pending-check.sh only reads/deletes a
small file. Neither should ever take more than a second or two; if one
does, something is broken, not just slow.
- Idempotency: before adding, check whether these hooks are already
registered — if so, don't duplicate the entries.
- If the
update-config skill is available in this session, prefer
delegating this merge to it instead of hand-editing the JSON — it
knows the current settings.json schema authoritatively and this
skill's copy of the schema can drift out of date.
Gitignore the pending file. Add .claude/hooks/.memory-pending.json
to .gitignore if it's not already covered — it's ephemeral scratch
state (may briefly contain a snippet of conversation content) and should
never be committed.
Verify memory/feedback_log.md exists. The filter's rubric routes
"confirmation of a working approach" signals there. If the project
copied an older version of this template without that file, create it
from memory/feedback_log.md in this repo (or prompt the user to pull
the latest template).
Confirm to the user in one or two sentences: both hooks installed,
Stop returns instantly (background worker does the real check), a
flagged turn surfaces as a reminder on the next message rather than
blocking the current one. Mention they can remove it by deleting both
hook entries from .claude/settings.json.
Do not
- Do not put the Haiku call directly in the
Stop hook — Stop is
synchronous, so anything slow there blocks the user after every single
response. Always fork it into memory-filter-worker.sh in the
background.
- Do not make either hook
decision: block the turn — that risks loops if
the filter is noisy, and defeats the non-blocking design. Both hooks only
ever use additionalContext.
- Do not run this skill's logic silently as a side effect of something else
— it edits
settings.json, which is why disable-model-invocation: true
is set. Only run it when the user explicitly asks (/init-mentoring).
1---2name: init-mentoring3description: Install the self-updating memory automation for this mentoring setup. Copies the hook scripts into the current project and registers them in .claude/settings.json. Run once, right after cloning/copying claude-code-mentoring into a project.4---56Install the memory automation into the **current project** (`${CLAUDE_PROJECT_DIR}`), so `./memory/` keeps growing on its own instead of relying on anyone remembering to update it by hand.78## What this does910Three scripts, two hooks:1112- **`memory-filter.sh`** (`Stop` hook) — fires after every response. Reads13 `transcript_path`/`cwd` from stdin and immediately forks14 `memory-filter-worker.sh` as a detached background process, then exits.15 This must stay near-instant: `Stop` is synchronous (Claude Code waits for16 it), so the actual work cannot happen here.17- **`memory-filter-worker.sh`** (background only, never registered as a18 hook) — does the real work. Pulls the last real user message plus every19 bit of assistant narration since then out of the transcript, sends it to20 a cheap/fast model (Haiku) with a rubric asking "is this a decision /21 feedback / progress update / pattern worth remembering?", and if `YES`,22 writes a one-line summary to `.claude/hooks/.memory-pending.json`. A `NO`23 writes nothing — costs nothing, leaves no trace anywhere.24- **`memory-pending-check.sh`** (`UserPromptSubmit` hook) — fires when the25 user submits their next message. Reads `.memory-pending.json` if it26 exists, surfaces it as `additionalContext` for that prompt, then deletes27 it (read-once). At that point the **main agent** (not Haiku) decides what28 to actually write and where, following `memory/mentoring_rules.md`'s29 SESSION UPDATE PROTOCOL — the filter never writes memory itself.3031**Why split into three instead of one hook doing everything:** measured32latency for a real headless `claude -p` call is ~5-35s (mostly CLI/network33overhead, not the model). A single synchronous `Stop` hook would add that34delay after *every single response*, which defeats the point of a "cheap"35background check. Splitting the slow part into a detached background36process means `Stop` returns in single-digit milliseconds — the check37still happens, it just surfaces on the next turn instead of blocking this38one. Best-effort, not guaranteed-immediate: if the user replies faster than39the worker finishes, that one reminder is skipped and the next turn's40worker run catches up instead.4142## Steps43441. **Check dependencies.** Run `command -v jq` and `command -v claude`. If45 either is missing, stop and tell the user which one — everything here46 fails open (never breaks a session) but is a no-op without them.47482. **Copy the hook scripts.**49 - `mkdir -p ${CLAUDE_PROJECT_DIR}/.claude/hooks`50 - Copy this skill's `memory-filter.sh`, `memory-filter-worker.sh`, and51 `memory-pending-check.sh` (all co-located next to this `SKILL.md`) to52 `${CLAUDE_PROJECT_DIR}/.claude/hooks/`.53 - `chmod +x` all three copies.54 - If files already exist at the destination, diff each against its55 source first — if identical, skip; if different, ask the user before56 overwriting (they may have customized it).57583. **Register both hooks in `.claude/settings.json`.**59 - Read the file if it exists; otherwise start from `{}`.60 - This is a **merge**, never a blind overwrite — preserve every existing61 key. Add (or extend, if either array already has entries) this block:62 ```json63 {64 "hooks": {65 "Stop": [66 {67 "type": "command",68 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/memory-filter.sh",69 "timeout": 10,70 "suppressOutput": true71 }72 ],73 "UserPromptSubmit": [74 {75 "type": "command",76 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/memory-pending-check.sh",77 "timeout": 5,78 "suppressOutput": true79 }80 ]81 }82 }83 ```84 Both timeouts are short on purpose — `memory-filter.sh` only forks a85 background process, and `memory-pending-check.sh` only reads/deletes a86 small file. Neither should ever take more than a second or two; if one87 does, something is broken, not just slow.88 - Idempotency: before adding, check whether these hooks are already89 registered — if so, don't duplicate the entries.90 - If the `update-config` skill is available in this session, prefer91 delegating this merge to it instead of hand-editing the JSON — it92 knows the current settings.json schema authoritatively and this93 skill's copy of the schema can drift out of date.94954. **Gitignore the pending file.** Add `.claude/hooks/.memory-pending.json`96 to `.gitignore` if it's not already covered — it's ephemeral scratch97 state (may briefly contain a snippet of conversation content) and should98 never be committed.991005. **Verify `memory/feedback_log.md` exists.** The filter's rubric routes101 "confirmation of a working approach" signals there. If the project102 copied an older version of this template without that file, create it103 from `memory/feedback_log.md` in this repo (or prompt the user to pull104 the latest template).1051066. **Confirm to the user** in one or two sentences: both hooks installed,107 `Stop` returns instantly (background worker does the real check), a108 flagged turn surfaces as a reminder on the *next* message rather than109 blocking the current one. Mention they can remove it by deleting both110 hook entries from `.claude/settings.json`.111112## Do not113114- Do not put the Haiku call directly in the `Stop` hook — `Stop` is115 synchronous, so anything slow there blocks the user after every single116 response. Always fork it into `memory-filter-worker.sh` in the117 background.118- Do not make either hook `decision: block` the turn — that risks loops if119 the filter is noisy, and defeats the non-blocking design. Both hooks only120 ever use `additionalContext`.121- Do not run this skill's logic silently as a side effect of something else122 — it edits `settings.json`, which is why `disable-model-invocation: true`123 is set. Only run it when the user explicitly asks (`/init-mentoring`).