Memorize
Persist a single fact or preference so it survives across sessions, machines, and agents. remember / /remember and always / /always are synonyms for this skill — same behavior; the wording the user happens to use doesn’t change anything.
Unlike ums (which reviews the whole session and may also update skill definitions), this stores exactly what the user says — no scanning, no skill updates. A memory counts only once it is committed to the repo that owns it (ai-config for a cross-repo rule or fact), so memorize commits and pushes the one change; otherwise the note is lost when the session ends (ephemeral cloud containers are reclaimed) and no other project or machine sees it.
When this fires
- “memorize …”, “remember that …”, “/remember …”, “note that …”, “add to memories: …”
- A standing directive phrased as a preference: “always …”, “never …”, “I prefer …”, “from now on …”
First: is it actually a memory?
If the request is an automated every-time action (“after each commit run X”, “whenever I edit Y do Z”), memory can’t execute it — that needs a hook in settings.json / settings.local.json (use the update-config skill). Say so and route it there; don’t store a note that will never fire.
Unsure whether a request is really a memory versus a skill, subagent, hook, or gha capability? config-ai (ca/cai) is the broader router across all of those forms — this skill is what it hands off to once memory is the answer.
Procedure
Parse the fact/preference from the user’s message.
Choose scope by relevance:
- Project-specific, a repo we own — a fact, convention, or gotcha tied to ONE specific repo we own (“renders with renv via
R_LIBS_USER”) → commit it to that project’s own repo via a PR (itsCLAUDE.md,.github/copilot-instructions.md, or whatever agent-doc infrastructure it already has), so the whole team and every@claudesession there can see it. (NOTmemories/repo/inside ai-config; that directory is removed.) If the repo has no agent-doc infrastructure yet, write to its local Claude project memory instead —~/.claude/projects/<project-path>/memory/<file>.md— as short-lived staging only, not a durable destination, and tell the user a PR adding agent-doc infrastructure to that repo (plus migrating the staged memory there) is still needed. The project path is the repo’s directory path with/replaced by-— e.g./Users/you/Documents/GitHub/rme→-Users-you-Documents-GitHub-rme. UpdateMEMORY.mdin that directory as an index entry when you used this local-staging fallback — not when the fact was committed directly to the owned repo’s own agent docs, which needs no local copy. - Project-specific, an external repo we don’t own — never open a direct PR autonomously. Route it through
upstream-issues: check the repo’s contribution policy first (some ban autonomous AI PRs/issues outright), then draft and get explicit user approval before posting anything. Until approved, stage the fact in that repo’s local Claude project memory as short-lived, not-yet-durable staging, and updateMEMORY.mdthere as an index entry too. - General standing rule — an always-apply working preference across ALL repos (“always link PRs in tables”, “use Pacific time”) → ai-config’s own
AGENTS.md(cross-agent) orCLAUDE.md/ ashared/fragment (Claude-specific detail), committed toMorrison-Lab/ai-configby PR. The plugin’shooks/inject-core-rules.pystarts every session withAGENTS.md’s section index and an order to read it in full, so that is what makes the rule reach other projects. Keep theAGENTS.mdentry to the rule in a line or two with a pointer, and put detail in ashared/fragment:AGENTS.mdhas a hard 32,768-byte cap. Do not write it to~/.claude/CLAUDE.mdunless that file is a symlink into an ai-config checkout: the symlink install was removed, and a plain file there is invisible to every other machine, container and project. - Host memory is a copy, never the home. A claude.ai project’s memory, a Cowork or desktop memory store, or any other memory the harness offers is read only inside that project. A cross-project rule goes to ai-config as above; the host memory may hold a pointer to it (ai-config#4208).
- General reference fact — a cross-project fact that only matters when relevant (“gh opens a pager — pipe to cat”) → a topical file in
/memories/, ortools.mdfor what fits none of them. Readmemories/MEMORY.mdfor the current set and what each one covers; it is the registry, so naming the files here too would only go stale. When you add a new file here (not just a bullet to an existing one), register it inmemories/MEMORY.mdas an index entry. - Conversation-only →
/memories/session/ - When ambiguous between project and general, judge by relevance; default to general.
- Project-specific, a repo we own — a fact, convention, or gotcha tied to ONE specific repo we own (“renders with renv via
Choose file: read the target’s current contents first. Append to an existing section/file if one fits; otherwise create a descriptively named file — and when you create a new file under
/memories/, add a row for it tomemories/MEMORY.md(the index). Don’t duplicate – grep the target file for the subject (the tool name, the API call, the error string), not just the region you’re appending to; a long file likememories/r-quarto.mdcan already cover it hundreds of lines away. Grep every topical file, not just the one you picked – a fact aboutgh workflow runcould plausibly have landed ingithub.mdorgithub-actions.md. If it’s already recorded, update in place rather than stacking a second copy, and say so. Delete a memory that turns out wrong instead of leaving a contradiction.Write a concise bullet (one line preferred), matching the file’s voice; include the why if it isn’t obvious. Don’t record what the repo already documents (code structure, git history) — capture only the non-obvious.
Commit & push the change so it persists. What that means depends on where step 2 wrote it:
- Project’s own repo, owned — commit, push a branch, and open a PR there, same as any other change to that repo.
- Project’s own repo, external (not owned) — never push/open a PR directly; follow
upstream-issues(policy check, draft, explicit user approval) instead. ~/.claude/projects/*/memory/staging (the project repo has no agent-doc infrastructure yet, or is external and not yet approved) — no git commit; it persists locally only. UpdateMEMORY.mdin that directory as an index entry. Tell the user this is temporary staging and what’s still needed (agent-doc infra added via a PR, or upstream approval)./memories/session/— skip; conversation-only notes shouldn’t enter the shared repo.- No
~/.claude/memoriessymlink (a cloud or project session, or any machine set up after the symlink install was removed) — attach or cloneMorrison-Lab/ai-config, commit the change there on a branch, and open a PR (push-memorydoes this). A write under~/.claudethat is not a symlink into ai-config is lost with the container or stays on one machine, which is how the user ends up repeating themselves. - Everything else gets committed to ai-config. The commands below apply only to a machine that still has the legacy
~/.claude/memoriessymlink into an ai-config checkout and works in that checkout; without the symlink, use the bullet above. When you’re working primarily in another repo and want to push a general memory to ai-config from there, usepush-memoryinstead — it delivers on a branch + PR and never touches the repo you’re in. Resolve the repo from thememories/symlink and stage the file by its path within the repo (git rev-parse --show-toplevelfollows the symlink to the repo root, robust across one or many hops, unlike single-hopreadlink):
[ -L ~/.claude/memories ] || { echo "no ~/.claude/memories symlink: use the no-symlink path (push-memory)"; exit 1; } repo="$(git -C ~/.claude/memories rev-parse --show-toplevel)" # ai-config repo root rel="CLAUDE.md" # or memories/<file>.md (NOT memories/repo/ — that's gone) git -C "$repo" add "$rel" \ && git -C "$repo" commit -m "memorize: <one-line summary>"Push as a separate Bash call, per
check-before-pushing’s “Keep the commit in its own Bash call”:repo="$(git -C ~/.claude/memories rev-parse --show-toplevel)" # re-derived: a separate Bash call does not inherit the variable git -C "$repo" push origin HEAD # current branch; not HEAD:main -- that would push a feature branch's commits onto mainThe push targets the ai-config repo’s current branch, so run memorize from a checkout on
main(the normal case) — that’s where shared memory belongs. In an ephemeral cloud session the push is mandatory: an unpushed commit dies with the container.Worktree session / occupied main checkout (legacy symlink machines). Where
~/.claude/memoriesand~/.claude/CLAUDE.mdare still symlinked to the main checkout,git -C ~/.claude/memories rev-parse --show-toplevelresolves to the main checkout — not your worktree. If that checkout is on a non-mainbranch (e.g. another session is working there, possibly with uncommitted edits), committing through the symlink lands your memory on the wrong branch and can tangle with that session’s work. In that case don’t commit through the symlink: edit the memory file at its path inside your worktree, commit on your worktree branch, and land it via branch + PR + merge. It only reaches the live symlinked memory once it merges tomainand the main checkout updates. (See the worktree-isolation and no-cd-in-worktree bullets inmemories/preferences.md, and thesession-lockskill.)Confirm: one sentence — what was stored, where, and that it was pushed.
Don’t
- Don’t run a full session review or touch skill files (that’s
ums). - Don’t commit unrelated changes — stage only the file you wrote.
- Don’t push conversation-only (
/memories/session/) notes to the shared repo. - Don’t store secrets, tokens, or passwords.
- Don’t over-elaborate — one bullet per fact.