Skip to main content
ClaudeWave
Slash Command3.6k repo starsupdated 1mo ago

claude-devtools:markdown-search

The markdown-search Claude Code item documents how the SearchBar and related components implement in-session and cross-session search across markdown text in user messages and AI outputs. Use this when modifying search functionality, highlighting logic, or the SearchBar component itself, particularly when working with the conversation slice, search utilities, or session searcher service that handles finding and navigating between matches.

Install in Claude Code
Copy
mkdir -p ~/.claude/commands && curl -fsSL https://raw.githubusercontent.com/matt1398/claude-devtools/HEAD/.claude/commands/devtools/markdown-search-logic.md -o ~/.claude/commands/claude-devtools-markdown-search.md
Then start a new Claude Code session; the slash command loads automatically.

markdown-search-logic.md

# Markdown Search Logic

How in-session and cross-session markdown search works end-to-end.

## Scope

Current in-session search intentionally covers:

- User message markdown text
- AI `lastOutput` text markdown

Current in-session search intentionally excludes:

- System items
- Tool result text blocks
- Thinking/subagent/internal display items

Primary source files:

- `src/renderer/components/search/SearchBar.tsx`
- `src/renderer/store/slices/conversationSlice.ts`
- `src/renderer/components/chat/ChatHistory.tsx`
- `src/renderer/components/chat/searchHighlightUtils.ts`
- `src/shared/utils/markdownTextSearch.ts`
- `src/main/services/discovery/SessionSearcher.ts`

## Core Data Model

`SearchMatch` (renderer store) in `src/renderer/store/types.ts`:

- `itemId`: chat group id (`user-*`, `ai-*`)
- `itemType`: `user | ai`
- `matchIndexInItem`: 0-based index inside one searchable item
- `globalIndex`: 0-based index across all matches
- `displayItemId`: optional (`lastOutput` for AI output)

Important distinction:

- `matchIndexInItem` is local to one item.
- `currentSearchIndex` is global position in the search result list.

## Pipeline Overview

### 1) Query input and initial match generation

`SearchBar` updates the query with tab-scoped conversation data:

- `setSearchQuery(query, conversation)` in `src/renderer/components/search/SearchBar.tsx`

`setSearchQuery` in `src/renderer/store/slices/conversationSlice.ts`:

- Scans conversation items
- Uses `findMarkdownSearchMatches` (shared parser logic) per searchable item
- Builds initial `searchMatches`, `searchResultCount`, `currentSearchIndex`

### 2) Rendering highlights

Search highlighting is rendered in markdown component trees through:

- `createSearchContext(...)` in `src/renderer/components/chat/searchHighlightUtils.ts`
- `highlightSearchInChildren(...)` in `src/renderer/components/chat/searchHighlightUtils.ts`

Each rendered highlight mark includes:

- `data-search-item-id`
- `data-search-match-index`
- `data-search-result` (`current` or `match`)

### 3) Canonicalization to rendered DOM (critical)

`ChatHistory` collects rendered `<mark>` elements in DOM order and calls:

- `syncSearchMatchesWithRendered(renderedMatches)` in `src/renderer/store/slices/conversationSlice.ts`

Why this exists:

- Real UI navigation must match visible marks exactly.
- Parser results can temporarily differ during render timing.
- DOM order is the final source of truth for nth navigation.

Safety guard:

- `ChatHistory` delays syncing when a transient empty mark snapshot appears, to avoid wiping results mid-render.

### 4) Next/prev navigation and scrolling

`nextSearchResult` / `previousSearchResult` in `src/renderer/store/slices/conversationSlice.ts`:

- Move `currentSearchIndex` with wrap-around

`ChatHistory` scroll effect:

- First tries exact selector:
  - `mark[data-search-item-id="..."][data-search-match-index="..."]`
- If missing, falls back to the global nth rendered mark (same `currentSearchIndex`)
- Final fallback walks text nodes under `[data-search-content]` roots

## Shared Markdown Search Engine

`src/shared/utils/markdownTextSearch.ts` is used by both renderer and main process:

- `findMarkdownSearchMatches`
- `countMarkdownSearchMatches`
- `extractMarkdownPlainText`

Design principle:

- Search parser mirrors markdown render behavior (remark + gfm + HAST traversal)
- Matching is segment-based (no cross-node match)

## Cross-Session Search (Command Palette / IPC)

Main process search path:

- IPC handler: `src/main/ipc/search.ts`
- Engine: `src/main/services/discovery/SessionSearcher.ts`

`SessionSearcher` also uses shared markdown search utils, and returns:

- `groupId`
- `itemType`
- `matchIndexInItem`
- `matchStartOffset`

These are passed into tab navigation context so opening a search result can jump to the exact in-session match.

## Invariants to Keep

When changing markdown/search code, keep these invariants:

1. Parser and renderer must agree on searchable text boundaries.
2. `matchIndexInItem` semantics must stay stable per item.
3. `currentSearchIndex` must represent the global nth visible match.
4. `searchResultCount` must reflect actual rendered match count after canonicalization.
5. Search source scope must be explicit (no accidental inclusion of hidden/internal text).

## If You Add New Searchable Markdown Surfaces

If you make a new markdown surface searchable:

1. Ensure it uses search context + `highlightSearchInChildren`.
2. Ensure emitted marks include `data-search-item-id` and `data-search-match-index`.
3. Ensure the content is included in `setSearchQuery` source scanning.
4. Ensure parser collection logic in `src/shared/utils/markdownTextSearch.ts` still mirrors render behavior.
5. Add/adjust alignment tests.

## Debug Playbook

Enable debug logs:

- `localStorage.setItem('search-debug', '1')`

Useful logs:

- `[search] query` / `[search] sample` from `setSearchQuery`
- `[search] sync-rendered` from DOM canonicalization
- `[search] next` / `[search] prev` navigation logs

Quick checks when behavior is off:

1. Compare `searchResultCount` vs number of rendered marks.
2. Verify `currentSearchIndex` increments exactly once per click.
3. Check whether exact mark selector exists for current match.
4. Confirm the active tab conversation is the same one used for `setSearchQuery`.
5. Confirm virtualization is disabled during active search.

## Tests

Main tests relevant to this logic:

- `test/shared/utils/markdownTextSearch.test.ts`
- `test/shared/utils/markdownSearchRendererAlignment.test.ts`

The alignment test ensures parser match indexes and rendered mark indexes stay identical across representative markdown cases.
claude-md-auditorSubagent

Use this agent when CLAUDE.md files or .claude/rules/ files may have drifted from the actual codebase state. This includes after significant refactors, feature additions, file renames, directory restructuring, or when you suspect documentation no longer matches reality. Use proactively after any large code change.\\n\\nExamples:\\n\\n- Example 1:\\n user: \"Refactor the services directory to split analysis into separate modules\"\\n assistant: \"I've completed the refactoring of the services directory. Let me now launch the claude-md-auditor agent to ensure all CLAUDE.md files reflect these structural changes.\"\\n <commentary>\\n Since a significant refactor was performed that likely changed file paths, exports, and directory structure documented in CLAUDE.md files, use the Task tool to launch the claude-md-auditor agent.\\n </commentary>\\n\\n- Example 2:\\n user: \"Add a new notifications feature with hooks, components, and a store slice\"\\n assistant: \"The notifications feature is now implemented. I'll use the claude-md-auditor agent to update the documentation to include the new files and patterns.\"\\n <commentary>\\n A new feature was added with multiple new files across components, hooks, and store slices. The CLAUDE.md files likely need updating to document these additions. Use the Task tool to launch the claude-md-auditor agent.\\n </commentary>\\n\\n- Example 3:\\n user: \"Rename isRealUserMessage to isParsedRealUserMessage across the codebase\"\\n assistant: \"The rename is complete across all source and test files. Now I'll launch the claude-md-auditor agent to update any documentation references to the old function name.\"\\n <commentary>\\n A function was renamed which is likely documented in CLAUDE.md type guard tables and conventions sections. Use the Task tool to launch the claude-md-auditor agent to fix stale references.\\n </commentary>\\n\\n- Example 4:\\n user: \"Can you audit the CLAUDE.md files to make sure they're up to date?\"\\n assistant: \"I'll launch the claude-md-auditor agent to systematically verify all documentation against the actual codebase.\"\\n <commentary>\\n The user explicitly requested a documentation audit. Use the Task tool to launch the claude-md-auditor agent.\\n </commentary>

quality-fixerSubagent

Use this agent when the user wants to fix all code quality issues in the project, including linting, formatting, and unused code detection. This agent runs `pnpm fix` followed by `pnpm quality` in a loop, delegating each iteration to a subagent, until all issues are resolved.\\n\\nExamples:\\n\\n- User: \"Fix all the quality issues\"\\n Assistant: \"I'll launch the quality-fixer agent to iteratively fix all linting, formatting, and quality issues.\"\\n (Uses Task tool to launch quality-fixer agent)\\n\\n- User: \"Run quality checks and fix everything\"\\n Assistant: \"Let me use the quality-fixer agent to handle that.\"\\n (Uses Task tool to launch quality-fixer agent)\\n\\n- User: \"Make sure the code passes all checks\"\\n Assistant: \"I'll use the quality-fixer agent to ensure all quality checks pass.\"\\n (Uses Task tool to launch quality-fixer agent)\\n\\n- After completing a large refactor or feature implementation:\\n Assistant: \"Now that the changes are complete, let me launch the quality-fixer agent to ensure everything passes quality checks.\"\\n (Uses Task tool to launch quality-fixer agent)

claude-devtools:chatgroup-architectureSlash Command

ChatGroup architecture — how conversation data flows from raw JSONL to rendered chat groups. Use when working on UserGroup, AIGroup, SystemGroup, display items, tool linking, chunks, or the rendering hierarchy.

claude-devtools:design-systemSlash Command

Design system and visual language — theming, CSS variables, Tailwind config, component styling patterns, icon usage, animations, and z-index layers. Use when creating or modifying UI components, working with the dark/light theme, or debugging visual issues.

claude-devtools:explain-visible-contextSlash Command

Explains what "Visible Context" is — the 6 trackable token categories, what falls outside tracking, how it's displayed, and why it matters. Use when someone asks about visible context, token attribution, or context window usage.

claude-devtools:navigation-scrollSlash Command

Navigation and scroll orchestration — tab navigation, error highlights, search scrolling, auto-scroll coordination, and common bug patterns. Use when working on useTabNavigationController, scroll restore, or navigation requests.