Files
claude-mem/docs/reports/2026-01-05--issue-544-mem-search-hint-claude-code.md
T
Alex Newman f38b5b85bc fix: resolve issues #543, #544, #545, #557 (#558)
* docs: add investigation reports for 5 open GitHub issues

Comprehensive analysis of issues #543, #544, #545, #555, and #557:

- #557: settings.json not generated, module loader error (node/bun mismatch)
- #555: Windows hooks not executing, hasIpc always false
- #545: formatTool crashes on non-JSON tool_input strings
- #544: mem-search skill hint shown incorrectly to Claude Code users
- #543: /claude-mem slash command unavailable despite installation

Each report includes root cause analysis, affected files, and proposed fixes.

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

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

* fix(logger): handle non-JSON tool_input in formatTool (#545)

Wrap JSON.parse in try-catch to handle raw string inputs (e.g., Bash
commands) that aren't valid JSON. Falls back to using the string as-is.

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

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

* fix(context): update mem-search hint to reference MCP tools (#544)

Update hint messages to reference MCP tools (search, get_observations)
instead of the deprecated "mem-search skill" terminology.

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

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

* fix(settings): auto-create settings.json on first load (#557, #543)

When settings.json doesn't exist, create it with defaults instead of
returning in-memory defaults. Creates parent directory if needed.

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

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

* fix(hooks): use bun runtime for hooks except smart-install (#557)

Change hook commands from node to bun since hooks use bun:sqlite.
Keep smart-install.js on node since it bootstraps bun installation.

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

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

* chore: rebuild plugin scripts

* docs: clarify that build artifacts must be committed

* fix(docs): update build artifacts directory reference in CLAUDE.md

* test: add test coverage for PR #558 fixes

- Fix 2 failing tests: update "mem-search skill" → "MCP tools" expectations
- Add 56 tests for formatTool() JSON.parse crash fix (Issue #545)
- Add 27 tests for settings.json auto-creation (Issue #543)

Test coverage includes:
- formatTool: JSON parsing, raw strings, objects, null/undefined, all tool types
- Settings: file creation, directory creation, schema migration, edge cases

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

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

* fix(tests): clean up flaky tests and fix circular dependency

Phase 1 of test quality improvements:

- Delete 6 harmful/worthless test files that used problematic mock.module()
  patterns or tested implementation details rather than behavior:
  - context-builder.test.ts (tested internal implementation)
  - export-types.test.ts (fragile mock patterns)
  - smart-install.test.ts (shell script testing antipattern)
  - session_id_refactor.test.ts (outdated, tested refactoring itself)
  - validate_sql_update.test.ts (one-time migration validation)
  - observation-broadcaster.test.ts (excessive mocking)

- Fix circular dependency between logger.ts and SettingsDefaultsManager.ts
  by using late binding pattern - logger now lazily loads settings

- Refactor mock.module() to spyOn() in several test files for more
  maintainable and less brittle tests:
  - observation-compiler.test.ts
  - gemini_agent.test.ts
  - error-handler.test.ts
  - server.test.ts
  - response-processor.test.ts

All 649 tests pass.

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

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

* refactor(tests): phase 2 - reduce mock-heavy tests and improve focus

- Remove mock-heavy query tests from observation-compiler.test.ts, keep real buildTimeline tests
- Convert session_id_usage_validation.test.ts from 477 to 178 lines of focused smoke tests
- Remove tests for language built-ins from worker-spawn.test.ts (JSON.parse, array indexing)
- Rename logger-coverage.test.ts to logger-usage-standards.test.ts for clarity

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

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

* docs(tests): phase 3 - add JSDoc mock justification to test files

Document mock usage rationale in 5 test files to improve maintainability:
- error-handler.test.ts: Express req/res mocks, logger spies (~11%)
- fallback-error-handler.test.ts: Zero mocks, pure function tests
- session-cleanup-helper.test.ts: Session fixtures, worker mocks (~19%)
- hook-constants.test.ts: process.platform mock for Windows tests (~12%)
- session_store.test.ts: Zero mocks, real SQLite :memory: database

Part of ongoing effort to document mock justifications per TESTING.md guidelines.

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

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

* test(integration): phase 5 - add 72 tests for critical coverage gaps

Add comprehensive test coverage for previously untested areas:

- tests/integration/hook-execution-e2e.test.ts (10 tests)
  Tests lifecycle hooks execution flow and context propagation

- tests/integration/worker-api-endpoints.test.ts (19 tests)
  Tests all worker service HTTP endpoints without heavy mocking

- tests/integration/chroma-vector-sync.test.ts (16 tests)
  Tests vector embedding synchronization with ChromaDB

- tests/utils/tag-stripping.test.ts (27 tests)
  Tests privacy tag stripping utilities for both <private> and
  <meta-observation> tags

All tests use real implementations where feasible, following the
project's testing philosophy of preferring integration-style tests
over unit tests with extensive mocking.

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

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

* context update

* docs: add comment linking DEFAULT_DATA_DIR locations

Added NOTE comment in logger.ts pointing to the canonical DEFAULT_DATA_DIR
in SettingsDefaultsManager.ts. This addresses PR reviewer feedback about
the fragility of having the default defined in two places to avoid
circular dependencies.

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

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 19:45:09 -05:00

14 KiB

Investigation Report: Issue #544 - mem-search Skill Hint Shown to Claude Code Users

Date: 2026-01-05 Issue: https://github.com/thedotmack/claude-mem/issues/544 Author: m.woelk (@neifgmbh) Status: Open


Issue Summary

The context footer displayed to users includes the message:

"Use the mem-search skill to access memories by ID instead of re-reading files."

This hint is misleading because:

  1. For Claude Code users: The "mem-search skill" terminology is confusing. In Claude Code, memory search is available through MCP tools (search, timeline, get_observations), not a "skill"
  2. For all users: The skill directories in plugin/skills/ are empty - no SKILL.md files exist

A second user (@niteeshm) confirmed the issue with "+1 the mem-search skill is missing."


Code Location Verification

Confirmed Locations

The message appears in two formatters and is rendered via FooterRenderer.ts:

1. MarkdownFormatter.ts (line 228-234)

File: /Users/alexnewman/Scripts/claude-mem/src/services/context/formatters/MarkdownFormatter.ts

export function renderMarkdownFooter(totalDiscoveryTokens: number, totalReadTokens: number): string[] {
  const workTokensK = Math.round(totalDiscoveryTokens / 1000);
  return [
    '',
    `Access ${workTokensK}k tokens of past research & decisions for just ${totalReadTokens.toLocaleString()}t. Use the mem-search skill to access memories by ID instead of re-reading files.`
  ];
}

2. ColorFormatter.ts (line 225-231)

File: /Users/alexnewman/Scripts/claude-mem/src/services/context/formatters/ColorFormatter.ts

export function renderColorFooter(totalDiscoveryTokens: number, totalReadTokens: number): string[] {
  const workTokensK = Math.round(totalDiscoveryTokens / 1000);
  return [
    '',
    `${colors.dim}Access ${workTokensK}k tokens of past research & decisions for just ${totalReadTokens.toLocaleString()}t. Use the mem-search skill to access memories by ID instead of re-reading files.${colors.reset}`
  ];
}

3. Additional References in Context Instructions

File: /Users/alexnewman/Scripts/claude-mem/src/services/context/formatters/MarkdownFormatter.ts (lines 70-79)

export function renderMarkdownContextIndex(): string[] {
  return [
    `**Context Index:** This semantic index (titles, types, files, tokens) is usually sufficient to understand past work.`,
    '',
    `When you need implementation details, rationale, or debugging context:`,
    `- Use the mem-search skill to fetch full observations on-demand`,
    `- Critical types ( bugfix, decision) often need detailed fetching`,
    `- Trust this index over re-reading code for past decisions and learnings`,
    ''
  ];
}

File: /Users/alexnewman/Scripts/claude-mem/src/services/context/formatters/ColorFormatter.ts (lines 72-81)

export function renderColorContextIndex(): string[] {
  return [
    `${colors.dim}Context Index: This semantic index (titles, types, files, tokens) is usually sufficient to understand past work.${colors.reset}`,
    '',
    `${colors.dim}When you need implementation details, rationale, or debugging context:${colors.reset}`,
    `${colors.dim}  - Use the mem-search skill to fetch full observations on-demand${colors.reset}`,
    ...
  ];
}

File: /Users/alexnewman/Scripts/claude-mem/src/services/context/sections/FooterRenderer.ts

export function renderFooter(
  economics: TokenEconomics,
  config: ContextConfig,
  useColors: boolean
): string[] {
  // Only show footer if we have savings to display
  if (!shouldShowContextEconomics(config) || economics.totalDiscoveryTokens <= 0 || economics.savings <= 0) {
    return [];
  }

  if (useColors) {
    return Color.renderColorFooter(economics.totalDiscoveryTokens, economics.totalReadTokens);
  }
  return Markdown.renderMarkdownFooter(economics.totalDiscoveryTokens, economics.totalReadTokens);
}

Environment Detection Analysis

Current State: No Detection Exists

Finding: Claude-mem does NOT currently differentiate between Claude Code and Claude Desktop environments.

Evidence:

  1. Searched entire src/ directory for environment detection patterns:

    • claude.?code, claude.?desktop, isClaudeCode, isClaudeDesktop, environment
    • Found 22 files, but none contain Claude Code vs Claude Desktop detection logic
  2. Hook input analysis (SessionStartInput in context-hook.ts):

    export interface SessionStartInput {
      session_id: string;
      transcript_path: string;
      cwd: string;
      hook_event_name?: string;
    }
    

    No environment identifier is passed to hooks.

  3. The ContextConfig type has no environment field:

    export interface ContextConfig {
      totalObservationCount: number;
      fullObservationCount: number;
      sessionCount: number;
      showReadTokens: boolean;
      showWorkTokens: boolean;
      // ... no environment field
    }
    

Why Detection Would Be Difficult

Claude Code and Claude Desktop both:

  • Use the same plugin system (hooks)
  • Use the same MCP server configuration
  • Receive the same hook input structure

Potential Detection Methods:

  1. Process name/parent - Check if running under "claude-code" or "Claude Desktop" process
  2. Environment variables - Claude may set different env vars (needs research)
  3. MCP config location - Different config paths for each client
  4. User agent/client header - If available in MCP protocol

Skill Availability Analysis

What Actually Exists

Claude Code MCP Tools (via .mcp.json)

File: /Users/alexnewman/Scripts/claude-mem/plugin/.mcp.json

{
  "mcpServers": {
    "mcp-search": {
      "type": "stdio",
      "command": "${CLAUDE_PLUGIN_ROOT}/scripts/mcp-server.cjs"
    }
  }
}

Available MCP Tools (from mcp-server.ts):

  1. search - Step 1: Search memory index
  2. timeline - Step 2: Get context around results
  3. get_observations - Step 3: Fetch full details by IDs
  4. __IMPORTANT - Workflow documentation

These tools ARE available in Claude Code via MCP protocol.

Claude Desktop Setup (Manual)

From documentation (docs/public/usage/claude-desktop.mdx):

  • Requires manual MCP server configuration in claude_desktop_config.json
  • Uses the same MCP server and tools as Claude Code
  • Documentation refers to this as the "mem-search skill"

Plugin Skills Directory (Empty)

Path: /Users/alexnewman/Scripts/claude-mem/plugin/skills/

skills/
  claude-mem-settings/  (empty)
  mem-search/
    operations/  (empty)
    principles/  (empty)
  search/
    operations/  (empty)
  troubleshoot/
    operations/  (empty)

Finding: All skill directories are empty - no SKILL.md files exist.

Terminology Confusion

What Users See What Actually Exists
"mem-search skill" MCP tools (search, timeline, get_observations)
"skill" Empty directory structures in plugin/skills/
"skill to fetch observations" get_observations MCP tool

The "skill" terminology is a legacy artifact from an earlier architecture. The current system uses MCP tools, not skills.


Root Cause

  1. Legacy Terminology: The footer message uses "skill" language from a previous architecture
  2. Architecture Evolution: The search system migrated from skill-based to MCP-based (documented in search-architecture.mdx):

    "Skill approach... was removed in favor of streamlined MCP architecture"

  3. Incomplete Migration: The message text was not updated when the architecture changed
  4. No Skill Files: The skill directories exist but contain no SKILL.md files

Proposed Fix Options

Change the message to accurately describe the MCP tools:

Before:

"Use the mem-search skill to access memories by ID instead of re-reading files."

After:

"Use MCP search tools (search, timeline, get_observations) to access memories by ID."

Files to modify:

  • src/services/context/formatters/MarkdownFormatter.ts (lines 75, 232)
  • src/services/context/formatters/ColorFormatter.ts (lines 77, 229)

Pros:

  • Accurate for both Claude Code and Claude Desktop
  • No environment detection needed
  • Simple change

Cons:

  • Longer message
  • Users need to know about MCP tools

Option 2: Remove the Hint Entirely

Simply remove the "Use the mem-search skill..." portion of the message.

Before:

"Access 5k tokens of past research & decisions for just 1,234t. Use the mem-search skill to access memories by ID instead of re-reading files."

After:

"Access 5k tokens of past research & decisions for just 1,234t."

Files to modify:

  • src/services/context/formatters/MarkdownFormatter.ts (lines 75, 232)
  • src/services/context/formatters/ColorFormatter.ts (lines 77, 229)

Pros:

  • Simplest fix
  • No confusion about terminology
  • Cleaner footer

Cons:

  • Loses the helpful hint about memory search
  • Users may not know about MCP tools

Option 3: Conditional Message Based on Environment Detection

Implement environment detection and show different messages:

export function renderFooter(economics: TokenEconomics, config: ContextConfig, useColors: boolean): string[] {
  const isClaudeCode = detectClaudeCodeEnvironment();
  const searchHint = isClaudeCode
    ? "Use MCP search tools to access memories by ID."
    : "Use the mem-search skill to access memories by ID.";
  // ...
}

Files to modify:

  • Create new utility: src/utils/environment-detection.ts
  • src/services/context/sections/FooterRenderer.ts
  • src/services/context/formatters/MarkdownFormatter.ts
  • src/services/context/formatters/ColorFormatter.ts

Pros:

  • Context-appropriate messaging
  • Maintains helpful hint

Cons:

  • Complex to implement
  • May be fragile (environment detection methods could break)
  • More maintenance burden
  • Unclear how to reliably detect environment

Option 4: Implement Actual Skills for Claude Code

Create SKILL.md files in plugin/skills/mem-search/:

Path: plugin/skills/mem-search/SKILL.md

---
name: mem-search
description: Search claude-mem memory database using MCP tools
---

# Memory Search

Use MCP tools to search your project memory...

Pros:

  • Makes the message accurate
  • Provides better user guidance
  • Consistent with skill-based architecture

Cons:

  • Skills may be deprecated in favor of MCP
  • More files to maintain
  • May confuse the architecture (skills wrapping MCP tools)

Implementation Recommendation

Recommended: Option 1 (Update Message to Reference MCP Tools)

Rationale

  1. Accuracy: MCP tools are the actual mechanism, not skills
  2. Simplicity: Single source of truth, no environment detection needed
  3. Documentation Alignment: Matches the architecture documentation
  4. Low Risk: Minimal code changes, no new systems

Specific Changes

MarkdownFormatter.ts

Line 75 (Context Index section):

// Before:
`- Use the mem-search skill to fetch full observations on-demand`,

// After:
`- Use MCP tools (search, get_observations) to fetch full observations on-demand`,

Lines 228-234 (Footer):

export function renderMarkdownFooter(totalDiscoveryTokens: number, totalReadTokens: number): string[] {
  const workTokensK = Math.round(totalDiscoveryTokens / 1000);
  return [
    '',
    `Access ${workTokensK}k tokens of past research & decisions for just ${totalReadTokens.toLocaleString()}t. Use MCP search tools to access memories by ID.`
  ];
}

ColorFormatter.ts

Line 77 (Context Index section):

// Before:
`${colors.dim}  - Use the mem-search skill to fetch full observations on-demand${colors.reset}`,

// After:
`${colors.dim}  - Use MCP tools (search, get_observations) to fetch full observations on-demand${colors.reset}`,

Lines 225-231 (Footer):

export function renderColorFooter(totalDiscoveryTokens: number, totalReadTokens: number): string[] {
  const workTokensK = Math.round(totalDiscoveryTokens / 1000);
  return [
    '',
    `${colors.dim}Access ${workTokensK}k tokens of past research & decisions for just ${totalReadTokens.toLocaleString()}t. Use MCP search tools to access memories by ID.${colors.reset}`
  ];
}

Testing

  1. Rebuild plugin: npm run build-and-sync
  2. Restart Claude Code
  3. Verify footer message appears correctly
  4. Verify context index instructions appear correctly

Additional Considerations

Empty Skill Directories

The empty plugin/skills/ directories should be addressed separately:

  • Either remove them (if skills are deprecated)
  • Or populate them with SKILL.md files (if skills are still supported)

This is a separate issue from the message text.

Documentation Updates

If Option 1 is implemented, documentation should also be reviewed:

  • docs/public/usage/claude-desktop.mdx references "mem-search skill"
  • README.md mentions "Skill-Based Search"
  • Various i18n README files

Consider creating a follow-up issue for documentation consistency.


Summary

Aspect Finding
Issue Valid? Yes - message is misleading
Location Verified? Yes - 4 locations in 2 formatters
Environment Detection? Does not exist
Skill Files? Empty directories, no SKILL.md
MCP Tools Available? Yes - in both Claude Code and Desktop
Recommended Fix Option 1: Update message to reference MCP tools
Complexity Low - 4 string changes
Risk Low - cosmetic text change

Report prepared for GitHub Issue #544