Skip to main content
Glama

Run Rego tests across multiple roots

rego_test_multiroot

Runs opa test once per test root and aggregates results, preventing package-conflict failures in repositories with multiple independent Rego package namespaces. Supports explicit root lists and automatic leaf-root scanning.

Instructions

Run opa test once per root and aggregate results. Solves the package-conflict problem that occurs when opa test . is run on a repo with multiple independent package namespaces (OPA issue #4724). Two modes: explicit (supply root list with optional per-root include paths for shared libraries) and scan (auto-discover leaf test roots using the leaf rule -- a directory is a root only if it directly contains *_test.rego files and none of its eligible subdirectories do, preventing OPA's automatic recursion from double-running tests). Use sharedPaths in scan mode to add shared library directories to every root's invocation without including them in discovery. Coverage and threshold work per-root; overallCoveragePct is the mean across roots that have coverage data.

Tool call template

This tool declares no required parameters. Add optional parameters from the input schema as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {},
    "name": "rego_test_multiroot"
  }
}

Input Schema

NameRequiredDescriptionDefault
rootsNoExplicit list of test root directories. Use when roots are known upfront or when scan mode cannot determine the correct roots. Mutually exclusive with `scanDir`.
scanDirNoTop-level directory to scan for test roots. Uses the leaf rule: a directory is a root only if it directly contains `*_test.rego` files and none of its eligible subdirectories do. Mutually exclusive with `roots`.
verboseNoEmit per-test pass/fail details for each root.
coverageNoAdd per-line coverage (`coverage`, `coveragePct`, and `overallCoveragePct` across roots) to the test results. Each root runs twice, once for the results and once for coverage. A root where a test fails or errors gets no coverage, and a `note` saying so: opa reports none for such a run.
maxDepthNoMaximum directory depth to scan. Default: 10. Only used with `scanDir`.
maxRootsNoMaximum number of test roots allowed. Returns INVALID_INPUT if scan finds more. Default: 50. Only used with `scanDir`.
thresholdNoMinimum coverage percentage required per root (0-100). A root whose tests pass below it gets `thresholdMet: false` and a COVERAGE_BELOW_THRESHOLD error. Implies `coverage`.
varValuesNoInclude local variable bindings in trace output (`--var-values`). Only useful with `verbose: true`.
runPatternNoRun only tests whose names match this regular expression (passed as `--run` to each root).
sharedPathsNoPaths added to every root's `opa test` invocation and excluded from auto-discovery. Use for shared library directories that all roots import from.
v0CompatibleNoRead the policy as Rego v0 (`--v0-compatible`), the syntax OPA used before 1.0: rules without `if`, partial sets as `deny[msg] { ... }`. Needed for a policy that has not been migrated, which OPA 1.x otherwise refuses to load. Where the tool also takes a query, the query is read as v0 too, with the future keywords imported so `in`, `every` and `some x in` still work in it.
ignorePatternsNoAdditional directory name patterns to skip during scan (e.g., ["vendor", "*.generated"]). Supports `*` wildcards. Only used with `scanDir`.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changedv0.9.1
    • changedInput schema / properties / coverage / description
      Previous value: -"Include per-line coverage data per root. Switches output to coverage-report mode: test record counts are not available, but `coverage`, `coveragePct`, and `overallCoveragePct` fields are populated."New value: +"Add per-line coverage (`coverage`, `coveragePct`, and `overallCoveragePct` across roots) to the test results. Each root runs twice, once for the results and once for coverage. A root where a test fails or errors gets no coverage, and a `note` saying so: opa reports none for such a run."
    • changedInput schema / properties / threshold / description
      Previous value: -"Minimum coverage percentage required per root (0-100). Roots below threshold have `thresholdMet: false` in their result. Implicitly enables coverage-report output mode."New value: +"Minimum coverage percentage required per root (0-100). A root whose tests pass below it gets `thresholdMet: false` and a COVERAGE_BELOW_THRESHOLD error. Implies `coverage`."
  2. Changed1 schema field changedv0.8.0
    • changedInput schema / properties / v0Compatible / description
      Previous value: -"Read the policy as Rego v0 (`--v0-compatible`), the syntax OPA used before 1.0: rules without `if`, partial sets as `deny[msg] { ... }`. Needed for a policy that has not been migrated, which OPA 1.x otherwise refuses to load."New value: +"Read the policy as Rego v0 (`--v0-compatible`), the syntax OPA used before 1.0: rules without `if`, partial sets as `deny[msg] { ... }`. Needed for a policy that has not been migrated, which OPA 1.x otherwise refuses to load. Where the tool also takes a query, the query is read as v0 too, with the future keywords imported so `in`, `every` and `some x in` still work in it."
  3. Changed1 schema field changedv0.7.0
    • addedInput schema / properties / v0Compatible
      Added value: +{
      +  "description": "Read the policy as Rego v0 (`--v0-compatible`), the syntax OPA used before 1.0: rules without `if`, partial sets as `deny[msg] { ... }`. Needed for a policy that has not been migrated, which OPA 1.x otherwise refuses to load.",
      +  "type": "boolean"
      +}
  4. Addedv0.1.17

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=false and openWorldHint=true, so the description carries most of the behavioral load, and it does: it discloses the leaf rule that prevents OPA's recursion from double-running tests, and that coverage and thresholds are evaluated per root with `overallCoveragePct` as a mean over roots that have coverage data. It stops short of stating concurrency or failure-handling behavior across roots (e.g., whether all roots still run when one fails).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded, then the mode split, then the two non-obvious semantics (leaf rule, per-root coverage). Every sentence contributes a fact an agent could not get from the structured fields alone, and the OPA issue reference is a compact identifier rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 12 optional parameters, no output schema, and sparse annotations, the description supplies the mode selection logic and result-aggregation semantics needed to call it correctly. The remaining gap is the response shape (per-root result entries, error codes like COVERAGE_BELOW_THRESHOLD), which is partially covered by field descriptions but not summarized in the description itself.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by explaining the mode split (`explicit` root list vs `scan`) and the aggregation semantics of coverage that the schema does not state on its own. The `sharedPaths` guidance in the text adds a usage-level meaning beyond the field description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb, resource, and scope: 'Run `opa test` once per root and aggregate results,' which cleanly separates it from the single-root sibling `rego_test`. The following sentence names the concrete problem it solves (package conflicts across independent namespaces, OPA issue #4724), so an agent can tell exactly what class of task this covers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains both operating modes and when each applies: `explicit` for known root lists (with per-root `include` for shared libraries) and `scan` for auto-discovery via the leaf rule, plus the scan-only role of `sharedPaths`. It never names `rego_test` as the alternative for a single-root run, leaving that routing to be inferred from the name and the 'once per root' phrasing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.