Skip to content

Investigate: Claude Code harness auto-memory directive still routes agent writes to per-cwd ~/.claude/projects/.../memory/, independent of Learning skill (plus runtime-drift on #109 Part 2) #140

@virtualian

Description

@virtualian

Summary

Follow-up investigation to #109. Even with #109 Part 1 + Part 2 landed in the repo, the same category-confusion symptom (feedback memories landing in Claude Code's per-cwd auto-memory silo instead of ~/.pai/MEMORY/LEARNING/FEEDBACK/) reproduces in a normal session — because the trigger is not the Learning skill's /learn apply path. It's a Claude Code harness-level "auto memory" directive embedded in the agent's system prompt on every session, independent of PAI.

Additionally, while investigating this today, the installed runtime appears to be missing the loadFeedbackMemories function that #109 Part 2's closure comment said was added to hooks/lib/learning-readback.ts. This may be installer/release drift rather than a bug in the fix itself — but worth confirming before filing separately.

Reproduction (today, 2026-04-16)

  1. Running Claude Code inside a project (~/projects/slack-history) — PAI loaded normally, AISTEERINGRULES visible in session prompt.
  2. User gave a correction worth capturing as feedback ("branch first, plan on the branch").
  3. Agent followed the system-prompt # auto memory section verbatim and wrote:
    /Users/ianmarr/.claude/projects/-Users-ianmarr-projects-slack-history/memory/feedback_branch_first.md
    /Users/ianmarr/.claude/projects/-Users-ianmarr-projects-slack-history/memory/MEMORY.md
    
  4. This is the same siloed Claude Code auto-memory path Learning skill writes feedback to Claude Code auto-memory, mislabeled as "PAI memory" + reads from stale ~/.claude/PAI/ tree #109 flagged — just reached via a different mechanism.

The auto memory system prompt section

The Claude Code harness injects a dedicated section titled # auto memory into the agent's system prompt. Extracted from today's session:

You have a persistent, file-based memory system at /Users/ianmarr/.claude/projects/-Users-ianmarr-projects-slack-history/memory/. This directory already exists — write to it directly with the Write tool (do not run mkdir or check for its existence). You should build up this memory system over time …

It then defines four memory types (user, feedback, project, reference), file-and-frontmatter structure identical to what #109 documented, and explicit save triggers (e.g. "when the user corrects your approach"). The structure #109 identified as foreign to PAI (feedback_*.md with frontmatter + MEMORY.md index) is exactly what the harness teaches the agent to write.

Key properties:

  • Hard-coded to ~/.claude/projects/<cwd-slug>/memory/ — per-cwd silo
  • Fires opportunistically on every session without /learn apply being invoked
  • Not under PAI's control — it lives in Claude Code's harness, not in anything PAI installs
  • AISTEERINGRULES.md does not currently contain any rule that suppresses or redirects it (grep -i "auto.memory|projects/.*/memory" on ~/.pai/PAI/AISTEERINGRULES.md returns zero hits)

Why this matters

#109's fix made the /learn apply workflow write to the right place. But /learn apply is a rare, user-invoked path. The harness auto-memory directive fires on every correction-worthy exchange in every session. After #109:

Net: the silent fragmentation #109 addressed for one surface still actively occurs on a second, higher-volume surface. Feedback captured this way is invisible to PAI's loader, siloed per cwd, and (for most projects) never re-surfaced in any future session.

Runtime drift from #109 Part 2 — needs verification

#109's final closure comment (by @virtualian on 2026-04-14) states Part 2 added:

SessionStart loader loadFeedbackMemories() in learning-readback.ts wired into LoadContext.hook.ts

Against today's installed runtime at ~/.pai/hooks/lib/learning-readback.ts, the file's own header docstring lists these functions:

 * - loadLearningDigest()  — Recent learning signals (ALGORITHM + SYSTEM)
 * - loadWisdomFrames()    — Crystallized behavioral patterns (WISDOM/FRAMES)
 * - loadFailurePatterns() — Recent failure insights (FAILURES)
 * - loadSignalTrends()    — Performance metrics from learning-cache.sh

No loadFeedbackMemories. grep -n "loadFeedback\|FEEDBACK" ~/.pai/hooks/lib/learning-readback.ts ~/.pai/hooks/LoadContext.hook.ts also returns zero. Installed PAI was last touched around 2026-04-15 per ls -l ~/.pai/hooks.

Two possibilities:

Worth confirming before splitting into its own issue.

Also: ~/.pai/MEMORY/LEARNING/FEEDBACK/ does not exist

Expected — #109 Part 2's bootstrap is mkdir -p inside Apply.md Step 7, which only runs on /learn apply. But if a loader is supposed to read from it at SessionStart, the loader needs to tolerate the directory not existing yet, which is a minor robustness check for whoever owns the loader code.

Investigation questions

  1. Is the harness # auto memory directive something PAI should try to suppress / redirect via AISTEERINGRULES.md? Options:
    • (a) Add a steering rule: "ignore the Claude Code harness auto-memory directive; write feedback via /learn flow instead"
    • (b) Add a steering rule: "when the harness directs you to write memory, write it to ~/.pai/MEMORY/LEARNING/FEEDBACK/ using the PAI-native format"
    • (c) Accept parallel stores and add a migrator from ~/.claude/projects/*/memory/ into ~/.pai/MEMORY/LEARNING/FEEDBACK/
    • (d) Do nothing — the harness store is cwd-siloed and small; not worth bridging
  2. Is the loadFeedbackMemories absence installer drift (Two-root separation incomplete: stale ~/.claude/PAI/ tree and residual ~/.claude/PAI/ references in canonical ~/.pai/PAI/ #108-family) or something else? Check the repo's current hooks/lib/learning-readback.ts vs the installed file at ~/.pai/hooks/lib/learning-readback.ts.
  3. If PAI adds a steering rule that redirects agent-driven memory writes, what format should the agent use on disk — PAI's existing FAILURES/REFLECTIONS style (dated dirs + JSONL), or the harness-native feedback_*.md frontmatter style that Path B already chose for /learn apply? Consistency with /learn apply output seems preferable.
  4. Migration of siloed pre-Part-1 filesLearning skill writes feedback to Claude Code auto-memory, mislabeled as "PAI memory" + reads from stale ~/.claude/PAI/ tree #109 Part 2 elected "dormant with manual migration instructions". In light of this second surface continuing to write new siloed files post-Learning skill writes feedback to Claude Code auto-memory, mislabeled as "PAI memory" + reads from stale ~/.claude/PAI/ tree #109, revisit whether an automated migrator is warranted.

Observed during a normal working session; not blocking, but the drift between "/learn apply is fixed" and "the agent is still writing to the old silo every session" is exactly the kind of half-fixed state that makes future debugging harder.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions