How patterns are scored

Each pattern scores 0.25 for framework match, 0.35 for keyword match and 0.40 for semantic similarity when RAG is on, minus 0.15 if older than 180 days. Scores under 0.3 are dropped and the top 3 kept. No command calls this in 1.91.1.

  • Patterns library
  • Checked against paqad-ai 1.91.1
  • Reviewed 25 September 2026 by Eliyce

What scoring does

Scoring ranks entries in the pattern library (the per-machine store of past solutions described on The cross-project pattern library) against a task, so that only the most relevant few would be suggested. The arithmetic is deterministic: a script computes it the same way every time. One optional part uses an embedding model, explained below.

The scoring routine is part of the paqad-ai 1.91.1 code and its JavaScript interface (suggestPatternsForProject), but no command, hook or workflow in this release calls it. paqad-ai patterns list filters patterns; it does not score them.

Step 1: only patterns for the same kind of project are considered

Before scoring, patterns are filtered. A pattern is kept only if its stack_filter.domain matches the current domain (coding or content) and, when the project has frameworks, it shares at least one framework with the project.

Step 2: each remaining pattern gets a score

score = 0.25 × framework match
      + 0.35 × keyword match
      + 0.40 × semantic similarity
      − 0.15 if the pattern is stale
PartHow it is worked out
Framework matchThe share of the project's frameworks that also appear in the pattern. A Laravel project and a Laravel pattern give 1.
Keyword matchThe share of the task's keywords that appear anywhere in the pattern's problem text or tags, ignoring upper and lower case. The solution text is not searched.
Semantic similarityHow close in meaning the keywords are to the pattern, measured by comparing their vectors (lists of numbers produced by an embedding model). This part is 0 unless RAG is turned on with an embedding provider and the pattern vector index is present and valid.
Stale penalty0.15 is taken off when the pattern's created_at is more than 180 days ago. The result is also flagged is_stale.

Without RAG the semantic part is always 0, so the highest possible score is 0.60.

Step 3: the best few are kept

Patterns scoring below 0.3 are dropped. The rest are sorted from highest to lowest and the top 3 are returned. Both numbers are defaults in the code; there is no setting for them in the project profile.

A worked example

A Laravel project, with the task keywords middleware, team and refund. A saved pattern has the framework laravel, a problem about team members opening invoices, and the tags middleware, teams and invoices. RAG is off.

  • Framework match: 1 of 1 frameworks, so 0.25 × 1 = 0.25.
  • Keyword match: middleware and team appear, refund does not, so 0.35 × 2/3 ≈ 0.23.
  • Semantic similarity: 0, because RAG is off.
  • Total: about 0.48, above 0.3, so the pattern is kept.

If the same pattern were 200 days old, 0.15 would come off, giving about 0.33. It would still be kept, marked as stale.

Machine arithmetic and model output

The framework match, keyword match, penalty, threshold and limit are plain arithmetic on stored text. The semantic similarity depends on the embedding model you configured for RAG, so its values change if you switch provider or model. Whether an AI tool then uses a suggested pattern well is model judgment.

The same 180-day age is the default for paqad-ai patterns prune, which permanently deletes patterns older than the threshold. Use --older-than <days> to change it. See the patterns command reference.

Something on this page out of date or unclear? Open an issue on GitHub and name the page.