Skip to content

feat(agents): attribute & group Claude per-project memory#99

Merged
RealZST merged 13 commits into
mainfrom
feat/claude-project-memory-scope
Jul 3, 2026
Merged

feat(agents): attribute & group Claude per-project memory#99
RealZST merged 13 commits into
mainfrom
feat/claude-project-memory-scope

Conversation

@RealZST

@RealZST RealZST commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

Claude stores per-project memory outside the project tree, under ~/.claude/projects/<encoded-cwd>/memory/, keyed by the session cwd. Previously HarnessKit surfaced all of these as a flat pile of Global rows on the Agents page, with no link to the project they belong to and no grouping.

This PR does two things:

  1. Backend — attribute memory to its project. A new generic adapter hook exposes "memory that lives outside the project tree, grouped by owning cwd". The Claude adapter implements it by reading the real cwd from each project's session transcript (the encoded directory name is a lossy, non-injective encoding, so it is never decoded). The scanner then assigns ConfigScope::Project when that cwd matches a registered project, or ConfigScope::Global otherwise.

  2. Frontend — group the MEMORY section. Memory files are grouped by their storage directory under collapsible headers. Registered projects show the project name + a muted store path; unregistered stores show the store path. Rows are indented and show filename + scope badge + size; the (repeated) path now lives once on the group header instead of on every row.

Backend

  • New trait method AgentAdapter::external_project_memory() -> Vec<(Option<PathBuf>, Vec<PathBuf>)> (default empty).
  • ClaudeAdapter implements it in a single pass over ~/.claude/projects/*, reading the cwd from the first transcript line (session_cwd); its old global_memory_files override is removed so memory now comes from exactly one place (no double-listing).
  • Scanner classifies each group to Project/Global. Unregistered or undeterminable cwd → Global (nothing is dropped).
  • Other agents are unaffected (they inherit the empty default).

Frontend

  • New groupMemoryFiles helper + MemoryGroup component; ConfigSection renders grouped headers for the memory category only, flat list elsewhere.
  • Shared extractions to avoid duplication: formatBytes (src/lib/format.ts) and a useCollapsibleState hook (src/hooks/), both reused by the new component and the existing ones.
  • ConfigFileEntry gains hideScopePath (hide only the path, keep the badge) and inset (indent via the row's own padding so the hover highlight fills to the left edge).
  • Path handling is separator-agnostic so grouping works in Windows web mode (backslash paths).

Test plan

  • cargo test -p hk-core — green (adapter, session_cwd, scanner classification, no-double-listing).
  • npx vitest run — green (grouping helper incl. POSIX + Windows paths, collapse hook, byte formatter, grouped-section rendering).
  • npx tsc --noEmit and npm run lint — clean.
  • Verified: macOS/Linux, and Windows web mode (registered paths are normalized server-side; frontend groups backslash paths correctly). Desktop/web handler parity confirmed.

Known limitations (by design)

  • Exact cwd match — the registered project path is compared to the transcript cwd without canonicalization, so a symlinked or case-different registration falls back to Global rather than misattributing (safe degrade).
  • First-transcript cwd — the owning cwd is taken from the first transcript in a store dir (matches how Claude itself keys the directory).
  • Encoded path not decoded — unregistered ("Global") group headers show the raw ~/.claude/projects/<encoded>/memory path on purpose, since the encoding is lossy and decoding would misrepresent where the files actually live.

🤖 Generated with Claude Code

@RealZST RealZST merged commit f7fc4d9 into main Jul 3, 2026
3 checks passed
@RealZST RealZST deleted the feat/claude-project-memory-scope branch July 3, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant