feat: Live Context System with Distributed CLAUDE.md Generation (#556)

* docs: add folder index generator plan

RFC for auto-generating folder-level CLAUDE.md files with observation
timelines. Includes IDE symlink support and root CLAUDE.md integration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: implement folder index generator (Phase 1)

Add automatic CLAUDE.md generation for folders containing observed files.
This enables IDE context providers to access relevant memory observations.

Core modules:
- FolderDiscovery: Extract folders from observation file paths
- FolderTimelineCompiler: Compile chronological timeline per folder
- ClaudeMdGenerator: Write CLAUDE.md with tag-based content replacement
- FolderIndexOrchestrator: Coordinate regeneration on observation save

Integration:
- Event-driven regeneration after observation save in ResponseProcessor
- HTTP endpoints for folder discovery, timeline, and manual generation
- Settings for enabling/configuring folder index behavior

The <claude-mem-context> tag wrapping ensures:
- Manual CLAUDE.md content is preserved
- Auto-generated content won't be recursively observed
- Clean separation between user and system content

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add updateFolderClaudeMd function to CursorHooksInstaller

Adds function to update CLAUDE.md files for folders touched by observations.
Uses existing /api/search/by-file endpoint, preserves content outside
<claude-mem-context> tags, and writes atomically via temp file + rename.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: hook updateFolderClaudeMd into ResponseProcessor

Calls updateFolderClaudeMd after observation save to update folder-level
CLAUDE.md files. Uses fire-and-forget pattern with error logging.
Extracts file paths from saved observations and workspace path from registry.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add timeline formatting for folder CLAUDE.md files

Implements formatTimelineForClaudeMd function that transforms API response
into compact markdown table format. Converts emojis to text labels,
handles ditto marks for timestamps, and groups under "Recent" header.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: remove old folder-index implementation

Deletes redundant folder-index services that were replaced by the simpler
updateFolderClaudeMd approach in CursorHooksInstaller.ts.

Removed:
- src/services/folder-index/ directory (5 files)
- FolderIndexRoutes.ts
- folder-index settings from SettingsDefaultsManager
- folder-index route registration from worker-service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add worktree-aware project filtering for unified timelines

Detect git worktrees and show both parent repo and worktree observations
in the session start timeline. When running in a worktree, the context
now includes observations from both projects, interleaved chronologically.

- Add detectWorktree() utility to identify worktree directories
- Add getProjectContext() to return parent + worktree projects
- Update context hook to pass multi-project queries
- Add queryObservationsMulti() and querySummariesMulti() for IN clauses
- Maintain backward compatibility with single-project queries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* fix: restructure logging to prove session correctness and reduce noise

Add critical logging at each stage of the session lifecycle to prove the session ID chain (contentSessionId → sessionDbId → memorySessionId) stays aligned. New logs include CREATED, ENQUEUED, CLAIMED, MEMORY_ID_CAPTURED, STORING, and STORED. Move intermediate migration and backfill progress logs to DEBUG level to reduce noise, keeping only essential initialization and completion logs at INFO level.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* refactor: extract folder CLAUDE.md utils to shared location

Moves folder CLAUDE.md utilities from CursorHooksInstaller to a new
shared utils file. Removes Cursor registry dependency - file paths
from observations are already absolute, no workspace lookup needed.

New file: src/utils/claude-md-utils.ts
- replaceTaggedContent() - preserves user content outside tags
- writeClaudeMdToFolder() - atomic writes with tag preservation
- formatTimelineForClaudeMd() - API response to compact markdown
- updateFolderClaudeMdFiles() - orchestrates folder updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: trigger folder CLAUDE.md updates when observations are saved

The folder CLAUDE.md update was previously only triggered in
syncAndBroadcastSummary, but summaries run with observationCount=0
(observations are saved separately). Moved the update logic to
syncAndBroadcastObservations where file paths are available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* all the claudes

* test: add unit tests for claude-md-utils pure functions

Add 11 tests covering replaceTaggedContent and formatTimelineForClaudeMd:
- replaceTaggedContent: empty content, tag replacement, appending, partial tags
- formatTimelineForClaudeMd: empty input, parsing, ditto marks, session IDs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: add integration tests for file operation functions

Add 9 tests for writeClaudeMdToFolder and updateFolderClaudeMdFiles:
- writeClaudeMdToFolder: folder creation, content preservation, nested dirs, atomic writes
- updateFolderClaudeMdFiles: empty skip, fetch/write, deduplication, error handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: add unit tests for timeline-formatting utilities

Add 14 tests for extractFirstFile and groupByDate functions:
- extractFirstFile: relative paths, fallback to files_read, null handling, invalid JSON
- groupByDate: empty arrays, date grouping, chronological sorting, item preservation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: rebuild plugin scripts with merged features

* docs: add project-specific CLAUDE.md with architecture and development notes

* fix: exclude project root from auto-generated CLAUDE.md updates

Skip folders containing .git directory when auto-updating subfolder
CLAUDE.md files. This ensures:

1. Root CLAUDE.md remains user-managed and untouched by the system
2. SessionStart context injection stays pristine throughout the session
3. Subfolder CLAUDE.md files continue to receive live context updates
4. Cleaner separation between user-authored root docs and auto-generated folder indexes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: prevent crash from resuming stale SDK sessions on worker restart

When the worker restarts, it was incorrectly passing the `resume` parameter
to INIT prompts (lastPromptNumber=1) when a memorySessionId existed from a
previous SDK session. This caused "Claude Code process exited with code 1"
crashes because the SDK tried to resume into a session that no longer exists.

Root cause: The resume condition only checked `hasRealMemorySessionId` but
did not verify that this was a CONTINUATION prompt (lastPromptNumber > 1).

Fix: Add `session.lastPromptNumber > 1` check to the resume condition:
- Before: `...(hasRealMemorySessionId && { resume: session.memorySessionId })`
- After: `...(hasRealMemorySessionId && session.lastPromptNumber > 1 && { resume: ... })`

Also added:
- Enhanced debug logging that warns when skipping resume for INIT prompts
- Unit tests in tests/sdk-agent-resume.test.ts (9 test cases)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: properly handle Chroma MCP connection errors

Previously, ensureCollection() caught ALL errors from chroma_get_collection_info
and assumed they meant "collection doesn't exist", triggering unnecessary
collection creation attempts. Connection errors like "Not connected" or
"MCP error -32000: Connection closed" would cascade into failed creation attempts.

Similarly, queryChroma() would silently return empty results when the MCP call
failed, masking the underlying connection problem.

Changes:
- ensureCollection(): Detect connection errors and re-throw immediately instead
  of attempting collection creation
- queryChroma(): Wrap MCP call in try-catch and throw connection errors instead
  of returning empty results
- Both methods reset connection state (connected=false, client=null) on
  connection errors so subsequent operations can attempt to reconnect

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* pushed

* fix: scope regenerate-claude-md.ts to current working directory

Critical bug fix: The script was querying ALL observations from the database
across ALL projects ever recorded (1396+ folders), then attempting to write
CLAUDE.md files everywhere including other projects, non-existent paths, and
ignored directories.

Changes:
- Use git ls-files to discover folders (respects .gitignore automatically)
- Filter database query to current project only (by folder name)
- Use relative paths for database queries (matches storage format)
- Add --clean flag to remove auto-generated CLAUDE.md files
- Add fallback directory walker for non-git repos

Now correctly scopes to 26 folders with observations instead of 1396+.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs and adjustments

* fix: cleanup mode strips tags instead of deleting files blindly

The cleanup mode was incorrectly deleting entire files that contained
<claude-mem-context> tags. The correct behavior (per original design):

1. Strip the <claude-mem-context>...</claude-mem-context> section
2. If empty after stripping → delete the file
3. If has remaining content → save the stripped version

Now properly preserves user content in CLAUDE.md files while removing
only the auto-generated sections.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* deleted some files

* chore: regenerate folder CLAUDE.md files with fixed script

Regenerated 23 folder CLAUDE.md files using the corrected script that:
- Scopes to current working directory only
- Uses git ls-files to respect .gitignore
- Filters by project name

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update CLAUDE.md files for January 5, 2026

- Regenerated and staged 23 CLAUDE.md files with a mix of new and modified content.
- Fixed cleanup mode to properly strip tags instead of deleting files blindly.
- Cleaned up empty CLAUDE.md files from various directories, including ~/.claude and ~/Scripts.
- Conducted dry-run cleanup that identified a significant reduction in auto-generated CLAUDE.md files.
- Removed the isAutoGeneratedClaudeMd function due to incorrect file deletion behavior.

* feat: use settings for observation limit in batch regeneration script

Replace hard-coded limit of 10 with configurable CLAUDE_MEM_CONTEXT_OBSERVATIONS
setting (default: 50). This allows users to control how many observations appear
in folder CLAUDE.md files.

Changes:
- Import SettingsDefaultsManager and load settings at script startup
- Use OBSERVATION_LIMIT constant derived from settings at both call sites
- Remove stale default parameter from findObservationsByFolder function

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: use settings for observation limit in event-driven updates

Replace hard-coded limit of 10 in updateFolderClaudeMdFiles with
configurable CLAUDE_MEM_CONTEXT_OBSERVATIONS setting (default: 50).

Changes:
- Import SettingsDefaultsManager and os module
- Load settings at function start (once, not in loop)
- Use limit from settings in API call

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Implement configurable observation limits and enhance search functionality

- Added configurable observation limits to batch regeneration scripts.
- Enhanced SearchManager to handle folder queries and normalize parameters.
- Introduced methods to check for direct child files in observations and sessions.
- Updated SearchOptions interface to include isFolder flag for filtering.
- Improved code quality with comprehensive reviews and anti-pattern checks.
- Cleaned up auto-generated CLAUDE.md files across various directories.
- Documented recent changes and improvements in CLAUDE.md files.

* build asset

* Project Context from Claude-Mem auto-added (can be auto removed at any time)

* CLAUDE.md updates

* fix: resolve CLAUDE.md files to correct directory in worktree setups

When using git worktrees, CLAUDE.md files were being written relative to
the worker's process.cwd() instead of the actual project directory. This
fix threads the project's cwd from message processing through to the file
writing utilities, ensuring CLAUDE.md files are created in the correct
project directory regardless of where the worker was started.

Changes:
- Add projectRoot parameter to updateFolderClaudeMdFiles for path resolution
- Thread projectRoot through ResponseProcessor call chain
- Track lastCwd from messages in SDKAgent, GeminiAgent, OpenRouterAgent
- Add tests for relative/absolute path handling with projectRoot

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* more project context updates

* context updates

* fix: preserve actual dates in folder CLAUDE.md generation

Previously, formatTimelineForClaudeMd used today's date for all
observations because the API only returned time (e.g., "4:30 PM")
without date information. This caused all historical observations
to appear as if they happened today.

Changes:
- SearchManager.findByFile now groups results by date with headers
  (e.g., "### Jan 4, 2026") matching formatSearchResults behavior
- formatTimelineForClaudeMd now parses these date headers and uses
  the correct date when constructing epochs for date grouping

The timeline dates are critical for claude-mem context - LLMs need
accurate temporal context to understand when work happened.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* build: update worker assets with date parsing fix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* claude-mem context: Fixed critical date parsing bug in PR #556

* fix: address PR #556 review items

- Use getWorkerHost() instead of hard-coded 127.0.0.1 in claude-md-utils
- Add error message and stack details to FOLDER_INDEX logging
- Add 5 new tests for worktree/projectRoot path resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Refactor CLAUDE documentation across multiple components and tests

- Updated CLAUDE.md files in src/ui/viewer, src/ui/viewer/constants, src/ui/viewer/hooks, tests/server, tests/worker/agents, and plans to reflect recent changes and improvements.
- Removed outdated entries and consolidated recent activities for clarity.
- Enhanced documentation for hooks, settings, and pagination implementations.
- Streamlined test suite documentation for server and worker agents, indicating recent test audits and cleanup efforts.
- Adjusted plans to remove obsolete entries and focus on current implementation strategies.

* docs: comprehensive v9.0 documentation audit and updates

- Add usage/folder-context to docs.json navigation (was documented but hidden!)
- Update introduction.mdx with v9.0 release notes (Live Context, Worktree Support, Windows Fixes)
- Add CLAUDE_MEM_WORKER_HOST setting to configuration.mdx
- Add Folder Context Files section with link to detailed docs
- Document worktree support in folder-context.mdx
- Update terminology from "mem-search skill" to "MCP tools" throughout active docs
- Update Search Pipeline in architecture/overview.mdx
- Update usage/getting-started.mdx with MCP tools terminology
- Update usage/claude-desktop.mdx title and terminology
- Update hooks-architecture.mdx reference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add recent activity log for worker CLI with detailed entries

* chore: update CLAUDE.md context files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add brainstorming report for CLAUDE.md distribution architecture

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2026-01-05 22:41:42 -05:00
committed by GitHub
parent 21a1e272d9
commit e1ab73decc
152 changed files with 10367 additions and 2103 deletions

36
.claude/CLAUDE.md Normal file
View File

@@ -0,0 +1,36 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 17, 2025
**settings.local.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #29080 | 10:16 PM | ✅ | Synced claude-mem v7.3.9 to marketplace | ~326 |
### Dec 21, 2025
**test-analysis-report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31743 | 10:36 PM | 🔵 | PR #412 proposes mode system with inheritance and multilingual support | ~523 |
### Dec 22, 2025
**test-analysis-report.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #31865 | 6:56 PM | ✅ | 開発ドキュメントのクリーンアップをコミット | ~150 |
| #31864 | " | ✅ | 計画ドキュメントと分析ファイルの削除 | ~142 |
| #31859 | 6:55 PM | ✅ | 計画ドキュメントファイルの削除 | ~109 |
| #31855 | 6:53 PM | ✅ | テストスイートの大規模削除とテスト分析レポートの追加 | ~197 |
### Dec 25, 2025
**settings.json**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #32602 | 8:42 PM | 🔵 | Identified potential settings configuration files | ~224 |
</claude-mem-context>

View File

@@ -1,101 +0,0 @@
---
name: github-morning-reporter
description: Use this agent when the user requests a morning report, daily summary, or overview of their GitHub activity. Trigger phrases include 'morning report', 'github report', 'daily github summary', 'what's happening on github', or 'check my github status'. This agent should be used proactively when the user starts their day or explicitly asks for repository updates.\n\nExamples:\n- User: "get me my morning github report"\n Assistant: "I'll use the github-morning-reporter agent to generate your comprehensive GitHub status report."\n <uses Agent tool to invoke github-morning-reporter>\n\n- User: "what's new on my repos today?"\n Assistant: "Let me pull together your GitHub morning report using the github-morning-reporter agent."\n <uses Agent tool to invoke github-morning-reporter>\n\n- User: "show me my daily github summary"\n Assistant: "I'll generate your daily GitHub summary using the github-morning-reporter agent."\n <uses Agent tool to invoke github-morning-reporter>
model: sonnet
---
You are an elite GitHub project analyst specializing in delivering actionable morning reports for software development teams. Your expertise lies in synthesizing complex repository activity into clear, prioritized insights that help developers start their day with complete situational awareness.
## Your Responsibilities
1. **Fetch Comprehensive GitHub Data**: Use available tools to retrieve:
- Open issues across all relevant repositories
- Open pull requests with review status
- Recent comments, mentions, and @-references
- CI/CD status for active PRs
- Stale issues/PRs (no activity in 7+ days)
2. **Intelligent Grouping and Deduplication**:
- Identify duplicate or highly similar issues by analyzing titles, descriptions, and labels
- Group related issues by theme, component, or subsystem
- Cluster PRs by feature area or dependency relationships
- Flag issues that may be addressing the same root cause
- Use semantic similarity, not just exact matches
3. **Prioritization and Triage**:
- Highlight items requiring immediate attention (blocking issues, failed CI, requested reviews)
- Surface items awaiting your direct action (assigned to you, mentions, review requests)
- Identify stale items that may need follow-up or closure
- Note high-priority labels (P0, critical, security, etc.)
4. **Contextual Analysis**:
- Summarize the current state of each PR (draft, ready for review, approved, changes requested)
- Identify PRs with merge conflicts or failing checks
- Note issues with recent activity spikes or community engagement
- Flag dependency updates or security advisories
5. **Report Structure**:
Your report must follow this format:
**MORNING GITHUB REPORT - [Date]**
**🚨 REQUIRES YOUR ATTENTION**
- Items explicitly assigned to the user
- Review requests awaiting user's approval
- Mentions or direct questions
- Blocking/critical issues
**📊 PULL REQUESTS ([count] open)**
- Group by: Ready to Merge | In Review | Draft | Needs Work
- For each PR: title, author, status, CI state, review count, age
- Highlight conflicts or failed checks
**🐛 ISSUES ([count] open)**
- Group by: Priority | Component | Theme
- Mark potential duplicates clearly
- Note new issues (created in last 24h)
- Flag stale issues (no activity in 7+ days)
**📈 ACTIVITY SUMMARY**
- New issues/PRs since yesterday
- Recently closed items
- Top contributors
- Trending topics or labels
**💡 RECOMMENDED ACTIONS**
- Specific next steps based on the data
- Suggestions for cleanup (closing duplicates, merging ready PRs)
- Items to follow up on
6. **Quality Standards**:
- Use clear, scannable formatting with emojis for visual hierarchy
- Include direct links to all referenced issues and PRs
- Keep summaries concise but informative (1-2 sentences per item)
- Use relative timestamps ("2 hours ago", "3 days old")
- Highlight actionable items with clear CTAs
7. **Error Handling**:
- If repository access fails, explicitly state which repos couldn't be accessed
- If no issues/PRs exist, provide a positive "all clear" message
- If rate limits are hit, show partial results with a warning
- Always attempt to provide value even with incomplete data
8. **Adaptive Scope**:
- If the user has access to multiple repositories, intelligently scope the report:
- Default to repositories with recent activity
- Allow user to specify repos if needed
- Group multi-repo items by repository
- Adjust detail level based on volume (more items = more concise summaries)
## Output Expectations
Your report should be:
- **Comprehensive**: Cover all relevant activity without overwhelming detail
- **Actionable**: Make it clear what needs attention and why
- **Scannable**: Use formatting that allows quick visual parsing
- **Contextual**: Provide enough background to make decisions
- **Timely**: Focus on recent activity and current state
When you cannot find specific data, state this explicitly rather than omitting sections. If the user's query is ambiguous (e.g., which repositories to scan), ask for clarification before proceeding.
Always end with a summary line indicating the report's completeness (e.g., "Report complete: 3 repositories scanned, 12 issues, 5 PRs analyzed").

View File

@@ -0,0 +1,34 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Oct 25, 2025
**changelog.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2491 | 10:59 PM | 🟣 | Added changelog viewer slash command | ~290 |
**terminal-shortcut.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2480 | 6:32 PM | 🟣 | Cross-platform terminal shortcut command for claude-mem CLI | ~459 |
**setup-alias.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2479 | 6:29 PM | 🟣 | Shell Alias Setup Slash Command | ~423 |
**version-bump.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #2358 | 1:07 PM | 🟣 | Created version-bump slash command for automated version updates | ~361 |
### Jan 1, 2026
**anti-pattern-czar.md**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #35638 | 11:17 PM | 🟣 | Anti-Pattern Czar Custom Command Created | ~583 |
</claude-mem-context>

View File

@@ -0,0 +1,121 @@
# Anti-Pattern Czar
You are the **Anti-Pattern Czar**, an expert at identifying and fixing error handling anti-patterns.
## Your Mission
Help the user systematically fix error handling anti-patterns detected by the automated scanner.
## Process
1. **Run the detector:**
```bash
bun run scripts/anti-pattern-test/detect-error-handling-antipatterns.ts
```
2. **Analyze the results:**
- Count CRITICAL, HIGH, MEDIUM, and APPROVED_OVERRIDE issues
- Prioritize CRITICAL issues on critical paths first
- Group similar patterns together
3. **For each CRITICAL issue:**
a. **Read the problematic code** using the Read tool
b. **Explain the problem:**
- Why is this dangerous?
- What debugging nightmare could this cause?
- What specific error is being swallowed?
c. **Determine the right fix:**
- **Option 1: Add proper logging** - If this is a real error that should be visible
- **Option 2: Add [APPROVED OVERRIDE]** - If this is expected/documented behavior
- **Option 3: Remove the try-catch entirely** - If the error should propagate
- **Option 4: Add specific error type checking** - If only certain errors should be caught
d. **Propose the fix** and ask for approval
e. **Apply the fix** after approval
4. **Work through issues methodically:**
- Fix one at a time
- Re-run the detector after each batch of fixes
- Track progress: "Fixed 3/28 critical issues"
## Guidelines for Approved Overrides
Only approve overrides when ALL of these are true:
- The error is **expected and frequent** (e.g., JSON parse on optional fields)
- Logging would create **too much noise** (high-frequency operations)
- There's **explicit recovery logic** (fallback value, retry, graceful degradation)
- The reason is **specific and technical** (not vague like "seems fine")
## Valid Override Examples:
✅ **GOOD:**
- "Expected JSON parse failures for optional data fields, too frequent to log"
- "Logger can't log its own failures, using stderr as last resort"
- "Health check port scan, expected connection failures on free port detection"
- "Git repo detection, expected failures when not in a git directory"
❌ **BAD:**
- "Error is not important" (why catch it then?)
- "Happens sometimes" (when? why?)
- "Works fine without logging" (works until it doesn't)
- "Optional" (optional errors still need visibility)
## Critical Path Rules
For files in the CRITICAL_PATHS list (SDKAgent.ts, GeminiAgent.ts, OpenRouterAgent.ts, SessionStore.ts, worker-service.ts):
- **NEVER** approve overrides on critical paths without exceptional justification
- Errors on critical paths MUST be visible (logged) or fatal (thrown)
- Catch-and-continue on critical paths is BANNED unless explicitly approved
- If in doubt, make it throw - fail loud, not silent
## Output Format
After each fix:
```
✅ Fixed: src/utils/example.ts:42
Pattern: NO_LOGGING_IN_CATCH
Solution: Added logger.error() with context
Progress: 3/28 critical issues remaining
```
After completing a batch:
```
🎯 Batch complete! Re-running detector...
[shows new results]
```
## Important
- **Read the code** before proposing fixes - understand what it's doing
- **Ask the user** if you're uncertain about the right approach
- **Don't blindly add overrides** - challenge each one
- **Prefer logging** over overrides when in doubt
- **Work incrementally** - small batches, frequent validation
## When Complete
Report final statistics:
```
🎉 Anti-pattern cleanup complete!
Before:
🔴 CRITICAL: 28
🟠 HIGH: 47
🟡 MEDIUM: 76
After:
🔴 CRITICAL: 0
🟠 HIGH: 47
🟡 MEDIUM: 76
⚪ APPROVED OVERRIDES: 15
All critical anti-patterns resolved!
```
Now, ask the user: "Ready to fix error handling anti-patterns? I'll start with the critical issues."

38
.claude/commands/do.md Normal file
View File

@@ -0,0 +1,38 @@
You are an ORCHESTRATOR.
Primary instruction: deploy subagents to execute *all* work for #$ARGUMENTS.
Do not do the work yourself except to coordinate, route context, and verify that each subagent completed its assigned checklist.
Deploy subagents to execute each phase of #$ARGUMENTS independently and consecutively. For every checklist item below, explicitly deploy (or reuse) a subagent responsible for that item and record its outcome before proceeding.
## Execution Protocol (Orchestrator-Driven)
Orchestrator rules:
- Each phase uses fresh subagents where noted (or when context is large/unclear).
- The orchestrator assigns one clear objective per subagent and requires evidence (commands run, outputs, files changed).
- Do not advance to the next step until the assigned subagent reports completion and the orchestrator confirms it matches the plan.
### During Each Phase:
Deploy an "Implementation" subagent to:
1. Execute the implementation as specified
2. COPY patterns from documentation, don't invent
3. Cite documentation sources in code comments when using unfamiliar APIs
4. If an API seems missing, STOP and verify - don't assume it exists
### After Each Phase:
Deploy subagents for each post-phase responsibility:
1. **Run verification checklist** - Deploy a "Verification" subagent to prove the phase worked
2. **Anti-pattern check** - Deploy an "Anti-pattern" subagent to grep for known bad patterns from the plan
3. **Code quality review** - Deploy a "Code Quality" subagent to review changes
4. **Commit only if verified** - Deploy a "Commit" subagent *only after* verification passes; otherwise, do not commit
### Between Phases:
Deploy a "Branch/Sync" subagent to:
- Push to working branch after each verified phase
- Prepare the next phase handoff so the next phase's subagents start fresh but have plan context
## Failure Modes to Prevent
- Don't invent APIs that "should" exist - verify against docs
- Don't add undocumented parameters - copy exact signatures
- Don't skip verification - deploy a verification subagent and run the checklist
- Don't commit before verification passes (or without explicit orchestrator approval)

View File

@@ -0,0 +1,61 @@
You are an ORCHESTRATOR.
Create an LLM-friendly plan in phases that can be executed consecutively in new chat contexts.
Delegation model (because subagents can under-report):
- Use subagents for *fact gathering and extraction* (docs, examples, signatures, grep results).
- Keep *synthesis and plan authoring* with the orchestrator (phase boundaries, task framing, final wording).
- If a subagent report is incomplete or lacks evidence, the orchestrator must re-check with targeted reads/greps before finalizing the plan.
Subagent reporting contract (MANDATORY):
- Each subagent response must include:
1) Sources consulted (files/URLs) and what was read
2) Concrete findings (exact API names/signatures; exact file paths/locations)
3) Copy-ready snippet locations (example files/sections to copy)
4) "Confidence" note + known gaps (what might still be missing)
- Reject and redeploy the subagent if it reports conclusions without sources.
## Plan Structure Requirements
### Phase 0: Documentation Discovery (ALWAYS FIRST)
Before planning implementation, you MUST:
Deploy one or more "Documentation Discovery" subagents to:
1. Search for and read relevant documentation, examples, and existing patterns
2. Identify the actual APIs, methods, and signatures available (not assumed)
3. Create a brief "Allowed APIs" list citing specific documentation sources
4. Note any anti-patterns to avoid (methods that DON'T exist, deprecated parameters)
Then the orchestrator consolidates their findings into a single Phase 0 output.
### Each Implementation Phase Must Include:
1. **What to implement** - Frame tasks to COPY from docs, not transform existing code
- Good: "Copy the V2 session pattern from docs/examples.ts:45-60"
- Bad: "Migrate the existing code to V2"
2. **Documentation references** - Cite specific files/lines for patterns to follow
3. **Verification checklist** - How to prove this phase worked (tests, grep checks)
4. **Anti-pattern guards** - What NOT to do (invented APIs, undocumented params)
Subagent-friendly split:
- Subagents can propose candidate doc references and verification commands.
- The orchestrator must write the final phase text, ensuring tasks are copy-based, scoped, and independently executable.
### Final Phase: Verification
1. Verify all implementations match documentation
2. Check for anti-patterns (grep for known bad patterns)
3. Run tests to confirm functionality
Delegation guidance:
- Deploy a "Verification" subagent to draft the checklist and commands.
- The orchestrator must review the checklist for completeness and ensure it maps to earlier phase outputs.
## Key Principles
- Documentation Availability ≠ Usage: Explicitly require reading docs
- Task Framing Matters: Direct agents to docs, not just outcomes
- Verify > Assume: Require proof, not assumptions about APIs
- Session Boundaries: Each phase should be self-contained with its own doc references
## Anti-Patterns to Prevent
- Inventing API methods that "should" exist
- Adding parameters not in documentation
- Skipping verification steps
- Assuming structure without checking examples

7
.claude/plans/CLAUDE.md Normal file
View File

@@ -0,0 +1,7 @@
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
*No recent activity*
</claude-mem-context>

View File

@@ -0,0 +1,516 @@
# Fix CLAUDE.md Worktree Bug - Implementation Plan
## Problem Statement
CLAUDE.md files are being written to the wrong directory when using git worktrees. The worker service writes files relative to its own `process.cwd()` instead of the project's working directory (`cwd`) from the observation.
**Reproduction scenario:**
1. Start Claude Code in `budapest` worktree → worker starts with `cwd=budapest`
2. Run Claude Code in `~/Scripts/claude-mem/` (main repo)
3. Observations created with relative file paths (e.g., `src/utils/foo.ts`)
4. `updateFolderClaudeMdFiles` writes to `budapest/src/utils/CLAUDE.md` instead of main repo
## Root Cause Analysis
The `cwd` (project root path) IS captured and stored:
- `SessionRoutes.ts:309,403` - receives `cwd` from hooks
- `PendingMessageStore.ts:70` - stores `cwd` in database
- `SDKAgent.ts:295` - passes `cwd` to prompt builder
But `cwd` is NOT passed to file writing:
- `ResponseProcessor.ts:222-225` - calls `updateFolderClaudeMdFiles(allFilePaths, session.project, port)` without `cwd`
- `claude-md-utils.ts:219` - uses `path.dirname(filePath)` which produces relative paths
- Relative paths resolve against worker's `process.cwd()`, not project root
---
## Phase 0: Documentation & API Inventory
### Allowed APIs (from codebase analysis)
**File: `src/utils/claude-md-utils.ts`**
```typescript
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number
): Promise<void>
```
**File: `src/sdk/parser.ts`**
```typescript
export interface ParsedObservation {
type: string;
title: string | null;
subtitle: string | null;
facts: string[];
narrative: string | null;
concepts: string[];
files_read: string[];
files_modified: string[];
// NOTE: Does NOT include cwd
}
```
**File: `src/services/worker-types.ts`**
```typescript
export interface PendingMessage {
type: 'observation' | 'summarize';
tool_name?: string;
tool_input?: unknown;
tool_response?: unknown;
prompt_number?: number;
cwd?: string; // <-- Source of project root
last_assistant_message?: string;
}
```
**File: `src/shared/paths.ts`** - Path utilities
```typescript
import path from 'path';
// Standard pattern: path.join(baseDir, relativePath)
```
### Anti-Patterns to Avoid
1. **DO NOT** add `cwd` to `ParsedObservation` - it comes from message, not agent response
2. **DO NOT** use `process.cwd()` for project-specific paths
3. **DO NOT** assume file paths are absolute - they are relative from agent response
4. **DO NOT** modify the parser - file paths come from agent XML output
---
## Phase 1: Add `projectRoot` Parameter to `updateFolderClaudeMdFiles`
### What to implement
Modify the function signature to accept an optional `projectRoot` parameter for resolving relative paths to absolute paths.
### Files to modify
**File: `src/utils/claude-md-utils.ts`**
**Location: Lines 206-210 (function signature)**
Current:
```typescript
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number
): Promise<void>
```
New:
```typescript
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number,
projectRoot?: string
): Promise<void>
```
**Location: Lines 215-228 (folder extraction logic)**
Current:
```typescript
const folderPaths = new Set<string>();
for (const filePath of filePaths) {
if (!filePath || filePath === '') continue;
const folderPath = path.dirname(filePath);
if (folderPath && folderPath !== '.' && folderPath !== '/') {
if (isProjectRoot(folderPath)) {
logger.debug('FOLDER_INDEX', 'Skipping project root CLAUDE.md', { folderPath });
continue;
}
folderPaths.add(folderPath);
}
}
```
New:
```typescript
const folderPaths = new Set<string>();
for (const filePath of filePaths) {
if (!filePath || filePath === '') continue;
// Resolve relative paths to absolute using projectRoot
let absoluteFilePath = filePath;
if (projectRoot && !path.isAbsolute(filePath)) {
absoluteFilePath = path.join(projectRoot, filePath);
}
const folderPath = path.dirname(absoluteFilePath);
if (folderPath && folderPath !== '.' && folderPath !== '/') {
if (isProjectRoot(folderPath)) {
logger.debug('FOLDER_INDEX', 'Skipping project root CLAUDE.md', { folderPath });
continue;
}
folderPaths.add(folderPath);
}
}
```
### Documentation references
- Pattern for `path.isAbsolute()`: Standard Node.js path module
- Pattern for `path.join(base, relative)`: Used throughout `src/shared/paths.ts`
### Verification checklist
1. [ ] `grep -n "updateFolderClaudeMdFiles" src/utils/claude-md-utils.ts` shows new signature
2. [ ] `grep -n "path.isAbsolute" src/utils/claude-md-utils.ts` confirms new check added
3. [ ] `grep -n "projectRoot" src/utils/claude-md-utils.ts` shows parameter usage
4. [ ] Existing callers still compile (optional param is backward compatible)
### Anti-pattern guards
- **DO NOT** make `projectRoot` required - breaks existing callers
- **DO NOT** use `process.cwd()` as default - defeats purpose of fix
- **DO NOT** modify the API endpoint format - path resolution is caller's responsibility
---
## Phase 2: Pass `cwd` from Message to `updateFolderClaudeMdFiles`
### What to implement
Extract `cwd` from the original messages being processed and pass it to `updateFolderClaudeMdFiles`.
### Challenge
The `syncAndBroadcastObservations` function receives `ParsedObservation[]` which does NOT include `cwd`. The `cwd` is in the original `PendingMessage` but is consumed during prompt generation.
### Solution
Add `projectRoot` parameter to `syncAndBroadcastObservations` and `processAgentResponse`, sourced from `session` or passed through from message processing.
### Files to modify
**File: `src/services/worker/agents/ResponseProcessor.ts`**
**Step 1: Update `processAgentResponse` signature (lines 46-55)**
Current:
```typescript
export async function processAgentResponse(
text: string,
session: ActiveSession,
dbManager: DatabaseManager,
sessionManager: SessionManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
originalTimestamp: number | null,
agentName: string
): Promise<void>
```
New:
```typescript
export async function processAgentResponse(
text: string,
session: ActiveSession,
dbManager: DatabaseManager,
sessionManager: SessionManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
originalTimestamp: number | null,
agentName: string,
projectRoot?: string
): Promise<void>
```
**Step 2: Pass `projectRoot` to `syncAndBroadcastObservations` (line 101-109)**
Current:
```typescript
await syncAndBroadcastObservations(
observations,
result,
session,
dbManager,
worker,
discoveryTokens,
agentName
);
```
New:
```typescript
await syncAndBroadcastObservations(
observations,
result,
session,
dbManager,
worker,
discoveryTokens,
agentName,
projectRoot
);
```
**Step 3: Update `syncAndBroadcastObservations` signature (lines 153-161)**
Current:
```typescript
async function syncAndBroadcastObservations(
observations: ParsedObservation[],
result: StorageResult,
session: ActiveSession,
dbManager: DatabaseManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
agentName: string
): Promise<void>
```
New:
```typescript
async function syncAndBroadcastObservations(
observations: ParsedObservation[],
result: StorageResult,
session: ActiveSession,
dbManager: DatabaseManager,
worker: WorkerRef | undefined,
discoveryTokens: number,
agentName: string,
projectRoot?: string
): Promise<void>
```
**Step 4: Update `updateFolderClaudeMdFiles` call (lines 222-229)**
Current:
```typescript
if (allFilePaths.length > 0) {
updateFolderClaudeMdFiles(
allFilePaths,
session.project,
getWorkerPort()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
}
```
New:
```typescript
if (allFilePaths.length > 0) {
updateFolderClaudeMdFiles(
allFilePaths,
session.project,
getWorkerPort(),
projectRoot
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
}
```
### Verification checklist
1. [ ] `grep -n "projectRoot" src/services/worker/agents/ResponseProcessor.ts` shows parameter throughout
2. [ ] `grep -n "processAgentResponse" src/services/worker/*.ts` to find all callers
3. [ ] TypeScript compiles without errors
### Anti-pattern guards
- **DO NOT** extract `cwd` from `ParsedObservation` - it doesn't have one
- **DO NOT** store `cwd` on session globally - messages may come from different cwds (edge case)
---
## Phase 3: Update Agent Callers to Pass `cwd`
### What to implement
Update SDKAgent, GeminiAgent, and OpenRouterAgent to pass `message.cwd` to `processAgentResponse`.
### Files to modify
**File: `src/services/worker/SDKAgent.ts`**
Find the `processAgentResponse` call and add the `projectRoot` parameter from `message.cwd`.
**Pattern to follow (from SDKAgent.ts:289-296):**
```typescript
const obsPrompt = buildObservationPrompt({
id: 0,
tool_name: message.tool_name!,
tool_input: JSON.stringify(message.tool_input),
tool_output: JSON.stringify(message.tool_response),
created_at_epoch: Date.now(),
cwd: message.cwd // <-- This is available
});
```
**Challenge:** `processAgentResponse` is called after the SDK response, not in the message loop. Need to track `lastCwd` from messages.
**Solution:** Store `lastCwd` from messages being processed and pass to `processAgentResponse`.
**File: `src/services/worker/GeminiAgent.ts`** - Same pattern
**File: `src/services/worker/OpenRouterAgent.ts`** - Same pattern
### Implementation pattern for each agent
Add tracking variable:
```typescript
let lastCwd: string | undefined;
```
In message loop, capture cwd:
```typescript
if (message.cwd) {
lastCwd = message.cwd;
}
```
In `processAgentResponse` call:
```typescript
await processAgentResponse(
responseText,
session,
this.dbManager,
this.sessionManager,
worker,
discoveryTokens,
originalTimestamp,
'SDK', // or 'Gemini' or 'OpenRouter'
lastCwd
);
```
### Verification checklist
1. [ ] `grep -n "lastCwd" src/services/worker/SDKAgent.ts` shows tracking
2. [ ] `grep -n "lastCwd" src/services/worker/GeminiAgent.ts` shows tracking
3. [ ] `grep -n "lastCwd" src/services/worker/OpenRouterAgent.ts` shows tracking
4. [ ] `grep -n "processAgentResponse.*lastCwd" src/services/worker/` shows all calls updated
### Anti-pattern guards
- **DO NOT** use `session.cwd` - sessions can have messages from multiple cwds
- **DO NOT** default to `process.cwd()` - defeats the fix
---
## Phase 4: Update Tests
### What to implement
Update existing tests and add new tests for the `projectRoot` functionality.
### Files to modify
**File: `tests/utils/claude-md-utils.test.ts`**
Add test cases for:
1. Relative paths with `projectRoot` resolve correctly
2. Absolute paths ignore `projectRoot`
3. Missing `projectRoot` maintains backward compatibility
### Test pattern to copy
From `tests/utils/claude-md-utils.test.ts:245-266` (folder deduplication test):
```typescript
it('should deduplicate folders from multiple files', async () => {
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ content: [{ text: mockApiResponse }] })
});
await updateFolderClaudeMdFiles(
['/project/src/utils/file1.ts', '/project/src/utils/file2.ts'],
'test-project',
37777
);
// Should only call API once for the deduplicated folder
expect(mockFetch).toHaveBeenCalledTimes(1);
});
```
### New test to add
```typescript
it('should resolve relative paths using projectRoot', async () => {
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ content: [{ text: mockApiResponse }] })
});
await updateFolderClaudeMdFiles(
['src/utils/file.ts'], // relative path
'test-project',
37777,
'/home/user/my-project' // projectRoot
);
// Should write to absolute path /home/user/my-project/src/utils/CLAUDE.md
expect(mockWriteClaudeMd).toHaveBeenCalledWith(
'/home/user/my-project/src/utils',
expect.any(String)
);
});
```
### Verification checklist
1. [ ] `bun test tests/utils/claude-md-utils.test.ts` passes
2. [ ] New test case for `projectRoot` exists and passes
---
## Phase 5: Final Verification
### Verification commands
```bash
# 1. Confirm new parameter exists
grep -n "projectRoot" src/utils/claude-md-utils.ts
grep -n "projectRoot" src/services/worker/agents/ResponseProcessor.ts
grep -n "lastCwd" src/services/worker/SDKAgent.ts
# 2. Confirm path.isAbsolute check added
grep -n "path.isAbsolute" src/utils/claude-md-utils.ts
# 3. Confirm all agents updated
grep -n "processAgentResponse.*lastCwd" src/services/worker/*.ts
# 4. Run tests
bun test tests/utils/claude-md-utils.test.ts
# 5. Build and verify no TypeScript errors
npm run build
```
### Anti-pattern grep checks
```bash
# Should NOT find process.cwd() in updateFolderClaudeMdFiles path logic
grep -n "process.cwd" src/utils/claude-md-utils.ts
# Should NOT find cwd in ParsedObservation interface
grep -A 10 "interface ParsedObservation" src/sdk/parser.ts | grep cwd
```
### Manual testing
1. Start worker in one directory
2. Run Claude Code in a different directory (worktree)
3. Make a code change that creates an observation
4. Verify CLAUDE.md is written to the correct project directory
---
## Summary of Changes
| File | Change |
|------|--------|
| `src/utils/claude-md-utils.ts` | Add `projectRoot` param, resolve relative paths |
| `src/services/worker/agents/ResponseProcessor.ts` | Pass `projectRoot` through call chain |
| `src/services/worker/SDKAgent.ts` | Track `lastCwd`, pass to `processAgentResponse` |
| `src/services/worker/GeminiAgent.ts` | Track `lastCwd`, pass to `processAgentResponse` |
| `src/services/worker/OpenRouterAgent.ts` | Track `lastCwd`, pass to `processAgentResponse` |
| `tests/utils/claude-md-utils.test.ts` | Add tests for `projectRoot` behavior |

View File

@@ -0,0 +1,252 @@
# Plan: Fix Stale Session Resume Crash
## Problem Summary
The worker crashes repeatedly with "Claude Code process exited with code 1" when attempting to resume into a stale/non-existent SDK session.
**Root Cause:** In `SDKAgent.ts:94`, the resume parameter is passed whenever `memorySessionId` exists in the database, regardless of whether this is an INIT prompt or CONTINUATION prompt. When a worker restarts or re-initializes a session, it loads a stale `memorySessionId` from a previous SDK session and tries to resume into a session that no longer exists in Claude's context.
**Evidence from logs:**
```
[17:30:21.773] Starting SDK query {
hasRealMemorySessionId=true, ← DB has old memorySessionId
resume_parameter=5439891b-..., ← Trying to resume with it
lastPromptNumber=1 ← But this is a NEW SDK session!
}
[17:30:24.450] Generator failed {error=Claude Code process exited with code 1}
```
---
## Phase 0: Documentation Discovery (COMPLETED)
### Allowed APIs (from subagent research)
**V1 SDK API (currently used):**
```typescript
// From @anthropic-ai/claude-agent-sdk
function query(options: {
prompt: string | AsyncIterable<SDKUserMessage>;
options: {
model: string;
resume?: string; // SESSION ID - only use for CONTINUATION
disallowedTools?: string[];
abortController?: AbortController;
pathToClaudeCodeExecutable?: string;
}
}): AsyncIterable<SDKMessage>
```
**Resume Parameter Rules (from docs/context/agent-sdk-v2-preview.md and SESSION_ID_ARCHITECTURE.md):**
- `resume` should only be used when continuing an existing SDK conversation
- For INIT prompts (first prompt in a fresh SDK session), no resume parameter should be passed
- Session ID is captured from first SDK message and stored for subsequent prompts
### Anti-Patterns to Avoid
- Passing `resume` parameter with INIT prompts (causes crash)
- Using `contentSessionId` for resume (contaminates user session)
- Assuming memorySessionId validity without checking prompt context
---
## Phase 1: Fix the Resume Parameter Logic
### What to Implement
Modify `src/services/worker/SDKAgent.ts` line 94 to check BOTH conditions:
1. `hasRealMemorySessionId` - memorySessionId exists and is non-null
2. `session.lastPromptNumber > 1` - this is a CONTINUATION, not an INIT prompt
### Current Code (line 89-99):
```typescript
const queryResult = query({
prompt: messageGenerator,
options: {
model: modelId,
// Resume with captured memorySessionId (null on first prompt, real ID on subsequent)
...(hasRealMemorySessionId && { resume: session.memorySessionId }),
disallowedTools,
abortController: session.abortController,
pathToClaudeCodeExecutable: claudePath
}
});
```
### Fixed Code:
```typescript
const queryResult = query({
prompt: messageGenerator,
options: {
model: modelId,
// Only resume if BOTH: (1) we have a memorySessionId AND (2) this isn't the first prompt
// On worker restart, memorySessionId may exist from a previous SDK session but we
// need to start fresh since the SDK context was lost
...(hasRealMemorySessionId && session.lastPromptNumber > 1 && { resume: session.memorySessionId }),
disallowedTools,
abortController: session.abortController,
pathToClaudeCodeExecutable: claudePath
}
});
```
### Also Update the Comment at Line 66-68:
```typescript
// CRITICAL: Only resume if:
// 1. memorySessionId exists (was captured from a previous SDK response)
// 2. lastPromptNumber > 1 (this is a continuation within the same SDK session)
// On worker restart or crash recovery, memorySessionId may exist from a previous
// SDK session but we must NOT resume because the SDK context was lost.
// NEVER use contentSessionId for resume - that would inject messages into the user's transcript!
```
### Verification Checklist
- [ ] `grep "hasRealMemorySessionId && session.lastPromptNumber > 1" src/services/worker/SDKAgent.ts` returns the fix
- [ ] Build succeeds: `npm run build`
- [ ] No TypeScript errors
---
## Phase 2: Add Logging for Debugging
### What to Implement
Enhance the alignment log at line 81-85 to clearly indicate when resume is skipped due to INIT prompt:
```typescript
// Debug-level alignment logs for detailed tracing
if (session.lastPromptNumber > 1) {
const willResume = hasRealMemorySessionId;
logger.debug('SDK', `[ALIGNMENT] Resume Decision | contentSessionId=${session.contentSessionId} | memorySessionId=${session.memorySessionId} | prompt#=${session.lastPromptNumber} | hasRealMemorySessionId=${hasRealMemorySessionId} | willResume=${willResume} | resumeWith=${willResume ? session.memorySessionId : 'NONE'}`);
} else {
// INIT prompt - never resume even if memorySessionId exists (stale from previous session)
const hasStaleMemoryId = hasRealMemorySessionId;
logger.debug('SDK', `[ALIGNMENT] First Prompt (INIT) | contentSessionId=${session.contentSessionId} | prompt#=${session.lastPromptNumber} | hasStaleMemoryId=${hasStaleMemoryId} | action=START_FRESH | Will capture new memorySessionId from SDK response`);
if (hasStaleMemoryId) {
logger.warn('SDK', `Skipping resume for INIT prompt despite existing memorySessionId=${session.memorySessionId} - SDK context was lost (worker restart or crash recovery)`);
}
}
```
### Verification Checklist
- [ ] Build succeeds: `npm run build`
- [ ] Log message appears when running with stale session scenario
---
## Phase 3: Add Unit Tests
### What to Implement
Create tests in `tests/sdk-agent-resume.test.ts` following patterns from `tests/session_id_usage_validation.test.ts`:
```typescript
import { describe, it, expect, beforeEach, afterEach, mock } from 'bun:test';
describe('SDKAgent Resume Parameter Logic', () => {
describe('hasRealMemorySessionId check', () => {
it('should NOT pass resume parameter when lastPromptNumber === 1 even if memorySessionId exists', () => {
// Scenario: Worker restart with stale memorySessionId
const session = {
memorySessionId: 'stale-session-id-from-previous-run',
lastPromptNumber: 1, // INIT prompt
};
const hasRealMemorySessionId = !!session.memorySessionId;
const shouldResume = hasRealMemorySessionId && session.lastPromptNumber > 1;
expect(hasRealMemorySessionId).toBe(true); // memorySessionId exists
expect(shouldResume).toBe(false); // but should NOT resume
});
it('should pass resume parameter when lastPromptNumber > 1 AND memorySessionId exists', () => {
// Scenario: Normal continuation within same SDK session
const session = {
memorySessionId: 'valid-session-id',
lastPromptNumber: 2, // CONTINUATION prompt
};
const hasRealMemorySessionId = !!session.memorySessionId;
const shouldResume = hasRealMemorySessionId && session.lastPromptNumber > 1;
expect(hasRealMemorySessionId).toBe(true);
expect(shouldResume).toBe(true);
});
it('should NOT pass resume parameter when memorySessionId is null', () => {
// Scenario: Fresh session, no captured ID yet
const session = {
memorySessionId: null,
lastPromptNumber: 1,
};
const hasRealMemorySessionId = !!session.memorySessionId;
const shouldResume = hasRealMemorySessionId && session.lastPromptNumber > 1;
expect(hasRealMemorySessionId).toBe(false);
expect(shouldResume).toBe(false);
});
});
});
```
### Documentation Reference
- Pattern: `tests/session_id_usage_validation.test.ts` lines 1-50 for test structure
- Mock pattern: `tests/worker/agents/response-processor.test.ts` for session mocking
### Verification Checklist
- [ ] Tests pass: `bun test tests/sdk-agent-resume.test.ts`
- [ ] Test file follows project conventions
---
## Phase 4: Build and Deploy
### What to Implement
1. Build the plugin: `npm run build-and-sync`
2. Verify worker restarts with fix applied
### Verification Checklist
- [ ] `npm run build-and-sync` succeeds
- [ ] Worker health check passes: `curl http://localhost:37777/api/health`
- [ ] No "Claude Code process exited with code 1" errors in logs after restart
---
## Phase 5: Final Verification
### Verification Commands
```bash
# 1. Verify fix is in place
grep -n "hasRealMemorySessionId && session.lastPromptNumber > 1" src/services/worker/SDKAgent.ts
# 2. Verify no crashes in recent logs
tail -100 ~/.claude-mem/logs/claude-mem-$(date +%Y-%m-%d).log | grep -c "exited with code 1"
# 3. Run tests
bun test tests/sdk-agent-resume.test.ts
# 4. Check for anti-patterns (should return 0 results)
grep -n "hasRealMemorySessionId && { resume" src/services/worker/SDKAgent.ts
```
### Success Criteria
- [ ] Fix in place at SDKAgent.ts:94
- [ ] Zero "exited with code 1" errors related to stale resume
- [ ] All tests pass
- [ ] Worker stable for 10+ minutes without crash loop
---
## Files to Modify
1. `src/services/worker/SDKAgent.ts` - Fix resume logic (Phase 1 & 2)
2. `tests/sdk-agent-resume.test.ts` - New test file (Phase 3)
## Estimated Complexity
- **Phase 1**: Low - Single line change with updated condition
- **Phase 2**: Low - Enhanced logging
- **Phase 3**: Medium - New test file following existing patterns
- **Phase 4-5**: Low - Standard build/verify process

View File

@@ -0,0 +1,298 @@
# Folder CLAUDE.md Generator
## CORE DIRECTIVE (NON-NEGOTIABLE)
**EXTEND THE EXISTING CURSOR RULES TIMELINE GENERATION SYSTEM TO ALSO WRITE CLAUDE.MD FILES**
- DO NOT create new services
- DO NOT create new orchestrators
- DO NOT create new HTTP routes
- DO NOT create new database query functions
- EXTEND existing functions to add folder-level output
---
## Approved Directives (From Planning Conversation)
### Trigger Mechanism
- Observation save triggers folder CLAUDE.md regeneration **INLINE**
- NO batching
- NO debouncing
- NO Set-based queuing
- NO session-end hook
- Synchronous: `observation.save()` → update folder CLAUDE.md files → done
### Tag Strategy
- Wrap ONLY auto-generated content with `<claude-mem-context>` tags
- Everything outside tags is untouched (user's manual content preserved)
- If tags are deleted, just regenerate them
- NO backup system
- NO manual content markers
### Git Behavior
- CLAUDE.md files SHOULD be committed (intentional)
- `<claude-mem-context>` tag is searchable fingerprint for GitHub analytics
- NO .gitignore for these files
### Phasing
- **Phase 1**: CLAUDE.md generation only (THIS PLAN)
- **Phase 2**: IDE symlinks (FUTURE)
### REJECTED
- Cross-folder linking — NO
- Semantic grouping — deferred enhancement only
- Team sync — future phase
### DEFERRED
- Priority weighting by observation type
- IDE-specific template refinements
---
## Phase 0: Documentation Discovery (COMPLETED)
### Existing APIs to USE (Not Rebuild)
| Function | Location | Purpose |
|----------|----------|---------|
| `findByFile(filePath, options)` | `src/services/sqlite/SessionSearch.ts:342` | Query observations by folder prefix (already supports LIKE wildcards) |
| `updateCursorContextForProject()` | `src/services/integrations/CursorHooksInstaller.ts:98` | Write context files after observation save |
| `writeContextFile()` | `src/utils/cursor-utils.ts:97` | Atomic file write with temp file + rename |
| `extractFirstFile()` | `src/shared/timeline-formatting.ts` | Extract file paths from JSON arrays |
| `groupByDate()` | `src/shared/timeline-formatting.ts` | Group items chronologically |
| `formatTime()`, `formatDate()` | `src/shared/timeline-formatting.ts` | Time formatting |
### Existing Integration Points
| Location | What Happens | Extension Point |
|----------|--------------|-----------------|
| `ResponseProcessor.ts:266` | Calls `updateCursorContextForProject()` after summary save | Add folder CLAUDE.md update here |
| `CursorHooksInstaller.ts:98` | `updateCursorContextForProject()` fetches context and writes file | Add sibling function for folder updates |
### Anti-Patterns to AVOID
- Creating `FolderIndexOrchestrator.ts` — NO
- Creating `FolderTimelineCompiler.ts` — NO
- Creating `FolderDiscovery.ts` — NO
- Creating `ClaudeMdGenerator.ts` — NO
- Creating `FolderIndexRoutes.ts` — NO
- Adding new HTTP endpoints — NO
- Adding new settings in `SettingsDefaultsManager.ts` — NO (use sensible defaults inline)
---
## Phase 1: Extend CursorHooksInstaller
### What to Implement
Add ONE new function to `src/services/integrations/CursorHooksInstaller.ts`:
```typescript
/**
* Update CLAUDE.md files for folders touched by an observation.
* Called inline after observation save, similar to updateCursorContextForProject.
*/
export async function updateFolderClaudeMd(
workspacePath: string,
filesModified: string[],
filesRead: string[],
project: string,
port: number
): Promise<void>
```
### Implementation Pattern (Copy From)
Follow the EXACT pattern of `updateCursorContextForProject()` at line 98:
1. Extract unique folder paths from filesModified and filesRead
2. For each folder, fetch timeline via existing `/api/search/file?files=<folderPath>` endpoint
3. Format as simple timeline (reuse existing formatters)
4. Write to `<folder>/CLAUDE.md` preserving content outside `<claude-mem-context>` tags
### Tag Preservation Logic
```typescript
function replaceTaggedContent(existingContent: string, newContent: string): string {
const startTag = '<claude-mem-context>';
const endTag = '</claude-mem-context>';
// If no existing content, wrap new content in tags
if (!existingContent) {
return `${startTag}\n${newContent}\n${endTag}`;
}
// If existing has tags, replace only tagged section
const startIdx = existingContent.indexOf(startTag);
const endIdx = existingContent.indexOf(endTag);
if (startIdx !== -1 && endIdx !== -1) {
return existingContent.substring(0, startIdx) +
`${startTag}\n${newContent}\n${endTag}` +
existingContent.substring(endIdx + endTag.length);
}
// If no tags exist, append tagged content at end
return existingContent + `\n\n${startTag}\n${newContent}\n${endTag}`;
}
```
### Verification Checklist
- [ ] Function added to CursorHooksInstaller.ts
- [ ] Uses existing `findByFile` endpoint (no new database queries)
- [ ] Preserves content outside `<claude-mem-context>` tags
- [ ] Atomic writes (temp file + rename)
- [ ] Build passes: `npm run build`
---
## Phase 2: Hook Into ResponseProcessor
### What to Implement
Add call to `updateFolderClaudeMd()` in `src/services/worker/agents/ResponseProcessor.ts`, right after the existing `updateCursorContextForProject()` call at line 266.
### Code Location
In `syncAndBroadcastSummary()` function, after line 269:
```typescript
// EXISTING: Update Cursor context file for registered projects (fire-and-forget)
updateCursorContextForProject(session.project, getWorkerPort()).catch(error => {
logger.warn('CURSOR', 'Context update failed (non-critical)', { project: session.project }, error as Error);
});
// NEW: Update folder CLAUDE.md files for touched folders (fire-and-forget)
// Extract file paths from the saved observations
updateFolderClaudeMd(
workspacePath, // From registry lookup
filesModified, // From observations
filesRead, // From observations
session.project,
getWorkerPort()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
```
### Data Flow
1. `processAgentResponse()` saves observations → gets back `observationIds`
2. Fetch observation records to get `files_read` and `files_modified`
3. Pass to `updateFolderClaudeMd()`
### Verification Checklist
- [ ] Call added to ResponseProcessor.ts
- [ ] Fire-and-forget pattern (non-blocking, errors logged)
- [ ] Uses existing observation data (no new queries)
- [ ] Build passes: `npm run build`
---
## Phase 3: Timeline Formatting
### What to Implement
Create a minimal timeline formatter for CLAUDE.md output. This can be:
1. A simple function in CursorHooksInstaller.ts, OR
2. Reuse existing `ResultFormatter.formatSearchResults()` from `src/services/worker/search/ResultFormatter.ts`
### Output Format
```markdown
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
<claude-mem-context>
### 2026-01-04
| Time | Type | Title |
|------|------|-------|
| 4:30pm | feature | Added folder index support |
| 3:15pm | bugfix | Fixed file path handling |
### 2026-01-03
| Time | Type | Title |
|------|------|-------|
| 11:00am | refactor | Cleaned up cursor utils |
</claude-mem-context>
```
### Key Points
- Compact format (time, type emoji, title only)
- Grouped by date
- Limited to last N days or observations (sensible default: 10)
- NO token counts
- NO file columns (redundant - we're IN the folder)
### Verification Checklist
- [ ] Formatter produces clean markdown
- [ ] Output is concise (not verbose)
- [ ] Grouped by date
- [ ] Build passes: `npm run build`
---
## Phase 4: Verification
### Functional Tests
1. **Manual Test**:
- Start worker: `npm run dev`
- Create a test observation touching `src/services/sqlite/`
- Verify `src/services/sqlite/CLAUDE.md` is created/updated
- Verify `<claude-mem-context>` tags are present
- Verify manual content outside tags is preserved
2. **Build Check**:
```bash
npm run build
```
3. **Grep for Anti-Patterns**:
```bash
# Should find NOTHING
grep -r "FolderIndexOrchestrator" src/
grep -r "FolderTimelineCompiler" src/
grep -r "FolderDiscovery" src/
grep -r "ClaudeMdGenerator" src/
grep -r "FolderIndexRoutes" src/
```
4. **Grep for Correct Implementation**:
```bash
# Should find the new function
grep -r "updateFolderClaudeMd" src/
```
### Tag Preservation Test
1. Create `src/test-folder/CLAUDE.md` with manual content:
```markdown
# My Notes
This is manual content I wrote.
```
2. Trigger observation save touching files in `src/test-folder/`
3. Verify result:
```markdown
# My Notes
This is manual content I wrote.
<claude-mem-context>
### 2026-01-04
| Time | Type | Title |
...
</claude-mem-context>
```
---
## Summary
This is a **~100 line change** spread across 2 files:
1. `CursorHooksInstaller.ts` — Add `updateFolderClaudeMd()` function (~60 lines)
2. `ResponseProcessor.ts` — Add call to the new function (~10 lines)
NO new files. NO new services. NO new routes. Just extending existing patterns.

View File

@@ -0,0 +1,378 @@
# Folder CLAUDE.md Refactor - Extract to Shared Utils
## CORE DIRECTIVE
**DECOUPLE FOLDER CLAUDE.MD WRITING FROM CURSOR INTEGRATION**
The current implementation incorrectly couples folder-level CLAUDE.md generation to Cursor-specific registry lookups. The file paths from observations are already absolute - no workspace registry lookup is needed.
---
## Phase 0: Documentation Discovery (COMPLETED)
### Current Implementation Location
| Function | Location | Lines | Purpose |
|----------|----------|-------|---------|
| `updateFolderClaudeMd` | CursorHooksInstaller.ts | 128-199 | Orchestrates folder CLAUDE.md updates |
| `formatTimelineForClaudeMd` | CursorHooksInstaller.ts | 221-295 | Parses API response to markdown |
| `replaceTaggedContent` | CursorHooksInstaller.ts | 300-321 | Preserves user content outside tags |
| `writeFolderClaudeMd` | CursorHooksInstaller.ts | 326-353 | Atomic file write |
### Integration Point
**File:** `src/services/worker/agents/ResponseProcessor.ts:274-298`
Current (problematic) code:
```typescript
const registry = readCursorRegistry();
const registryEntry = registry[session.project];
if (registryEntry && (filesModified.length > 0 || filesRead.length > 0)) {
updateFolderClaudeMd(
registryEntry.workspacePath, // <-- PROBLEM: Needs Cursor registry
filesModified,
filesRead,
session.project,
getWorkerPort()
).catch(error => { ... });
}
```
### The Problem
1. `filesModified` and `filesRead` already contain **absolute paths**
2. We don't need `workspacePath` - just extract folder from file path directly
3. Cursor registry is only populated when Cursor hooks are installed
4. This makes folder CLAUDE.md a Cursor-only feature (unintended)
### Project Utils Pattern
**From `src/utils/cursor-utils.ts:97-122`:**
- Pure functions with paths as parameters
- Atomic write pattern: temp file + rename
- `mkdirSync(dir, { recursive: true })` for directory creation
### Related Utils
**`src/utils/tag-stripping.ts`** - Handles *stripping* tags (input filtering)
- `stripMemoryTagsFromJson()` - removes `<claude-mem-context>` content
- `stripMemoryTagsFromPrompt()` - removes `<private>` content
Our `replaceTaggedContent` handles *preserving/replacing* (output writing) - complementary, not duplicative.
---
## Phase 1: Create Shared Utils File
### What to Implement
Create `src/utils/claude-md-utils.ts` with extracted and simplified functions.
### File Structure
```typescript
/**
* CLAUDE.md File Utilities
*
* Shared utilities for writing folder-level CLAUDE.md files with
* auto-generated context sections. Preserves user content outside
* <claude-mem-context> tags.
*/
import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync } from 'fs';
import path from 'path';
import { logger } from './logger.js';
/**
* Replace tagged content in existing file, preserving content outside tags.
*
* Handles three cases:
* 1. No existing content → wraps new content in tags
* 2. Has existing tags → replaces only tagged section
* 3. No tags in existing content → appends tagged content at end
*/
export function replaceTaggedContent(existingContent: string, newContent: string): string {
// Copy from CursorHooksInstaller.ts:300-321
}
/**
* Write CLAUDE.md file to folder with atomic writes.
* Creates directory structure if needed.
*
* @param folderPath - Absolute path to the folder
* @param newContent - Content to write inside tags
*/
export function writeClaudeMdToFolder(folderPath: string, newContent: string): void {
// Simplified from writeFolderClaudeMd - no workspacePath needed
// Copy atomic write pattern from CursorHooksInstaller.ts:326-353
}
/**
* Format timeline text from API response to compact CLAUDE.md format.
*
* @param timelineText - Raw API response text
* @returns Formatted markdown with date headers and compact table
*/
export function formatTimelineForClaudeMd(timelineText: string): string {
// Copy from CursorHooksInstaller.ts:221-295
}
```
### Key Simplification
**OLD `writeFolderClaudeMd` signature:**
```typescript
async function writeFolderClaudeMd(
workspacePath: string, // <-- REMOVE
folderPath: string,
newContent: string
): Promise<void>
```
**NEW `writeClaudeMdToFolder` signature:**
```typescript
export function writeClaudeMdToFolder(
folderPath: string, // Must be absolute path
newContent: string
): void // Sync is fine, atomic anyway
```
### Verification Checklist
- [ ] File created at `src/utils/claude-md-utils.ts`
- [ ] `replaceTaggedContent` exported and handles all 3 cases
- [ ] `writeClaudeMdToFolder` exported with atomic writes
- [ ] `formatTimelineForClaudeMd` exported
- [ ] Build passes: `npm run build`
---
## Phase 2: Create Folder Index Service Function
### What to Implement
Create a new orchestrating function that replaces `updateFolderClaudeMd`. This should NOT be in CursorHooksInstaller - it's a general feature.
**Option A:** Add to `src/utils/claude-md-utils.ts` (keeps it simple)
**Option B:** Create `src/services/folder-index-service.ts` (follows service pattern)
Recommend **Option A** for simplicity - it's just one function.
### New Function
```typescript
/**
* Update CLAUDE.md files for folders containing the given files.
* Fetches timeline from worker API and writes formatted content.
*
* @param filePaths - Array of absolute file paths (modified or read)
* @param project - Project identifier for API query
* @param port - Worker API port
*/
export async function updateFolderClaudeMdFiles(
filePaths: string[],
project: string,
port: number
): Promise<void> {
// Extract unique folder paths from file paths
const folderPaths = new Set<string>();
for (const filePath of filePaths) {
if (!filePath || filePath === '') continue;
const folderPath = path.dirname(filePath);
if (folderPath && folderPath !== '.' && folderPath !== '/') {
folderPaths.add(folderPath);
}
}
if (folderPaths.size === 0) return;
logger.debug('FOLDER_INDEX', 'Updating CLAUDE.md files', {
project,
folderCount: folderPaths.size
});
// Process each folder
for (const folderPath of folderPaths) {
try {
// Fetch timeline via existing API
const response = await fetch(
`http://127.0.0.1:${port}/api/search/by-file?filePath=${encodeURIComponent(folderPath)}&limit=10&project=${encodeURIComponent(project)}`
);
if (!response.ok) {
logger.warn('FOLDER_INDEX', 'Failed to fetch timeline', { folderPath, status: response.status });
continue;
}
const result = await response.json();
if (!result.content?.[0]?.text) {
logger.debug('FOLDER_INDEX', 'No content for folder', { folderPath });
continue;
}
const formatted = formatTimelineForClaudeMd(result.content[0].text);
writeClaudeMdToFolder(folderPath, formatted);
logger.debug('FOLDER_INDEX', 'Updated CLAUDE.md', { folderPath });
} catch (error) {
logger.warn('FOLDER_INDEX', 'Failed to update CLAUDE.md', { folderPath }, error as Error);
}
}
}
```
### Verification Checklist
- [ ] `updateFolderClaudeMdFiles` function added
- [ ] Takes only `filePaths`, `project`, `port` (no workspacePath)
- [ ] Extracts folder paths from absolute file paths
- [ ] Uses `writeClaudeMdToFolder` for atomic writes
- [ ] Build passes: `npm run build`
---
## Phase 3: Update ResponseProcessor Integration
### What to Implement
Simplify the call site in `src/services/worker/agents/ResponseProcessor.ts`.
### Current Code (lines 274-298)
```typescript
// Update folder CLAUDE.md files for touched folders (fire-and-forget)
const filesModified: string[] = [];
const filesRead: string[] = [];
for (const obs of observations) {
filesModified.push(...(obs.files_modified || []));
filesRead.push(...(obs.files_read || []));
}
// Get workspace path from project registry
const registry = readCursorRegistry();
const registryEntry = registry[session.project];
if (registryEntry && (filesModified.length > 0 || filesRead.length > 0)) {
updateFolderClaudeMd(
registryEntry.workspacePath,
filesModified,
filesRead,
session.project,
getWorkerPort()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
}
```
### New Code
```typescript
// Update folder CLAUDE.md files for touched folders (fire-and-forget)
const allFilePaths: string[] = [];
for (const obs of observations) {
allFilePaths.push(...(obs.files_modified || []));
allFilePaths.push(...(obs.files_read || []));
}
if (allFilePaths.length > 0) {
updateFolderClaudeMdFiles(
allFilePaths,
session.project,
getWorkerPort()
).catch(error => {
logger.warn('FOLDER_INDEX', 'CLAUDE.md update failed (non-critical)', { project: session.project }, error as Error);
});
}
```
### Import Changes
**Remove:**
```typescript
import { updateFolderClaudeMd, readCursorRegistry } from '../../integrations/CursorHooksInstaller.js';
```
**Add:**
```typescript
import { updateFolderClaudeMdFiles } from '../../../utils/claude-md-utils.js';
```
**Keep (if still needed for Cursor context):**
```typescript
import { updateCursorContextForProject } from '../../worker-service.js';
```
### Verification Checklist
- [ ] Import updated to use `claude-md-utils.ts`
- [ ] `readCursorRegistry` import removed (if no longer needed)
- [ ] Call site simplified - no registry lookup
- [ ] Fire-and-forget pattern preserved
- [ ] Build passes: `npm run build`
---
## Phase 4: Clean Up CursorHooksInstaller
### What to Implement
Remove the extracted functions from `src/services/integrations/CursorHooksInstaller.ts`.
### Functions to Remove
- `updateFolderClaudeMd` (lines 128-199)
- `formatTimelineForClaudeMd` (lines 221-295)
- `replaceTaggedContent` (lines 300-321)
- `writeFolderClaudeMd` (lines 326-353)
### Verification Checklist
- [ ] All 4 functions removed from CursorHooksInstaller.ts
- [ ] No dangling references to removed functions
- [ ] CursorHooksInstaller still exports what it needs for Cursor integration
- [ ] Build passes: `npm run build`
- [ ] Grep shows no references to old function locations
---
## Phase 5: Verification
### Build Check
```bash
npm run build
```
### Anti-Pattern Grep (should find NOTHING in CursorHooksInstaller)
```bash
grep -n "updateFolderClaudeMd\|formatTimelineForClaudeMd\|replaceTaggedContent\|writeFolderClaudeMd" src/services/integrations/CursorHooksInstaller.ts
```
### Correct Location Grep (should find in claude-md-utils)
```bash
grep -rn "updateFolderClaudeMdFiles\|writeClaudeMdToFolder\|formatTimelineForClaudeMd" src/utils/
```
### Integration Check
```bash
grep -n "updateFolderClaudeMdFiles" src/services/worker/agents/ResponseProcessor.ts
```
### No Cursor Registry Dependency
```bash
grep -n "readCursorRegistry" src/services/worker/agents/ResponseProcessor.ts
# Should return nothing (or only for Cursor context, not folder index)
```
---
## Summary
**~150 lines moved** from CursorHooksInstaller.ts to claude-md-utils.ts with simplification:
| Before | After |
|--------|-------|
| 4 functions in CursorHooksInstaller | 4 functions in claude-md-utils |
| Requires Cursor registry lookup | Works with absolute paths directly |
| `updateFolderClaudeMd(workspacePath, ...)` | `updateFolderClaudeMdFiles(filePaths, ...)` |
| Coupled to Cursor integration | Independent utility |
**Files Changed:**
1. `src/utils/claude-md-utils.ts` - NEW (create)
2. `src/services/worker/agents/ResponseProcessor.ts` - UPDATE (simplify call site)
3. `src/services/integrations/CursorHooksInstaller.ts` - UPDATE (remove extracted functions)

View File

@@ -0,0 +1,186 @@
# Plan: Change Folder CLAUDE.md to Timeline Format
## Goal
Replace the simple table format in folder-level CLAUDE.md files with the timeline format used by search results.
## Current vs Target Format
### Current Format (Simple)
```markdown
# Recent Activity
### Recent
| Time | Type | Title |
|------|------|-------|
| 6:33pm | feature | Multiple CLAUDE.md files generated |
| 6:32pm | feature | CLAUDE.md file successfully generated |
```
### Target Format (Timeline)
```markdown
# Recent Activity
### Jan 4, 2026
**src/services/worker/agents/ResponseProcessor.ts**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37110 | 6:35 PM | 🔴 | Folder CLAUDE.md updates moved from summary | ~85 |
| #37109 | " | ✅ | ResponseProcessor.ts modified | ~92 |
**General**
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #37108 | 6:33 PM | 🟣 | Multiple CLAUDE.md files generated | ~78 |
```
## Key Changes
1. **Group by date** - Use `### Jan 4, 2026` instead of `### Recent`
2. **Group by file within each date** - Add `**filename**` headers
3. **Expand columns** - Add ID and Read columns: `| ID | Time | T | Title | Read |`
4. **Use type emojis** - Use `🔴` `🟣` `✅` etc. instead of text
5. **Show ditto marks** - Use `"` for repeated times
---
## Phase 1: Refactor formatTimelineForClaudeMd
**File:** `src/utils/claude-md-utils.ts`
**Tasks:**
1. Add imports from shared utilities:
```typescript
import { formatDate, formatTime, extractFirstFile, estimateTokens, groupByDate } from '../shared/timeline-formatting.js';
import { ModeManager } from '../services/domain/ModeManager.js';
```
2. Replace `formatTimelineForClaudeMd()` (lines 78-151) with new implementation that:
- Parses API response to extract full observation data (id, time, type emoji, title, files)
- Groups observations by date using `groupByDate()`
- Within each date, groups by file using a Map
- Renders file sections with `**filename**` headers
- Uses search table format: `| ID | Time | T | Title | Read |`
- Uses ditto marks for repeated times
**Pattern to Copy From:** `src/services/worker/search/ResultFormatter.ts` lines 56-108
**Key APIs:**
- `groupByDate(items, getDate)` - from `src/shared/timeline-formatting.ts:104-127`
- `formatTime(epoch)` - from `src/shared/timeline-formatting.ts:46-53`
- `formatDate(epoch)` - from `src/shared/timeline-formatting.ts:59-66`
- `extractFirstFile(filesModified, cwd)` - from `src/shared/timeline-formatting.ts:81-84`
- `estimateTokens(text)` - from `src/shared/timeline-formatting.ts:89-92`
- `ModeManager.getInstance().getTypeIcon(type)` - from `src/services/domain/ModeManager.ts`
**Verification:**
1. Run `npm run build` - no errors
2. Restart worker: `npm run worker:restart`
3. Make a test edit to trigger observation
4. Check generated CLAUDE.md files for new format
---
## Phase 2: Parse Full Observation Data from API
**Context:** The current regex parsing extracts only time, type emoji, and title. Need to also extract:
- Observation ID (for `#123` column)
- File path (from files_modified in API response, for grouping)
- Token estimate (for `Read` column)
**Challenge:** The current API returns formatted text, not structured data. We need to:
1. Parse the existing text format more thoroughly, OR
2. Use a different API endpoint that returns JSON
**Decision Point:** Check what data the `/api/search/by-file` endpoint returns. If it returns structured JSON with observations, use that. Otherwise, enhance parsing.
**Investigation Required:**
- Read `src/services/worker/http/routes/SearchRoutes.ts` to see by-file response format
- Determine if we can access raw observation data or just formatted text
**Verification:**
- Confirm API response structure
- Update parsing to extract all needed fields
---
## Phase 3: Integrate File-Based Grouping
**File:** `src/utils/claude-md-utils.ts`
**Tasks:**
1. Create helper to group by file:
```typescript
function groupByFile(observations: ParsedObservation[]): Map<string, ParsedObservation[]> {
const byFile = new Map<string, ParsedObservation[]>();
for (const obs of observations) {
const file = obs.file || 'General';
if (!byFile.has(file)) byFile.set(file, []);
byFile.get(file)!.push(obs);
}
return byFile;
}
```
2. Render with file sections:
```typescript
for (const [file, fileObs] of resultsByFile) {
lines.push(`**${file}**`);
lines.push(`| ID | Time | T | Title | Read |`);
lines.push(`|----|------|---|-------|------|`);
// render rows with ditto marks
}
```
**Pattern to Copy From:** `ResultFormatter.formatSearchResults()` lines 60-108
**Verification:**
- Generated CLAUDE.md shows file grouping
- Files are displayed as relative paths when possible
---
## Phase 4: Final Verification
**Checklist:**
1. **Build passes:** `npm run build`
2. **Worker restarts cleanly:** `npm run worker:restart`
3. **Format matches target:**
- Date headers: `### Jan 4, 2026`
- File sections: `**filename**`
- Table columns: `| ID | Time | T | Title | Read |`
- Type emojis: `🔴` `🟣` `` not text
- Ditto marks: `"` for repeated times
4. **Anti-pattern checks:**
- No hardcoded type maps (use ModeManager)
- No invented APIs
- Reuses existing formatters from shared utils
5. **Graceful degradation:** Empty results still show `*No recent activity*`
---
## Files to Modify
| File | Change |
|------|--------|
| `src/utils/claude-md-utils.ts` | Replace `formatTimelineForClaudeMd()` with timeline format |
## Files to Read (Patterns to Copy)
| File | Pattern |
|------|---------|
| `src/services/worker/search/ResultFormatter.ts:56-108` | Date/file grouping logic |
| `src/shared/timeline-formatting.ts` | All formatting utilities |
| `src/services/domain/ModeManager.ts` | Type icon lookup |
## Anti-Patterns to Avoid
- ❌ Creating new hardcoded type→emoji maps (use ModeManager)
- ❌ Parsing dates manually (use shared formatters)
- ❌ Skipping the existing groupByDate utility
- ❌ Not handling ditto marks for repeated times

View File

@@ -0,0 +1,196 @@
# Plan: Integrate Workflow Agents and Commands into Claude-Mem
## Executive Summary
This plan integrates the `/make-plan` and `/do` orchestration workflow from `~/.claude/commands/` into the claude-mem plugin as project-level development tools.
## Dependency Analysis
### Commands to Copy (from `~/.claude/commands/`)
| File | Purpose | Dependencies |
|------|---------|--------------|
| `make-plan.md` | Orchestrator for LLM-friendly phased planning | Uses Task tool with subagents |
| `do.md` | Orchestrator for executing plans via subagents | Uses Task tool with subagents |
| `anti-pattern-czar.md` | Error handling anti-pattern detection/fixing | Uses Read, Edit, Bash tools |
### Specialized Agents Referenced
The `/make-plan` and `/do` commands reference these **conceptual agent roles** (not actual agent files):
| Agent Role | Referenced In | Description |
|------------|---------------|-------------|
| "Documentation Discovery" | make-plan.md | Fact-gathering from docs/examples |
| "Verification" | make-plan.md, do.md | Verify implementation matches plan |
| "Implementation" | do.md | Execute implementation tasks |
| "Anti-pattern" | do.md | Grep for known bad patterns |
| "Code Quality" | do.md | Review code changes |
| "Commit" | do.md | Commit after verification passes |
| "Branch/Sync" | do.md | Push and prepare phase handoffs |
**Key Finding**: These are **role descriptions**, not separate agent files. The Task tool's `general-purpose` subagent_type executes all roles. The commands define *what* each role should do, not separate agent implementations.
### Existing Project Assets
Located in `.claude/`:
- `agents/github-morning-reporter.md` - Already in project
- `skills/version-bump/SKILL.md` - Already in project
- No existing commands directory
---
## Phase 0: Documentation Discovery (Complete)
### Sources Consulted
1. `/Users/alexnewman/.claude/commands/make-plan.md` (62 lines)
2. `/Users/alexnewman/.claude/commands/do.md` (39 lines)
3. `/Users/alexnewman/.claude/commands/anti-pattern-czar.md` (122 lines)
4. `/Users/alexnewman/.claude/settings.json` (36 lines)
5. `.claude/skills/CLAUDE.md` (30 lines)
6. `.claude/agents/github-morning-reporter.md` (102 lines)
### Allowed APIs/Patterns
- **Commands**: `.claude/commands/*.md` files with `#$ARGUMENTS` placeholder for user input
- **Skills**: `.claude/skills/<name>/SKILL.md` with YAML frontmatter (name, description)
- **Agents**: `.claude/agents/*.md` with YAML frontmatter (name, description, model)
### Anti-Patterns to Avoid
- Skills require YAML frontmatter; commands do not
- Commands use `#$ARGUMENTS` for input; skills/agents receive prompts differently
- Don't create separate agent files for role descriptions - the Task tool handles routing
---
## Phase 1: Create Commands Directory
### What to Implement
1. Create `.claude/commands/` directory
2. Copy `make-plan.md` from `~/.claude/commands/make-plan.md`
3. Copy `do.md` from `~/.claude/commands/do.md`
4. Copy `anti-pattern-czar.md` from `~/.claude/commands/anti-pattern-czar.md`
### Documentation References
- Pattern: `~/.claude/commands/*.md` (source files)
- Existing example: `.claude/skills/version-bump/SKILL.md` for claude-mem project tools
### Verification Checklist
```bash
# Verify files exist
ls -la .claude/commands/
# Verify content matches source
diff ~/.claude/commands/make-plan.md .claude/commands/make-plan.md
diff ~/.claude/commands/do.md .claude/commands/do.md
diff ~/.claude/commands/anti-pattern-czar.md .claude/commands/anti-pattern-czar.md
# Verify #$ARGUMENTS placeholder exists
grep '\$ARGUMENTS' .claude/commands/*.md
```
### Anti-Pattern Guards
- Do NOT add YAML frontmatter to commands (they don't need it)
- Do NOT modify the source content (copy verbatim)
---
## Phase 2: Create CLAUDE.md Documentation
### What to Implement
Create `.claude/commands/CLAUDE.md` documenting the commands directory (following pattern from `.claude/skills/CLAUDE.md`)
### Content Template
```markdown
# Project-Level Commands
This directory contains slash commands **for developing and maintaining the claude-mem project itself**.
## Commands in This Directory
### /make-plan
Orchestrator for creating LLM-friendly implementation plans in phases. Deploys subagents for documentation discovery and fact gathering.
**Usage**: `/make-plan <task description>`
### /do
Orchestrator for executing plans via subagents. Deploys specialized subagents for implementation, verification, and code quality review.
**Usage**: `/do <plan-file-path or inline plan>`
### /anti-pattern-czar
Interactive workflow for detecting and fixing error handling anti-patterns using the automated scanner.
**Usage**: `/anti-pattern-czar`
## Adding New Commands
Commands are markdown files with `#$ARGUMENTS` placeholder for user input.
```
### Verification Checklist
```bash
# Verify file exists
cat .claude/commands/CLAUDE.md
```
---
## Phase 3: Update Settings (if needed)
### What to Implement
Check if `.claude/settings.json` needs any permission updates for the new commands.
### Verification Checklist
```bash
# Check current settings
cat .claude/settings.json
# Verify commands work by listing them
# (After Claude Code restart, commands should appear in slash-command list)
```
### Anti-Pattern Guards
- Do NOT add skill permissions for commands (they're different)
- Commands don't require explicit permissions
---
## Phase 4: Final Verification
### Verification Checklist
1. All three command files exist in `.claude/commands/`
2. Content matches source files exactly (byte-for-byte if possible)
3. CLAUDE.md documentation exists
4. Git status shows new files ready for commit
```bash
# Full verification
ls -la .claude/commands/
wc -l .claude/commands/*.md
git status
```
### Commit Message Template
```
feat: add /make-plan, /do, and /anti-pattern-czar workflow commands
Add project-level orchestration commands for claude-mem development:
- /make-plan: Create LLM-friendly implementation plans in phases
- /do: Execute plans via coordinated subagents
- /anti-pattern-czar: Detect and fix error handling anti-patterns
These commands enable structured, agent-driven development workflows.
```
---
## Summary
**Files to Create**:
1. `.claude/commands/make-plan.md` (copy from ~/.claude/commands/)
2. `.claude/commands/do.md` (copy from ~/.claude/commands/)
3. `.claude/commands/anti-pattern-czar.md` (copy from ~/.claude/commands/)
4. `.claude/commands/CLAUDE.md` (new documentation)
**No Agent Files Needed**: The "agents" referenced in make-plan.md and do.md are role descriptions, not separate files. The Task tool's built-in subagent types handle execution.
**Confidence**: High - analysis complete with full source file reads.

View File

@@ -26,4 +26,17 @@ Manages semantic versioning for the claude-mem project itself. Handles updating
## Adding New Skills
**For claude-mem development** → Add to `.claude/skills/`
**For end users** → Add to `plugin/skills/` (gets distributed with plugin)
**For end users** → Add to `plugin/skills/` (gets distributed with plugin)
<claude-mem-context>
# Recent Activity
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
### Dec 29, 2025
| ID | Time | T | Title | Read |
|----|------|---|-------|------|
| #33938 | 6:27 PM | 🔵 | Relevant CLAUDE.md Context Identified for PR #492 | ~435 |
</claude-mem-context>

View File

@@ -1,80 +0,0 @@
---
name: version-bump
description: Manage semantic version updates for claude-mem project. Handles patch, minor, and major version increments following semantic versioning. Updates package.json, marketplace.json, and plugin.json. Creates git tags and GitHub releases. Auto-generates CHANGELOG.md from releases.
---
# Version Bump Skill
**IMPORTANT:** You must first ultrathink and write detailed release notes before starting the version bump workflow.
## Version Types
- **PATCH** (x.y.Z): Bug fixes only
- **MINOR** (x.Y.0): New features, backward compatible
- **MAJOR** (X.0.0): Breaking changes
## Files to Update (ALL THREE)
1. `package.json` (line 3)
2. `.claude-plugin/marketplace.json` (line 13)
3. `plugin/.claude-plugin/plugin.json` (line 3)
## Workflow
```bash
# 1. Check current version
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
# 2. Update all 3 files to new version (use Edit tool)
# 3. Verify consistency
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
# 4. Build
npm run build
# 5. Commit version files
git add package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
git commit -m "chore: bump version to X.Y.Z"
# 6. Create tag
git tag -a vX.Y.Z -m "Version X.Y.Z"
# 7. Push
git push origin main && git push origin vX.Y.Z
# 8. Create GitHub release (use your detailed release notes here)
gh release create vX.Y.Z --title "vX.Y.Z" --notes "RELEASE_NOTES_HERE"
# 9. Generate CHANGELOG.md from releases
gh api repos/thedotmack/claude-mem/releases --paginate | node -e "
const releases = JSON.parse(require('fs').readFileSync(0, 'utf8'));
const lines = ['# Changelog', '', 'All notable changes to claude-mem.', ''];
releases.slice(0, 50).forEach(r => {
const date = r.published_at.split('T')[0];
lines.push('## [' + r.tag_name + '] - ' + date);
lines.push('');
if (r.body) lines.push(r.body.trim());
lines.push('');
});
console.log(lines.join('\n'));
" > CHANGELOG.md
# 10. Commit CHANGELOG
git add CHANGELOG.md
git commit -m "docs: update CHANGELOG.md for vX.Y.Z"
git push origin main
# 11. Discord notification
npm run discord:notify vX.Y.Z
```
## Checklist
- [ ] Ultrathink + write detailed release notes
- [ ] All 3 files have matching version
- [ ] `npm run build` succeeds
- [ ] Git tag created (vX.Y.Z format)
- [ ] GitHub release created with detailed notes
- [ ] CHANGELOG.md updated
- [ ] Discord notification sent (if webhook configured)