references/diagnosis_and_scoping.md
# Diagnosis & Scoping
## The scope decision table
Classify each memory file by **scope** — who/what needs it — not by "is it messy".
| Memory content | Goes to | Why |
|---|---|---|
| Team rules, coding standards, project SOPs | project `CLAUDE.md` / `docs/` | version-controlled, team-visible, reviewable |
| Project-specific architecture, decisions, war-stories, operational SOPs | project `docs/` (decisions / architecture / references / reports / troubleshooting) | same reasoning as above; these are project artifacts, not user profile |
| User profile, background, values, identity | global `~/.claude/references/user/` | cross-tool + cross-project; any AI should read it first |
| Collaboration preferences / feedback (how to work with this user) | global `~/.claude/references/user/` | cross-tool; not a project artifact |
| User's methodology / principles | global `~/.claude/references/user/` | cross-tool |
| Personal affairs (life facts the AI needs to act correctly) | global `~/.claude/references/user/` | cross-tool, but mark as privacy |
| Temporary handoff snapshot (state for the next session) | **stays in memory** | this is memory's legitimate purpose |
| External system pointer (a ticket, a channel id) | **stays in memory** | personal working context |
## The deciding question (three steps, in order)
1. Would a **teammate** opening this project need this rule/standard? → project `CLAUDE.md` / `docs/`.
2. Else, would **another AI tool** (Codex, Cursor) or **another project** need this user fact/preference? → global `~/.claude/references/user/` (tool-agnostic).
3. Else — it's just a handoff for the next session, or an external pointer? → leave it in `memory/`.
The pre-existing project rule may say "user preferences → memory". That rule predates multi-tool use; this migration supersedes it for the cross-tool bucket. Update the rule (see tool_agnostic_migration.md) so it stops contradicting reality.
## Caveat: agents can't judge private-context data
When deciding keep-vs-delete, content that depends on the user's **private context** (their correction dictionary, their internal naming, their idiosyncratic preferences) **cannot be batch-judged by a subagent** — agents have generic common sense but not "what *this* user actually values". A subagent will confidently flag a context-correct entry as wrong.
So: agents may **surface candidates**, but the user (or you, holding full context) **decides**. Multi-agent workflows are good for **objective** classification (broken links, derived counts, structural matches), not for "is this private fact worth keeping".
## Privacy check: don't migrate PII into shared docs
Some memory contains personally identifying information: real-name-to-username maps, private contacts, home addresses, medical/life details, etc. Even when the *topic* is project-relevant, the *identifying payload* is not a team artifact. Route it like this:
- **Identity mapping / real names** → keep in private memory (thin to a pointer if the SSOT is elsewhere); do not put in project docs.
- **Operational facts that happen to contain a name** (e.g., "ask 星月 for the Alipay key") → de-identify if you migrate them, or leave in memory.
- **PII that is also cross-tool user profile** (rare) → `~/.claude/references/user/` is still private to the user's machine, but mark the file clearly as privacy-sensitive.
## Inline discipline: some rules belong in CLAUDE.md body, not just references/
Even when a rule is about "how to work with the user" (which normally goes to `references/user/`), consider inlining it into `~/.claude/CLAUDE.md` if it governs **every message the agent produces**. Examples:
- Commitment-word discipline ("已修复" must pair with a tool call).
- Tone / language defaults that shape output.
- Private-context correction rules the agent must apply before speaking.
The test is: *if this rule is missed because the agent didn't open the reference, will the user's trust erode immediately?* If yes, inline it.
## Phase 6 cleanup decisions (for memory that did NOT migrate)
- **Clean → archive**: expired (a dated handoff whose event has passed) OR stale derived values (a stored count/total/aggregate that should be computed, not persisted).
- **Thin**: a handoff that restated a SSOT living elsewhere (a repo README, a design doc). Cut the duplicated detail; keep **only** the pointer + the volatile state that isn't in the SSOT (e.g. "the staging instance is still billing — shut it down").
- **Keep**: already a clean pointer, or a genuine live handoff.
### Derived values: not "dedup later", but "never store"
A count, a total, an aggregate status, a "last updated" you could recompute — don't persist it; compute on demand. If you encounter one inside a file you're **already editing**, remove it (SSOT hygiene). Don't open files you aren't otherwise touching just to hunt them — that's unbounded scope creep.
references/failure_cases.md
# Failure Cases — the war-stories behind each Do-NOT
Each happened in the live run this skill was distilled from. They are why the rules exist; read them when you doubt whether a rule is worth following.
## 1. "Delete first" was wrong — twice
The first instinct was to delete bloated memory. Then it became "actually, move it". Then "actually, thin it". The correct frame is **migrate / thin / keep / delete**, decided per file by scope. Treating cleanup as "delete the mess" loses both migratable value and legitimate handoffs. Cost: two full reversals before landing on the right model.
## 2. reference + pointer ≠ guaranteed-to-load
The plan was "put the profile in `references/`, point at it from CLAUDE.md — now it's tool-agnostic". Wrong: a plain-text pointer is **on-demand in both tools**; the agent may never open it. The fix was the two-layer split — inline the hardcore into CLAUDE.md body (guaranteed), pointer to the rest. Finding this required actually checking how each tool loads docs, not assuming.
## 3. Codex does not follow text pointers (official-docs-confirmed)
It was assumed Codex would follow "see `~/.claude/references/...`" written inside CLAUDE.md. It does **not** — it only auto-injects the doc files on its directory chain, and treats inline paths as plain text. Verified (2026-06, codex v0.142.3) against Codex's official AGENTS.md docs **and** a real session log. Consequence: the symlink (so the global CLAUDE.md *is* one of those auto-injected files) is load-bearing, and the hardcore must live in that file's body.
## 4. The 32 KiB truncation nobody knew about
Codex's `project_doc_max_bytes` defaults to 32 KiB. A long global CLAUDE.md had its **entire back half silently dropped** in Codex — for however long the user had been running Codex. Only running codex + grepping a back-of-file string revealed it. Fix: raise the limit in `config.toml`, and keep the user-context section near the top regardless.
## 5. Changed the table row, missed the judgment sentence
A governance table's "user preferences → memory" row was updated to "→ references/user/", but the prose "decision method" sentence three lines below still said "→ memory". A row and its surrounding logic drift apart if you only edit the eye-catching one. Rule: after changing one fact, grep/read the **whole section**.
## 6. The hub forgot to index its own child
The hub (`user-profile.md`) was built with an index of 4 children; a 5th child file was created later and never added to the index. From the entry point, the 5th file was unreachable — its whole content effectively invisible. A multi-agent review caught it. Rule: when you add a child, update the hub index in the same breath.
## 7. Deleting would have dangled live links
Before deleting migrated memory, a grep found **surviving** (non-migrating) memory files still `[[linking]]` to them. Deleting first would have left dangling links. Rule: grep cross-references **before** deleting; repoint survivors to the new reference.
## 8. "You can verify it yourself later" — no
After wiring the symlink, the instinct was to tell the user "next time you run Codex, grep the log to confirm". That hands an **agent-doable** verification back to the user. The right move: run codex right now, grep the log, report the proof. Owning the feedback loop is the whole point of the skill.
## 9. (meta) Don't load past-session JSONL into context to "mine history"
When distilling a skill from *prior* sessions, do **not** read the multi-MB transcript JSONL into your own context — it blows the window (one attempt died ~17 tokens over the limit and lost the whole session). Delegate extraction to subagents that parse line-by-line with a script and return only a distilled lessons list. (For this skill the live run was already in-context, so no mining was needed — but the instinct to "just read the history" is the trap.)
## 10. The archive was left inside `memory/`
A soft-delete moved `feedback_*.md` into `memory/archive/2026-07-05/`. Because the memory loader scans the `memory/` tree recursively, those files were still live memory. The fix: move the dated archive to a sibling directory **outside** `memory/` (e.g., `~/.claude/projects/<slug>/.memory-archive-2026-07-05/`) and update the index pointer. Verifying: `grep -R "feedback_" memory/` should only hit the explicit archive pointer or text references, not the archived files.
## 11. "Symlink looks correct" was mistaken for Codex verification
After creating `~/.codex/AGENTS.md → ~/.claude/CLAUDE.md`, the agent stopped there. Later, a live `codex exec` run revealed the global file was loading, but the verification protocol had hardcoded `"User context"` while the actual inlined section was titled `"用户上下文"`, so the heading grep returned `0`. The fix: run `codex exec --skip-git-repo-check`, extract the session id from the header, find the rollout JSONL, and grep for the **actual** heading string plus a back-half string. Only that empirical check is proof.
## 13. Dangling references were hiding in project docs, not just memory (2026-07-06)
A memory file about the prod cutover was referenced by the project's own `CLAUDE.md` and by a handoff doc in `docs/handoff/`. The cross-reference agent had only been asked to grep the memory directory, so those live-doc pointers would have dangled after archival. The fix: extend the pre-archive grep to **project docs, CLAUDE.md, and handoff docs** — anywhere a memory basename might be cited.
## 14. A real-name identity map almost migrated into project docs (2026-07-06)
`project_user_management_sop.md` contained a table mapping `user3 → 慧如` and other real-name-to-system-username pairs. It was project-relevant (useful for ops), but the real names are PII and the mapping is not a team artifact. Migrating it into version-controlled `docs/` would have leaked identifying information. The fix: keep identity-mapping in private memory, thin it to a pointer to the public SOP, and add an explicit privacy check in Phase 1.
## 15. Partial duplicates were overwritten instead of merged (2026-07-06)
Several memory files (`architecture_v2_decision.md`, `cache_regression_2026_04_12.md`, `project_upstream_capture_shipped_2026_05_13.md`) were partial duplicates of existing project docs. The first instinct was to replace the doc with the memory version; that would have lost doc-only updates and formatting. The correct move: diff the two, append the memory's **unique** details to the existing doc, and archive the memory.
references/review_and_verification.md
# Multi-Agent Review + Empirical Verification
## Phase 3 — four parallel review agents
Spawn all four in **one message** (multiple Task calls) so they run concurrently. Give each: the source memory dir, the new references, and the changed CLAUDE.md. Tell each to **cite real file/line evidence, not guesses**, and that its output is a hypothesis for you to filter.
Copy-pasteable prompt skeletons (fill in `<paths>`):
```
[Content completeness] Read every memory file under <memory-dir> and every new file under ~/.claude/references/user/. Diff them: did any fact (number, date, war-story, how-to-apply item) get dropped or altered in the condensing? Return a coverage matrix (each memory → which reference) + a lost/weakened list with quoted evidence. Cite file:line.
[Cross-reference breakage] grep all of <memory-dir> AND the project docs / CLAUDE.md / handoff docs for references (wikilinks `[[...]]`, plain-text filenames, or markdown links) to the memory files being archived. Report only TRUE breaks: a link FROM a file that will survive, pointing AT a file that will be deleted. (Links between two to-be-deleted files vanish together — not a break.) Also verify the new references' internal pointers resolve. **Extra:** confirm the archive directory will sit outside `memory/` so it cannot be re-read as live memory, and that no surviving file links into it. Give grep evidence.
[Tool-agnostic link integrity] Verify: (a) readlink ~/.codex/AGENTS.md resolves to ~/.claude/CLAUDE.md and the target exists; (b) the CLAUDE.md "User context" pointer paths all exist; (c) whether Codex actually reads reference CONTENT or only the inlined CLAUDE.md text — check Codex's official AGENTS.md docs + ~/.codex/config.toml. Report what would silently fail to load.
[Duplication / drift] Does any reference duplicate a rule already in CLAUDE.md? Full-text duplication across files is a drift source. A DELIBERATE inline (the hardcore, with a stated reason) is NOT — don't flag it. List each duplication with both locations.
```
**Filter findings** before acting and before reporting to the user: probability × cost × does-this-actually-happen-in-the-user's-setup. Don't forward raw agent output.
## Phase 5 — verify by RUNNING codex (the protocol)
Reasoning "the symlink is correct, so Codex must see it" is **not** verification. Run it. The command block below was empirically verified (2026-06): every line ran clean on a real machine.
**Preconditions**: codex installed and authenticated. If `command -v codex` is empty, **skip Phase 5 entirely** — the `references/` + inline-CLAUDE.md work still stands; just note that wiring Codex later needs the symlink + `project_doc_max_bytes`.
```bash
CODEX=$(command -v codex || echo /Applications/Codex.app/Contents/Resources/codex) # mac fallback; on Linux/WSL codex is just on PATH, no Codex.app
# Run from ANY dir. --skip-git-repo-check is REQUIRED: codex exec refuses to run outside a
# git repo by default (exit 1: "Not inside a trusted directory"), and migrating GLOBAL memory
# is naturally done from ~ — a non-repo dir. A neutral dir is also the cleaner test (no repo AGENTS.md noise).
"$CODEX" exec --skip-git-repo-check "Reply with exactly: ok. Do not run any tool." 2>&1 | tee /tmp/cx-verify.txt | tail -3
# Extract the session id from the HEADER. It is NOT in the tail — do NOT pipe the capture through `tail`.
# sed is POSIX; avoid grep -P \K (macOS BSD grep has no -P).
SID=$(grep "session id:" /tmp/cx-verify.txt | head -1 | sed -E 's/.*session id: ([0-9a-f-]{36}).*/\1/')
# Match the rollout by FULL UUID — never by `find ... -printf '%T@' | sort` (mtime returns an
# already-open OLDER session, a real trap that wastes a verification cycle).
NEW=$(find ~/.codex/sessions -name "rollout-*$SID*.jsonl")
# Before running, check CLAUDE.md size vs the configured limit.
CLAUDE_SIZE=$(wc -c < ~/.claude/CLAUDE.md)
MAX_BYTES=$(grep -E '^project_doc_max_bytes\s*=' ~/.codex/config.toml | sed -E 's/.*= *([0-9]+).*/\1/')
[ "$CLAUDE_SIZE" -lt "$MAX_BYTES" ] || echo "WARNING: CLAUDE.md ($CLAUDE_SIZE bytes) is larger than project_doc_max_bytes ($MAX_BYTES); tail may be truncated." >&2
# Use the ACTUAL title of your inlined hardcore section (e.g. "User context", "用户上下文", ...).
HARDCORE_HEADING="<Your inlined section heading>"
grep -c "$HARDCORE_HEADING" "$NEW" # inlined hardcore section — EXPECT: 1
grep -c "<a string that appears ONLY in your global CLAUDE.md>" "$NEW" # whole-file injection — EXPECT: 1
# 32 KiB check — ONLY if CLAUDE.md > 32 KiB. Pick a heading you KNOW sits in the file's SECOND half
# (not a fixed line number — that's tied to one file's size):
grep -c "<a heading from the back half of your CLAUDE.md>" "$NEW" # 0 → truncation; raise project_doc_max_bytes, re-run
```
**What a passing run prints** (so you know success when you see it):
```
1 ← User context inlined section is present
1 ← whole global CLAUDE.md was injected
1 ← back half present (skip this line entirely if CLAUDE.md < 32 KiB)
```
Interpretation:
| inlined section | back-of-file string | meaning |
|---|---|---|
| 1 | 1 | full injection works — done |
| 1 | 0 | 32 KiB truncation (front survived because the section is near the top). Raise `project_doc_max_bytes`, re-run |
| 0 | 0 | the symlink / global layer isn't wiring up. Re-check `readlink ~/.codex/AGENTS.md`, that the target exists, and that codex's `project_doc_fallback_filenames` includes `CLAUDE.md` |
Caveats:
- **CLAUDE.md < 32 KiB**: skip the back-half grep (there is no back half) and skip the `project_doc_max_bytes` config edit. Only the `User context` check applies.
- **`codex exec --ephemeral`** (or a no-persist config) writes no rollout file → grep finds nothing even on success. Use a normal persisted session.
- Match only with the **full** UUID; a partial id can collide with another session.
This is empirical proof, captured in seconds, that beats any amount of "it should work". Do this yourself — never tell the user "you can check the log next time".
## Note: `project_doc_max_bytes` is a combined budget
It is **one shared budget across the whole AGENTS.md hierarchy** (root → git-root → cwd), decremented file by file and truncating each as the budget runs out — **not** a per-file cap (the official config-reference's "Maximum bytes read from AGENTS.md" wording is misleading; the source is the truth). For the common topology (one big global CLAUDE.md) the practical effect is "its tail is dropped" — but it also means an oversized global file **starves repo-level `AGENTS.md`** of budget entirely. Raising the limit fixes both.
references/tool_agnostic_migration.md
# Tool-Agnostic Migration — the architecture in detail
## Directory layout (hub-and-spoke)
```
~/.claude/references/
├── user-profile.md # HUB: one-liner + condensed core + INDEX of children
└── user/
├── background-and-skills.md
├── values-and-decisions.md
├── personal-affairs.md # privacy-marked
├── operating-entity.md # legal/identity facts, if any
└── collaboration-and-methodology.md # how to work with the user + their principles
```
(File names above are **illustrative** — name them whatever fits the user's content; the real ones may be in any language.) Group memory content **by theme**, not one-file-per-memory. Start each file with a provenance line: `source: original memory <name>, migrated <YYYY-MM-DD>`. Keep references **one level deep** — Claude and Codex both read a directly-linked file completely, but may only partial-read a file reached through another reference.
## The hub (`user-profile.md`)
Holds: a one-liner, the **condensed** core (a few sentences per theme), and an **index** linking every child. The hub's core is a navigational summary; the child files are the SSOT.
**Keep the index complete.** Forgetting to index a child you created later is the single most common self-inflicted bug — that child becomes unreachable from the entry point. When you add a child file, add its index line in the same edit.
## Inline the hardcore into CLAUDE.md (the guaranteed-hit layer)
Add a short `# User context` section near the **top** of `~/.claude/CLAUDE.md`. Put **only** the few facts that must hold every single turn — because references are on-demand and may not be read by either tool. Everything else stays a pointer.
A good hardcore set is **3–6 bullets**: how to address/talk to the user, the one or two hard preferences that ruin the interaction if missed, the single most important identity/entity fact, the resource/scope stance.
**State in that section WHY it's inlined** ("inlined because references are on-demand and not guaranteed to load") so a future editor doesn't "deduplicate" it away thinking it's redundant with the references. A deliberate, documented inline is not drift.
## Symlink for Codex's global layer
```bash
mkdir -p ~/.codex # ln fails if ~/.codex doesn't exist yet (Codex never run)
TARGET="$HOME/.claude/CLAUDE.md"
if [ -L ~/.codex/AGENTS.md ]; then
# already a symlink — but a STALE one pointing elsewhere won't self-heal; repoint it
[ "$(readlink ~/.codex/AGENTS.md)" = "$TARGET" ] || ln -sf "$TARGET" ~/.codex/AGENTS.md
elif [ -s ~/.codex/AGENTS.md ]; then
echo "~/.codex/AGENTS.md is a real non-empty file — do NOT clobber it."
echo "To keep BOTH: merge its content into ~/.claude/CLAUDE.md, then replace it with the symlink;"
echo "or leave it as-is and accept that Codex's global layer won't pick up CLAUDE.md."
else
rm -f ~/.codex/AGENTS.md; ln -s "$TARGET" ~/.codex/AGENTS.md # absent or 0-byte placeholder
fi
```
This makes Codex's **global** instruction layer inject the exact same file Claude Code reads. (Codex resolves docs along `~/.codex → git-root → cwd`; `~/.codex/AGENTS.md` is the global slot.)
## config.toml — defeat the 32 KiB truncation
Codex's `project_doc_max_bytes` is **one combined budget across the whole AGENTS.md hierarchy** (not per-file), defaulting to **32768** (32 KiB). A global CLAUDE.md larger than that loses its **tail** in Codex (silently) — and also starves any repo-level `AGENTS.md` of budget. Add to `~/.codex/config.toml` (**create the file if absent**; if the key is already set to a smaller value, **raise** it):
```toml
project_doc_max_bytes = 98304 # 96 KiB, or larger than your CLAUDE.md
```
**If CLAUDE.md is already < 32 KiB**, skip this step (and the Phase 5 back-half grep) — there's no tail to lose. Either way, keep the `# User context` section within the first 32 KiB so even an unconfigured Codex still gets the hardcore.
## Fix the governance rule (don't leave it contradicting itself)
If a CLAUDE.md "where does knowledge go" rule says "user preferences → memory", it now contradicts this migration. Update it to add the tool-agnostic tier:
> Cross-tool user profile / preferences / methodology → `~/.claude/references/user/` (tool-agnostic, Codex reads it via the symlink). Temporary handoff → memory.
When you edit the **table row**, also fix the **judgment sentence** in the same section (the "ask: would a teammate need it? yes→docs, no→memory" prose). They drift apart if you only touch the obvious one — grep the whole section after editing.
SKILL.md
---
name: claude-migrate-memory-to-doc
description: >-
Migrates Claude Code personal memory (the per-project memory/ directory) into
tool-agnostic reference docs, so other AI CLIs that auto-load AGENTS.md (Codex
primarily; the content architecture transfers to Cursor and others) working in
the same directory can read the same user profile, collaboration preferences,
and methodology instead of being blind to them. Use this whenever the user says
things like "migrate my memory", "my memory is locked to Claude Code", "make
Codex/Cursor read my profile", "memory should live in docs not one tool", or
reports that a second AI tool doesn't know who they are; also use it when memory
has grown bloated with content that should be shared across tools or projects.
Covers diagnosis, the references/ + CLAUDE.md-inline + AGENTS.md-symlink
architecture, multi-agent review, empirical codex verification, and memory
cleanup. Inline only — it orchestrates review subagents and runs codex.
---
# Migrate Claude Code Memory to Tool-Agnostic Docs
## Why this skill exists
Claude Code's personal memory lives in `~/.claude/projects/<project-slug>/memory/`. It is **locked to Claude Code**: not version-controlled with the repo, invisible to every other tool. The moment the user runs Codex, Cursor, or any other AI CLI in the same directory, those tools cannot read "who the user is / how to work with them" — even though a user profile and collaboration preferences are exactly what *any* AI assistant should read first.
This skill moves the **cross-tool-shareable** content out of memory into a tool-agnostic location, and leaves memory as a thin handoff cache. The real problem it solves is **tool lock-in**, not "messy memory".
This skill runs **inline** (never `context: fork`): it spawns parallel review subagents and runs `codex` via Bash — a forked subagent could do neither.
## The core insight — read this before touching anything
The hard part is not moving files. It is this:
> **A reference file reached only by a plain-text pointer is read on-demand and is NOT guaranteed to load — in *either* tool.**
- **Claude Code** auto-preloads a reference only via `@import` syntax. A plain-text pointer ("see `~/.claude/references/user/foo.md`") is on-demand: the agent must choose to open it.
- **Codex** is stricter: it does **not parse or follow** text paths written inside CLAUDE.md at all. It only auto-injects the doc *files themselves* (its `AGENTS.md` / configured fallback) along the `~/.codex → git-root → cwd` chain. Reference files named anything else, sitting in `~/.claude/references/`, are **never auto-loaded** by Codex.
Therefore the architecture must be a **two-layer split**:
| Layer | Where | Guarantee |
|---|---|---|
| **Guaranteed-hit** — the few facts that must be true every turn | inlined into **CLAUDE.md body** (both tools inject it) | always present |
| **On-demand detail** — full profile, war-stories, edge cases | `references/` files, reached by pointer | loaded when relevant |
Putting the hardcore facts *only* in a reference and trusting a pointer is the #1 way this migration silently fails. Inline them.
## Tool-agnostic architecture
```
~/.claude/CLAUDE.md global instructions — BOTH tools inject this.
Inline the hardest user facts here (a short "User context" section).
~/.claude/references/user/ SSOT for profile / preferences / methodology / personal affairs.
~/.claude/references/user-profile.md hub: condensed core + index into the user/ files
~/.codex/AGENTS.md ──symlink──▶ ~/.claude/CLAUDE.md
so Codex's GLOBAL layer injects the same file Claude Code reads.
~/.codex/config.toml raise project_doc_max_bytes — Codex truncates docs at 32 KiB by default,
which silently drops the back half of a long CLAUDE.md.
```
> **Scope note**: the wiring (the `~/.codex/` symlink, the config edit, and the Phase 5 verification) is **Codex-specific** and was verified against Codex only (2026-06). The `~/.claude/references/user/` content layer transfers to any tool that auto-loads a project doc, but Cursor and others need their own wiring (Cursor reads `.cursor/rules` / a project-root `AGENTS.md`, not `~/.codex/`) — not implemented or verified here.
## Workflow
Copy this checklist into your working notes and check items off:
```
Memory → Tool-Agnostic Doc Migration:
- [ ] Phase 1: Diagnose & scope — classify every memory file by SCOPE
- [ ] Phase 2: Tool-agnostic migration — references/ + inline hardcore + symlink + config
- [ ] Phase 3: Multi-agent review — 4 parallel reviewers
- [ ] Phase 4: Fix everything review surfaced
- [ ] Phase 5: VERIFY BY RUNNING CODEX (not by reasoning)
- [ ] Phase 6: Memory cleanup — clean / thin / keep + soft-delete to backup
```
### Phase 1 — Diagnose & scope
**Preflight — find the memory directory.** Claude Code memory lives at `~/.claude/projects/<project-slug>/memory/`, where `<project-slug>` is the working directory path with `/` → `-`. A user may have memory across several projects — list them with `ls ~/.claude/projects/*/memory/` and pick (or merge) the project(s) whose memory holds the cross-tool user content.
List every file under that memory directory. Classify each by **scope**, not by "is it messy". Full decision table and the agent-can't-judge-private-context caveat: read **[references/diagnosis_and_scoping.md](references/diagnosis_and_scoping.md)**.
The short version:
- **Team rules / standards / SOPs** → project `CLAUDE.md` or `docs/` (version-controlled, team-visible).
- **Cross-tool user profile / collaboration preferences / methodology / personal affairs** → `~/.claude/references/user/` (tool-agnostic). **This is the bucket that migrates.**
- **Temporary handoff snapshots / external system pointers** → **stay in memory**. This is memory's legitimate purpose; do not migrate them.
Do NOT migrate everything. Over-migrating handoff state into long-lived docs is its own mistake. **But do look at the whole directory** — not just `feedback_*.md` — because project SOPs and operational war-stories often sit in `project_*.md` or `architecture_*.md` files and belong in the repo's docs.
Also flag **private-context / PII** in this pass: a memory file that maps system usernames to real names, private contacts, or other personally identifying information should **stay in private memory** even if it is project-relevant. Project docs are version-controlled and potentially shared; identity-mapping belongs in the thin handoff layer.
### Phase 2 — Tool-agnostic migration
**Snapshot CLAUDE.md first** (`cp ~/.claude/CLAUDE.md ~/.claude/CLAUDE.md.bak`) — you're about to edit it. If `~/.claude/CLAUDE.md` doesn't exist, create it (some users only have a project-level one).
**If `command -v codex` is empty** (Codex not installed): do only steps 1 and 4 below (the `references/` + inline-CLAUDE.md work), and **skip** the symlink (2), config (3), and all of Phase 5. The content migration still stands; leave a note that wiring Codex later needs the symlink + `project_doc_max_bytes`.
For each "migrates" item, move the content into `~/.claude/references/user/` (group by theme into a handful of files + a `user-profile.md` hub). Then wire the two-layer architecture:
1. **Inline the hardcore** into a `# User context` section near the **top** of `~/.claude/CLAUDE.md` (within the first ~32 KiB so Codex sees it): the 3–6 facts that must hold every turn (e.g. how to address the user, hard preferences, the single most important identity fact). Everything else stays as pointers.
2. **Symlink** `~/.codex/AGENTS.md → ~/.claude/CLAUDE.md` (only if `~/.codex/AGENTS.md` is absent or an empty placeholder — never clobber a real file).
3. **Raise `project_doc_max_bytes`** in `~/.codex/config.toml` if CLAUDE.md exceeds 32 KiB.
4. **Update the project's knowledge-storage rule** (if one exists) so "user preferences → memory" doesn't contradict the new "user profile → `~/.claude/references/user/`" reality.
Exact directory layout, the hub-and-spoke pattern, and the governance-rule fix: **[references/tool_agnostic_migration.md](references/tool_agnostic_migration.md)**.
### Phase 3 — Multi-agent review
Spawn 4 review subagents in parallel (one message, multiple Task calls). Each audits one dimension: **content completeness** (did any fact get dropped/altered), **cross-reference breakage** (which `[[links]]` will dangle if memory is deleted), **tool-agnostic link integrity** (does the symlink/pointer chain actually resolve; does Codex really read it), **duplication/drift** (does a reference duplicate a CLAUDE.md rule). Exact prompts: **[references/review_and_verification.md](references/review_and_verification.md)**.
Agent findings are hypotheses, not verdicts — filter them (probability × cost × does-it-actually-happen) before acting.
### Phase 4 — Fix
Address what review surfaced. Common real findings (all from a live run): a hub file that forgot to index one of its own children; hardcore facts left only in a reference (move them inline); `[[links]]` in surviving files pointing at to-be-deleted memory (repoint to the new reference); a governance table row updated but the judgment sentence in the same section left contradicting it.
### Phase 5 — VERIFY BY RUNNING CODEX (do not skip, do not delegate to the user)
The step you'll be tempted to replace with "looks right" or "you can check it yourself later". Don't. **Run codex from any dir with `--skip-git-repo-check`, match its session log by session id (not by mtime), and grep for your inlined hardcore section + a back-of-file string.** The inlined section may be titled `# User context`, `# 用户上下文`, or whatever localization the user uses — grep for the *actual* heading string, not a hardcoded English one. A passing run greps `1` for that heading and `1` for the back-half string (if CLAUDE.md > 32 KiB). The exact, empirically-verified command block — `--skip-git-repo-check`, session-id extraction (it's in the header, not the tail), the 32 KiB check, plus the `< 32 KiB` and `codex-not-installed` shortcuts and expected console output — is in **[references/review_and_verification.md](references/review_and_verification.md)**. Use it verbatim; don't hand-roll a variant here (that's how the two copies drift).
### Phase 6 — Memory cleanup
For the memory files that did NOT migrate, do one of three things (decision detail in **[references/diagnosis_and_scoping.md](references/diagnosis_and_scoping.md)**):
- **Clean** — expired (past-dated handoffs) or stale (derived counts that should be computed, not stored) → archive.
- **Thin** — a handoff that restated a SSOT living elsewhere → cut the duplication, keep only the pointer + the volatile state (e.g. "instance X still billing, shut it down").
- **Keep** — legitimate handoff / already a clean pointer → leave it.
Update the memory index (e.g. `MEMORY.md`) to drop migrated entries and add one migration pointer.
**Before moving anything, grep the whole memory dir AND the project docs / CLAUDE.md for references to the files you are about to archive.** A surviving file or active doc that links to an archived file ends up with a dangling reference. Repoint those links to the new doc location or to a plain-text pointer. Memory cross-links are not the only risk — project `CLAUDE.md` and handoff docs often cite memory files by name.
**Soft-delete, never hard-`rm`.** Move migrated/cleaned files to a dated backup dir **outside** `memory/` (e.g., a sibling `~/.claude/projects/<slug>/.memory-archive-2026-07-06/` — use the **actual current date**, not a placeholder). Putting the archive inside `memory/` leaves it readable as live memory, defeating the cleanup. Update the index pointer to the new outside-memory path. Tell the user they can `rm` the backup after a couple of weeks of confirming both tools behave.
**After a migration that taught you something new, update this skill.** If you hit a failure mode not listed in `references/failure_cases.md`, append it; if a step was underspecified, tighten the SKILL.md checklist. A skill that isn't fed back its own lessons will repeat the same mistakes.
## Do NOT (each one learned by getting it wrong in a live run)
- **Don't reach for "delete" first.** The instinct is to delete messy memory. Wrong order: first classify migrate / thin / keep. Most "messy" memory is either migratable value or legitimate handoff — deleting loses the value.
- **Don't assume `reference + pointer` = tool-agnostic.** A pointer is on-demand in *both* tools. The hardcore facts must be inlined into CLAUDE.md body, or they silently won't load.
- **Don't believe Codex follows text pointers.** It reads the AGENTS.md/CLAUDE.md file itself, not paths written inside it. Verified against official docs + a real session log.
- **Don't forget Codex's 32 KiB doc truncation.** A long CLAUDE.md loses its back half in Codex unless `project_doc_max_bytes` is raised. The user may have been running half a CLAUDE.md for months without knowing.
- **Don't change a governance table row and leave the judgment logic in the same section contradicting it.** Grep the whole section after editing one fact.
- **Don't delete a memory file before grepping for `[[cross-references]]` to it.** A surviving file pointing at a deleted one becomes a dangling link.
- **Don't let an agent batch-decide what to delete/keep when the content depends on the user's private context.** Agents lack "what the user actually values"; surface candidates, let the user (or you, with full context) decide.
- **Don't make the user verify.** Running codex and grepping the log is agent-doable — own the verification loop, don't hand it back.
- **Don't treat "the symlink exists" as Codex verification.** A correct symlink is necessary but not sufficient; the only proof is a real `codex exec` session whose rollout log contains your inlined hardcore section.
- **Don't put the archive inside `memory/`.** It remains readable as live memory there, defeating the cleanup. Move it to a sibling dir outside `memory/`.
- **Don't migrate real-name identity maps or PII into project docs.** Project docs are version-controlled and shared. If a memory file maps `user3 → 慧如`, keep it in private memory (thinned to a pointer if the SSOT lives elsewhere) — do not move it to `docs/`.
- **Don't overwrite an existing doc with a memory duplicate without diffing first.** Many memory files are *partial* duplicates of docs (e.g., `architecture_v2_decision.md` vs `docs/decisions/2026-02-21-v2-architecture.md`). Migrate only the **unique** details; append them to the existing doc rather than replacing it.
- **Don't forget to repoint links in project docs, not just memory.** `CLAUDE.md` and handoff docs often cite memory files by basename. Grep them before archiving.
## Failure cases (the full war-stories)
The reasoning behind the Do-NOTs, with what actually broke each time: **[references/failure_cases.md](references/failure_cases.md)**.