/query-patterns
You are the lookup surface for the project's Tier 2 pattern library
at .claude/patterns/. You read every pattern file's frontmatter and
body, score against a free-text problem description, and return the
top-N ranked matches.
You do NOT modify the pattern library — capture new candidates with
/track-idea intake, promote manually into .claude/patterns/ when
they satisfy the Tier 2 gate in .claude/docs/pattern-library.md,
deprecation is a manual edit, and research is /mature-existing-ideas.
You do NOT search the Tier 1 ledger — unpromoted ideas don't have
validated value yet, and surfacing them by default would dilute the
signal.
The pattern format, promotion gate, qualifier graduation rules, and
status lifecycle live in .claude/docs/pattern-library.md. Read that
file before reasoning about a query that the matcher handles
ambiguously.
A lower-friction companion to this skill is the inline prompt template
at .claude/docs/query-patterns-inline.md — paste-into-context for
ad-hoc reads when a full skill invocation is overkill.
How success is judged
- The matcher command is run exactly as documented with
.venv/bin/python, and the final reply pastes the matcher output plus the exit code when it is nonzero. - Exit 0 means at least one pattern matched above threshold. Exit 1 means no match or an empty library, and is a valid lookup result when the rendered guidance is delivered. Exit 2 is usage error and does not count as a completed lookup.
- No pattern files, ledger files, or docs are modified by this skill. The run may append one effectiveness-log line only after the matcher output has been delivered.
- No-match guidance routes to
/track-idea intakeand manual Tier 2 promotion per.claude/docs/pattern-library.md; it must not name a nonexistent promotion skill.
Core beliefs
- Read frontmatter first, body second. The most-queried field is
problem_class; the next ispros+cons+ the "Use this when X" one-liner from the Problem fit section. Don't expand to the whole body unless the frontmatter doesn't match — patterns are designed so the frontmatter is the headline. - "No match" is a valid output. If the library has nothing that fits, say so. Don't fabricate a fit. The matcher's exit-1 path is the correct answer when the problem is genuinely new to the project.
- Surface composability. When a pattern matches, also surface its
composes_with/lineage_parents/lineage_childrenfrontmatter so the reader can follow the graph one hop without re-querying. - Status filters defaults. By default, exclude
deprecatedpatterns from the ranked list. Surface them only when explicitly requested via--include-deprecated.
Argument parsing
Single positional argument: a free-text problem description. Flags modify presentation.
/query-patterns <problem description> [--top N] [--json] [--include-deprecated]
Examples:
/query-patterns extract structured product data from a Next.js site
/query-patterns reduce LLM cost on a per-site discovery loop
/query-patterns deduplicate three-way clone clusters detected by jscpd
If the argument is empty, abort with usage guidance.
Pipeline
Stage 0 — Setup
Pre: problem description received. Post: patterns directory located.
The patterns live at ${REPO_ROOT}/.claude/patterns/*.md. If the
directory is missing or empty (Tier 2 not yet populated), the matcher
returns exit 1 with a message recommending /track-idea intake for
capture and manual Tier 2 promotion once an idea satisfies the adoption
gate in .claude/docs/pattern-library.md.
Stage 1 — Run the matcher
Pre: problem description and patterns directory in hand. Post: matcher output captured.
.venv/bin/python .claude/skills/query-patterns/scripts/query.py "${PROBLEM}" \
[--top N] [--json] [--include-deprecated] [--project-root DIR]
The pattern library is read from <project-root>/.claude/patterns/;
--project-root defaults to the git toplevel of the cwd (else the cwd).
The matcher returns:
query— verbatim problem texttotal_patterns— count of pattern files scannedmatches[]— ranked list with score, slug, title, headline (Use this when X), status, generalizability, problem_class, composes_with, lineage_parents, lineage_children
Exit code 0 = at least one match scored above the relevance threshold. Exit code 1 = no match; the script still prints an informative message. Exit code 2 = usage error.
Stage 2 — Render the recommendation
Pre: matcher output in hand. Post: user sees the ranking.
Default Markdown render shape:
Query: <verbatim problem>
Library size: N patterns (deprecated excluded)
## Top matches
### 1. `<slug>` — <title> [status / generalizability]
**Use this when**: <one-line headline from Problem fit>
**Problem class**: <frontmatter problem_class>
**Composes with**: <slug>, <slug> (or "(none)")
**Lineage**: ← parents: <slug>, → children: <slug> (omit if both empty)
Score: <N>
### 2. ...
When --json is passed, print the matcher payload verbatim.
When total_patterns == 0:
Library size: 0 patterns.
No patterns recorded yet. Capture the problem with /track-idea intake
and promote manually into .claude/patterns/ when it satisfies the Tier 2
gate in .claude/docs/pattern-library.md.
When matches is empty:
Query: <verbatim>
Library size: N patterns
Top match score: 0 (below threshold)
No patterns in the library match this problem closely. Either:
- The problem is genuinely new — capture with /track-idea intake.
- The match heuristic missed it — re-query with different wording.
Stage 3 — Effectiveness log
Pre: ranking delivered. Post: one line appended to
reports/_meta/effectiveness.jsonl.
.venv/bin/python scripts/log_effectiveness.py \
--skill query-patterns \
--scan-id "query-$(date +%s)" \
--target "${PROBLEM_SLUG}" \
--findings-total ${N_MATCHES} \
--buckets "{\"matched\": ${N_MATCHES}, \"no_match\": ${ZERO_OR_ONE}}"
The log enables a future audit: "how often does /query-patterns return no matches?" — high frequency signals an under-populated library, not a broken matcher.
Stage 4 — Stop
Do not invoke a downstream skill. The ranking is the work. The user decides whether to adopt a pattern, capture a new idea, or proceed unaided.
Non-goals
- Writing to the pattern library (manual Tier 2 promotion per
.claude/docs/pattern-library.md). - Editing pattern files (open them directly for content edits).
- Searching the Tier 1 ledger (use
/track-idea listinstead). - Recommending external libraries / docs (this is project-local prior
art only —
context7MCP server is the right tool for library docs). - Composing a new pattern from multiple matches — surface the matches; the user composes.
When things go sideways
| Symptom | Action |
|---|---|
| Empty problem description | Abort with usage example |
.claude/patterns/ doesn't exist |
Treat matcher exit 1 as a valid no-match result; render capture guidance |
| Pattern file has malformed YAML | Surface the file path and parse error; skip the file; continue with the others |
| All scores 0 | Render the "no match" template; suggest re-wording |
| Matcher exits 2 | Treat as invocation failure; paste stderr and do not log effectiveness |
| Same pattern slug appears twice (file system case-collision) | Surface both; do not silently dedupe |
--include-deprecated flips a deprecated pattern to top rank |
Render it; mark [deprecated] in the status field clearly |
Repository layout
.claude/skills/query-patterns/
├── SKILL.md # this file — orchestrator
└── scripts/
└── query.py # the matcher (uses scripts/_lib/yaml_frontmatter)
The matcher uses the shared YAML frontmatter parser at
scripts/_lib/yaml_frontmatter.py — same one decisions.py,
plans.py, skill_meta.py, specs.py, and which-skill/match.py
depend on. Use .venv/bin/python so PyYAML is available.
Replay case
For exit-code or no-match guidance changes, replay two boundaries:
EMPTY_ROOT="$(mktemp -d)"
mkdir -p "${EMPTY_ROOT}/.claude/patterns"
.venv/bin/python .claude/skills/query-patterns/scripts/query.py \
"workflow registry guard" \
--project-root "${EMPTY_ROOT}"
printf 'rc=%s\n' "$?"
.venv/bin/python .claude/skills/query-patterns/scripts/query.py \
"workflow registry guard" \
--project-root "$(git rev-parse --show-toplevel)"
printf 'rc=%s\n' "$?"
The empty-library replay passes only when the output says no patterns
are recorded, names /track-idea intake, does not name a promotion skill,
and exits rc=1. The populated-library replay passes when the exit code
matches the rendered result: rc=0 for matches, rc=1 for no match.
Cross-references
- Schema, promotion gate, status lifecycle:
.claude/docs/pattern-library.md - Tier 1 ledger schema:
.claude/docs/idea-ledger.md - Inline lower-friction lookup:
.claude/docs/query-patterns-inline.md - ADR motivating this system:
ai-docs/decisions/0013-idea-tracking-system.md - Companion skills:
/track-idea,/find-orphaned-ideas