* fix: stop generating empty CLAUDE.md files - Return empty string instead of "No recent activity" when no observations exist - Skip writing CLAUDE.md files when formatted content is empty - Remove redundant "auto-generated by claude-mem" HTML comment - Clean up 98 existing empty CLAUDE.md files across the codebase - Update tests to expect empty string for empty input Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * build assets * refactor: implement in-process worker architecture for hooks Replaces spawn-based worker startup with in-process architecture: - Hook processes now become the worker when port 37777 is free - Eliminates Windows spawn issues (NO SPAWN rule) - SessionStart chains: smart-install && stop && context Key changes: - worker-service.ts: hook case starts WorkerService in-process - hook-command.ts: skipExit option prevents process.exit() when hosting worker - hooks.json: single chained command replaces separate start/hook commands - worker-utils.ts: ensureWorkerRunning() returns boolean, doesn't block - handlers: graceful fallback when worker unavailable All 761 tests pass. Manual verification confirms hook stays alive as worker. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * context * a * MAESTRO: Mark PR #722 test verification task complete All 797 tests passed (3 skipped, 0 failed) after merge conflict resolution. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * MAESTRO: Mark PR #722 build verification task complete * MAESTRO: Mark PR #722 code review task complete Code review verified: - worker-service.ts hook case starts WorkerService in-process - hook-command.ts has skipExit option - hooks.json uses single chained command - worker-utils.ts ensureWorkerRunning() returns boolean Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * MAESTRO: Mark PR #722 conflict resolution push task complete Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
8.2 KiB
Plan: Fix Empty CLAUDE.md File Generation
Problem Statement
Currently the CLAUDE.md generator creates files with wasteful content:
- Empty files with "No recent activity" - Files are created even when there are zero observations for a folder
- Redundant HTML comment - "" is unnecessary since the
<claude-mem-context>tag already conveys this information
These issues create noisy, wasteful context that loads automatically and provides no value.
Phase 0: Documentation Discovery
Allowed APIs (from code analysis)
formatTimelineForClaudeMd(timelineText: string): string- src/utils/claude-md-utils.ts:139formatObservationsForClaudeMd(observations, folderPath): string- scripts/regenerate-claude-md.ts:238writeClaudeMdToFolder(folderPath, newContent): void- src/utils/claude-md-utils.ts:94updateFolderClaudeMdFiles(filePaths, project, port, projectRoot): Promise<void>- src/utils/claude-md-utils.ts:257replaceTaggedContent(existingContent, newContent): string- src/utils/claude-md-utils.ts:64
Key Locations
| File | Lines | Purpose |
|---|---|---|
src/utils/claude-md-utils.ts |
139-235 | Main formatting function |
src/utils/claude-md-utils.ts |
143 | HTML comment generation |
src/utils/claude-md-utils.ts |
209-211 | "No recent activity" handling |
src/utils/claude-md-utils.ts |
322-323 | Write decision point |
scripts/regenerate-claude-md.ts |
238-286 | Regeneration script formatting |
scripts/regenerate-claude-md.ts |
242 | HTML comment generation (duplicate) |
scripts/regenerate-claude-md.ts |
245-247 | "No recent activity" handling |
scripts/regenerate-claude-md.ts |
452-453 | Write decision point |
tests/utils/claude-md-utils.test.ts |
96-109 | Tests for "No recent activity" behavior |
Anti-patterns to avoid
- Do NOT add new configuration options for this behavior - just fix it
- Do NOT add logging for skipped files (unnecessary noise)
Phase 1: Modify formatTimelineForClaudeMd to Return Empty on No Observations
Task 1.1: Update formatTimelineForClaudeMd return behavior
File: src/utils/claude-md-utils.ts
Lines: 139-235
Changes:
- Remove HTML comment line at line 143
- Change the empty observations case (lines 209-211) to return an empty string instead of "No recent activity"
Before (lines 141-144):
lines.push('# Recent Activity');
lines.push('');
lines.push('<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->');
lines.push('');
After:
lines.push('# Recent Activity');
lines.push('');
Before (lines 209-212):
if (observations.length === 0) {
lines.push('*No recent activity*');
return lines.join('\n');
}
After:
if (observations.length === 0) {
return '';
}
Verification
- Run
bun test tests/utils/claude-md-utils.test.ts - Tests at lines 96-109 will FAIL (expected - they test for "No recent activity")
- Update tests to expect empty string for empty input
Phase 2: Update updateFolderClaudeMdFiles to Skip Empty Content
Task 2.1: Add empty content check before writing
File: src/utils/claude-md-utils.ts
Lines: 322-323
Changes: After formatting, check if result is empty and skip writing if so.
Before (lines 321-325):
const formatted = formatTimelineForClaudeMd(result.content[0].text);
writeClaudeMdToFolder(folderPath, formatted);
logger.debug('FOLDER_INDEX', 'Updated CLAUDE.md', { folderPath });
After:
const formatted = formatTimelineForClaudeMd(result.content[0].text);
if (!formatted) {
logger.debug('FOLDER_INDEX', 'No observations for folder, skipping', { folderPath });
continue;
}
writeClaudeMdToFolder(folderPath, formatted);
logger.debug('FOLDER_INDEX', 'Updated CLAUDE.md', { folderPath });
Verification
- Grep for files containing "No recent activity": should find none after running
Phase 3: Update Regeneration Script
Task 3.1: Remove HTML comment from formatObservationsForClaudeMd
File: scripts/regenerate-claude-md.ts
Lines: 238-286
Changes:
- Remove HTML comment line at line 242
- Change empty observations case (lines 245-247) to return empty string
Before (lines 240-244):
lines.push('# Recent Activity');
lines.push('');
lines.push('<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->');
lines.push('');
After:
lines.push('# Recent Activity');
lines.push('');
Before (lines 245-248):
if (observations.length === 0) {
lines.push('*No recent activity*');
return lines.join('\n');
}
After:
if (observations.length === 0) {
return '';
}
Task 3.2: Update regenerateFolder to handle empty formatted content
File: scripts/regenerate-claude-md.ts
Lines: 432-459
The script already skips folders with no observations (lines 443-444), so this change is already compatible. The formatObservationsForClaudeMd returning empty string doesn't change behavior since observations are checked before calling it.
Verification
- Run
bun scripts/regenerate-claude-md.ts --dry-runin the project - Should NOT show any folders with 0 observations
Phase 4: Update Tests
Task 4.1: Update tests for new empty behavior
File: tests/utils/claude-md-utils.test.ts
Lines: 96-109
Changes: Update the two tests that expect "No recent activity" to expect empty string instead.
Before (lines 96-101):
it('should return "No recent activity" for empty input', () => {
const result = formatTimelineForClaudeMd('');
expect(result).toContain('# Recent Activity');
expect(result).toContain('*No recent activity*');
});
After:
it('should return empty string for empty input', () => {
const result = formatTimelineForClaudeMd('');
expect(result).toBe('');
});
Before (lines 103-109):
it('should return "No recent activity" when no table rows exist', () => {
const input = 'Just some plain text without table rows';
const result = formatTimelineForClaudeMd(input);
expect(result).toContain('*No recent activity*');
});
After:
it('should return empty string when no table rows exist', () => {
const input = 'Just some plain text without table rows';
const result = formatTimelineForClaudeMd(input);
expect(result).toBe('');
});
Task 4.2: Remove HTML comment assertions from any other tests
Search for tests that assert on "auto-generated" comment and update accordingly.
Verification
- Run full test suite:
bun test - All tests should pass
Phase 5: Cleanup Existing Empty Files
Task 5.1: Run cleanup to remove existing empty CLAUDE.md files
Command:
bun scripts/regenerate-claude-md.ts --clean
This will:
- Find all CLAUDE.md files with
<claude-mem-context>tags - Strip the tagged section
- Delete files that become empty after stripping
- Preserve files that have user content outside the tags
Verification
grep -r "No recent activity" . --include="CLAUDE.md"should return no resultsgrep -r "auto-generated by claude-mem" . --include="CLAUDE.md"should return no results
Summary of Changes
| File | Change |
|---|---|
src/utils/claude-md-utils.ts:143 |
Remove HTML comment line |
src/utils/claude-md-utils.ts:209-211 |
Return empty string instead of "No recent activity" |
src/utils/claude-md-utils.ts:322 |
Skip writing if formatted content is empty |
scripts/regenerate-claude-md.ts:242 |
Remove HTML comment line |
scripts/regenerate-claude-md.ts:245-247 |
Return empty string instead of "No recent activity" |
tests/utils/claude-md-utils.test.ts:96-109 |
Update tests to expect empty string |
Final Verification Checklist
bun testpasses- No "No recent activity" CLAUDE.md files exist
- No "auto-generated" comments in CLAUDE.md files
- Build succeeds:
npm run build-and-sync - New observations correctly generate CLAUDE.md files with content
- Folders without observations get no CLAUDE.md file created