Skip to content

usm/query-layer [built]

Predicate query language over .usm data — a tiny expression grammar (selectors, comparisons, and/or/not, has, contains) evaluated against parsed .usm files, exposed as usm query CLI and usm_query MCP tool. Turns grep-and-guess into typed impact analysis.

Status: built

Intent

Agents currently list everything or grep raw YAML to answer questions like "which planned features have no contracts?" or "what does this service own?". The semantic model is where computation should live (Fowler): a typed query surface over parsed .usm data serves drift checks, impact analysis, and triage — for agents via MCP and humans via CLI. Read-only; touches nothing about storage or format.

Decisions

tiny-grammar-not-sql

Decision: A ~200-line recursive-descent grammar, not SQL/jq subset

Rationale: Covers selector+predicate use cases agents actually have; keeps error messages precise and the surface teachable in one rules-file line.

missing-field-is-false

Decision: Unknown/absent fields make predicates false instead of erroring

Rationale: Queries like 'feedback where severity = high' must not explode on feature files that lack severity; absence is simply not a match.

Flows

Run a query from the CLI (run-query-cli)

  1. parse → query string into selector + predicate AST
  2. collect → all .usm files in the monorepo (same discovery as validate/generate)
  3. evaluate → filter files by selector and predicate
  4. output → table lines by default, --json for full objects, --limit cap

Run a query via the usm_query MCP tool (query-via-mcp)

  1. accept → query string + optional limit
  2. evaluate → same parser and evaluator as CLI
  3. return → id/type/status/summary/path per hit, total count, truncated flag (capped at 50 default)

Compose predicates (compose-predicates)

  1. support → selectors: features services systems apis data policies operations feedback all
  2. support → comparisons: = != > < >= <= ~ (contains) and has <field>
  3. support → boolean: and or not with parentheses; fields: type id status summary intent system service kind severity contracts flows tests decisions interfaces version

Contracts

selector-and-predicates

The grammar covers type selection, field comparison, existence, contains, and boolean composition

Acceptance criteria:

  • [ ] Selector maps to $type filtering (features→feature etc, all→any)
  • [ ] = != on strings; > < >= <= on numeric fields (array lengths, version)
  • [ ] ~ substring contains case-insensitive; has field for existence/non-empty
  • [ ] and or not with parentheses, standard precedence (not > and > or)

friendly-errors

Parse failures produce actionable messages, never raw stack traces

Acceptance criteria:

  • [ ] Message names the token and position and what was expected
  • [ ] Unknown fields resolve to missing (has is false, comparisons false) rather than erroring

read-only-and-capped

Query never writes; MCP results are capped for context safety

Acceptance criteria:

  • [ ] No file writes on any query path
  • [ ] MCP default limit 50 with total + truncated in the response

one-evaluator-two-surfaces

CLI and MCP share a single parser/evaluator module

Acceptance criteria:

  • [ ] src/query module is the only implementation
  • [ ] MCP response includes path so agents can usm_read hits directly

Tests

parser-cases

Given:

  • query_strings: ["features where status = planned","features where contracts > 0 and not (status = deprecated)","all where summary ~ auth","services where has decisions"]

Then:

  • assertion: each parses to expected AST without error
  • assertion: malformed string yields friendly parse error with position

evaluator-cases

Given:

  • fixture_usm_files: "feature planned w/o contracts, feature built w/ 2 contracts, service, feedback high"

Then:

  • assertion: status = planned returns only the planned feature
  • assertion: contracts > 0 returns the built feature
  • assertion: all where summary ~ AUTH matches case-insensitively
  • assertion: feedback where severity = high returns the feedback file

cli-smoke

Given:

  • fixture_project: true

Then:

  • assertion: usm query 'features where status = planned' prints matching ids
  • assertion: --json emits parseable JSON array

mcp-tool

Given:

  • fixture_project: true

Then:

  • assertion: usm_query returns results with id and path
  • assertion: limit caps results and sets truncated true

Implementation

  • Primary: src/query/index.ts
  • Test code: tests/query.test.ts
  • Test code status: manual

See Also

  • usm/mcp-read
  • usm/cli-generate