Five minutes from install to an answer to: what protects this repo, where is that protection weak, and what will this PR put at risk? No config, no setup, no test execution required.
brew install pmclSF/terrain/mapterrain # Homebrew (macOS / Linux)
npm install -g mapterrain # npm (Node 22+)
go install github.com/pmclSF/terrain/cmd/terrain@latest # GoOr download a signed binary from the releases page.
cd your-repo
terrain analyzeYou'll see a one-line headline (the most surprising finding), a Key Findings block ranked by severity, repository profile, and risk posture. Every finding names specific files and signals — no vague handwaving.
On a feature branch with a diff against main:
terrain report pr --base mainA change-scoped risk report — what your diff actually affects, ranked by confidence, each line tied to a specific file. Add --fail-on=high to turn it into a CI gate (exit code 6 on blocking findings).
terrain report impact --base main --explain-selectionThe selected tests plus the reason chain for each. --explain-selection shows why a test made the cut and why others didn't — clarity, not safe-skip advice.
That's the core loop. Everything below adds depth.
Terrain reads what your tools already produce. Each integration is one flag:
# Coverage data → precise structural coverage mapping
pytest --cov --cov-report=lcov
terrain analyze --coverage coverage/lcov.info
# Runtime artifacts → flaky / slow / dead test detection
pytest --junitxml=junit.xml
terrain analyze --runtime junit.xml
# Snapshot for trend tracking
terrain analyze --write-snapshot
terrain compare # laterterrain test is the CI-mode wrapper. It writes JUnit XML (GitHub's test reporter shows Terrain findings as test cases) and a markdown step-summary (visible on the workflow run page):
- name: Terrain pre-flight
run: |
terrain test \
--junit terrain-results.xml \
--summary "$GITHUB_STEP_SUMMARY"The --summary value is the file Terrain writes; $GITHUB_STEP_SUMMARY is the file GitHub Actions reads. Set them equal and findings appear on the run page automatically. Full templates in docs/examples/gate/.
If your repo has prompts, RAG pipelines, or eval suites, Terrain maps them automatically:
terrain ai list # inventory
terrain ai run --base main --dry-run # which evals does this change affect?
terrain ai doctor # validate setup
terrain ai findings --json # CI-consumable eval-gap findingsterrain report pr flags changed AI surfaces with no covering eval. The dependency graph that powers test selection for application code also traces AI surface edges.
Two generators produce a test suite around a prompt without invoking the model — the assertion is yours:
# Boundary-case mutation tests from a JSON Schema
terrain scaffold --schema schemas/input.json --prompt prompts/main.md \
> tests/test_prompt_boundaries.py
# Jailbreak-shaped inputs matched against the prompt body
terrain inject --prompt prompts/main.md \
> tests/test_prompt_injection.pyDefault output is pytest; use --lang typescript for vitest.
Every terrain analyze and terrain test run writes a canonical .terrain/findings.json (schema version 1). terrain mcp reads it; IDE plugins consume it; SARIF uploaders transform it.
- CLI specification — every command, every flag
- Compatibility — supported frameworks, languages, schemas, eval tools, pipelines
- Example reports — full sample outputs for analyze / impact / insights / explain
- Signal catalog — every detector and what it fires on
- Contributing — extending Terrain