--- disable-model-invocation: true name: text-search description: "Search indexed text corpora with qmd. For indexed content, prefer qmd over grep." --- # text-search Use qmd to search indexed text corpora such as session logs, notes, docs, and logs. For indexed content, use qmd for discovery instead of raw `grep`. ## First checks Before searching, confirm what is indexed: ```bash qmd status qmd collection list qmd context list ``` Do not assume collection names, paths, or contexts. ## Core rule For indexed corpora, use qmd for discovery. Do **not** use `grep`/`find`/`jq`/`cat` directly on indexed files to search for meaning. This is especially important for session JSONL, which is noisy and hard to interpret raw. Shell usage is still fine for: - filtering tool output after discovery - housekeeping and file targeting - non-indexed content - helper scripts in this skill ## Choose the right qmd command For exact clues, start with `qmd search`. - Use `qmd search` for exact clues: tool names, error strings, repo names, JSON fields, literal phrases - Use `qmd query` when lexical search is weak, the request is conceptual, or you want hybrid retrieval + reranking - Use `qmd vsearch` only when you specifically want pure semantic similarity ```bash qmd search '"toolName":"rp_exec"' qmd search 'apply_edits' qmd query "OAuth redirect flow" qmd vsearch "the session where we changed direction" ``` Operational notes: - `qmd query` may trigger local model startup or model downloads, so it is not always the fastest first step - For session discovery, prefer `--files` first so you get compact path output instead of long snippets ## Build better queries ### Use `--intent` when the request is ambiguous `intent` is a steering hint. Use it when the same words could refer to multiple things or when the user remembers the topic better than the exact wording. ```bash qmd query --intent "Pi/Codex/Claude agent sessions about repo editing failures" \ -c sessions \ "apply_edits error" ``` ### Use structured query documents for important searches Multi-line query documents are useful when you have both exact clues and fuzzy memory. - `lex:` exact terms, phrases, identifiers, JSON fields - `vec:` natural-language meaning - `hyde:` what the answer likely looked like - `intent:` optional steering context ```bash qmd query $'intent: agent sessions about RepoPrompt edits and patch failures lex: apply_edits rp_exec "search block not found" vec: debugging failed file edits in agent sessions hyde: The agent tried to edit a file several times, the edit did not match, and it switched to a narrower or different approach' ``` Operational details: - The first typed query gets 2x fusion weight, so put the strongest signal first - `expand:` must stand alone; do not mix it with typed lines - lex queries support quoted phrases and exclusions such as `-sports` or `-"test data"` ### Useful output and tuning flags ```bash qmd query --files -n 20 "agent session about flaky tests" qmd query --json -n 10 "session where we redesigned the search flow" qmd query --json --explain -c sessions "apply_edits error" qmd query -C 20 --min-score 0.3 -c sessions "OAuth redirect flow" ``` Use: - `--files` for compact discovery output and path-based follow-up - `--json` for structured inspection when you need scores/snippets - `--explain` when ranking looks wrong - `-C, --candidate-limit` to reduce reranking work - `--min-score` to drop weak matches - `-c, --collection` to scope the search For session hunting, `--files` is usually the best first output mode. ## Retrieval commands ```bash qmd get "#abc123" qmd multi-get "docs/*.md" --json qmd ls sessions qmd ls sessions/claude ``` Use `get`, `multi-get`, and `ls` to retrieve or browse content after discovery. For session discovery, use this inspection path: ```bash # 1. Discover a session transcript qmd search -c sessions --files 'apply_edits' -n 5 # 2. Read the session transcript directly qmd get "qmd://sessions/path/to/session-transcript.md" --full ``` Each session transcript includes `original_session` metadata in frontmatter. When exact commands, SQL, edits, or ad-hoc code matter, recover them from the original session JSONL with `session_ask` or `session-view --include-tool-calls`. Add `--include-tool-results` only when tool outputs are evidence. ## If qmd is missing ```bash npm install -g @tobilu/qmd qmd --version qmd status ``` --- # Sessions Agent session transcripts are indexed as the `sessions` collection. The `sessions` collection is a corpus of agent session transcripts generated from session JSONL via `session-view`. It is optimized for readable search. Very large sessions may be split across multiple transcript documents; use the `original_session` metadata when you need exact raw-session recovery. ## Required workflow Use this three-step process: 1. **Discover** candidate sessions with qmd or `analyze-sessions.sh` 2. **Inspect** the session transcript with `qmd get` 3. **Recover exact raw-session details only when needed** via `original_session` + `session_ask` or `session-view --include-tool-calls` Do **not** try to understand a session from raw JSONL snippets alone. ## Inspecting session transcript paths Use one reliable inspection path: ```bash # Read the session transcript directly qmd get "qmd://sessions/path/to/session-transcript.md" --full ``` If the transcript is enough, stop there. If exact raw-session details matter: ```bash # 1. Read the transcript and note its `original_session` frontmatter qmd get "qmd://sessions/path/to/session-transcript.md" --full # 2. Recover exact tool-call details from the original session session-view --include-tool-calls /absolute/path/to/original/session.jsonl ``` Or use `session_ask` against that `original_session` path when you want targeted recovery without reading the whole session. ### If `original_session` is missing or stale A session transcript's `original_session` frontmatter may point to a materialized indexing path rather than the live Pi session JSONL. If that path does not exist, use `relative_session` plus Pi's configured session directory. For Pi sessions: - `relative_session: pi/.jsonl` - live path: `/.jsonl` Resolve the Pi session dir using Pi's documented precedence: 1. `--session-dir` if known from the command/session context 2. `PI_CODING_AGENT_SESSION_DIR` if set 3. `sessionDir` in Pi settings 4. default: `~/.pi/agent/sessions` Example: ```text relative_session: pi/--Users-ww-project--/session-id.jsonl ``` with the default session dir maps to: ```text ~/.pi/agent/sessions/--Users-ww-project--/session-id.jsonl ``` If the effective session dir cannot be determined, try the default path first, then ask the user for their Pi session directory rather than assuming the qmd `original_session` path is still valid. Filtering transcript output is fine: ```bash qmd get "qmd://sessions/path/to/session-transcript.md" --full | grep -iE 'USER:.*(error|bug|regression)' ``` ## Session search playbook ### Ask for narrowing clues when memory is vague If the request is fuzzy, ask for: - approximate timeframe - which agent/tool produced the session - repo or project involved - remembered phrase, error text, or tool name After 2-3 bad searches, stop iterating blindly and ask for more context. ### Exact session search Start here when you have hard clues. Use `--files` first to avoid wasting tokens on snippets. If lexical search returns an obvious hit, inspect it immediately instead of escalating to `query`. ```bash qmd search -c sessions --files 'rp_exec' -n 20 qmd search -c sessions --files 'apply_edits' -n 20 qmd search -c sessions --files 'git rebase' -n 20 qmd search -c sessions --files 'search block not found' -n 20 ``` If lexical search returns many same-score candidates because the clue is broad or common, do not keep repeating broad lexical searches. Tighten the query with a more distinctive phrase, tool name, error string, or timeframe clue, or switch to `qmd query --intent ...`. ### Escalate when lexical search is weak Use `query`, add `intent`, and scope to `sessions` when exact search is weak or the request is conceptual. Keep `--files` on unless you specifically need snippets. ```bash qmd query --intent "Pi/Codex/Claude agent sessions about git trouble during implementation work" \ -c sessions \ --files \ -n 10 \ "git rebase gone wrong" ``` ### Mixed exact + fuzzy session search ```bash qmd query -c sessions --files $'intent: agent sessions about broken code edits in RepoPrompt workflows lex: apply_edits rp_exec "oldText" "search block not found" vec: session where file edits failed repeatedly and the agent had to retry' ``` ### Browse after narrowing ```bash qmd ls sessions qmd ls sessions/claude qmd ls sessions/pi ``` ## Inspect with `session-view` `session-view` lives at `~/.pi/agent/skills/text-search/scripts/session-view`. Use it when a session transcript points you at an `original_session` and you need exact raw-session details. It also accepts RepoPrompt `AgentSession-*.json` files when you want the compressed RP-side view plus its `codexRolloutPath`. For Codex sessions, `session-view` strips the leading injected AGENTS/environment preamble through `` before rendering the transcript. ```bash # Default: prose-only; omit tool calls and tool result/output blocks session-view /absolute/path/to/original/session.jsonl # Opt-in: include assistant tool invocations with full arguments session-view --include-tool-calls /absolute/path/to/original/session.jsonl # Escalate only when tool outputs are evidence session-view --include-tool-calls --include-tool-results /absolute/path/to/original/session.jsonl # RepoPrompt AgentSession JSON session-view ~/Library/Application\ Support/RepoPrompt/Workspaces/.../AgentSessions/AgentSession-ABC123.json ``` You can also inspect the latest local session directly: ```bash # Default: prose-only; omit tool calls and tool result/output blocks session-view --latest pi session-view --latest codex session-view --latest claude session-view --latest rp # Opt-in: include full tool-call arguments session-view --include-tool-calls --latest pi ``` Default rendered output looks like this: ```text USER: message ASSISTANT: response text ``` With `--include-tool-calls`, assistant tool invocations are rendered with full JSON arguments: ```text ASSISTANT: [tool_name] { "path": "file.txt" } ``` If you opt in to tool results with `--include-tool-results`, you'll also see bounded output blocks: ```text TOOL [name]: ✓ truncated_output ``` ## Example workflows ### Find a specific session with hard clues ```bash # 1. Start with lexical search and compact path output qmd search -c sessions --files 'git rebase' -n 20 # 2. Inspect the transcript qmd get "qmd://sessions/path/to/session-transcript.md" --full # 3. If exact details matter, recover full tool calls from original_session session-view --include-tool-calls /absolute/path/to/original/session.jsonl ``` ### Escalate when lexical search is weak ```bash qmd query --intent "Pi/Codex/Claude sessions about git trouble during coding work" \ -c sessions \ --files \ -n 20 \ "git rebase gone wrong" ``` ## Supplemental helper: `analyze-sessions.sh` Location: `~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh` Use it for time-windowed or operational reporting rather than ranked corpus search. ```bash ~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh --hours 24 --report ~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh --hours 48 --pattern "apply_edits|rp_exec" ~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh --hours 36 --edit-diagnostics ~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh --hours 48 --tool-errors ~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh --hours 24 --tool-stats ~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh --hours 72 --report --project pi-mono ~/.pi/agent/skills/text-search/scripts/analyze-sessions.sh --hours 72 --tool-stats --tool rp_exec ``` Use qmd for ranked discovery across the corpus. Use `analyze-sessions.sh` for recent-window reports and regex-style operational triage. ## Session JSONL structure reference Each JSONL line has a `type` field: | Type | Key fields | |------|------------| | `message` | `role`, `content`, `toolCall` | | `toolResult` | `toolName`, `isError`, `content` | | `custom` | `customType`, `data` | ```