Pretorin Developer & Agent Docs
Beta — Pretorin is currently in closed beta. Framework and control browsing works for authenticated users. Platform write features (evidence, narratives, monitoring) require a beta code. Sign up for early access.
Pretorin gives developers and AI agents direct access to compliance data, implementation context, and evidence workflows. The primary surfaces are the CLI, the MCP server, and skill-driven agent workflows. It supports 26 compliance frameworks and profiles, including NIST 800-53, NIST 800-171, FedRAMP, and CMMC.
The CLI and MCP tooling in this repository are open source under Apache-2.0. Access to Pretorin-hosted platform services, APIs, and account-scoped data is authenticated and governed separately by the applicable platform terms.
Start Here
Choose the path that matches how you work:
- CLI-first — Use the Pretorin CLI directly for framework browsing, evidence workflows, reviews, scans, and agent execution.
- AI-agent-first — Connect
pretorin mcp-serveto Claude Code, Codex CLI, Cursor, or another MCP-compatible tool. - Hosted agent runtime — Use
pretorin agent runwhen you want Pretorin-managed model execution with built-in skills.
Start with Installation, Authentication, and Quick Start if this is your first time here.
Core Paths
Pretorin is usually used in one of these modes:
-
Bring-your-own-agent mode — Run
pretorin mcp-serveand connect the MCP server to your existing AI tool (Claude Code, Codex CLI, Cursor, Windsurf, etc.). Your agent gets compliance tools without changing your workflow. Pair withpretorin skill installto give your agent explicit guidance for using pretorin (see “Bundled skill” below). -
Pretorin-hosted agent mode — Run
pretorin agent runto use Pretorin’s built-in agent runtime when you don’t have your own local agent. Pretorin manages the AI runtime; you supply prompts. -
Direct CLI mode — Use
pretorinsubcommands directly for browsing frameworks, managing context, authoring evidence, updating narratives, and running scans. No agent involved.
Important architectural detail. The vast majority of the CLI and the entire MCP server are thin wrappers over the platform API — no LLM runs in pretorin in those paths. When you use mode 1 (your own agent via MCP), your local agent does all the reasoning. Pretorin is the tool surface. The only place pretorin runs its own LLM is pretorin agent run (mode 2), provided as a fallback for users without a local agent.
Bundled skill (pretorin skill install)
pretorin skill install copies a bundled skill into ~/.claude/skills/pretorin/ (or ~/.codex/skills/pretorin/). The skill is markdown + scripts that tell your agent how to use pretorin’s MCP tools effectively — which to call first, how to scope by system + framework, how to handle evidence and narrative writes. Highly recommended when using mode 1.
What You Can Do
- Browse compliance frameworks — Query controls, families, metadata, and AI guidance from authoritative sources
- Manage implementation context — Set an active system and framework, then track progress across controls
- Create and manage evidence — Generate local evidence files, push them to the platform, and link them to controls
- Write implementation narratives — Draft and push auditor-ready narratives for each control
- Run AI-powered compliance tasks — Use the built-in Codex agent with bundled skills (gap-analysis, narrative-generation, evidence-collection, security-review, stig-scan, cci-assessment)
- Run compliance recipes — Author or invoke recipe playbooks (markdown + scripts) that the calling agent executes for evidence capture, baseline scanning, and other procedures
- Review code against controls — Analyze your codebase for control coverage
- Track monitoring events — Record security scans, access reviews, configuration changes, and compliance checks
- Generate compliance artifacts — Produce structured JSON artifacts documenting control implementations
- Browse STIGs and CCIs — Look up STIG benchmarks, rules, and trace CCIs through the full control hierarchy
- Manage vendors — Track third-party vendors, link evidence to vendor assessments, and upload vendor documents
- Complete policy and scope questionnaires — Answer org-policy and scope questions through a guided workflow with AI-assisted generation and review
Recommended Sections
- Quick Start for first commands and setup
- MCP Integration for Claude, Codex, Cursor, and other agent tools
- Agent Overview for Pretorin-hosted runtime usage
- CLI Reference for command-level detail
- Workflows for end-to-end compliance tasks
- Authoring Recipes for writing or invoking compliance playbooks
Architecture
Pretorin CLI is three things, with one shared API client at the bottom:
┌──────────────────────────────────────────────────────────────────────┐
│ Developer │
│ │
│ ┌──────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Terminal │ │ Local AI Agent │ │ pretorin agent │ │
│ │ (direct │ │ (Claude Code, │ │ run │ │
│ │ pretorin│ │ Codex CLI, │ │ (Pretorin's own │ │
│ │ cmds) │ │ Cursor, ...) │ │ CodexAgent — for│ │
│ │ │ │ │ │ users w/o local │ │
│ │ │ │ + bundled │ │ agent) │ │
│ │ │ │ pretorin │ │ │ │
│ │ │ │ skill │ │ │ │
│ │ │ │ (optional) │ │ │ │
│ └────┬─────┘ └────────┬─────────┘ └────────┬─────────┘ │
│ │ │ │ │
│ │ │ stdio │ │
│ │ ┌────────┴─────────┐ │ │
│ │ │ MCP Server │ │ │
│ │ │ pretorin │ │ │
│ │ │ mcp-serve │ │ │
│ │ │ │ │ │
│ │ │ Tool surface │ │ │
│ │ │ (no LLM here) │ │ │
│ │ └────────┬─────────┘ │ │
│ │ │ │ │
│ └──────────────┬───────┴──────────┬───────────────┘ │
│ │ │ │
│ ┌────────┴──────────────────┴─────────┐ │
│ │ Pretorin API Client │ │
│ │ (shared — only place that talks │ │
│ │ to the platform) │ │
│ └────────────────┬────────────────────┘ │
└───────────────────────────────┼───────────────────────────────────────┘
│
┌────────┴─────────┐
│ Pretorin │
│ Platform API │
└──────────────────┘
Three things, one client:
- Direct CLI —
pretorin <command>runs synchronously, talks to the platform via the shared client. No LLM. - MCP server —
pretorin mcp-serveexposes the same platform features as MCP tools. The local agent does all the reasoning; pretorin is the tool surface. No LLM runs in pretorin in this path. pretorin agent run— Pretorin’s own LLM, used when the user doesn’t have a local agent. Calls the same platform-API tools as the MCP server, just over a Python in-process boundary.
The bundled skill (pretorin skill install) is content delivered to the local agent’s skill directory; it’s not a fourth path, it’s a way to give path 2 better instructions.
Links
Installation
Pretorin CLI requires Python 3.10 or later.
Recommended: uv
uv installs the CLI as an isolated tool with its own dependencies:
uv tool install pretorin
pip
pip install pretorin
pipx
pipx provides isolated installation similar to uv:
pipx install pretorin
Docker
A multi-stage Dockerfile is included in the repository. The production target builds an image that runs the pretorin CLI as its entrypoint:
git clone https://github.com/pretorin-ai/pretorin-cli.git
cd pretorin-cli
docker build --target production -t pretorin .
docker run --rm pretorin --help
Mount your config directory to persist credentials between runs:
docker run --rm -v "$HOME/.pretorin:/home/pretorin/.pretorin" pretorin frameworks list
The included docker-compose.yml defines test, test-coverage, lint, typecheck, and integration services for contributors. Each is invoked with docker compose run --rm <service>, not docker compose up. See Contributing for development workflows.
Verify Installation
pretorin version
Expected output:
pretorin version 0.22.14
Updating
Check for and install the latest version:
pretorin update
pretorin update checks PyPI first. If you are current, it prints that you are already on the latest version. If a newer version is available, it uses the installer that owns the current CLI environment (uv, pipx, or pip) to perform the upgrade.
Older uv-installed Pretorin versions may fail with No module named pip because uv tool environments do not include pip. If that happens, run this one-time recovery command:
uv tool install --force --refresh pretorin@latest
The CLI also checks for updates automatically on startup and notifies you when a new version is available. To disable passive update notifications:
export PRETORIN_DISABLE_UPDATE_CHECK=1
# or
pretorin config set disable_update_check true
Development Installation
For contributing to Pretorin CLI:
git clone https://github.com/pretorin-ai/pretorin-cli.git
cd pretorin-cli
uv pip install -e ".[dev]"
This installs the package in editable mode with development dependencies (pytest, ruff, mypy, etc.).
Authentication
Getting an API Key
Get your API key from platform.pretorin.com.
Beta Note: Framework and control browsing works for authenticated users. Platform write features (evidence, narratives, monitoring) require a beta code. Systems can only be created on the platform, not through the CLI or MCP. Sign up for early access.
All hosted API access is account-scoped and authenticated. Access to Pretorin-hosted services and any returned account-scoped data is governed by the applicable platform terms in addition to the open-source license for this repository.
Login
pretorin login
Options:
| Flag | Description |
|---|---|
--api-key, -k | API key (will prompt if not provided) |
--api-url | Custom API base URL (for self-hosted instances) |
You’ll be prompted to enter your API key. Credentials are stored in ~/.pretorin/config.json.
If you’re already authenticated, pretorin login validates your existing key against the API and skips the prompt. To re-authenticate with a different key, pass it explicitly:
pretorin login --api-key <new-key>
If you log into a different API endpoint or switch API keys, Pretorin clears the stored active system + framework context so stale scope does not bleed into the new environment.
Verify Authentication
$ pretorin whoami
╭──────────────────────────────── Your Session ────────────────────────────────╮
│ Status: Authenticated │
│ API Key: pretorin...9v7o │
│ API URL: https://platform.pretorin.com/api/v1/public │
│ Frameworks Available: 8 │
╰──────────────────────────────────────────────────────────────────────────────╯
For machine-readable output, use the global --json flag:
pretorin --json whoami
Logout
Clear stored credentials:
pretorin logout
API Key via Environment Variable
You can set your API key via environment variable instead of pretorin login. The environment variable takes precedence over stored config:
export PRETORIN_API_KEY=pretorin_your_key_here
This is useful for CI/CD pipelines and containerized environments.
Customer-Managed Air-Gapped Installs
Use this guide when Pretorin is installed from a customer-managed or air-gapped deployment bundle and the CLI needs to talk to that private platform instead of the hosted Pretorin service.
The platform bundle owns Kubernetes install, data seeding, embedding, and AI provider validation. The CLI owns developer and agent access to the installed platform.
Security Notes
Do not paste secret values, decoded Kubernetes secrets, API tokens, model API keys, or full environment dumps into support tickets or chat. The commands below intentionally check non-secret configuration values or secret key names only.
When validating secrets, confirm that required keys exist without decoding their values:
kubectl get secret -n pretorin pretorin-platform-secrets \
-o go-template='{{range $k, $_ := .data}}{{println $k}}{{end}}'
Platform Validation
After the platform is installed and object storage is initialized, run the bundle smoke test from the deployment bundle:
NAMESPACE=pretorin scripts/customer/validate-airgap-install.sh
The smoke test runs inside the deployed API pod and verifies:
- database connectivity
- seeded framework, package, source, document requirement, and crosswalk data
- NIST 800-53 catalog presence
- OSCAL control embedding coverage and vector dimensions
- direct local AI provider chat and embedding calls
- API-to-AI service connectivity
- dashboard AI chat streaming and chat message persistence
For staged troubleshooting, skip chat first:
NAMESPACE=pretorin scripts/customer/validate-airgap-install.sh --skip-chat
That confirms data seeding, embeddings, provider reachability, and AI service health before testing the full streaming chat path.
CLI Configuration
Point the CLI at the private platform public API endpoint:
pretorin config set platform_api_base_url https://<platform-host>/api/v1/public
pretorin config set model_api_base_url https://<platform-host>/api/v1/public/model
pretorin whoami
pretorin frameworks list
pretorin config set platform_api_base_url prompts for an API key for the new
endpoint and validates it before saving the change.
For non-interactive hosts, use environment variables:
export PRETORIN_API_KEY=<platform-api-token>
export PRETORIN_PLATFORM_API_BASE_URL=https://<platform-host>/api/v1/public
export PRETORIN_MODEL_API_BASE_URL=https://<platform-host>/api/v1/public/model
pretorin whoami
pretorin frameworks list
If you use MCP, the MCP server inherits the same CLI configuration:
pretorin mcp-serve
For Codex, Claude, Cursor, and other MCP client setup, see MCP Setup Guides.
Agent Runtime Notes
For pretorin agent run, model credential precedence is:
OPENAI_API_KEYconfig.api_keyconfig.openai_api_key
If you want the agent runtime to use the customer platform model endpoint, keep
PRETORIN_MODEL_API_BASE_URL pointed at:
https://<platform-host>/api/v1/public/model
If OPENAI_API_KEY is set in the shell, it overrides stored Pretorin
credentials for model calls. Unset it when you expect model calls to route
through the customer Pretorin platform.
Common Issues
| Symptom | Likely cause | First check or fix |
|---|---|---|
pretorin whoami or pretorin frameworks list hits hosted Pretorin | CLI base URL is still using hosted config | Run pretorin config list, then set platform_api_base_url to https://<platform-host>/api/v1/public. |
| CLI returns 401 or 403 | API key is for another endpoint, expired, or missing required scopes | Run pretorin login or pretorin config set platform_api_base_url ... and enter a token from the customer platform. |
pretorin agent run uses the wrong model credentials | Shell OPENAI_API_KEY overrides stored CLI credentials | Unset shell OPENAI_API_KEY, or intentionally set PRETORIN_MODEL_API_BASE_URL for the customer endpoint. |
AI provider validation failed during platform install | OPENAI_BASE_URL is wrong, missing /v1, or unreachable from the cluster | In the deployment environment, run python -m app.cli.validate_ai_provider inside the API pod and confirm DNS, port, TLS, and provider path. |
| Provider calls time out | NetworkPolicy blocks API or AI egress to the local model endpoint | Add matching API and AI NetworkPolicy egress rules, then rerun Helm upgrade. |
OPENAI_API_KEY is required or provider env is missing | Platform secret was not created or was created before env vars were exported | Rerun scripts/customer/create-customer-secrets.sh, then restart API and AI deployments. |
| Embedding count is zero or below the control count | The embedding hook failed, is still running, or the API does not have the local embedding model env | Check pretorin-api-embedding-sync-* job logs and confirm API env includes OPENAI_BASE_URL and OPENAI_EMBEDDING_MODEL. |
| Embedding dimension mismatch | Local embedding model does not return 1536-dimensional vectors | Use a 1536-dimension embedding model for OPENAI_EMBEDDING_MODEL. |
| Data seeding fails or NIST 800-53 is missing | Framework seed hook did not complete | Check pretorin-api-seed-frameworks-* job logs and rerun Helm upgrade after fixing the error. |
Smoke test passes with --skip-chat but fails without it | Provider supports basic calls but not streaming chat, tool calling, or the configured chat model | Confirm the model supports streaming chat completions and tool calls; update OPENAI_MODEL if needed. |
| Chat stream emits an error after a session is created | AI service can start the request but failed during agent execution | Check deployment/pretorin-ai logs around the smoke-test timestamp. |
Useful platform-side checks:
kubectl get pods,jobs -n pretorin
kubectl logs -n pretorin job/<failed-job-name>
kubectl exec -n pretorin deployment/pretorin-api -- \
sh -c 'env | grep -E "^(OPENAI_BASE_URL|OPENAI_MODEL|OPENAI_EMBEDDING_MODEL|OPENAI_USE_RESPONSES|AI_REQUIRE_LOCAL_PROVIDER|AI_PROVIDER_KIND|AI_PROVIDER_DEFAULT_PROFILE_ID|AI_PROVIDER_DEFAULT_PROFILE_NAME|AI_SERVICE_URL)="'
kubectl exec -n pretorin deployment/pretorin-ai -- \
sh -c 'env | grep -E "^(OPENAI_BASE_URL|OPENAI_MODEL|OPENAI_EMBEDDING_MODEL|OPENAI_USE_RESPONSES|AI_REQUIRE_LOCAL_PROVIDER|AI_PROVIDER_KIND|AI_PROVIDER_DEFAULT_PROFILE_ID|AI_PROVIDER_DEFAULT_PROFILE_NAME|AI_SERVICE_URL)="'
What Passing Looks Like
A healthy install can:
- return
pretorin whoami - list seeded frameworks with
pretorin frameworks list - run
scripts/customer/validate-airgap-install.shwithout failures - use chat in the web UI
- route MCP tools through
pretorin mcp-serve - route
pretorin agent runthrough the configured customer model endpoint
Quick Start
After installing and authenticating, here are some common first steps.
Browse Frameworks
List all available compliance frameworks:
pretorin frameworks list
Get details on a specific control:
pretorin frameworks control nist-800-53-r5 ac-02
Set Up Context
Set your active system and framework for platform operations:
# Interactive selection
pretorin context set
# Or explicit
pretorin context set --system "My Application" --framework fedramp-moderate
Create Evidence
Create a local evidence file:
pretorin evidence create ac-02 fedramp-moderate \
--description "Role-based access control in Azure AD" \
--artifact "**Evidence**\n- Verified RBAC role bindings in Azure AD\n- Reviewed conditional access policies" \
--type configuration \
--name "RBAC Configuration"
Push evidence to the platform:
pretorin evidence push
Run an Agent Task
Use the Codex agent for compliance analysis:
pretorin agent run "Assess AC-02 implementation gaps for my system"
Or use a predefined skill:
pretorin agent run --skill gap-analysis "Analyze my system compliance gaps"
Connect Your AI Tool
If you use Claude Code, Codex CLI, or another MCP-compatible AI tool:
# Install the skill (teaches your agent how to use Pretorin tools)
pretorin skill install
# Add the MCP server (Claude Code example)
claude mcp add --transport stdio pretorin -- pretorin mcp-serve
# Then ask your AI agent about compliance
# "What controls are in the Access Control family for FedRAMP Moderate?"
Check install status with pretorin skill status. See the MCP Setup Guides for other tools.
Run a Recipe
Recipes are markdown-plus-scripts playbooks that the calling agent invokes through MCP for evidence capture, baseline scanning, and other procedures:
# List available recipes (built-in + user + project)
pretorin recipe list
# Show one recipe's manifest and prose body
pretorin recipe show inspec-baseline
# Scaffold a new recipe in ~/.pretorin/recipes/<id>/
pretorin recipe new my-first-recipe
See Authoring Recipes for the full guide.
Browse STIGs and CCIs
Look up STIG benchmarks, rules, and CCI traceability:
# List available STIG benchmarks
pretorin stig list
# View STIG benchmark details
pretorin stig show <stig_id>
# Trace a control's full CCI + STIG chain
pretorin cci chain <control-id>
Run the Demo Walkthrough
An interactive demo script is included in the repository:
bash tools/demo-walkthrough.sh
Framework Browsing
The frameworks command group lets you browse compliance frameworks, control families, and individual controls. The browsing commands documented on this page are read-only and available to all authenticated users.
The same command group also exposes write-side commands for authoring, validating, uploading, forking, and rebasing custom frameworks — see Custom Framework Authoring at the bottom of this page for a quick index, or jump directly to the Custom Frameworks guide for the end-to-end workflow.
List All Frameworks
$ pretorin frameworks list
[°~°] Consulting the compliance archives...
Available Compliance Frameworks
┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┓
┃ ID ┃ Title ┃ Version ┃ Tier ┃ Families ┃ Controls ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
│ cmmc-l1 │ CMMC 2.0 │ 2.0 │ tier1_essen… │ 6 │ 17 │
│ │ Level 1 │ │ │ │ │
│ cmmc-l2 │ CMMC 2.0 │ 2.0 │ tier1_essen… │ 14 │ 110 │
│ │ Level 2 │ │ │ │ │
│ ... │ │ │ │ │ │
└─────────────┴─────────────┴─────────────┴──────────────┴──────────┴──────────┘
Total: 26 framework(s)
The ID column is what you use in all other commands.
The exact total and available framework set can vary as the platform catalog expands. Use pretorin frameworks list to see the live catalog available to your account.
Get Framework Details
$ pretorin frameworks get fedramp-moderate
[°~°] Gathering framework details...
╭───────────────── Framework: FedRAMP Rev 5 Moderate Baseline ─────────────────╮
│ ID: fedramp-moderate │
│ Title: FedRAMP Rev 5 Moderate Baseline │
│ Version: fedramp2.1.0-oscal1.0.4 │
│ OSCAL Version: 1.0.4 │
│ Tier: tier1_essential │
│ Category: government │
│ Published: 2024-09-24T02:24:00Z │
╰──────────────────────────────────────────────────────────────────────────────╯
List Control Families
$ pretorin frameworks families nist-800-53-r5
[°~°] Gathering control families...
Control Families - nist-800-53-r5
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━┓
┃ ID ┃ Title ┃ Class ┃ Controls ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━┩
│ access-control │ Access Control │ ac │ 25 │
│ audit-and-accountability │ Audit and Accountability │ au │ 16 │
│ awareness-and-training │ Awareness and Training │ at │ 6 │
│ configuration-management │ Configuration Management │ cm │ 14 │
│ ... │ │ │ │
└─────────────────────────────┴─────────────────────────────┴───────┴──────────┘
Important: Family IDs are slugs like
access-control, not short codes likeac. The short code is shown in the Class column for reference, but commands require the full slug ID.
CMMC Family IDs
CMMC frameworks use level-specific family slugs:
$ pretorin frameworks families cmmc-l2
CMMC family IDs include the level suffix, e.g., access-control-level-2 instead of access-control.
Get Family Details
pretorin frameworks family nist-800-53-r5 access-control
List Controls
# Family filter via positional argument
pretorin frameworks controls nist-800-53-r5 access-control
# Family filter via flag (equivalent)
pretorin frameworks controls nist-800-53-r5 --family access-control --limit 10
# All controls in the framework (no family filter)
pretorin frameworks controls fedramp-moderate
The family filter is optional and may be passed as a positional argument or with --family/-f. Without --limit (default 0), all matching controls are shown.
Important: Control IDs are zero-padded — use
ac-01, notac-1. See Control ID Formats for details.
Get Control Details
$ pretorin frameworks control nist-800-53-r5 ac-02
[°~°] Looking up control details...
╭─────────────────────────────── Control: AC-02 ───────────────────────────────╮
│ ID: ac-02 │
│ Title: Account Management │
│ Class: SP800-53 │
│ Type: organizational │
│ │
│ AI Guidance: Available │
╰──────────────────────────────────────────────────────────────────────────────╯
Parameters:
- ac-02_odp.01: prerequisites and criteria
- ac-02_odp.02: attributes (as required)
- ac-02_odp.03: personnel or roles
- ac-02_odp.04: policy, procedures, prerequisites, and criteria
- ac-02_odp.05: personnel or roles
Brief Mode
By default, the full control is shown including statement, guidance, and references. Use --brief to show only the basic info panel:
$ pretorin frameworks control nist-800-53-r5 ac-02 --brief
The default (no flag) includes:
- Statement — the formal control requirement text
- Guidance — implementation guidance from the framework
- Related Controls — other controls that relate to this one
Common Mistakes
Using the wrong ID format produces an error:
$ pretorin frameworks control nist-800-53-r5 ac-1
[°~°] Looking up control details...
[°︵°] Couldn't find control ac-1 in nist-800-53-r5
Try pretorin frameworks controls nist-800-53-r5 to see available controls.
Use zero-padded IDs: ac-01, not ac-1.
Framework Metadata
Get per-control metadata for a framework:
pretorin frameworks metadata nist-800-53-r5
Submit Artifacts
Submit a compliance artifact JSON file:
pretorin frameworks submit-artifact artifact.json
See Artifact Generation for the artifact schema.
JSON Output
All framework commands support JSON output for scripting and AI agents:
pretorin --json frameworks list
pretorin --json frameworks control nist-800-53-r5 ac-02
Custom Framework Authoring
In addition to the read-only browsing commands above, the frameworks group exposes the write-side commands that drive the custom-framework revision lifecycle. These let you author your own catalog, validate it locally, upload it as a draft revision, and fork or rebase against an upstream Pretorin-managed framework.
| Command | Description |
|---|---|
pretorin frameworks init-custom <id> | Scaffold a minimal valid unified.json for a new custom framework. |
pretorin frameworks validate-custom <unified.json> | Validate a unified.json artifact against the bundled JSON Schema. |
pretorin frameworks build-custom <input> -f <id> | Normalize an OSCAL or custom catalog into uploadable unified.json. |
pretorin frameworks upload-custom <unified.json> [--publish] | Upload as a draft revision, optionally publishing in one step. |
pretorin frameworks fork-framework <upstream-id> | Create a linked-fork draft from an upstream framework. |
pretorin frameworks rebase-fork <fork-id> | Create a rebase draft for a fork against the latest upstream revision. |
pretorin frameworks revisions <framework-id> | List all draft and published revisions for a framework. |
pretorin frameworks export-oscal <unified.json> | Regenerate an OSCAL catalog from a unified.json artifact. |
See the Custom Frameworks guide for the full end-to-end workflow, the supported input shapes recognized by build-custom, and the linked-fork / rebase model.
Context Management
The context command group manages your active system and framework scope. Platform-backed compliance operations (evidence, narratives, issues, monitoring, control status) run inside exactly one system + framework pair at a time.
This works similarly to kubectl config use-context — set your scope once, then run commands within it.
List Available Systems
$ pretorin context list
[°~°] Fetching your systems...
Your Systems
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ System ┃ Framework ID ┃ Progress % ┃ Status ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ My Application │ nist-800-53-r5 │ 42% │ in_progress │
│ My Application │ fedramp-moderate │ 28% │ in_progress │
│ Internal Tool │ cmmc-l2 │ 75% │ implemented │
└──────────────────┴────────────────────┴────────────┴───────────┘
Set Active Context
# Interactive — prompts for system and framework selection
pretorin context set
# Explicit
pretorin context set --system "My Application" --framework nist-800-53-r5
# Skip automatic source verification after setting context
pretorin context set --system "My Application" --framework nist-800-53-r5 --no-verify
| Option | Description |
|---|---|
--system / -s | System name or ID |
--framework / -f | Framework ID (e.g., fedramp-moderate) |
--no-verify | Skip source verification after setting context |
Pretorin stores the canonical system ID for stability and also caches the last known system name for display. After setting context, source verification runs automatically unless --no-verify is passed. If you change API keys or platform endpoints with pretorin login, the stored active context is cleared automatically so old scope does not leak into the new environment.
Show Current Context
$ pretorin context show
╭──────────────────────── Active Context ─────────────────────────╮
│ System: My Application (sys-1234...) │
│ Framework: nist-800-53-r5 │
│ Progress: 42% │
│ Status: in_progress │
╰─────────────────────────────────────────────────────────────────╯
# Compact summary for shell use
pretorin context show --quiet
# Fail fast if the stored context is missing, stale, or cannot be verified
pretorin context show --quiet --check
context show validates the stored system and framework against the platform when credentials are available. If the system has been deleted or the framework is no longer attached, the command reports that state explicitly instead of silently showing a stale context.
Verify Context
Verify the active context against source attestation:
# Full output
pretorin context verify
# Compact output with custom TTL
pretorin context verify --ttl 7200 --quiet
| Option | Description |
|---|---|
--ttl | Verification TTL in seconds (default: 3600) |
--quiet / -q | Compact output |
Source Manifest
Show the resolved source manifest and evaluate it against detected sources:
pretorin context manifest
pretorin context manifest --quiet
Clear Context
pretorin context clear
Single-Scope Enforcement
All platform write operations must target exactly one system + framework pair. This includes:
- Evidence creation and push
- Narrative updates
- Control issues
- Monitoring events
- Control status updates
If you need to work across multiple frameworks (e.g., fedramp-low and fedramp-moderate), run them as separate operations:
# Work on FedRAMP Moderate
pretorin context set --system "My App" --framework fedramp-moderate
pretorin evidence push
# Switch to FedRAMP Low
pretorin context set --system "My App" --framework fedramp-low
pretorin evidence push
Some commands also accept explicit --system and --framework flags, which override the stored context for that invocation.
Evidence Commands
The evidence command group manages local evidence files and syncs them to the Pretorin platform.
Create Local Evidence
pretorin evidence create ac-02 fedramp-moderate \
--name "RBAC Configuration" \
--description "Role-based access control in Azure AD" \
--artifact-content "**Evidence**\n\n- RBAC roles are configured in Azure AD." \
--type configuration
Creates a markdown file under evidence/<framework>/<control>/ with YAML frontmatter containing metadata (control ID, framework, name, type, status, short description). The Markdown body is the evidence artifact that will be sent as artifact_content when pushed.
| Option | Description |
|---|---|
--description / -d | Short human summary of what the evidence demonstrates (required) |
--artifact-content / --artifact | Markdown body containing the actual evidence (required) |
--type / -t | Evidence type (required) — see Evidence Types for canonical values |
--name / -n | Evidence name (defaults to a description summary) |
The CLI does not default --type to policy_document; you get a hard error listing canonical types if you omit it or pass an unknown value. Evidence artifacts should describe only the artifact and what it supports. Gaps, missing evidence, ambiguity, and remediation work belong in pretorin issues, not in evidence or narratives. Markdown headings (#, ##, etc.) are automatically converted to bold section labels with spacing because headings can break report rendering.
Format Evidence Markdown
Use this when you already have Markdown with headings and want the report-safe evidence style:
# Print reformatted Markdown to stdout
pretorin evidence format-markdown artifact.md
# Rewrite in place
pretorin evidence format-markdown artifact.md --write
# CI check
pretorin evidence format-markdown artifact.md --check
List Local Evidence
# List all local evidence
pretorin evidence list
# Filter by framework
pretorin evidence list --framework fedramp-moderate
Push Evidence to Platform
pretorin evidence push
Pushes local evidence files to the platform using find-or-create upsert logic. Exact matches are reused and reported separately.
Requires an active single scope from pretorin context set, unless both --system and --framework are provided explicitly.
Search Platform Evidence
# Search by control
pretorin evidence search --control-id ac-02 --framework-id fedramp-moderate
# Search by system
pretorin evidence search --system "My Application" --framework-id fedramp-moderate --limit 100
Upload Evidence File
Upload a file directly as evidence:
pretorin evidence upload screenshot.png ac-02 fedramp-moderate \
--name "MFA Screenshot" --type screenshot
pretorin evidence upload config.yaml ac-06 fedramp-moderate \
--name "Auth Config" --type configuration --description "IdP auth config"
Creates an evidence record with the uploaded file and links it to the specified control. The file’s SHA-256 checksum is computed locally and verified server-side for integrity.
| Option | Description |
|---|---|
--name / -n | Evidence name (required) |
--type / -t | Evidence type (default: other) |
--description / -d | Evidence description |
--system / -s | System name or ID (uses active context if omitted) |
Upsert Evidence
Find-or-create evidence and link it to a control:
pretorin evidence upsert ac-02 fedramp-moderate \
--name "RBAC Configuration" \
--description "Role mapping in IdP" \
--artifact-content "**Evidence**\n\n- Role mapping is enforced in the IdP export." \
--type configuration
--description is the short human summary. --artifact-content is the Markdown evidence body that the platform materializes as the stored artifact. This searches for an exact match on (name + description + type + control + framework) within the active system scope. If found, it reuses the existing item; otherwise, it creates a new one. It then ensures the evidence is linked to the specified control.
Code Context Options
When upserting evidence, you can attach source code context:
| Option | Description |
|---|---|
--code-file | Path to source file |
--code-lines | Line range (e.g., 10-25) |
--code-repo | Git repository URL |
--code-commit | Git commit hash |
If --code-repo or --code-commit are not provided, the CLI auto-populates them from the attested source verification snapshot when available.
Audit Sufficiency Options
For evidence whose auditor sufficiency depends on the period it covers or the query/filter that produced it (typical for log extracts, scan exports, and continuous-compliance feeds):
| Option | Description |
|---|---|
--coverage-start | ISO 8601 start of the period the evidence content describes |
--coverage-end | ISO 8601 end of the period; omit for point-in-time evidence |
--capture-query | Query / filter / command that produced the artifact (IPE reproducibility) |
--cadence-days | Refresh cadence in days (1–365); evidence requires re-verification after this window. Server computes expires_at from this value. |
Cadenced evidence transitions to expired automatically when expires_at lapses. Prefer evidence validate (below) so the CLI compares the fresh source-material hash before re-verifying.
Source Provenance Options
Audit-grade provenance metadata, captured into audit_metadata and used by evidence validate to detect drift against the original source material:
| Option | Description |
|---|---|
--source-uri | Stable source path, URL, object id, report id, or export id used for provenance |
--source-label | Human-readable source title or section label for auditors |
--source-locator | Precise source locator, e.g. section id or lines 84-88 |
--source-excerpt | Short quoted excerpt or source material used to produce the evidence claim |
--capture-method | Source capture method, e.g. repository_file_read, api_export, scanner_output |
Link Evidence to a Control
Link an existing platform evidence item to a control:
pretorin evidence link ev-abc123 ac-02
pretorin evidence link ev-abc123 ac-02 --framework-id fedramp-moderate --system "My System"
Options:
--framework-id / -f— Framework ID (uses active context if omitted)--system / -s— System name or ID (uses active context if omitted)
Link Evidence to a CCI Implementation
Attach evidence to a per-system CCI implementation row:
pretorin evidence link-cci ev-abc123 <cci_implementation_id>
pretorin evidence link-cci ev-abc123 <cci_implementation_id> --system "My System"
Options:
--system / -s— System name or ID (uses active context if omitted)--override-system-mismatch— Permit cross-system attachment (must be paired with--override-reason)--override-reason TEXT— Justification recorded with the override
The CCI implementation UUID can be obtained from pretorin cci impl or from the CCI status rollup.
Link Evidence to a STIG Rule Workflow
Attach remediation proof, mitigating-control documentation, or waiver-justification artifacts to a STIG rule:
pretorin evidence link-stig ev-abc123 <stig_rule_id>
pretorin evidence link-stig ev-abc123 <stig_rule_id> --system "My System"
The first link to a given (system, stig_rule) pair lazy-creates the workflow row on the platform.
Options match link-cci: --system, --override-system-mismatch, --override-reason.
Mark Evidence Current
Re-affirm that an evidence item is still current — bumps expires_at by the evidence’s refresh_cadence_days, transitions status from expired back to valid if needed, and auto-resolves any open evidence.expiring / evidence.expired monitoring events:
pretorin evidence mark-current ev-abc123
pretorin evidence mark-current ev-abc123 --system "My System"
Options:
--system / -s— System name or ID (uses active context if omitted)
Fails with HTTP 400 if the evidence has no refresh_cadence_days set — only cadenced evidence (set via evidence upsert --cadence-days N) can be marked current. This is the entry-point for the continuous-compliance refresh loop: cron jobs, recipes, and operators all call mark-current to confirm evidence is still representative without rewriting its body.
Validate Evidence Source
Validate file-backed evidence against its recorded audit_metadata.content_hash:
pretorin evidence validate ev-abc123 --system "My System"
# Resolve relative source_uri values against a specific repo checkout
pretorin evidence validate ev-abc123 --source-root /path/to/repo
# Provide the replacement artifact body and reviewer note up front when drift is expected
pretorin evidence validate ev-abc123 \
--artifact-content "**Evidence**\n\n- Updated RBAC mapping after Q2 IdP migration." \
--description "RBAC mapping (post Q2 IdP migration)" \
--drift-note "Source file rotated during Q2 IdP migration; review updated artifact."
If the fresh source-material hash is unchanged, the CLI calls mark-current and Pretorin records a re_verified lineage event. If the source changed, the CLI calls the artifact update endpoint with a new Markdown artifact and a drift_note so reviewers see the drift instead of silently marking stale evidence current.
| Option | Description |
|---|---|
--system / -s | System name or ID (uses active context if omitted) |
--source-root | Root directory for relative file-backed source_uri values (defaults to current directory) |
--artifact-content / --artifact | Updated Markdown artifact body to use if drift is detected; otherwise an excerpt artifact is generated |
--description / -d | Updated short summary to use if drift is detected |
--drift-note | Reviewer-facing note created when drift is detected (defaults to a generic review-needed prompt) |
Delete Evidence
# Delete with confirmation prompt
pretorin evidence delete ev-abc123
# Skip confirmation (for automation)
pretorin evidence delete ev-abc123 --yes
# Explicit system scope
pretorin evidence delete ev-abc123 --system "My Application" --framework-id fedramp-moderate --yes
Permanently deletes an evidence item from the platform. This is system-scoped and requires WRITE access. Associated evidence embeddings are removed as part of the delete lifecycle.
| Option | Description |
|---|---|
--system / -s | System name or ID (uses active context if omitted) |
--framework-id / -f | Framework ID (uses active context if omitted) |
--yes / -y | Skip confirmation prompt |
Evidence Attestations (DSSE)
The platform may sign each evidence record with a DSSE in-toto attestation envelope (ADR 0003) so auditors and downstream tooling can independently verify integrity and provenance. Two commands surface that envelope from the CLI:
# Fetch the latest signed envelope as a pretty summary
pretorin evidence attestation get ev-abc123
# Emit raw DSSE JSON (pipe to cosign or any DSSE verifier)
pretorin evidence attestation get ev-abc123 --json | cosign verify-blob-attestation --key <pub> --signature -
# List all attestations for one evidence record (newest first)
pretorin evidence attestation get ev-abc123 --lineage
# Verify the signature locally against the platform's key registry
pretorin evidence attestation verify ev-abc123 # exit 0 on success, 1 on failure
pretorin evidence attestation verify ev-abc123 --env staging
pretorin evidence attestation verify ev-abc123 --key-fingerprint <sha256-of-DER-SPKI>
The verifier ports the platform’s own implementation (apps/api/app/services/attestation/verifier.py). It checks the ECDSA P-256 + SHA-256 signature over the DSSE PAE bytes (not the canonical JSON Statement bytes — a subtle but load-bearing distinction), resolves the signing key through GET /api/v1/public/keys rather than trusting any embedded PEM, and honors key validity windows, revocation timestamps, and environment labels.
See Evidence Attestation for the full verification model, CI integration, and a worked example.
Evidence Types
Valid evidence types:
| Type | Description |
|---|---|
policy_document | Policy or procedure document |
screenshot | Screenshot evidence |
screen_recording | Screen recording |
log_file | Log file extract |
configuration | Configuration file or setting |
test_result | Test output or report |
certificate | Certificate or attestation document |
attestation | Signed attestation |
code_snippet | Code excerpt |
repository_link | Link to source repository |
scan_result | Security scan output |
interview_notes | Interview or assessment notes |
system_spec_inventory_attestation | System-spec inventory attestation snapshot |
system_spec_boundary_diagram | System-spec boundary diagram snapshot |
system_spec_network_dfd | System-spec network data-flow diagram snapshot |
system_spec_ppsm | System-spec PPSM snapshot |
system_spec_interconnection | System-spec interconnection snapshot |
other | Other evidence type |
AI-Drift Normalization
Non-CLI write paths (MCP handlers, agent tools, upsert_evidence workflow, campaign apply) run a client-side normalizer before submitting evidence to the platform. It maps known AI-drift aliases to canonical types (e.g. audit_log → log_file, plural test_results → test_result, screenshoot → screenshot) and uses difflib fuzzy matching for novel typos before falling back to other. The CLI itself does not run the normalizer; users get a hard error listing the canonical types and can self-correct.
Markdown Artifact Requirements
Evidence descriptions are short summaries. The actual evidence belongs in artifact_content / --artifact-content as Markdown:
- Markdown headings are allowed in the artifact body.
- Markdown images are not accepted on JSON evidence writes; upload files with
evidence upload. - Source path, line, timestamp, and capture details belong in structured
audit_metadata, not appended to the description.
These requirements are validated before push/upsert operations.
Narrative Commands
The narrative command group manages implementation narratives for controls. Narratives describe how a specific control is implemented within your system.
Create Local Narrative
pretorin narrative create ac-02 fedramp-moderate \
-c "- RBAC enforced via IdP\n\n\`\`\`yaml\nroles:\n admin: ...\n\`\`\`"
Creates a local markdown file at narratives/<framework>/<control>/<slug>.md with YAML frontmatter. Markdown is validated at create time (same rules as push).
Options:
--content / -c— Narrative content (required)--name / -n— Custom name (defaults to<control>-<framework>)--ai-generated— Mark the narrative as AI-generated
List Local Narratives
pretorin narrative list
pretorin narrative list --framework fedramp-moderate
Displays a table of local narrative files: Control, Framework, Name, AI Generated, Synced.
Push Narratives
pretorin narrative push --dry-run
pretorin narrative push
Batch-pushes all unsynced local narratives to the platform. After a successful push, the local file’s platform_synced frontmatter is set to true.
Get Current Narrative
pretorin narrative get ac-02 fedramp-moderate --system "My System"
Returns the current narrative text, status, and AI confidence metadata when present.
Push a Single File (Legacy)
pretorin narrative push-file ac-02 fedramp-moderate "My System" narrative-ac02.md
Reads a markdown or text file and submits it as the implementation narrative for the specified control.
Markdown Quality Requirements
Narratives must be auditor-ready markdown:
- No markdown headings (
#,##, etc.) - At least two rich markdown elements (fenced code blocks, tables, lists, or links)
- At least one structural element (code block, table, or list)
- No markdown images (temporarily disabled pending platform image upload support)
These requirements are validated at create time and before push.
Generating Narratives with AI
To generate narratives using the agent runtime:
pretorin agent run --skill narrative-generation "Generate narrative for AC-02"
Or use the MCP server’s generate_control_artifacts tool for read-only drafts through your AI agent.
See Skills for more on agent-powered narrative generation.
No-Hallucination Requirements
Generated narratives must only document observable facts:
- Treat existing Pretorin narratives, issues, and status fields as a starting point, not proof that a control gap exists.
- Before writing a narrative update or issue, inspect the relevant implementation in the workspace and connected systems.
- If observed implementation is stronger than the current platform record, update the narrative to match the observed implementation and record any remaining evidence gap as an issue.
- Do not include gap lists, missing-information placeholders, unresolved caveats, or remediation backlog in narrative text.
Issues Commands
The issues command group manages control implementation issues. Issues are the durable home for gaps, missing evidence, unresolved ambiguity, and remediation work.
Narratives should describe the implemented control state only. Evidence should describe the artifact and what it supports only. Do not use narratives or evidence descriptions as a workaround issue log.
Create Local Issue
pretorin issues create ac-02 fedramp-moderate \
-c "Gap: Missing SSO evidence. Manual next step: collect IdP configuration screenshots."
Creates a local markdown file at issues/<framework>/<control>/<slug>.md with YAML frontmatter. Existing local notes/ files remain supported through the deprecated pretorin notes compatibility commands.
Options:
--content / -c— Issue content (required)--name / -n— Custom name (defaults to content summary)
Push Issues
pretorin issues push --dry-run
pretorin issues push
Batch-pushes all unsynced local issues to the platform. Issues are append-only on the platform. After a successful push, the local file’s platform_synced frontmatter is set to true.
List Issues
pretorin issues list --local
pretorin issues list --local --framework fedramp-moderate
pretorin issues list ac-02 fedramp-moderate --system "My System"
Use --local to list local issue files. Without --local, provide a control and framework to list platform issues for that control.
Add an Issue
pretorin issues add ac-02 fedramp-moderate \
--content "Gap: Missing SSO evidence. Manual next step: collect IdP configuration screenshots."
Options:
--content / -c— Issue content (required)--system / -s— System name or ID (uses active context if omitted)
Resolve or Reopen an Issue
pretorin issues resolve ac-02 fedramp-moderate <issue_id> --resolution-note "SSO config verified in IdP logs."
pretorin issues resolve ac-02 fedramp-moderate <issue_id> --reopen
Options:
--system / -s— System name or ID--reopen— Reopen a resolved issue instead of resolving it--resolution-note / --justification— Required when resolving; stored as the closure audit trail--content / -c— Optional updated issue content--pinned— Optional pinned state
Compatibility
pretorin notes ... remains available as a deprecated alias for one compatibility window. Existing ./notes/<framework>/<control>/<slug>.md files can still be listed and pushed through that command group. New local files should use ./issues/.
Notes Commands
The notes command group is a deprecated compatibility alias for control issues. Prefer pretorin issues ... for new work. Existing local notes/ files remain supported for one compatibility window.
Issues are the durable home for gaps, missing evidence, unresolved ambiguity, and remediation work. Narratives should describe implemented control state only, and evidence should describe artifacts and what they support only.
Create Local Note
pretorin notes create ac-02 fedramp-moderate \
-c "Gap: Missing SSO evidence. Manual next step: collect IdP configuration screenshots."
Creates a local markdown file at notes/<framework>/<control>/<slug>.md with YAML frontmatter. No markdown validation is applied to notes.
Options:
--content / -c— Note content (required)--name / -n— Custom name (defaults to content summary)
Push Notes
pretorin notes push --dry-run
pretorin notes push
Batch-pushes all unsynced local notes to the platform. Notes are append-only on the platform. After a successful push, the local file’s platform_synced frontmatter is set to true.
List Local Notes
pretorin notes list --local
pretorin notes list --local --framework fedramp-moderate
Use the --local flag to list local note files instead of platform notes.
List Platform Notes
pretorin notes list ac-02 fedramp-moderate --system "My System"
Add a Note (Direct to Platform)
pretorin notes add ac-02 fedramp-moderate \
--content "Gap: Missing SSO evidence. Manual next step: collect IdP configuration screenshots."
pretorin notes add ac-02 fedramp-moderate \
--content "MFA verified" --system "My System"
Options:
--content / -c— Note content (required)--system / -s— System name or ID (uses active context if omitted)
Resolve or Reopen a Note
# Resolve a note with an audit-trail justification
pretorin notes resolve ac-02 fedramp-moderate <note_id> --resolution-note "SSO config verified in IdP logs."
# Resolve with updated content and a resolution justification
pretorin notes resolve ac-02 fedramp-moderate <note_id> --resolution-note "SSO config verified." --content "Updated note text."
# Reopen a resolved note
pretorin notes resolve ac-02 fedramp-moderate <note_id> --reopen
Options:
--system / -s— System name or ID--reopen— Reopen a resolved note instead of resolving it--resolution-note / --justification— Required when resolving; stored as the closure audit trail--content / -c— Optional updated note content--pinned— Optional pinned state
Gap Issue Format
When adding issues for unresolved gaps, use this structured format:
Gap: <short title>
Observed: <what was verifiably found>
Missing: <what could not be verified>
Why missing: <access/system limitation>
Manual next step: <explicit user/platform action>
This format ensures consistency across CLI, MCP, and agent workflows when documenting compliance gaps. Prefer pretorin issues add for new work.
Monitoring Commands
The monitoring command group records security and compliance events against a system.
Push a Monitoring Event
pretorin monitoring push --system "My System" --title "Quarterly Access Review" \
--event-type access_review --severity info
Event Types
| Type | Description |
|---|---|
security_scan | Automated security scan result |
configuration_change | Infrastructure or application configuration change |
access_review | Periodic access review or audit |
compliance_check | Compliance posture check or assessment |
Severity Levels
| Severity | Description |
|---|---|
critical | Requires immediate attention |
high | Significant finding |
medium | Moderate finding |
low | Minor finding |
info | Informational event |
Options
| Option | Description |
|---|---|
--system / -s | System name or ID (uses active context if omitted) |
--framework / -f | Framework ID (uses active context if omitted) |
--title / -t | Event title (required) |
--severity | Event severity (default: high) |
--control / -c | Control ID (e.g., sc-07, ac-02) |
--description / -d | Detailed event description |
--event-type | Event type (default: security_scan) |
--update-control-status | Also update the control status to in_progress |
Context Requirement
The monitoring push command requires an active system context. Set it with pretorin context set or pass --system explicitly.
Campaign Workflows
The campaign command group runs bulk compliance operations across multiple controls, policies, or scope questions in a single coordinated run. Campaigns support an external-agent-first pattern with checkpoint persistence and lease-based concurrency for safe fan-out to multiple agents.
Campaign Domains and Modes
| Domain | Mode | Description |
|---|---|---|
controls | initial | Draft new narratives and evidence for controls |
controls | issues-fix | Address platform issues on existing controls |
controls | notes-fix | Deprecated alias for issues-fix |
controls | review-fix | Fix findings from a family review job |
policy | answer | Generate answers for policy questions |
policy | review-fix | Fix findings from a policy review |
scope | answer | Generate answers for scope questions |
scope | review-fix | Fix findings from a scope review |
Control Campaigns
Draft New Narratives for a Family
pretorin campaign controls --mode initial --family AC \
--system "My System" --framework-id fedramp-moderate
Fix Controls with Platform Issues
pretorin campaign controls --mode issues-fix --all-open-issues
Fix Controls after Family Review
pretorin campaign controls --mode review-fix --family AC --review-job <job-id>
Options
| Option | Description |
|---|---|
--system | Target system ID or name |
--framework-id | Target framework ID |
--family | Control family to target (e.g., AC, AU) |
--controls | Specific control IDs (comma-separated) |
--all-controls | Target all controls in the framework |
--mode | Campaign mode: initial, issues-fix, notes-fix, review-fix |
--all-open-issues | Target controls with open issues in the system/framework context |
--issue-source | Optional issue source filter |
--issue-control | Optional comma-separated issue control filter |
--issue-family | Optional issue family filter |
--include-resolved | Include resolved issues in issue discovery |
--artifacts | Artifact types to generate: narratives, evidence, or both (default: both) |
--review-job | Review job ID (required for review-fix mode) |
--concurrency | Number of parallel workers |
--max-retries | Maximum retry attempts per item |
--checkpoint | Path to checkpoint file for resume |
--apply | Apply proposals to platform after completion |
--output | Output mode: auto, live, compact, json |
Policy Campaigns
Answer All Incomplete Policy Questions
pretorin campaign policy --mode answer --all-incomplete
Fix Policy Review Findings
pretorin campaign policy --mode review-fix --policies <policy-id>
Options
| Option | Description |
|---|---|
--policies | Specific policy IDs (comma-separated) |
--all-incomplete | Target all incomplete policies |
--mode | Campaign mode: answer, review-fix |
--system | Optional system context passthrough |
--concurrency | Number of parallel workers (default: 4) |
--max-retries | Maximum retry attempts per item (default: 2) |
--checkpoint | Path to checkpoint file for resume |
--apply | Apply proposals to platform after completion |
--output | Output mode: auto, live, compact, json |
Scope Campaigns
Answer Scope Questions
pretorin campaign scope --mode answer \
--system "My System" --framework-id fedramp-moderate
Options
| Option | Description |
|---|---|
--system | Target system ID or name (required) |
--framework-id | Target framework ID (required) |
--mode | Campaign mode: answer, review-fix |
--concurrency | Number of parallel workers (default: 4) |
--max-retries | Maximum retry attempts per question (default: 2) |
--checkpoint | Path to checkpoint file for resume |
--apply | Apply proposals to platform after completion |
--output | Output mode: auto, live, compact, json |
Checking Campaign Status
pretorin campaign status --checkpoint .pretorin/campaign-checkpoint.json
Campaign Lifecycle
- Prepare — The campaign snapshots platform state and creates a local checkpoint file
- Claim — Items are claimed with TTL-based leases (safe for multiple agents)
- Draft — Each item gets full context and drafting instructions
- Propose — Proposals are submitted without writing to the platform
- Apply — All accepted proposals are pushed to the platform in one operation
Use --apply to automatically apply after completion, or run campaign status to review before applying.
Vendor Management
The vendor command group manages vendor entities and their evidence documents. Vendors represent external providers (CSPs, SaaS, managed services) or internal teams whose controls your system inherits.
List Vendors
pretorin vendor list
Create a Vendor
pretorin vendor create "AWS" --type csp --description "Primary cloud provider" \
--authorization-level "FedRAMP High P-ATO"
Vendor Types
| Type | Description |
|---|---|
csp | Cloud Service Provider |
saas | Software as a Service |
managed_service | Managed service provider |
internal | Internal team or shared service |
Get Vendor Details
pretorin vendor get <vendor_id>
Update a Vendor
pretorin vendor update <vendor_id> --name "AWS GovCloud" --authorization-level "FedRAMP High"
Delete a Vendor
pretorin vendor delete <vendor_id>
pretorin vendor delete <vendor_id> --force # skip confirmation
Upload Vendor Documents
Upload SOC 2 reports, Customer Responsibility Matrices (CRMs), FedRAMP packages, or other vendor evidence:
pretorin vendor upload-doc <vendor_id> ./aws-soc2-report.pdf \
--name "AWS SOC 2 Type II" \
--description "Annual SOC 2 report covering 2025" \
--attestation-type third_party_attestation
Attestation Types
| Type | Description |
|---|---|
self_attested | Vendor’s own assertion |
third_party_attestation | Independent auditor report (SOC 2, FedRAMP) |
vendor_provided | Documentation provided by vendor |
List Vendor Documents
pretorin vendor list-docs <vendor_id>
Related: Control Inheritance
Once vendors are created and documents uploaded, use the MCP tools or platform to set control responsibility edges:
set_control_responsibility— Mark controls as inherited/sharedgenerate_inheritance_narrative— AI-draft inheritance narratives from vendor docsget_stale_edges/sync_stale_edges— Monitor and sync inheritance
Risk Management
The risk command group manages a system’s risk register: list and create risks, attach artifact links (controls / evidence / findings / vendors), record a mitigation strategy, and refresh AI summaries. The risk library is org-level; everything else is system-scoped — resolve the active system before any risk operation.
Workflow notes
- Risks are system-scoped. Every command except
risk library listtakes a system as its first argument. - Auto-link is opt-in.
risk createandrisk seedonly auto-link controls when--frameworkis supplied and the system hasControlImplementationrows for that framework. Without those, the risk is created with zero links — follow up withrisk link add. - Mitigation is just
risk update. There is no separate/mitigateendpoint. Set--treatment(one ofmitigate/accept/transfer/avoid) plus--treatment-planand--treatment-due-datethrough the update command. - AI refresh is best-effort.
risk refresh-summaryalways re-scores. The AI summary regenerates only if the AI service is up and the org has quota; check whetherai_summary_generated_atadvanced if you need to confirm AI ran.
List Risks
pretorin risk list <system_id>
pretorin risk list <system_id> --category availability --risk-level high --status open
Show a Risk
pretorin risk show <system_id> <risk_id>
Returns the full risk including eager-loaded artifact_links.
Create a Risk
Custom risk with no auto-linking:
pretorin risk create <system_id> \
--title "Phishing campaign against ops team" \
--category confidentiality
Custom risk with mitigation recorded in one call and control auto-linking against a framework:
pretorin risk create <system_id> \
--title "Stolen credential abuse" \
--category confidentiality \
--treatment mitigate \
--treatment-plan "Roll out hardware MFA to all admin accounts" \
--treatment-due-date 2026-06-30 \
--framework nist-800-53-r5 \
--suggested-control-family AC \
--suggested-control-family IA
Treatment values
| Value | Meaning |
|---|---|
mitigate | Reduce likelihood/impact through controls |
accept | Document and accept the residual risk |
transfer | Shift the risk (insurance, vendor SLA, etc.) |
avoid | Eliminate the activity that causes the risk |
Seed from the Library
Bulk-instantiate library templates against a system + framework:
pretorin risk seed <system_id> \
--framework nist-800-53-r5 \
--template-id tpl-phishing \
--template-id tpl-insider \
--template-id tpl-data-loss
Each template is scored against the system, and controls are auto-linked per the template’s suggested_control_families when matching ControlImplementation rows exist.
Update / Mitigate a Risk
This is the mitigation surface — record how a risk will be addressed by updating the same fields:
pretorin risk update <system_id> <risk_id> \
--treatment mitigate \
--treatment-plan "Hardware MFA deployed Q2 2026" \
--treatment-due-date 2026-06-30
Any other risk fields (title, description, category, likelihood, impact, owner_id, status, review_frequency_days) can be updated through the same command.
Retiring a Risk
There is no public hard-delete endpoint for risks — risks are part of the audit chain. Retire a risk by setting its status to a terminal value:
pretorin risk update <system_id> <risk_id> --status closed
Conventional terminal values follow the platform’s other status-bearing models (FindingStatus, POAMItemStatus, RFIStatus): closed for risks that have been remediated or are no longer relevant. The risk list --status filter can then exclude them from active views (pretorin risk list <system_id> --status identified).
This is a CLI-side convention; the platform’s status field is currently an unconstrained string. A future platform-level lineage model is expected to formalize risk-retirement semantics across artifact types.
Attach Artifact Links
Risks can link to controls, evidence, findings, vendors, or monitoring events. Pass exactly one artifact flag.
# A control that mitigates this risk
pretorin risk link add <system_id> <risk_id> \
--link-type mitigates_risk \
--control AC-2 \
--framework nist-800-53-r5
# Evidence demonstrating the risk is real
pretorin risk link add <system_id> <risk_id> \
--link-type evidence_of_risk \
--evidence <evidence_id>
# A vendor whose service introduces the risk
pretorin risk link add <system_id> <risk_id> \
--link-type contributes_to_risk \
--vendor <vendor_id>
Link types
| Value | Meaning |
|---|---|
contributes_to_risk | Artifact increases the risk |
mitigates_risk | Artifact reduces the risk |
evidence_of_risk | Artifact demonstrates the risk has occurred or could |
Remove a Link
pretorin risk link rm <system_id> <risk_id> <link_id>
Refresh Score + AI Summary
Re-score the risk using the latest analytics and trigger a best-effort AI summary regeneration:
pretorin risk refresh-summary <system_id> <risk_id>
The endpoint always returns 200 with the updated entry. The score commits regardless of AI availability; the AI summary updates only if the AI service is reachable and the org has quota.
Risk Library
Browse the org-level template library to see what can be seeded. Templates expose a scenario (the risk description), category, cia_category, and suggested_control_families:
pretorin risk library list
pretorin risk library list --category "Access control"
Use --json to capture the full template payload, including suggested_control_families, for scripting.
Related: Risk Assessment Reports
Risk Assessment Report (RAR) generation is not exposed through the CLI or MCP — it remains a platform-only multi-section AI-assembled document. Drive RAR builds from the Pretorin platform UI when needed.
STIG & CCI Browsing
The stig and cci command groups let you browse STIG benchmarks, rules, and CCIs with full traceability from NIST 800-53 controls down to individual STIG check rules.
STIG Commands
List STIG Benchmarks
pretorin stig list
pretorin stig list --technology-area "Network"
pretorin stig list --product "Windows" --limit 10
Show STIG Details
pretorin stig show <stig_id>
Shows benchmark metadata including title, version, release info, and severity breakdown of rules.
List Rules for a STIG
pretorin stig rules <stig_id>
pretorin stig rules <stig_id> --severity cat_i
pretorin stig rules <stig_id> --cci CCI-000015 --limit 20
Show Applicable STIGs
# Uses active system context
pretorin stig applicable
# Explicit system
pretorin stig applicable --system "My System"
AI-Infer Applicable STIGs
pretorin stig infer
pretorin stig infer --system "My System"
Uses the system’s profile to recommend which STIG benchmarks should apply.
CCI Commands
CCIs (Control Correlation Identifiers) bridge NIST 800-53 controls to specific STIG rules via SRGs (Security Requirements Guides).
List CCIs
pretorin cci list
pretorin cci list --control ac-2
pretorin cci list --status draft --limit 50
Show CCI Details
pretorin cci show CCI-000015
Shows the CCI definition, linked SRGs, and linked STIG rules.
Full Traceability Chain
pretorin cci chain ac-2
pretorin cci chain ac-2 --system "My System"
Shows the complete chain: NIST 800-53 Control -> CCIs -> SRGs -> STIG rules (and test results when --system is provided).
This is useful for understanding exactly which technical checks validate a given control requirement.
Per-System CCI Implementation
pretorin cci impl <cci_uuid> --system "My System"
Reads the per-system CCI implementation row by (system, cci_uuid). Returns the live impl detail — status, status source, narrative (operator-authored or AI-generated draft), evidence count, conflict flag, and eMASS fields. A 404 means the impl row hasn’t been initialized yet for this system.
Use this when you already have the CCI catalog UUID (from cci show or upstream tooling) and want the system-specific compliance state without walking the full rollup.
STIG-to-CCI assignment is catalog-level. DISA defines the STIG-rule → CCI relationship in the catalog. There is no “assign STIG X to CCI Y on this system” operation — per-system applicability and per-system test results combine with the catalog mapping to produce the rollup. Use
cci chain --systemfor the full picture.
STIG Scanning
Note: The legacy
pretorin scancommand was removed when the recipes system landed. Scanning now happens through recipes: each scanner ships as a built-in recipe that the calling AI agent (Claude Code, Codex CLI, custom MCP client, orpretorin agent) invokes through MCP.If you have local automation that called
pretorin scan run, switch it to invoke the recipe directly via the agent or usepretorin recipe listto discover the equivalent recipe.
Available Scanner Recipes
| Recipe ID | Wraps | CLI requirement |
|---|---|---|
inspec-baseline | Chef InSpec | inspec |
openscap-baseline | OpenSCAP | oscap |
cloud-aws-baseline | AWS APIs (boto3) | aws |
cloud-azure-baseline | Azure APIs | az |
manual-attestation | Human attestation (no external tool) | — |
List them locally:
pretorin recipe list
pretorin recipe show inspec-baseline
How a Calling Agent Runs a Scan
The agent (running in your IDE or via pretorin agent run) opens a recipe
context, calls the recipe’s run_scan script with a STIG id, and submits the
returned per-rule results to the platform via submit_test_results.
The recipe body (the markdown under the frontmatter in recipe.md) is the
prompt the agent reads to know what to do. You don’t run the recipe by hand;
you ask the agent something like:
“Run an inspec-baseline scan against
RHEL_9_STIGon this system.”
Behind the scenes the agent:
- Calls
start_recipe(id="inspec-baseline", system_id=...). - Calls the recipe’s
run_scantool withstig_id="RHEL_9_STIG". - Reads the returned summary (per-rule pass/fail/error/not_applicable counts).
- Submits results via
submit_test_results. - Calls
end_recipe(...).
Test Manifest
Browse what’s testable for a system without running anything:
pretorin stig applicable --system "My System"
pretorin cci chain ac-2 --system "My System"
The MCP equivalent is get_test_manifest — the calling agent uses
this to figure out which rules apply before running a scan.
Authoring Your Own Scanner Recipe
Scanner recipes are just recipes. If you have an internal tool that produces
STIG-style results, scaffold a recipe and drop it in
~/.pretorin/recipes/<id>/ (user) or <repo>/.pretorin/recipes/<id>/ (team):
pretorin recipe new my-scanner --location user
See the Authoring recipes docs for the full contract.
Submitting Results Manually
If you have raw scan output and want to push it without running the recipe flow, the platform endpoint is exposed directly:
submit_test_results(system_id, results)
via MCP. Each result needs rule_id, benchmark_id, status, and tool
metadata — see the STIG / CCI workflow for
schema details.
Review Commands
The review command group helps you review local code against framework controls.
Run a Review
# Uses active context for system/framework
pretorin review run --control-id ac-02 --path ./src
# Explicit system/framework override
pretorin review run --control-id ac-02 --framework-id nist-800-53-r5 --system "My System" --path ./src
# Local-only mode — saves control context as markdown, no system required
pretorin review run --control-id ac-02 --framework-id fedramp-moderate --local
# Custom output directory for local artifacts
pretorin review run --control-id ac-02 --framework-id fedramp-moderate --local --output-dir ./compliance-notes
pretorin review run does not push narratives or evidence to the platform. In normal mode, it fetches control requirements and current implementation details for comparison. In --local mode, it writes a markdown review artifact under .pretorin/reviews/ or the path specified with --output-dir.
Options
| Option | Description |
|---|---|
--control-id / -c | Control ID to review against (required) |
--framework-id / -f | Framework ID (uses active context if omitted) |
--system / -s | System name or ID (uses active context if omitted) |
--path / -p | Path to files to review (default: .) |
--local | Force local-only output (no API calls for implementation data) |
--output-dir / -o | Output directory for local review artifacts (default: .pretorin/reviews) |
Check Implementation Status
pretorin review status --control-id ac-02
pretorin review status --control-id sc-07 --framework-id fedramp-moderate --system my-system
| Option | Description |
|---|---|
--control-id / -c | Control ID (required) |
--system / -s | System name or ID (uses active context if omitted) |
--framework-id / -f | Framework ID (uses active context if omitted) |
Configuration
The config command group manages CLI configuration stored at ~/.pretorin/config.json.
List Configuration
$ pretorin config list
Pretorin Configuration
┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Key ┃ Value ┃ Source ┃
┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ api_key │ pretorin...9v7o │ config file │
└─────────┴─────────────────┴─────────────┘
Config file: /home/user/.pretorin/config.json
Get a Config Value
pretorin config get api_key
Set a Config Value
pretorin config set api_base_url https://custom-api.example.com/api/v1
Show Config File Path
$ pretorin config path
/home/user/.pretorin/config.json
Config File Format
The config file is JSON:
{
"api_key": "pretorin_...",
"api_base_url": "https://platform.pretorin.com/api/v1/public",
"platform_api_base_url": "https://platform.pretorin.com/api/v1/public",
"model_api_base_url": "https://platform.pretorin.com/api/v1/public/model",
"active_system_id": "sys-abc123",
"active_system_name": "My Application",
"active_framework_id": "nist-800-53-r5",
"disable_update_check": false
}
Configuration Keys
| Key | Description |
|---|---|
api_key | Pretorin API key |
api_base_url | Platform REST API URL |
platform_api_base_url | Platform API base URL |
model_api_base_url | Model API URL for agent runtime |
openai_api_key | Optional model key for agent runtime |
active_system_id | Currently active system ID |
active_system_name | Cached display name for the active system |
active_framework_id | Currently active framework ID |
disable_update_check | Disable passive update notifications |
Environment Variable Overrides
Environment variables take precedence over config file values. See Environment Variables for the full list.
Customer-Managed Platforms
For air-gapped or customer-managed platform installs, point the CLI at the customer platform public API instead of hosted Pretorin:
pretorin config set platform_api_base_url https://<platform-host>/api/v1/public
pretorin config set model_api_base_url https://<platform-host>/api/v1/public/model
See Customer-Managed Air-Gapped Installs for the full setup and troubleshooting guide.
Complete Command Reference
Global Options
| Option | Description |
|---|---|
--json | JSON output mode for scripting and AI agents |
--version, -V | Show version and exit |
--help | Show command help |
Root Commands
| Command | Description |
|---|---|
pretorin login | Authenticate with the Pretorin API (--api-key/-k, --api-url) |
pretorin logout | Clear stored credentials |
pretorin whoami | Display authentication status |
pretorin version | Show CLI version |
pretorin update [VERSION] | Update to latest version, or a specific version |
pretorin mcp-serve | Start the MCP server (stdio transport) |
pretorin mcp-smoke-test | Smoke-test the cross-harness MCP tool surface (check_context, list_tools, get_instructions, get_workflow schema bundling); exits 1 on failure |
Framework Commands
| Command | Description |
|---|---|
pretorin frameworks list | List all frameworks |
pretorin frameworks get <id> | Get framework details |
pretorin frameworks families <id> | List control families |
pretorin frameworks family <fw> <family> | Get control family details |
pretorin frameworks controls <id> [FAMILY_ID] | List controls (--family/-f, --limit/-n) |
pretorin frameworks control <fw> <ctrl> | Get control details (--brief/-b) |
pretorin frameworks metadata <id> | Get per-control framework metadata |
pretorin frameworks submit-artifact <file> | Submit a compliance artifact JSON file |
Custom Frameworks
Subcommands of pretorin frameworks for authoring, validating, and uploading
custom or forked frameworks. See Custom Frameworks
for the full authoring workflow.
| Command | Description |
|---|---|
pretorin frameworks init-custom <framework_id> | Scaffold a minimal valid unified.json (--title/-t, --output/-o, --force/-f) |
pretorin frameworks validate-custom <file> | Validate a unified.json artifact against the bundled JSON Schema |
pretorin frameworks build-custom <input> | Normalize a source catalog (unified, OSCAL, or known custom) into uploadable unified.json (--framework-id/-f required, --output/-o, --force) |
pretorin frameworks upload-custom <file> | Upload a unified.json artifact as a draft revision (--framework-id/-f, --version-label/-v, --publish) |
pretorin frameworks fork-framework <source_id> <new_id> | Create a linked-fork draft from an upstream framework (--version-label/-v) |
pretorin frameworks rebase-fork <framework_id> | Create a rebase draft for a fork against the latest upstream revision (--version-label/-v) |
pretorin frameworks revisions <framework_id> | List all draft and published revisions for a framework |
pretorin frameworks export-oscal <file> | Regenerate an OSCAL catalog from a unified.json artifact (--output/-o, --force) |
Context Commands
| Command | Description |
|---|---|
pretorin context list | List systems and frameworks with progress |
pretorin context set | Set active system/framework context (--system/-s, --framework/-f, --no-verify) |
pretorin context show | Display and validate current active context (--quiet/-q, --check) |
pretorin context clear | Clear active context |
pretorin context verify | Verify active context with source attestation (--ttl, --quiet/-q) |
pretorin context manifest | Show resolved source manifest and evaluate against detected sources (--quiet/-q) |
Control Commands
| Command | Description |
|---|---|
pretorin control status <ctrl> <status> | Start/reopen control authoring; status must be in_progress (--framework-id/-f, --system/-s) |
pretorin control context <ctrl> | Get rich control context with AI guidance (--framework-id/-f, --system/-s) |
Evidence Commands
| Command | Description |
|---|---|
pretorin evidence create <ctrl> <fw> | Create a local evidence file (--name/-n, --description/-d, --artifact-content, --type/-t) |
pretorin evidence format-markdown [file] | Convert Markdown headings to report-safe bold section labels (--write, --check) |
pretorin evidence list | List local evidence files (--framework/-f) |
pretorin evidence push | Push local evidence to the platform (--dry-run) |
pretorin evidence search | Search platform evidence (--control-id/-c, --framework-id/-f, --system/-s, --limit/-n) |
pretorin evidence upsert <ctrl> <fw> | Find-or-create evidence and link it (--name/-n, --description/-d, --artifact-content, --type/-t, --system/-s, --code-file, --code-lines, --code-repo, --code-commit, --coverage-start, --coverage-end, --capture-query, --source-uri, --source-label, --source-locator, --source-excerpt, --capture-method, --cadence-days) |
pretorin evidence upload <file> <ctrl> <fw> | Upload a file as evidence (--name/-n, --type/-t, --description/-d, --system/-s) |
pretorin evidence link <evidence_id> <ctrl> | Link evidence to a control (--framework-id/-f, --system/-s) |
pretorin evidence link-cci <evidence_id> <cci_implementation_id> | Link evidence to a per-system CCI implementation row (--system/-s, --override-system-mismatch, --override-reason) |
pretorin evidence link-stig <evidence_id> <stig_rule_id> | Link evidence to a STIG rule workflow (lazy-creates the row) (--system/-s, --override-system-mismatch, --override-reason) |
pretorin evidence mark-current <evidence_id> | Re-affirm evidence freshness; bumps expires_at by the refresh cadence and resolves any expiring/expired monitoring events (--system/-s) |
pretorin evidence validate <evidence_id> | Compare recorded source-material hash before re-verifying or replacing a drifted Markdown artifact (--system/-s, --source-root, --artifact-content/--artifact, --description/-d, --drift-note) |
pretorin evidence delete <evidence_id> | Delete an evidence item (--system/-s, --framework-id/-f, --yes/-y) |
Narrative Commands
| Command | Description |
|---|---|
pretorin narrative create <ctrl> <fw> | Create a local narrative file (--content/-c, --name/-n, --ai-generated) |
pretorin narrative list | List local narrative files (--framework/-f) |
pretorin narrative push | Push local narratives to the platform (--dry-run) |
pretorin narrative push-file <ctrl> <fw> <sys> <file> | Push a single narrative file to the platform |
pretorin narrative get <ctrl> <fw> | Get current control narrative (--system/-s) |
Notes Commands
| Command | Description |
|---|---|
pretorin issues create <ctrl> <fw> | Create a local issue file (--content/-c, --name/-n) |
pretorin issues list [ctrl] [fw] | List issues — platform (--system/-s) or local (--local, --framework/-f) |
pretorin issues push | Push local issues to the platform (--dry-run) |
pretorin issues add <ctrl> <fw> | Add an issue directly on the platform (--content/-c, --system/-s) |
pretorin issues resolve <ctrl> <fw> <issue_id> | Resolve or reopen a control issue (--system/-s, --resolution-note/--justification, --reopen, --content/-c, --pinned) |
pretorin notes create <ctrl> <fw> | Create a local note file (--content/-c, --name/-n) |
pretorin notes list [ctrl] [fw] | List notes — platform (--system/-s) or local (--local, --framework/-f) |
pretorin notes push | Push local notes to the platform (--dry-run) |
pretorin notes add <ctrl> <fw> | Add a note directly on the platform (--content/-c, --system/-s) |
pretorin notes resolve <ctrl> <fw> <note_id> | Resolve or reopen a control note (--system/-s, --resolution-note/--justification, --reopen, --content/-c, --pinned) |
Monitoring Commands
| Command | Description |
|---|---|
pretorin monitoring push | Push a monitoring event (--system/-s, --framework/-f, --title/-t, --event-type, --severity, --control/-c, --description/-d, --update-control-status) |
Policy Commands
| Command | Description |
|---|---|
pretorin policy list | List org policies available for questionnaire work |
pretorin policy show | Show persisted policy questionnaire state (--policy) |
pretorin policy populate | Draft policy questionnaire updates from the current workspace (--policy, --path/-p, --apply) |
Scope Commands
| Command | Description |
|---|---|
pretorin scope show | Show scope questionnaire state and review findings (--system/-s, --framework-id/-f) |
pretorin scope populate | Draft scope questionnaire updates from the current workspace (--system/-s, --framework-id/-f, --path/-p, --apply) |
Scope Artifacts
Subcommands of pretorin scope artifacts for managing the auditor-required
system_spec artifacts (asset inventory + 4 snapshot kinds). The inventory
group wraps the recipe-driven scan flow and posts a classified diff
(added / modified / decommissioned) against the platform inventory.
| Command | Description |
|---|---|
pretorin scope artifacts list | List the 5 system_spec artifact kinds with required/toggle/attest state (--system/-s) |
pretorin scope artifacts toggle <kind> | Toggle an artifact kind required/optional; rationale required on toggle-off (--system/-s, --optional/--required, --rationale/-r) |
pretorin scope artifacts inventory show | Show the current (or historical) asset inventory (--system/-s, --as-of) |
pretorin scope artifacts inventory upload <csv> | Parse a CSV client-side, classify rows, and post a single inventory diff (--system/-s, --yes/-y) |
pretorin scope artifacts inventory scan <source> | Run a recipe-driven scan (aws, azure, k8s, iac-workspace) and post the resulting diff (--system/-s, --yes/-y, --dry-run) |
Agent Commands
| Command | Description |
|---|---|
pretorin agent run "<task>" | Run a compliance task (--skill/-s, --model/-m, --base-url, --working-dir/-w, --no-stream, --legacy, --max-turns, --no-mcp) |
pretorin agent doctor | Validate Codex runtime setup |
pretorin agent install | Download the pinned Codex binary |
pretorin agent version | Show pinned Codex version and install status |
pretorin agent skills | List available agent skills |
pretorin agent mcp-list | List configured MCP servers for the agent |
pretorin agent mcp-add <name> <transport> <cmd> | Add an MCP server configuration (--arg/-a, --scope) |
pretorin agent mcp-remove <name> | Remove an MCP server configuration |
Skill Commands
| Command | Description |
|---|---|
pretorin skill install | Install the Pretorin skill for AI coding agents (--agent/-a, --path/-p, --force/-f) |
pretorin skill uninstall | Uninstall the Pretorin skill (--agent/-a, --path/-p) |
pretorin skill status | Show installation status of the Pretorin skill |
pretorin skill list-agents | List all known agents and their skill directories |
Review Commands
| Command | Description |
|---|---|
pretorin review run | Review code against a control (--control-id/-c, --framework-id/-f, --system/-s, --path/-p, --local, --output-dir/-o) |
pretorin review status | Check implementation status for a control (--control-id/-c, --framework-id/-f, --system/-s) |
Config Commands
| Command | Description |
|---|---|
pretorin config list | List all configuration |
pretorin config get <key> | Get a config value |
pretorin config set <key> <value> | Set a config value |
pretorin config path | Show config file path |
Campaign Commands
| Command | Description |
|---|---|
pretorin campaign controls | Run bulk control narrative/evidence campaign (--system, --framework-id, --mode, --family, --controls, --all-controls, --artifacts, --review-job, --concurrency, --max-retries, --checkpoint, --apply, --output) |
pretorin campaign policy | Run bulk policy questionnaire campaign (--mode, --policies, --all-incomplete, --system, --concurrency, --max-retries, --checkpoint, --apply, --output) |
pretorin campaign scope | Run bulk scope questionnaire campaign (--system, --framework-id, --mode, --concurrency, --max-retries, --checkpoint, --apply, --output) |
pretorin campaign status | Show campaign progress from a checkpoint file (--checkpoint, --output) |
Campaign Modes
| Domain | Mode | Description |
|---|---|---|
| controls | initial | Draft new narratives and evidence for controls |
| controls | issues-fix | Address platform issues on existing controls |
| controls | notes-fix | Deprecated alias for issues-fix |
| controls | review-fix | Fix findings from a family review job |
| policy | answer | Generate answers for policy questions |
| policy | review-fix | Fix findings from a policy review |
| scope | answer | Generate answers for scope questions |
| scope | review-fix | Fix findings from a scope review |
Vendor Commands
| Command | Description |
|---|---|
pretorin vendor list | List all vendors in the organization |
pretorin vendor create <name> | Create a vendor (--type/-t, --description/-d, --authorization-level/-a) |
pretorin vendor get <vendor_id> | Get vendor details |
pretorin vendor update <vendor_id> | Update vendor fields (--name, --description/-d, --type/-t, --authorization-level/-a) |
pretorin vendor delete <vendor_id> | Delete a vendor (--force/-f) |
pretorin vendor upload-doc <vendor_id> <file> | Upload a vendor evidence document (--name/-n, --description/-d, --attestation-type) |
pretorin vendor list-docs <vendor_id> | List documents linked to a vendor |
Vendor Types
csp, saas, managed_service, internal
Risk Commands
Manage a system’s risk register. Risks are system-scoped except for the org-level risk library subgroup. See Risk Management for the full workflow.
| Command | Description |
|---|---|
pretorin risk list <system_id> | List risks for a system (--category, --risk-level, --status) |
pretorin risk show <system_id> <risk_id> | Show full risk including eager-loaded artifact links |
pretorin risk create <system_id> | Create a custom risk (--title, --category, --description/-d, --cia-category, --likelihood, --impact, --owner-id, --treatment, --treatment-plan, --treatment-due-date, --review-frequency-days, --framework, --suggested-control-family repeatable) |
pretorin risk seed <system_id> | Seed risks from library templates (--framework, --template-id repeatable) |
pretorin risk update <system_id> <risk_id> | Update fields including mitigation (--title, --description/-d, --category, --cia-category, --likelihood, --impact, --owner-id, --status, --review-frequency-days, --treatment, --treatment-plan, --treatment-due-date) |
pretorin risk link add <system_id> <risk_id> | Attach an artifact (--link-type, exactly one of --control + --framework, --evidence, --finding, --vendor, --monitoring-event) |
pretorin risk link rm <system_id> <risk_id> <link_id> | Remove a risk artifact link |
pretorin risk refresh-summary <system_id> <risk_id> | Re-score risk and trigger best-effort AI summary regeneration |
pretorin risk library list | Browse the org-level risk template library (--category) |
Risk Treatment Values
mitigate, accept, transfer, avoid
Risk Link Types
contributes_to_risk, mitigates_risk, evidence_of_risk
STIG Commands
| Command | Description |
|---|---|
pretorin stig list | List STIG benchmarks (--technology-area/-t, --product/-p, --limit/-l) |
pretorin stig show <stig_id> | Show STIG benchmark detail with severity breakdown |
pretorin stig rules <stig_id> | List rules for a benchmark (--severity/-s, --cci, --limit/-l) |
pretorin stig applicable | Show applicable STIGs for the active system (--system/-s) |
pretorin stig infer | AI-infer applicable STIGs from system profile (--system/-s) |
CCI Commands
| Command | Description |
|---|---|
pretorin cci list | List CCIs (--control/-c, --status, --limit/-l) |
pretorin cci show <cci_id> | Show CCI detail with linked SRGs and STIG rules (e.g., CCI-000015) |
pretorin cci chain <control_id> | Full traceability chain: Control -> CCIs -> SRGs -> STIG rules (--system/-s) |
pretorin cci impl <cci_uuid> | Show the per-system CCI implementation row (status, narrative, evidence_ids, eMASS fields) — 404 means uninitialized (--system/-s) |
Recipe Commands
Recipes are markdown + script playbooks the calling AI agent executes. See Recipes for authoring guidance.
| Command | Description |
|---|---|
pretorin recipe list | List all loaded recipes with id, name, tier, author, and source path (--tier, --source) |
pretorin recipe show <recipe_id> | Display a recipe’s manifest, body, and (with --sources) all loader paths |
pretorin recipe new <recipe_id> | Scaffold a new recipe directory (--location user/project/builtin, --author, --name) |
pretorin recipe validate <recipe_id> | Validate a recipe’s manifest, scripts, and description quality (--path for path-based override) |
pretorin recipe run <recipe_id> | Run a recipe’s script locally for testing (--script/-s, --param/-p repeatable, --path, --system, --framework, --no-context) |
Scanning
The legacy pretorin scan command was removed when the recipes system landed.
Scanning now happens through built-in recipes that the calling AI agent invokes
via MCP. See STIG Scanning for the recipe-based workflow.
| Recipe ID | Wraps | CLI requirement |
|---|---|---|
inspec-baseline | Chef InSpec | inspec |
openscap-baseline | OpenSCAP | oscap |
cloud-aws-baseline | AWS APIs | aws |
cloud-azure-baseline | Azure APIs | az |
manual-attestation | Human attestation | — |
Deprecated Commands
| Command | Description |
|---|---|
pretorin harness init | Deprecated: initialize harness config |
pretorin harness doctor | Deprecated: validate harness setup |
pretorin harness run "<task>" | Deprecated: run task through harness backend |
MCP Integration Overview
The Pretorin CLI includes a built-in Model Context Protocol (MCP) server that enables AI assistants to access compliance framework data directly during conversations.
Why MCP?
The Model Context Protocol allows AI assistants to:
- Access real-time data — Query the latest compliance frameworks, controls, and requirements
- Understand context — Get detailed control guidance and related controls for better recommendations
- Reduce hallucination — Work with authoritative compliance data instead of training knowledge
- Streamline workflows — No need to copy-paste control requirements or switch between tools
How It Works
The MCP server communicates via stdio (standard input/output) using JSON-RPC messages. When you start it with pretorin mcp-serve, your AI tool connects and gains access to 113 static compliance tools plus 15 dynamic recipe-script tools (128 total).
┌──────────────┐ stdio ┌──────────────┐ HTTPS ┌──────────────┐
│ AI Agent │◄──────────────►│ Pretorin │◄─────────────►│ Pretorin │
│ (Claude, │ JSON-RPC │ MCP Server │ │ Platform │
│ Cursor, │ │ │ │ │
│ Codex) │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
Scope
Scoped compliance execution tools on the MCP server run inside exactly one system + framework pair at a time. Set the active scope with pretorin context set, or pass both values explicitly. If a request spans multiple frameworks or systems, split it into separate runs.
Before running write-heavy MCP workflows from a shell or GUI wrapper, prefer validating the stored scope with:
pretorin context show --quiet --check
Tool Categories
The 113 static MCP tools are organized into categories. An additional 15 per-recipe-script tools (recipe_<id>__<script>) are registered dynamically from the recipe registry.
| Category | Tools | Access |
|---|---|---|
| Task Routing | 4 | Read-only, all users |
| Framework & Control Reference | 7 | Read-only, all users |
| Systems | 6 | Read-only |
| Evidence Management | 8 | Read/Write, requires beta |
| Implementation Context | 10 | Read/Write, requires beta |
| Monitoring | 1 | Write, requires beta |
| Workflow State & Analytics | 4 | Read-only |
| Family Operations | 4 | Read/Write, requires beta |
| Scope Workflow | 7 | Read/Write, requires beta |
| Policy Workflow | 10 | Read/Write, requires beta |
| Campaign Operations | 6 | Read/Write, requires beta |
| Risk Management | 9 | Read/Write, requires beta |
| Vendor Management | 8 | Read/Write, requires beta |
| Inheritance & Responsibility | 6 | Read/Write, requires beta |
| STIG & CCI | 13 | Read-only / Write mix |
| Recipes & Workflows | 7 | Read-only |
| System Spec Artifacts | 3 | Read/Write, requires beta |
See Tool Reference for the complete list.
Quick Setup
# 1. Install
uv tool install pretorin
# 2. Authenticate
pretorin login
# 3. Add to your AI tool (example: Claude Code)
claude mcp add --transport stdio pretorin -- pretorin mcp-serve
See Setup Guides for other AI tools.
Example Conversations
Getting Started with a Framework
You: What compliance frameworks are available for government systems?
Claude: Uses list_frameworks — I can see several frameworks available including NIST 800-53 Rev 5, NIST 800-171, and FedRAMP at various impact levels…
Understanding a Control
You: I need to implement Account Management for our FedRAMP Moderate system. What does it require?
Claude: Uses get_control and get_control_references — Account Management requires organizations to manage system accounts including identifying account types, establishing conditions for membership, and specifying authorized users…
Control Family Overview
You: Give me an overview of the Audit controls in NIST 800-53
Claude: Uses list_controls with family filter — The Audit and Accountability family contains controls for audit events, content, storage, review, and reporting…
MCP Setup Guides
Prerequisites
Install and authenticate the Pretorin CLI:
uv tool install pretorin
pretorin login
Install the Pretorin Skill
The skill teaches your AI agent how to use MCP tools for compliance workflows — control ID formats, narrative authoring rules, gap analysis methodology, and more. Install it before setting up MCP:
pretorin skill install # both Claude Code and Codex CLI
pretorin skill install --agent claude # Claude Code only
pretorin skill install --agent codex # Codex CLI only
pretorin skill status # check what's installed
The skill is copied to ~/.claude/skills/pretorin/ and/or ~/.codex/skills/pretorin/ and auto-discovered by each agent.
Claude Code
Quick setup — run a single command:
claude mcp add --transport stdio pretorin -- pretorin mcp-serve
This registers the server for your current project. To make it available across all your projects, add --scope user.
Team setup — add a .mcp.json file to your project root so every team member gets the server automatically:
{
"mcpServers": {
"pretorin": {
"type": "stdio",
"command": "pretorin",
"args": ["mcp-serve"]
}
}
}
Claude Code detects the file automatically.
Claude Desktop
Add to your Claude Desktop configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"pretorin": {
"command": "pretorin",
"args": ["mcp-serve"]
}
}
}
Restart Claude Desktop after saving.
Cursor
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"pretorin": {
"command": "pretorin",
"args": ["mcp-serve"]
}
}
}
Restart Cursor after saving.
OpenAI Codex CLI
Add to ~/.codex/config.toml:
[mcp_servers.pretorin]
command = "pretorin"
args = ["mcp-serve"]
If you installed Pretorin with uv tool install or pipx, prefer pinning the absolute path from command -v pretorin to avoid PATH drift between shells and GUI apps.
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"pretorin": {
"command": "pretorin",
"args": ["mcp-serve"]
}
}
}
Restart Windsurf after saving.
Other MCP Clients
The Pretorin MCP server follows the standard Model Context Protocol and works with any MCP-compatible client. The server communicates via stdio.
To test the server manually:
pretorin mcp-serve
The server accepts JSON-RPC messages on stdin and responds on stdout.
PATH Considerations
If your AI tool can’t find the pretorin command, use the full path:
# Find the full path
command -v pretorin
Then use that path in your configuration:
{
"mcpServers": {
"pretorin": {
"command": "/home/user/.local/bin/pretorin",
"args": ["mcp-serve"]
}
}
}
This is especially important for uv tool and pipx installations where the binary may not be on the PATH available to GUI applications.
Before debugging scoped MCP write failures, validate the active CLI scope:
pretorin context show --quiet --check
MCP Tool Reference
The MCP server provides 128 tools organized by category (113 static + 15 dynamic per-recipe-script tools).
Cross-Harness Discovery (RFC #113)
Three small tools let any MCP client — Claude Code, Cursor, Codex, vanilla Agents SDK — ground itself and reach the routing layer without depending on the initialize instructions block. Call them at session start.
check_context
Cheap, unauthenticated probe of session grounding. Reads local CLI config only — no platform calls. Returns:
{
"connected": true,
"active_system": {"id": "sys-1", "name": "Primary"},
"active_framework_id": "nist-800-53-r5",
"suggested_next": "Ready. Call `start_task` with an `intent_verb` to route the user's request to a workflow.",
"pending_attention": {}
}
suggested_next is deterministic and tells the agent exactly what to do given current state — call pretorin login, call list_systems, set a framework, or proceed with start_task.
Parameters: None.
When to call: Once at session start. Always safe; never makes a platform call.
list_tools
Compact catalog of every available tool. Returns one short record per tool:
{
"total": 128,
"tier_counts": {"default": 8, "workflow": 12, "reference": 93, "recipe": 15},
"tools": [
{"name": "check_context", "purpose": "Cheap, unauthenticated probe of session grounding", "tier": "default", "requires_workflow": false},
...
]
}
The full payload fits in roughly 100 lines — far smaller than fetching every tool’s inputSchema. Tier classification:
| Tier | Meaning |
|---|---|
default | Always advertised. Minimum surface to ground a session and route a task. |
reference | Read-only browsing of frameworks, controls, systems, recipes. Safe without prior routing. |
workflow | Requires prior start_task context. Calling without it raises WorkflowRoutingError. |
recipe | Dynamic per-recipe-script tools (recipe_<id>__<script>). |
Parameters: None.
When to call: Once at session start (or anytime “what’s available?” comes up).
get_instructions
Returns the server’s routing instructions as a regular tool response. Mirrors the text the MCP initialize handshake advertises in the instructions field, for harnesses (Cursor, Codex, vanilla Agents SDK) that don’t render that text to the agent.
Parameters: None.
When to call: If the agent didn’t receive routing rules via the initialize handshake, or wants to re-read them mid-session.
Routing Errors (errors-as-instructions)
Workflow-tier tools require an active routing context — either an active system/framework set via pretorin context set, or the context that start_task resolves. Calling a workflow write without context returns a structured error payload, not just plain text:
{
"error": "workflow_required",
"message": "No active system/framework context. Call start_task with an intent_verb to route the request to the right workflow, or run `pretorin context set --system <id> --framework <id>` in the terminal.",
"routing_hint": {
"reason": "no_active_context",
"next_action": "call_start_task",
"missing": ["system_id", "framework_id"],
"suggested_intent_verb": "collect_evidence"
}
}
The response carries isError=true so agents that only check the error flag still surface the failure, but the parseable body tells them exactly which start_task call to make. This means routing rules live in the protocol, not the preamble — harnesses that ignore instructions still see the rules in the error payload they have to read anyway.
Evidence and narrative producer writes add one more guardrail: create_evidence, create_evidence_batch, and update_narrative require recipe_context_id from start_recipe. Missing recipe context returns recipe_required with a recipe_gap before scope resolution, so agents converge on start_task → source preflight → start_recipe → write.
suggested_intent_verb is set when the called tool has a registered mapping (see _TOOL_TO_INTENT_VERB in src/pretorin/mcp/server.py). Every tool in WORKFLOW_TIER has one; tools added to that set without a mapping will fail the sync test in CI.
Workflow Schema Bundling
When the agent calls get_workflow, the response includes required_tool_schemas — the full MCP Tool definitions for every tool the workflow body references:
{
"id": "single-control",
"manifest": { "..." },
"body": "## Single Control Update\n\n...",
"required_tool_schemas": [
{"name": "create_evidence", "description": "...", "inputSchema": {...}},
{"name": "update_narrative", "description": "...", "inputSchema": {...}},
...
]
}
Single round trip equips the agent. Schemas are response data — agents can read them as reference regardless of whether their harness supports dynamic tool registration.
Telemetry
The server emits structured telemetry events to stderr so MCP hosts can capture them through their existing log pipeline. Each event is one line:
PRETORIN_TELEMETRY_EVENT {"ts": 1747249200.12, "event_type": "workflow_routing_required", "tool": "create_evidence", "reason": "no_active_context", "missing": ["system_id", "framework_id"], "suggested_intent_verb": "collect_evidence"}
PRETORIN_TELEMETRY_EVENT {"ts": 1747249200.99, "event_type": "recipe_required", "tool": "create_evidence", "reason": "agent write attempted without recipe_context_id", "requested_evidence_type": "code_snippet", "suggested_next": "call_start_task_then_start_recipe"}
Events emitted:
| event_type | When |
|---|---|
start_task_succeeded | A start_task call completed successfully (the canonical-path signal). |
workflow_routing_required | A write tool raised WorkflowRoutingError (the bypass signal). |
recipe_required | An evidence or narrative producer write returned the structured recipe-context guardrail before scope resolution. |
For the post-recipe producer path, compute the combined bypass rate as:
(workflow_routing_required + recipe_required) / start_task_succeeded
When your log pipeline can group by MCP session, count only bypass events that did not have the expected preceding canonical calls in that same session: start_task for workflow_routing_required, and start_task → source preflight → start_recipe for recipe_required. The recipe_required event carries only non-content shape data such as evidence type, item count, narrative length, and suggested_next; it must not include artifact content, narrative text, evidence ids, control ids, or source excerpts.
Per RFC #113 and issue #121, this combined bypass data gates any phase-4 default-surface cull or capability-negotiation work.
Opt-out: set PRETORIN_MCP_TELEMETRY_DISABLED=1 in the environment before starting the MCP server. Local-only — no PII or content leaves the user’s machine.
Common Write-Side Parameters
Most write-side tools (evidence, narratives, issues, control status, monitoring events) accept two shared audit-trail flags. Both default to false and should only be set when the calling agent has a deliberate reason to bypass the corresponding guardrail:
allow_scope_override— Permit a write outside the active system/framework context.allow_unverified_sources— Permit a write when source attestation shows a mismatch.
Where listed below as “(audit-trail flags)”, a tool accepts both fields. MCP agent evidence and narrative writes require recipe_context_id returned by start_recipe; writes without one return a structured recipe_required error.
Task Routing
start_task
Route a user prompt to the right workflow. Call this FIRST whenever the user references compliance work (a control, system, framework, questionnaire, or campaign). The calling agent extracts entities from the user prompt and supplies them as structured args; pretorin applies deterministic rules to pick a workflow and bundles the platform read-state (workflow_state, compliance_status, pending items) into the response. The agent then reads the selected workflow’s body via get_workflow and follows it.
The one exception is pure reference questions (“show me AC-2”, “list frameworks”) — those go directly to the read-side tools without start_task.
Parameters:
entities(required) — Structured entities extracted from the user prompt. Required sub-fields:intent_verb(one ofwork_on,collect_evidence,draft_narrative,answer,campaign,inspect_status) andraw_prompt(original verbatim text). Optional:system_id,framework_id,control_ids,scope_question_ids,policy_question_ids.active_system_id(optional) — The user’s active CLI context system_id, if any. Used to detect cross-system writes.active_framework_id(optional) — The user’s active CLI context framework_id, if any. Used byinspect_statuswhen the user asks for current status without naming a framework.skip_inspect(optional) — Skip the server-side platform reads when the calling agent already has fresh state. Default:false
Returns: Selected workflow id, resolved scope (system/framework/items), platform-state bundle, and suggested_capture_plan for source/recipe preflight when the workflow produces evidence or narratives.
Framework & Control Reference
These tools are read-only and available to all authenticated users.
list_frameworks
List all available compliance frameworks.
Parameters: None
Returns: List of frameworks with ID, title, version, tier, and control counts.
get_framework
Get detailed metadata about a specific framework including AI context (purpose, target audience, regulatory context).
Parameters:
framework_id(required) — e.g.,nist-800-53-r5,fedramp-moderate
Returns: Framework details including description, version, OSCAL version, and dates.
list_control_families
List control families for a framework with AI context (domain summary, risk context, implementation priority).
Parameters:
framework_id(required)
Returns: List of control families with ID, title, class, and control count.
list_controls
List controls for a framework, optionally filtered by family.
Parameters:
framework_id(required)family_id(optional) — Family IDs are slugs likeaccess-control, not short codes. CMMC families include a level suffix (e.g.,access-control-level-2).
Returns: List of controls with ID, title, and family.
get_control
Get detailed control information including AI guidance (summary, control intent, evidence expectations, implementation considerations, common failures, complexity).
Parameters:
framework_id(required)control_id(required) — NIST/FedRAMP: zero-padded (ac-01). CMMC: dotted (AC.L2-3.1.1).
Returns: Control details including parameters, parts, and enhancement count.
get_controls_batch
Get detailed control data for many controls in one framework-scoped request.
Parameters:
framework_id(required)control_ids(optional) — List of canonical control IDs; omit to retrieve all controls in the framework
Returns: Full control detail records for the requested controls.
get_control_references
Get reference information including statement, guidance, objectives, and related controls.
Parameters:
framework_id(required)control_id(required)
Returns: Statement, guidance, objectives, parameters, and related controls.
Systems
list_systems
List systems in the current organization.
Parameters: None
Returns: System IDs, names, and summary metadata.
get_cli_status
Return the local Pretorin CLI version status, including update availability and upgrade guidance for MCP hosts and agents.
Parameters:
force(optional) — Bypass local cache and re-check PyPI for the latest version. Default:false
Returns: Current version, latest version, update available flag, and upgrade instructions.
get_source_manifest
Get the resolved source manifest for a system and evaluate it against currently detected sources. Shows which external sources (git, cloud, HRIS, etc.) are required, recommended, or optional, and whether each is currently satisfied.
Parameters:
system_id(optional) — System ID or name
Returns: Source manifest with per-source satisfaction status. Returns null manifest if none is configured.
get_system
Get system metadata including attached frameworks and security impact level.
Parameters:
system_id(required) — System ID or name
Returns: System metadata.
list_connected_sources
List source connections bound to a system for recipe preflight. Older platform
deployments return availability: "unknown" instead of blocking recipe
discovery.
Parameters:
system_id(optional) — Defaults to active scope
Returns: Source availability plus normalized source rows (kind, connected, identifier, binding_role, last_checked, probe_status).
get_compliance_status
Get framework progress and implementation posture for a system.
Parameters:
system_id(required) — System ID or friendly system name
Returns: Framework status summaries and progress metrics.
Evidence Management
search_evidence
Search current evidence items.
Parameters:
system_id(optional) — System ID or friendly system name. When omitted, the active CLI scope is used if available.control_id(optional) — Filter by controlframework_id(optional) — Filter by frameworklimit(optional) — Maximum number of results. Default:20
Returns: Matching evidence items. The server uses the same compatibility search path as the CLI for deployments that only expose system-scoped evidence routes.
create_evidence
Upsert evidence on the platform (find-or-create by default). If dedupe is true, exact matching evidence in the active system/framework scope is reused; otherwise a new record is created.
Parameters:
name(required)description(required) — Short human summary of what the evidence demonstratesartifact_content(required) — Markdown body containing the actual evidence artifact. Use bold section labels with spacing instead of Markdown headings. Do not include gap, issue, or remediation discussion.evidence_type(required) — Must be one of the canonical evidence typessystem_id(optional) — Defaults to active scopecontrol_id(optional)framework_id(optional)dedupe(optional) — Default:truecode_file_path(optional) — Path to source file (relative to workspace root)code_line_numbers(optional) — Line range (e.g.,10-25)code_snippet(optional) — Relevant code excerptcode_repository(optional) — Git repository URLcode_commit_hash(optional) — Git commit hashsource_uri,source_label,source_locator,source_excerpt,capture_method(optional) — Structured provenance inputs. If omitted, the handler derives safe defaults from code context or active scope.recipe_context_id(required) — Active recipe execution context fromstart_recipe; evidence is stampedproducer_kind='recipe'automatically.allow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns:
evidence_idcreated— true if new, false if reusedlinked— whether control/system link succeededmatch_basis—exact_name_desc_type_control_frameworkornone
create_evidence_batch
Create and link multiple evidence items within one system/framework scope in a single request.
Parameters:
items(required) — Array of evidence payloads. Each item:name,description,artifact_content,control_id,evidence_type(required); optionalrelevance_notes,code_file_path,code_line_numbers,code_snippet,code_repository,code_commit_hash,source_uri,source_label,source_locator,source_excerpt,capture_method. Artifact content uses the same no-heading, no-gap-discussion rule ascreate_evidence.system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scoperecipe_context_id(required) — Active recipe execution context fromstart_recipe; every item in the batch is stampedproducer_kind='recipe'. All items share the same context — per-item context variation is not supported in v1.allow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: Batch creation summary with per-item results and created evidence IDs.
link_evidence
Link an existing evidence item to a control.
Parameters:
evidence_id(required)control_id(required)system_id(optional) — Defaults to active scopeframework_id(optional)allow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: Link confirmation.
link_evidence_to_cci_implementation
Link an existing evidence item to a per-system CCI implementation row. Use when you already have the CCI implementation UUID (from get_cci_implementation or get_cci_status).
Parameters:
evidence_id(required)cci_implementation_id(required)system_id(optional) — Defaults to active scopeoverride_system_mismatch(optional, defaultfalse) — Permit cross-system attachmentoverride_reason(optional) — Required whenoverride_system_mismatchis true
Returns: Link confirmation with link_summary.cci_implementation_id.
link_evidence_to_stig_rule_workflow
Link an existing evidence item to a STIG rule workflow. Lazy-creates the workflow row if none exists yet for (system, stig_rule). Use to attach remediation proof, mitigating-control documentation, or waiver-justification artifacts to a failing rule.
Parameters:
evidence_id(required)stig_rule_id(required) — STIG catalog rule UUIDsystem_id(optional) — Defaults to active scopeoverride_system_mismatch(optional, defaultfalse)override_reason(optional) — Required whenoverride_system_mismatchis true
Returns: Link confirmation with link_summary.stig_rule_workflow_id.
upload_evidence
Upload a file as evidence to the platform (system-scoped, requires WRITE access).
Parameters:
file_path(required) — Absolute path to the file to uploadname(required) — Evidence namesystem_id(optional) — Defaults to active scopeevidence_type(optional) — Default:otherdescription(optional) — Evidence descriptioncontrol_id(optional)framework_id(optional)allow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: Uploaded evidence record.
delete_evidence
Delete an evidence item from the platform (system-scoped, requires WRITE access).
Parameters:
evidence_id(required) — The evidence item ID to deletesystem_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopeallow_scope_override(optional, audit-trail flag)
Returns: Deletion confirmation.
get_narrative
Get the current narrative record for a control.
Parameters:
control_id(required)system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopeallow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: Narrative text, status, and AI confidence metadata.
Implementation Context
get_control_context
Get rich context for a control including AI guidance, statement, objectives, scope status, and current implementation details.
Parameters:
control_id(required)system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scope
Returns: Combined control metadata and implementation details.
get_scope
Get system scope and policy information including excluded controls and Q&A responses.
Parameters:
system_id(required)framework_id(required)
Returns: Scope narrative, excluded controls, Q&A responses, and scope status.
patch_scope_qa
Apply partial scope questionnaire updates for a system/framework.
Parameters:
system_id(required)framework_id(required)updates(required) — Non-empty list of{question_id, answer}objects
Returns: Updated scope questionnaire state, including the saved responses.
list_org_policies
List organization policies available for questionnaire work.
Parameters: None
Returns: Policy summaries including id, name, template linkage, and questionnaire status.
get_org_policy_questionnaire
Get the canonical questionnaire state for one organization policy.
Parameters:
policy_id(required)
Returns: Policy metadata, saved answers, and the merged template/question set when available.
patch_org_policy_qa
Apply partial questionnaire updates for one organization policy.
Parameters:
policy_id(required)updates(required) — Non-empty list of{question_id, answer}objects
Returns: Updated organization policy questionnaire state.
get_control_implementation
Get implementation details for a control in a system.
Parameters:
control_id(required)system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopeallow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: Current status, narrative, evidence count, and issue metadata.
get_control_issues
Get issues for a control implementation.
Parameters:
control_id(required)system_id(optional) — Defaults to active scopeframework_id(optional)
Returns: Issue list with total count.
get_control_notes
Deprecated alias for get_control_issues.
Parameters:
control_id(required)system_id(optional) — Defaults to active scopeframework_id(optional)
Returns: Issue list with total count. Compatibility responses also include notes.
update_narrative
Push a narrative text update produced by a narrative recipe.
Parameters:
control_id(required)narrative(required) — Must be auditor-ready markdown (no headings, 2+ rich elements, 1+ structural element, no images). Do not include gap, issue, or remediation discussion; useadd_control_issue.system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopeis_ai_generated(optional) — Default:falserecipe_context_id(required) — Active narrative-producing recipe context fromstart_recipeevidence_ids(required) — Evidence ids cited by the narrativeallow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: Update confirmation.
add_control_issue
Add an issue for unresolved gaps or manual follow-up actions. Content is plain text (no markdown validation required). Issues are the durable home for gaps, missing evidence, unresolved ambiguity, and remediation work.
Parameters:
control_id(required)content(required)system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopeallow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: The created issue record.
add_control_note
Deprecated alias for add_control_issue.
resolve_control_issue
Resolve, unresolve, or update an existing control issue. Use this to clear blocking issues so control status can advance. Resolving an issue requires a resolution_note justification for the audit trail.
Parameters:
control_id(required)issue_id(required)system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopeis_resolved(optional) — Default:trueresolution_note(required when resolving) — Explain why the issue can be closed; stored as the resolution audit trail and cascaded to linked RFIs/findingscontent(optional) — Updated issue contentis_pinned(optional)
resolve_control_note
Deprecated alias for resolve_control_issue.
allow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: The updated note record.
Compliance Updates
update_control_status
Start or reopen authoring for a control.
Parameters:
control_id(required)status(required) —in_progresssystem_id(optional) — Defaults to active scopeframework_id(optional)allow_scope_override,allow_unverified_sources(optional, audit-trail flags)
CLI/MCP callers cannot set ready_to_approve, implemented, or not_applicable; those decisions happen in the Pretorin UI by a human.
Returns: Status update confirmation.
push_monitoring_event
Create a monitoring event for a system.
Parameters:
title(required)system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopeseverity(optional) —critical,high,medium,low,info. Default:mediumevent_type(optional) —security_scan,configuration_change,access_review,compliance_check. Default:security_scancontrol_id(optional)description(optional)allow_scope_override,allow_unverified_sources(optional, audit-trail flags)
Returns: The created monitoring event.
generate_control_artifacts
Generate read-only AI drafts for a control narrative, evidence recommendations, and recommended issues.
Parameters:
system_id(required)control_id(required)framework_id(required)working_directory(optional) — Local workspace path for code-aware draftingmodel(optional) — Model override
Returns: Draft narrative text, evidence recommendations, and recommended issues. Does not write to the platform.
To persist approved evidence or narrative changes, first open the matching
recipe context; create_evidence and update_narrative require
recipe_context_id.
Workflow State & Analytics
get_workflow_state
Get the lifecycle state for a system+framework, showing which stage needs work next (scope, policies, controls, evidence).
Parameters:
system_id(required)framework_id(required)
Returns: Current workflow stage, completion percentages, and next recommended action.
get_analytics_summary
Get a lightweight system progress snapshot.
Parameters:
system_id(required)framework_id(required)
Returns: Scope completion, policy completion, control coverage, and evidence gaps.
get_family_analytics
Get per-family breakdown with narrative coverage, evidence coverage, and status distribution.
Parameters:
system_id(required)framework_id(required)
Returns: Per-family metrics.
get_policy_analytics
Get per-policy breakdown with answer completion and review status.
Parameters:
policy_id(required)
Returns: Per-policy completion metrics.
Family Operations
get_pending_families
Identify which control families need work.
Parameters:
system_id(required)framework_id(required)
Returns: Families with counts of pending vs total controls.
get_family_bundle
Get all controls in one family with status, narrative presence, evidence presence, and note counts.
Parameters:
system_id(required)family_id(required)framework_id(required)
Returns: Complete family bundle with per-control details.
trigger_family_review
Trigger AI review of all controls in a family. Takes 2-4 minutes for large families.
Parameters:
system_id(required)family_id(required)framework_id(required)
Returns: Review job ID for polling.
get_family_review_results
Poll family review results.
Parameters:
system_id(required)job_id(required)
Returns: Aggregated findings with severity, affected control IDs, and recommended fixes.
Scope Workflow
get_pending_scope_questions
Get only unanswered scope questions (lightweight).
Parameters:
system_id(required)framework_id(required)
Returns: List of unanswered questions with IDs.
get_scope_question_detail
Get guidance, tips, and example responses for a specific scope question.
Parameters:
system_id(required)question_id(required)framework_id(required)
Returns: Question text, guidance, tips, and example answers.
answer_scope_question
Answer one scope question.
Parameters:
system_id(required)question_id(required)answer(required)framework_id(required)
Returns: Updated question state.
trigger_scope_generation
Trigger AI generation of scope document from answered questions. By default the same durable job also runs an AI review after generation.
Parameters:
system_id(required)framework_id(required)include_review(optional) — Run AI review after generation in the same job. Default:true
Returns: Generation job ID for polling.
trigger_scope_review
Trigger AI review of scope answers.
Parameters:
system_id(required)framework_id(required)
Returns: Review job ID for polling.
get_scope_review_results
Poll for structured scope review findings.
Parameters:
system_id(required)job_id(required)
Returns: Findings with severity levels and recommended fixes.
Policy Workflow
get_pending_policy_questions
Get only unanswered policy questions.
Parameters:
policy_id(required)
Returns: List of unanswered questions.
get_policy_question_detail
Get guidance, tips, and examples for a specific policy question.
Parameters:
policy_id(required)question_id(required)
Returns: Question text, guidance, and example answers.
answer_policy_question
Answer one policy question.
Parameters:
policy_id(required)question_id(required)answer(required)
Returns: Updated question state.
get_policy_workflow_state
Get per-policy workflow state including completion, generation, and review status.
Parameters:
policy_id(required)
Returns: Policy workflow state.
trigger_policy_generation
Trigger AI generation of policy document from answered questions. By default the same durable job also runs an AI review after generation.
Parameters:
policy_id(required)system_id(optional) — System ID for scope contextinclude_review(optional) — Run AI review after generation in the same job. Default:true
Returns: Generation job status.
trigger_policy_review
Trigger AI review of policy answers/document.
Parameters:
policy_id(required)
Returns: Review job ID for polling.
get_policy_review_results
Poll for structured policy review findings.
Parameters:
policy_id(required)job_id(required)
Returns: Findings with severity levels and recommended fixes.
Campaign Operations
Campaigns enable bulk compliance operations with checkpoint persistence and lease-based concurrency.
prepare_campaign
Prepare a workflow-aligned campaign run with a platform state snapshot.
Parameters:
domain(required) —controls,policy, orscopemode(required) — Campaign mode for the selected domainsystem_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scopefamily_id(optional) — Target family for control campaignscontrol_ids(optional) — Explicit control IDs to includeall_controls(optional) — Include all controls. Default:falseartifacts(optional) — Artifact type:narratives,evidence, orboth. Default:bothreview_job(optional) — Family review job ID forreview-fixmodepolicy_ids(optional) — Explicit policy IDs to includeall_incomplete(optional) — Include all incomplete items. Default:falseapply(optional) — Apply proposals immediately. Default:falseoutput(optional) — Output format:auto,live,compact,json. Default:jsoncheckpoint_path(optional) — Local checkpoint file pathworking_directory(optional) — Working directory for executorsconcurrency(optional) — Parallel execution limit. Default:4max_retries(optional) — Retry limit per item. Default:2
Returns: Campaign checkpoint with item list and metadata.
claim_campaign_items
Claim items for drafting with TTL-based leases. Safe for fan-out to multiple agents.
Parameters:
checkpoint_path(required) — Local campaign checkpoint pathlease_owner(optional) — Stable identifier for the claiming agentmax_items(optional) — Number of items to claim. Default:1lease_ttl_seconds(optional) — Lease time-to-live. Default:300
Returns: Claimed items with lease metadata.
get_campaign_item_context
Get full item context plus drafting instructions for a claimed item.
Parameters:
checkpoint_path(required)item_id(required)
Returns: Control/policy/scope context, current state, and drafting guidance.
submit_campaign_proposal
Submit an external agent’s proposal without applying it to the platform.
Parameters:
checkpoint_path(required)item_id(required)proposal(required) — Campaign proposal payload object
Returns: Proposal acceptance confirmation.
apply_campaign
Push stored proposals to the platform.
Parameters:
checkpoint_path(required)item_ids(optional) — Subset of item IDs to apply; omit to apply all
Returns: Apply results with per-item status.
get_campaign_status
Get structured campaign status with a stable transcript snapshot.
Parameters:
checkpoint_path(required)
Returns: Campaign progress, item states, and transcript.
Risk Management
Risks are system-scoped (except list_risk_library, which is org-level). Mitigation is recorded via update_risk — there is no separate /mitigate endpoint. Control auto-link on create/seed is opt-in: it requires framework_id plus matching ControlImplementation rows on the system.
list_risks
List risks for a system with optional filters.
Parameters:
system_id(required)category(optional) — Filter by risk category (confidentiality,integrity,availability, etc.)risk_level(optional) — Filter by overall risk level (critical,high,medium,low)status(optional) — Filter by lifecycle status
Returns: Risk list with summary metadata.
get_risk
Get the full risk detail including eager-loaded artifact_links (controls, evidence, findings, vendors, monitoring events).
Parameters:
system_id(required)risk_id(required)
Returns: Full risk record with artifact_links.
create_risk
Create a custom risk for a system. Control auto-link is opt-in: pass framework_id plus suggested_control_families and the platform will only auto-link controls that already have ControlImplementation rows for that framework.
Parameters:
system_id(required)title(required)category(required) —confidentiality,integrity,availability, etc.description(optional)cia_category(optional)likelihood(optional)impact(optional)owner_id(optional)treatment(optional) —mitigate,accept,transfer,avoidtreatment_plan(optional)treatment_due_date(optional) — ISO date stringreview_frequency_days(optional) — How often the risk should be re-reviewedframework_id(optional) — Required for control auto-linksuggested_control_families(optional) — List of family short codes (e.g.,["AC", "IA"])
Returns: The created risk including artifact_links.
seed_risks
Bulk-instantiate library templates against a system + framework. Each template is scored against the system, and controls are auto-linked per the template’s suggested_control_families when matching ControlImplementation rows exist.
Parameters:
system_id(required)framework_id(required)template_ids(required) — Non-empty list of risk template IDs
Returns: Seed summary with the created risks.
update_risk
Update risk fields. This is the mitigation surface — set treatment, treatment_plan, and treatment_due_date here rather than via a separate endpoint. Set status to a terminal value (e.g., closed) to retire a risk; there is no public hard-delete because risks are part of the audit chain.
Parameters:
system_id(required)risk_id(required)title(optional)description(optional)category(optional)cia_category(optional)likelihood(optional)impact(optional)owner_id(optional)status(optional)review_frequency_days(optional)treatment(optional) —mitigate,accept,transfer,avoidtreatment_plan(optional)treatment_due_date(optional)
Returns: Updated risk record.
link_risk_artifact
Attach an artifact (control, evidence, finding, vendor, or monitoring event) to a risk. Pass exactly one artifact reference.
Parameters:
system_id(required)risk_id(required)link_type(required) —contributes_to_risk,mitigates_risk,evidence_of_riskcontrol_id(optional) — Pair withframework_idframework_id(optional) — Required when linking a controlevidence_id(optional)finding_id(optional)vendor_id(optional)monitoring_event_id(optional)
Returns: The created artifact link record.
unlink_risk_artifact
Remove a previously attached artifact link.
Parameters:
system_id(required)risk_id(required)link_id(required)
Returns: Removal confirmation.
refresh_risk_summary
Re-score the risk using the latest analytics and trigger a best-effort AI summary regeneration. The endpoint always returns 200 with the updated entry. The score commits regardless of AI availability; the AI summary updates only if the AI service is reachable and the org has quota — check whether ai_summary_generated_at advanced to confirm AI ran.
Parameters:
system_id(required)risk_id(required)
Returns: Updated risk entry.
list_risk_library
Browse the org-level risk template library. Templates expose a scenario, category, cia_category, and suggested_control_families.
Parameters:
category(optional) — Filter templates by category
Returns: Library template list.
System Spec Artifacts
Auditor-required artifacts (asset inventory plus four snapshot kinds) that anchor a system’s audit chain. See System Spec Artifacts for the full schema.
list_artifact_requirements
List the 5 auditor-required system_spec artifact kinds for a system (asset inventory + 4 snapshot kinds). Returns each kind’s effective_required, optional/toggled-off state, attestation timestamp, and rationale.
Parameters:
system_id(required)
Returns: Artifact-requirement rows with required/optional state and attestation metadata.
get_asset_inventory
Return the system’s asset inventory. Active rows by default; pass as_of (ISO-8601 timestamp) to replay historical state.
Parameters:
system_id(required)as_of(optional) — ISO-8601 timestamp for historical replay
Returns: Asset inventory rows with provenance and snapshot timestamp.
submit_asset_inventory_diff
Submit an asset-inventory diff produced by a recipe-driven scan. At least one of added / modified / decommissioned must be non-empty. recipe_id is a free-form CLI string the platform records as cli:<recipe_id> provenance per row. idempotency_key defaults to sha256(system_id, recipe_id, scan_timestamp); pass your own when replaying a scan. recipe_context_id (from start_recipe) is optional — the diff endpoint accepts it cleanly but does not require it.
Parameters:
system_id(required)recipe_id(required) — Free-form CLI recipe id (e.g.,asset-inventory-aws-baseline); stored as provenance per rowidempotency_key(optional) — Defaults tosha256(system_id, recipe_id, scan_timestamp)[:32]recipe_context_id(optional) — UUID returned bystart_recipewhen the diff is produced inside an active recipe contextadded(optional) — Array of new asset rows. Required per row:external_id. Recommended:name,asset_type,environment,data_classification,criticalitymodified(optional) — Array of changed asset rows keyed byexternal_id; same shape asaddeddecommissioned(optional) — Array of{external_id, rationale}for assets to mark decommissioned
Returns: Diff acceptance summary with per-row outcomes.
Vendor Management
list_vendors
List all vendor entities in the organization.
Parameters: None
Returns: Vendor list with IDs, names, types, and authorization levels.
create_vendor
Create a new vendor entity.
Parameters:
name(required)provider_type(required) —csp,saas,managed_service,internaldescription(optional)authorization_level(optional)
Returns: Created vendor record.
get_vendor
Get vendor details.
Parameters:
vendor_id(required)
Returns: Vendor metadata and linked documents.
update_vendor
Update vendor fields.
Parameters:
vendor_id(required)name(optional)description(optional)provider_type(optional) —csp,saas,managed_service,internalauthorization_level(optional)
Returns: Updated vendor record.
delete_vendor
Delete a vendor entity.
Parameters:
vendor_id(required)
Returns: Deletion confirmation.
upload_vendor_document
Upload vendor evidence documents (SOC 2 reports, CRMs, FedRAMP packages).
Parameters:
vendor_id(required)file_path(required)name(optional)description(optional)attestation_type(optional) —self_attested,third_party_attestation,vendor_provided. Default:vendor_provided
Returns: Uploaded document record.
list_vendor_documents
List documents linked to a vendor.
Parameters:
vendor_id(required)
Returns: Document list with metadata.
link_evidence_to_vendor
Link an evidence item to a vendor with attestation type. Set vendor_id to null to unlink.
Parameters:
evidence_id(required)vendor_id(optional) — Vendor ID; null to unlinkattestation_type(optional) —self_attested,third_party_attestation,vendor_provided
Returns: Link confirmation.
Inheritance & Responsibility
set_control_responsibility
Create or update an inheritance edge for a control.
Parameters:
system_id(required)control_id(required)framework_id(required)responsibility_mode(required) —inheritedorsharedsource_type(optional) —provider,internal, orhybridvendor_id(optional) — Vendor providing the inherited control
Returns: Created responsibility edge.
get_control_responsibility
Check if a control is inherited and from where.
Parameters:
system_id(required)control_id(required)framework_id(required)
Returns: Responsibility edge details or null.
remove_control_responsibility
Convert an inherited control back to system-specific.
Parameters:
system_id(required)control_id(required)framework_id(required)
Returns: Removal confirmation.
generate_inheritance_narrative
AI-generate an inheritance narrative grounded in vendor documentation.
Parameters:
system_id(required)control_id(required)framework_id(required)
Returns: Draft inheritance narrative text.
get_stale_edges
Identify controls where the source narrative changed but the inherited control hasn’t been updated.
Parameters:
system_id(required)
Returns: List of stale inheritance edges with source change timestamps.
sync_stale_edges
Bulk update inherited controls by regenerating narratives from latest source.
Parameters:
system_id(required)
Returns: Sync results with per-control status.
STIG & CCI
list_stigs
List STIG benchmarks with optional filters.
Parameters:
technology_area(optional) — Filter by technology areaproduct(optional) — Filter by product namelimit(optional) — Default:100offset(optional) — Pagination offset. Default:0
Returns: STIG benchmark list with IDs, titles, and rule counts.
get_stig
Get STIG benchmark detail.
Parameters:
stig_id(required)
Returns: Benchmark metadata including title, version, release info, and severity breakdown.
list_stig_rules
List rules for a STIG benchmark.
Parameters:
stig_id(required)severity(optional) — Filter by severity (high,medium,low)cci_id(optional) — Filter by CCI identifierlimit(optional) — Default:100offset(optional) — Pagination offset. Default:0
Returns: Rule list with IDs, titles, severities, and linked CCIs.
get_stig_rule
Get full STIG rule detail.
Parameters:
stig_id(required)rule_id(required)
Returns: Check text, fix text, discussion, and linked CCIs.
list_ccis
List CCIs with optional filters.
Parameters:
nist_control_id(optional) — Filter by NIST 800-53 control ID (e.g.,AC-2)status(optional)limit(optional) — Default:100offset(optional) — Pagination offset. Default:0
Returns: CCI list with definitions and linked controls.
get_cci
Get CCI detail with linked SRGs and STIG rules.
Parameters:
cci_id(required) — e.g.,CCI-000015
Returns: CCI definition, linked SRGs, and linked STIG rules.
get_cci_chain
Get the full traceability chain: Control -> CCIs -> SRGs -> STIG rules.
Parameters:
nist_control_id(required) — NIST 800-53 control ID (e.g.,AC-2)
Returns: Complete traceability from control requirements to technical checks.
get_cci_status
Get CCI-level compliance rollup for a system.
Parameters:
system_id(required)nist_control_id(optional) — Filter by NIST control ID (e.g.,AC-2)
Returns: Per-CCI pass/fail status.
get_cci_implementation
Read a single per-system CCI implementation row by (system_id, cci_uuid). Returns the live impl detail (status, status_source, narrative, ai_generated_narrative, evidence_ids, eMASS fields, has_status_conflict). 404 means the row hasn’t been initialized for this system yet.
Parameters:
system_id(required)cci_uuid(required) — The CCI catalog UUID (the unique catalog row id, not theCCI-000XXXlabel)
Returns: Full CCI implementation detail.
get_stig_applicability
Get which STIGs apply to a system based on its profile.
Parameters:
system_id(required)
Returns: List of applicable STIG benchmarks.
infer_stigs
AI-infer applicable STIGs from the system’s profile.
Parameters:
system_id(required)
Returns: Recommended STIG benchmarks with reasoning.
get_test_manifest
Fetch the test manifest (applicable STIGs + rules) for a system.
Parameters:
system_id(required)stig_id(optional) — Scope manifest to a specific STIG benchmark
Returns: Test manifest with applicable rules and scanner assignments.
submit_test_results
Upload STIG scan results to the platform.
Parameters:
system_id(required)cli_run_id(required) — CLI scan run identifierresults(required) — Array of test result objectscli_version(optional) — CLI version string
Returns: Submission confirmation with per-result status.
Recipes & Workflows
Recipes are markdown playbooks the calling agent reads and executes; workflows describe how to iterate items in a domain and which recipes to pick per item. See RFC 0001 for the contract spec and docs/src/recipes/ for authoring guides.
list_recipes
List loaded recipes with their summary metadata (id, name, tier, description, use_when, produces). When system_id is supplied, recipes missing required connected sources are hidden by default. Use this to discover which recipes are available, then call get_recipe(id) to read the full body.
Parameters:
tier(optional) — Filter to one tier:official,partner, orcommunityproduces(optional) — Filter by what the recipe produces:evidence,narrative,both, oranswerssystem_id(optional) — Filter to recipes runnable against the system’s connected sourcesinclude_unavailable(optional) — Include recipes missing required sources with unavailable reasons. Default:false
Returns: Recipe summaries with manifest metadata, required sources, and per-recipe source availability.
get_recipe
Return one recipe’s full manifest and body. The body is the markdown playbook the calling agent reads to understand the procedure.
Parameters:
recipe_id(required) — Recipe id to fetch
Returns: Recipe manifest plus the markdown body.
check_sources
Preflight source reachability and candidate recipes for one workflow/control.
Use after start_task and before opening recipe contexts when the agent needs
fresh source/recipe detail.
Parameters:
workflow_id(required) — Workflow id returned bystart_taskcontrol_id(required)system_id(optional) — Defaults to active scopeframework_id(optional) — Defaults to active scope
Returns: Capture-plan items with source kind, connected state, candidate recipes, selected recipe, and structured recipe_gap entries.
start_recipe
Open a recipe execution context. Returns a context_id the caller passes on subsequent platform-API write tool calls so audit metadata is stamped with producer_kind='recipe' automatically. One recipe per session at a time (nesting forbidden in v1). Contexts auto-expire after 1 hour of inactivity.
Parameters:
recipe_id(required) — Recipe id (must be loadable from the registry)recipe_version(required) — Recipe version the caller intends to run. Cross-checked against the loaded recipe; mismatch is an error.params(optional) — Inputs the calling agent supplies, validated against the recipe’s params schemaselection(optional) — StructuredRecipeSelectionrecord from the engagement layer, stored on the context for the eventualRecipeResultevidence_ids(optional) — Evidence ids supplied as inputs for narrative-producing recipes
Returns: Context id and the resolved recipe manifest snapshot.
end_recipe
Close a recipe execution context and return the RecipeResult summary (status, evidence and narrative counts, errors, elapsed time). Must be called once the recipe’s work is complete; failure to call leaves the context in place until the 1-hour expiry sweep.
Parameters:
context_id(required) — Context id returned bystart_recipestatus(optional) — Caller-supplied disposition:pass,fail, orneeds_input. Default:pass
Returns: RecipeResult summary.
list_workflows
List loaded workflow playbooks (single-control, scope-question, policy-question, campaign). Each workflow describes how to iterate items in its domain and which recipes to pick per item. Use this before picking a recipe so the agent works at the right granularity.
Parameters:
iterates_over(optional) — Filter to one item-iteration shape:single_control,scope_questions,policy_questions, orcampaign_items
Returns: Workflow summaries with manifest metadata.
get_workflow
Return one workflow’s full manifest and body. The body is the markdown playbook the calling agent reads to know how to iterate items and pick recipes per item in this workflow’s domain.
Parameters:
workflow_id(required) — Workflow id to fetch
Returns: Workflow manifest plus the markdown body.
MCP Resources
The MCP server exposes read-only resources across three URI schemes: analysis://, status://, and workflow://.
Available Resources
| Resource URI | Description |
|---|---|
analysis://schema | JSON schema for compliance artifacts |
analysis://guide/{framework_id} | Analysis guide for a specific framework |
analysis://control/{framework_id}/{control_id} | Analysis guidance for a specific control within one framework scope |
status://cli | Current CLI version, update availability, and upgrade guidance |
workflow://recipe/{recipe_id} | Step-by-step workflow recipe for common compliance tasks |
Usage
Access these resources via ReadMcpResourceTool with server: "pretorin" in your MCP client.
Analysis Schema
analysis://schema
Returns the JSON schema for structured compliance artifacts. Use this when generating artifact JSON to ensure correct structure. See Artifact Schema for documentation.
Framework Analysis Guide
analysis://guide/{framework_id}
Available framework guides:
analysis://guide/fedramp-moderateanalysis://guide/nist-800-53-r5analysis://guide/nist-800-171-r3
Returns framework-specific analysis guidance including purpose, target audience, scope, and assessment methodology.
Control Analysis Guidance
analysis://control/{framework_id}/{control_id}
Example: analysis://control/fedramp-moderate/ac-02
Returns control-specific analysis guidance including search patterns, evidence examples, and assessment criteria for one framework scope.
CLI Status
status://cli
Returns the current CLI version, latest available version, whether an update is available, passive notification status, check state (verified/unverified), and the upgrade command. MCP hosts can inspect this resource to surface update guidance.
Workflow Recipes
workflow://recipe/{recipe_id}
Returns a step-by-step workflow recipe for common compliance tasks. Available recipes are listed dynamically via the MCP list_resources method.
MCP Troubleshooting
“Not authenticated” Error
Ensure you’ve logged in:
pretorin login
pretorin whoami # Verify authentication
MCP Server Not Found
-
Verify pretorin is installed and in your PATH:
which pretorin pretorin --version -
Try using the full path in your configuration:
{ "mcpServers": { "pretorin": { "command": "/path/to/pretorin", "args": ["mcp-serve"] } } } -
For
uv toolorpipxinstallations, find the path:command -v pretorin -
If the MCP client can talk to Pretorin but scoped write tools behave strangely, validate the stored CLI context:
pretorin context show --quiet --checkThis catches deleted systems, detached frameworks, and other stale local scope before you debug the MCP client itself.
Server Crashes or Hangs
Check the MCP server logs:
pretorin mcp-serve 2>&1 | tee mcp-debug.log
Ensure your API key is valid:
pretorin whoami
Framework or Control Not Found
- Verify the framework ID exists:
pretorin frameworks list - Verify the control ID exists:
pretorin frameworks controls <framework_id> - Check Control ID Formats for correct formatting
Common ID Mistakes
| Error | Fix |
|---|---|
ac-1 not found | Use zero-padded: ac-01 |
ac family not found | Use slug: access-control |
AC.l2-3.1.1 not found | CMMC is case-sensitive: AC.L2-3.1.1 |
3.1.1 control not found | 800-171 needs leading zeros: 03.01.01 |
No Systems Found
If list_systems returns no systems, you need a beta code to create one on the Pretorin platform. Systems cannot be created through the CLI or MCP. Sign up for early access.
Rate Limiting
The API uses rate limiting. If you receive 429 Too Many Requests errors, the client automatically retries with exponential backoff. For persistent issues, reduce request frequency.
Support
- Documentation: platform.pretorin.com/api/docs
- Issues: github.com/pretorin-ai/pretorin-cli/issues
- Platform: platform.pretorin.com
Agent Overview
The agent command group runs autonomous compliance tasks using the Codex agent runtime. This is the Pretorin-hosted model mode — Pretorin manages the AI runtime and routes model calls through its /v1 endpoints.
If you already use another AI agent (Claude Code, Cursor, etc.), use the MCP mode instead (pretorin mcp-serve) and connect Pretorin tools to your existing agent.
Running a Compliance Task
# Free-form task
pretorin agent run "Assess AC-02 implementation gaps for my system"
# Use a predefined skill
pretorin agent run --skill gap-analysis "Analyze my system compliance gaps"
Options
| Option | Description |
|---|---|
--skill/-s <name> | Use a predefined skill template |
--model/-m <model> | Model override |
--base-url <url> | Custom model API endpoint |
--working-dir/-w <path> | Working directory for code analysis |
--no-stream | Disable streaming output |
--legacy | Use legacy OpenAI Agents SDK (deprecated) |
--max-turns <n> | Maximum agent turns (legacy mode only, default 15) |
--no-mcp | Disable external MCP servers (legacy mode only) |
Hosted Model Setup
Use this setup when you want pretorin agent run to call Pretorin-hosted model endpoints.
# 1. Login with your Pretorin API key
pretorin login
# 2. Optional: override the default model proxy endpoint
# (default: https://platform.pretorin.com/api/v1/public/model)
pretorin config set model_api_base_url https://your-proxy.example.com/v1
# 3. Validate runtime
pretorin agent doctor
pretorin agent install
# 4. Run a task
pretorin agent run "Assess AC-02 implementation gaps for my system"
Model Key Precedence
The Codex agent resolves API keys in this order:
config.api_key(frompretorin login) — used as bearer key for the platform model proxyOPENAI_API_KEYenvironment variableconfig.openai_api_key
When --base-url is explicitly provided (non-platform endpoint), the order changes to prefer OPENAI_API_KEY first, then falls back to config keys.
Custom Model Endpoints
The agent supports any OpenAI-spec LLM endpoint, including:
- Azure OpenAI
- vLLM
- LiteLLM
- Ollama
Configure via --base-url flag or the model_api_base_url config key.
The deprecated --legacy path uses the same configured endpoint and sends
requests through the Responses API.
How It Works
The agent runtime uses the Codex SDK with a pinned binary in ~/.pretorin/bin/ and an isolated CODEX_HOME at ~/.pretorin/codex/. The agent:
- Downloads and pins a specific Codex binary version
- Runs in an isolated
CODEX_HOMEenvironment (never touches~/.codex/) - Automatically injects the Pretorin MCP server for compliance tool access
- Streams events and output in real-time (unless
--no-streamis passed)
See Agent Runtime Management for the full set of pretorin agent lifecycle commands.
Agent Skills
Skills are predefined task templates that guide the agent through specific compliance workflows.
Available Skills
| Skill | Description | Max Turns |
|---|---|---|
gap-analysis | Analyze system compliance gaps across frameworks | 20 |
narrative-generation | Generate implementation narratives for controls | 15 |
evidence-collection | Collect and map evidence from codebase to controls | 20 |
security-review | Review codebase for security controls and compliance posture | 25 |
stig-scan | Run STIG compliance scans against a system | 15 |
cci-assessment | Assess CCI compliance for a specific control | 15 |
max_turns is enforced only in --legacy mode. The Codex runtime governs turn count via its own session loop.
Using Skills
# Gap analysis
pretorin agent run --skill gap-analysis "Analyze my system compliance gaps"
# Narrative generation
pretorin agent run --skill narrative-generation "Generate narratives for all AC controls"
# Evidence collection
pretorin agent run --skill evidence-collection "Collect evidence for AC-02 in this repo"
# Security review
pretorin agent run --skill security-review "Review this codebase for AC-02 coverage"
# STIG scan
pretorin agent run --skill stig-scan "Check STIG applicability for my system"
# CCI assessment
pretorin agent run --skill cci-assessment "Assess CCI compliance for AC-02"
List Skills
pretorin agent skills
Skill Details
Gap Analysis
Read-only platform analysis that identifies controls without complete implementation. The agent:
- Lists systems and their associated frameworks
- Checks the compliance status for each system
- Identifies controls that are not yet implemented or only partially implemented
- Prioritizes gaps by risk level (controls in higher-impact families first)
- Provides actionable recommendations for closing each gap
This skill does not write to the platform — it produces a structured report with sections for each framework. To capture findings as evidence or update narratives, follow up with evidence-collection or narrative-generation.
See Gap Analysis Workflow for the broader methodology that combines this skill with codebase search.
Narrative Generation
Generates control implementation narratives that meet auditor-readiness requirements:
- No markdown headings
- At least two rich markdown elements (code blocks, tables, lists, links)
- At least one structural element (code block, table, or list)
- No gaps, missing-information placeholders, or remediation backlog in narrative text
- Only documents observable facts (no hallucination)
Evidence Collection
Searches the codebase for evidence that maps to specific controls:
- Identifies relevant files and code patterns
- Creates evidence items with auditor-ready descriptions
- Links evidence to controls via the platform
- Records gaps as issues when evidence is missing
Security Review
Reviews the codebase against specific controls and records findings on the platform:
- Analyzes code for control coverage
- Identifies implementation strengths and weaknesses
- Documents findings with file paths and line numbers
- Pushes monitoring events for critical or high-severity findings
- Reopens control authoring with
in_progressand drafts narratives based on findings - Adds issues for findings that require manual remediation
- Produces remediation recommendations
This is the broadest write-side skill — it can call push_monitoring_event, update_control_status (only in_progress), update_narrative, create_evidence, link_evidence, and add_control_issue/resolve_control_issue in addition to the read-side platform tools.
STIG Scan
Runs STIG compliance scans against a system:
- Checks which STIGs apply to the system (applicability)
- Gets the test manifest (rules to evaluate)
- Reports available scanners and rule coverage
- Summarizes the scan plan and gaps in automated coverage
CCI Assessment
Assesses CCI-level compliance for a specific control:
- Gets control context and implementation status
- Lists CCIs for the target control
- Checks CCI-level test results (pass/fail/not tested)
- Identifies CCIs with no test coverage
- Presents results as a traceability chain: Control -> CCIs -> STIG rules -> test results
Agent Runtime Management
The agent runtime uses a managed Codex binary with isolated configuration.
Check Runtime Health
pretorin agent doctor
Validates that the Codex runtime is properly installed and configured. On macOS, this also runs the system execution trust check for the pinned binary so revoked or blocked signatures are reported before an agent run.
Install Codex Binary
pretorin agent install
Downloads the pinned Codex binary to ~/.pretorin/bin/. The version is pinned by the CLI to ensure compatibility.
Check Version
pretorin agent version
Shows the pinned Codex version and whether it’s currently installed.
Manage MCP Servers
The agent can connect to additional MCP servers beyond Pretorin. This lets the agent access other tools (filesystem, databases, etc.) during compliance tasks.
List Configured Servers
pretorin agent mcp-list
Add a Server
# stdio transport
pretorin agent mcp-add <name> stdio <command> --arg <arg1> --arg <arg2>
# http transport
pretorin agent mcp-add <name> http <url>
Options:
| Option | Description |
|---|---|
--arg/-a <arg> | Additional args for stdio transport (repeatable) |
--scope <scope> | Config scope: project (default, .pretorin-mcp.json) or global (~/.pretorin/mcp.json) |
Examples:
pretorin agent mcp-add github stdio uvx --arg mcp-server-github
pretorin agent mcp-add aws http https://mcp.example.com/aws
pretorin agent mcp-add tools stdio node --arg /path/to/server --scope global
Remove a Server
pretorin agent mcp-remove <name>
Runtime Architecture
The Codex runtime is fully isolated:
- Binary location:
~/.pretorin/bin/ - Configuration:
~/.pretorin/codex/(CODEX_HOME) - Version pinning: The CLI pins a specific Codex version for compatibility
- Trust diagnostics:
pretorin agent doctorchecks whether the pinned binary is trusted by the host OS before it is launched - MCP injection: Pretorin MCP server is automatically available to the agent
This isolation ensures the agent runtime never interferes with any user-installed Codex instances.
Authoring Recipes
Recipes are markdown-plus-Python playbooks that the calling AI agent invokes
through MCP. Each recipe is a directory with a recipe.md (frontmatter +
prose body) and one or more script files. The agent reads the body to
understand what the recipe does, picks one when its use_when matches the
task, and calls the recipe’s scripts as MCP tools.
If you’ve ever written a Claude Code skill, the shape will feel familiar — recipes are the same idea, scoped to compliance work and stamped with audit metadata automatically.
Why You Might Write One
Three concrete reasons:
- Your team has a non-obvious procedure for capturing a particular kind of evidence (e.g., “pull the latest IAM policy from the prod account, redact customer ARNs, attach as a configuration record”). Encoding it as a recipe means every teammate’s agent does the same steps the same way.
- You wrap an internal scanner that produces STIG-style results. A recipe
exposes it next to the built-in
inspec-baseline/openscap-baselineso the calling agent can pick it for the rules it covers. - You’re contributing back upstream. First-party scanner recipes
(
inspec-baseline,openscap-baseline, etc.) live undersrc/pretorin/recipes/_recipes/. New contributions follow the same shape.
Write Your First Recipe in 10 Minutes
# 1. Scaffold a fresh recipe in your user folder.
pretorin recipe new my-first-recipe
# 2. The scaffolder drops a directory at ~/.pretorin/recipes/my-first-recipe/
# with recipe.md, scripts/main.py, README.md, tests/test_recipe.py.
# 3. Edit the description, use_when, and the body of recipe.md.
$EDITOR ~/.pretorin/recipes/my-first-recipe/recipe.md
# 4. Edit scripts/main.py — implement `async def run(ctx, **params)`.
$EDITOR ~/.pretorin/recipes/my-first-recipe/scripts/main.py
# 5. Validate.
pretorin recipe validate my-first-recipe
# 6. Run it locally to test (no agent / MCP boundary involved).
pretorin recipe run my-first-recipe --param key=value
If validate passes and run prints the result you expect, the recipe is in the registry. Restart your MCP client and the agent can use it on the next task.
pretorin recipe run is a local-testing path: writes go through your
authenticated PretorianClient directly, so audit-metadata stamping requires
explicit audit_metadata on each create_evidence call (see Writer
tools). The agent path through MCP stamps automatically.
What Ships in v1
- Four loader paths with clear precedence: explicit > project > user > built-in. See Loader paths below.
pretorin recipe list / show / new / validate / runCLI commands.list_recipes/get_recipeMCP discovery tools, including source-aware filtering withlist_recipes(system_id=...).list_connected_sources/check_sourcesMCP preflight tools for capture planning.- Per-script MCP tools auto-registered as
recipe_<safe_id>__<script_name>. - Audit-metadata stamping: the calling agent opens a recipe execution
context with
start_recipe(...); every platform write inside the context is stamped withproducer_kind="recipe", the recipe id, and the recipe version. The platform records the full chain. - Workflow playbooks (
list_workflows/get_workflow) for the four item-iteration shapes: single-control, scope-question, policy-question, campaign. Workflows describe how to iterate; recipes describe what to do per item. - Recipe-only MCP writes for evidence and narratives: agents pass
recipe_context_idon write tools, and narrative recipes also pass citedevidence_ids.
Loader Paths
| Source | Path | Use it when |
|---|---|---|
| Built-in | src/pretorin/recipes/_recipes/<id>/ | First-party recipes shipped with pretorin-cli. |
| User folder | ~/.pretorin/recipes/<id>/ | Your local recipes — survives across projects. |
| Project folder | <repo>/.pretorin/recipes/<id>/ | Team-shared recipes checked into the compliance repo. |
| Explicit path | pretorin recipe show --path /abs/... | Testing a recipe while authoring. |
If the same id appears in two paths, the higher-precedence one wins.
pretorin recipe show <id> --sources lists every location and marks which
is active.
Tier
Each loaded recipe gets a tier set by the loader from its source path:
official— built-in, shipped with pretorin-cli (forced regardless of what the manifest says).community— anything from the user/project folders or explicit paths.partner— reserved for installed packages (v1.5).
The calling agent sees the tier in list_recipes output and can
factor it in when picking. Community recipes are first-class — the tier
is signal, not a permission gate.
Where to Read Next
- Manifest reference — every frontmatter field with examples.
- Script contract — the
async def run(ctx, **params) -> dictsignature. - Writer tools — the platform-API tools your scripts call, and how audit metadata gets stamped.
- Testing — pytest fixtures and patterns.
- Publishing — how to share a community recipe or PR an official one.
- Workflows — the layer above recipes: how the calling agent picks a workflow, then picks recipes per item.
- Worked example — a community recipe walked through end-to-end.
Manifest Reference
The manifest is the YAML frontmatter at the top of recipe.md. It’s the
public contract between recipe authors and pretorin. The schema is defined
by the pydantic models in src/pretorin/recipes/manifest.py and frozen per
contract_version.
Minimal Example
---
id: my-first-recipe
version: 0.1.0
name: "My First Recipe"
description: "Capture the active IAM role's trust policy and attach it as a configuration record."
use_when: "The agent needs evidence that an IAM role's trust policy meets least-privilege requirements."
produces: evidence
author: "Jane Doe"
license: Apache-2.0
requires:
sources:
- kind: aws_account
binding_role: primary
probe: "aws sts get-caller-identity"
source_version_kind: cloud_account_scan_time
scripts:
capture:
path: scripts/capture.py
description: "Pull the trust policy from AWS and return it as a redacted dict."
---
# My First Recipe Body
The agent reads everything below the closing `---` to understand what to do.
Required Fields
| Field | Type | Notes |
|---|---|---|
id | string | Kebab-case (^[a-z][a-z0-9-]*$). Globally unique across loader paths. |
version | string | SemVer-ish. Bumped when behavior changes. Stamped on evidence. |
name | string | Display name shown in pretorin recipe list. |
description | string | ≥ 50 chars. The text the agent reads to decide if this recipe fits. |
use_when | string | ≥ 30 chars. Explicit “when the agent has X and needs Y” guidance. |
produces | enum | evidence / narrative / both / answers. What the recipe writes back to the platform. |
author | string | Attribution. Stamped in evidence provenance. |
Optional Fields
| Field | Type | Default | Notes |
|---|---|---|---|
tier | enum | community | official / partner / community. Loader overrides from source path. |
license | string | Apache-2.0 | SPDX identifier. Required for any recipe shared publicly. |
params | map | {} | Recipe-level inputs. See Params. |
requires | object | {} | Connected sources, CLI binaries, and env vars the recipe needs. See Requires. |
attests | list | [] | [{control, framework}] hints. Filter, not binding. |
scripts | map | {} | tool_name → ScriptDecl. Each becomes an MCP tool. See Scripts. |
contract_version | int | 1 | Frontmatter shape version. Bumps only on breaking changes. |
recipe_schema_version | string | "1.0" | Schema this recipe is written against. |
min_pretorin_version | string | null | Loader refuses to load if running pretorin is older. |
Tier
tier is set by the loader from the recipe’s source path, overriding
whatever the manifest declares:
- Built-in path →
official - User folder, project folder, explicit path →
community partner→ reserved for installed packages (v1.5)
Authors should still declare a tier — it documents intent, and any manifest-internal validation runs against the declared value.
Params
Recipe-level params are inputs the calling agent supplies via
start_recipe(...). They flow through to scripts as kwargs.
params:
stig_id:
type: string
description: "STIG benchmark id targeting Linux baseline controls"
required: true
target:
type: string
description: "Optional connection string (e.g., 'ssh://host')"
default: "local"
Supported types: string, integer, number, boolean, array. For
array, declare items: { type: ... } so the MCP renderer can emit a
real JSON Schema.
Requires
Document the runtime environment and connected system sources the recipe
needs. sources is the MCP preflight contract; cli and env remain
local runtime requirements for recipe scripts.
requires:
sources:
- kind: github_org
binding_role: primary
probe: "gh auth status"
source_version_kind: github_api_etag
cli:
- { name: inspec, probe: "inspec --version" }
- { name: jq, probe: "jq --version" }
env:
- AWS_PROFILE
- INSPEC_TARGET
Supported source kinds: workspace_repo, github_org, aws_account,
azure_tenant, k8s_cluster, slack_workspace, and emass.
source_version_kind tells the agent/platform what counts as the source
anchor for evidence emitted by this recipe: for example git_commit,
github_api_etag, cloud_account_scan_time, or capture_timestamp.
When list_recipes(system_id=...) is called, recipes whose required
sources are not connected are hidden unless include_unavailable=true.
Attests
attests is a list of {control, framework} entries the recipe is
likely relevant to. It’s a hint for filtering, never a binding —
the agent picks recipes by reading description and use_when, not
by joining on attests.
attests:
- { control: AC-2, framework: nist-800-53-r5 }
- { control: AC-6, framework: nist-800-53-r5 }
Scripts
Each ScriptDecl becomes an MCP tool:
scripts:
run_scan:
path: scripts/run_scan.py
description: "Pull the manifest, run the scan, return per-rule results."
params:
stig_id:
type: string
description: "STIG benchmark id"
required: true
target:
type: string
description: "Connection string"
timeout_seconds: 600
writes_evidence: false
| Field | Notes |
|---|---|
path | Relative to the recipe directory. The validator checks the file exists and contains async def run. |
description | One-liner the agent sees on the tool. Be specific — this is the tool’s “tooltip”. |
params | Per-script JSON Schema input. Independent of recipe-level params. |
timeout_seconds | Wall-clock cap for one invocation. Default 300. |
writes_evidence | Declared intent. The trust gate for community recipes considers it. |
The MCP tool name for this script is recipe_<safe_id>__run_scan,
where safe_id is the recipe id with hyphens converted to underscores
(MCP tool names can’t contain hyphens). The recipe author doesn’t construct
this name — pretorin does.
Contract and Schema Versioning
Two version fields exist for forward compatibility:
contract_version— bumps only on backwards-incompatible shape changes to the frontmatter itself. Most recipes pin to1.recipe_schema_version— the schema this specific recipe is written against. The loader refuses to load a recipe whose schema is newer than what the running pretorin supports, with a hint to upgrade.
min_pretorin_version lets a recipe author require a specific runtime
version (e.g., when a recipe uses a writer tool that only exists in
pretorin ≥ 0.18).
What the Loader Does to Your Manifest
- Parses the YAML frontmatter.
- Validates against the pydantic schema. A failure raises
RecipeManifestErrorfor that recipe — the registry keeps loading other recipes. - Overrides
tierfrom the source path (built-in → official, otherwise community). - Caches the parsed manifest by
(path, mtime). If you edit the file, the next load re-parses it.
Script Contract
Every script declared under scripts: in recipe.md must export a single
async function:
async def run(ctx, **params) -> dict:
...
That’s the entire contract. The recipe runner imports the module, calls
run, awaits the result, and hands it back to the calling agent as the
MCP tool response.
The Signature
from typing import Any
async def run(ctx: Any, *, stig_id: str, target: str = "local") -> dict[str, Any]:
"""Run a baseline scan and return per-rule results."""
...
| Argument | Type | What it is |
|---|---|---|
ctx | RecipeScriptContext | Per-invocation execution context (see below). |
**params | varies | The keyword args the agent supplied, validated against scripts.<name>.params in the manifest. |
The function must be async. Use await for I/O. Pretorin’s writer
tools are async; using sync HTTP or sync subprocess for slow operations
will block the recipe runner’s event loop.
The return value must be a JSON-serializable dict. Anything with
tuple, set, datetime, or custom classes will fail to serialize back
through MCP.
The ctx Argument
RecipeScriptContext (defined in src/pretorin/recipes/runner.py):
@dataclass
class RecipeScriptContext:
system_id: str | None
framework_id: str | None
api_client: Any # PretorianClient — see writer-tools.md
logger: logging.Logger
recipe_id: str
recipe_version: str
recipe_context_id: str | None
The two you’ll use most:
ctx.api_client— the authenticatedPretorianClient. Use this to call platform-API methods (ctx.api_client.create_evidence(...),ctx.api_client.get_test_manifest(...), etc.). See Writer tools for the full surface.ctx.logger— alogging.Loggernamed for the recipe. Prefer this overprintso the calling agent’s logs stay structured.
ctx.system_id is set when the calling agent specified a system at
start_recipe time. Use it for any per-system platform call. If
your recipe doesn’t make sense without a system, raise early with a clear
error.
ctx.recipe_context_id is the active execution context id. The MCP write
handlers read it from the session automatically — you only need to pass
it explicitly if your script makes a platform write outside the MCP
boundary (e.g., a direct httpx call against a custom internal endpoint).
Returning Results
Whatever your script returns becomes the MCP tool response the calling agent reads. Keep it structured: nested dicts the agent can inspect, with clear keys.
async def run(ctx, *, stig_id: str) -> dict[str, Any]:
rules = await fetch_rules(ctx.api_client, ctx.system_id, stig_id)
results = await scan(rules)
return {
"stig_id": stig_id,
"summary": {
"total": len(results),
"passed": sum(1 for r in results if r.status == "pass"),
"failed": sum(1 for r in results if r.status == "fail"),
},
"rules": [r.to_dict() for r in results],
}
Return shapes the agent can pattern-match are easier to act on than freeform prose. Save the prose for the recipe body — let the script return data.
Imports Inside scripts/
The runner adds the recipe’s scripts/ directory to sys.path for the
duration of the call, so a sibling module is reachable as a top-level
import:
# scripts/run_scan.py
from helpers import normalize_results # reaches scripts/helpers.py
The path is removed after the call returns. You don’t have to
__init__.py-decorate the directory.
Error Handling
Don’t swallow exceptions inside run. Let them propagate — the runner
catches them, logs them, and returns a structured error to the calling
agent. Catching and returning a string error makes the agent think the
call succeeded.
# Bad
async def run(ctx, *, stig_id: str) -> dict[str, Any]:
try:
return await fetch(ctx, stig_id)
except Exception as e:
return {"error": str(e)} # agent sees a "successful" call
# Good
async def run(ctx, *, stig_id: str) -> dict[str, Any]:
return await fetch(ctx, stig_id) # exceptions surface as tool errors
Patterns
Three shapes cover most recipes:
Capture-from-source
The recipe pulls a thing (a config file, a snippet of code, a query result), redacts it, and registers an evidence record.
async def run(ctx, *, file_path: str, line_range: str | None = None) -> dict[str, Any]:
text = (Path(file_path).read_text()).split("\n")
snippet = _slice(text, line_range)
redacted, summary = redact_secrets(snippet)
composed = compose_audit_markdown(redacted, file_path=file_path, line_range=line_range)
evidence_id = await ctx.api_client.create_evidence(
system_id=ctx.system_id,
...
)
return {"evidence_id": evidence_id, "redaction_summary": summary.to_dict()}
Wrap-a-scanner
The recipe wraps an external tool (oscap, inspec, az, aws), runs it against the platform’s test manifest, and returns per-rule results.
async def run(ctx, *, stig_id: str, target: str = "local") -> dict[str, Any]:
manifest = await fetch_test_manifest(ctx.api_client, ctx.system_id, stig_id=stig_id)
rules = rules_for_stig(manifest, stig_id)
scanner = InSpecScanner()
results = await scanner.execute(rules, config={"target": target})
return {
"stig_id": stig_id,
"summary": summarize_results(results),
}
The five built-in scanner recipes are exactly this shape — each is a thin
adapter over a pretorin.scanners.* class.
Q-and-A attestation
The recipe is the agent collecting human attestations interactively, with no external tool involved. Inputs are structured answers; the recipe just records them.
async def run(ctx, *, stig_id: str, attestations: list[dict]) -> dict[str, Any]:
scanner = ManualScanner()
results = await scanner.execute(rules, config={"attestations": attestations})
return {"stig_id": stig_id, "summary": summarize_results(results)}
When to Write Multiple Scripts
If your recipe has steps that the calling agent might want to interleave with reasoning (e.g., “redact, show me, then compose”), expose each step as its own script. The agent can then call them as separate MCP tools and inspect the intermediate output.
The code-evidence-capture recipe ships two scripts (redact_secrets and
compose_snippet) for exactly this reason.
Writer Tools
Recipe scripts call the platform API through ctx.api_client, which is
the same PretorianClient the rest of pretorin uses. This page covers the
common write paths and how audit metadata gets stamped automatically when
your recipe runs inside an execution context.
How Audit Metadata Gets Stamped
The calling agent opens an execution context with
start_recipe(recipe_id, recipe_version, params) and gets back a
context_id. Subsequent platform writes from that MCP session pick up the
context automatically and stamp:
{
"producer_kind": "recipe",
"producer_id": "<recipe_id>",
"producer_version": "<recipe_version>",
"recipe_context_id": "<context_id>"
}
When the calling agent makes an MCP-routed write — i.e. the write goes
through create_evidence, create_evidence_batch, or update_narrative
— it must pass recipe_context_id. The MCP handler reads that context and
builds the metadata. Direct agent writes without a recipe context return a
structured recipe_required error.
When your script makes a write directly through ctx.api_client
(skipping MCP), you have to pass audit_metadata yourself. The helper to
build it lives at pretorin.evidence.audit_metadata:
from pretorin.evidence.audit_metadata import build_recipe_metadata
audit_metadata = build_recipe_metadata(
body=source_excerpt,
source_uri="file://config/rbac.yaml",
source_type="repo_file",
recipe_id=ctx.recipe_id,
recipe_version=ctx.recipe_version,
source_label="RBAC configuration",
source_locator="lines 12-30",
source_excerpt=source_excerpt,
capture_method="repository_file_read",
redaction_summary=...,
)
evidence = EvidenceCreate(
control_id="ac-2",
framework_id="nist-800-53-r5",
name="...",
evidence_type="configuration",
description="RBAC role mapping is enforced in the IdP configuration.",
artifact_content=composed_markdown,
audit_metadata=audit_metadata,
)
await ctx.api_client.create_evidence(ctx.system_id, evidence)
Most recipes don’t need the direct path — write through MCP and let the handler stamp.
Read-Side Helpers
You’ll often need to read platform state before writing. The most useful
methods on ctx.api_client:
| Method | Returns | Use |
|---|---|---|
list_systems() | list[dict] | Find a system id when one wasn’t passed in ctx.system_id. |
get_test_manifest(system_id, stig_id=None) | dict | The applicable rules for a system, optionally narrowed to one STIG. |
get_control(framework_id, control_id) | ControlDetail | Full control text + family + status. |
get_controls_batch(framework_id, control_ids) | dict | Batch fetch — cheaper than N calls. |
get_control_implementation(...) | dict | Current narrative + status for one control. |
get_stig_applicability(system_id) | dict | Which STIGs apply to a system. |
get_compliance_status(system_id, framework_id) | dict | High-level coverage rollup. |
get_source_manifest(system_id) | dict | Verified-sources state for the system. |
Manifest helpers for scanner recipes
If you’re building a scanner recipe, three helpers in
pretorin.scanners.manifest cover the common shape:
from pretorin.scanners.manifest import (
fetch_test_manifest,
rules_for_stig,
summarize_results,
)
manifest = await fetch_test_manifest(ctx.api_client, ctx.system_id, stig_id="RHEL_9_STIG")
rules = rules_for_stig(manifest, "RHEL_9_STIG")
results = await my_scanner.execute(rules, config={"target": "local"})
summary = summarize_results(results)
Every built-in scanner recipe uses exactly this pattern. If you’re wrapping
a new scanner, copy inspec-baseline/scripts/run_scan.py as a starting
point.
Write-Side: Evidence
from pretorin.client.models import EvidenceCreate
evidence = EvidenceCreate(
control_id="ac-2",
framework_id="nist-800-53-r5",
name="RBAC configuration excerpt",
evidence_type="configuration",
description="RBAC role mapping is enforced in the IdP configuration.",
artifact_content=composed_markdown,
audit_metadata=audit_metadata,
)
result = await ctx.api_client.create_evidence(ctx.system_id, evidence)
For batched writes (much faster when you have ≥ 10):
from pretorin.client.models import EvidenceBatchItemCreate
items = [
EvidenceBatchItemCreate(
control_id="ac-2",
name="...",
description="Short summary",
artifact_content=composed_markdown,
evidence_type="...",
audit_metadata=audit_metadata,
)
for _ in batch
]
response = await ctx.api_client.create_evidence_batch(
ctx.system_id,
framework_id="nist-800-53-r5",
items=items,
)
For binary/unstructured artifacts (a screenshot, a PDF, an exported report), upload the file:
result = await ctx.api_client.upload_evidence(
system_id=ctx.system_id,
file_path="/tmp/my-screenshot.png",
name="Console screenshot — IAM users page",
evidence_type="screenshot",
control_id="ac-2",
)
Write-Side: Narratives
await ctx.api_client.update_narrative(
system_id=ctx.system_id,
framework_id="nist-800-53-r5",
control_id="ac-2",
narrative=composed_text,
recipe_context_id=ctx.recipe_context_id,
evidence_ids=["ev-123"],
)
Narrative-producing recipes must cite evidence ids. Open the context with
start_recipe(..., evidence_ids=[...]), compose only from those evidence
items, then pass the same ids to update_narrative.
Write-Side: Test Results
For scanner recipes:
await ctx.api_client.submit_test_results(
system_id=ctx.system_id,
benchmark_id="RHEL_9_STIG",
results=[...], # list of TestResult dicts
)
Redaction and Markdown Composition
Two helpers from pretorin.evidence:
from pretorin.evidence.redact import redact_secrets
from pretorin.evidence.markdown import compose
redacted_text, redaction = redact_secrets(raw_text)
markdown = compose(
prose="The IAM trust policy is configured to require MFA for assume-role.",
snippet=redacted_text,
snippet_lang="json",
file_path="iam/trust-policy.json",
)
redact_secrets returns a RedactionResult with counts per secret type
(AWS access keys, GitHub tokens, JWTs, etc.). compose turns prose +
snippet into the audit-grade markdown body the platform expects on
evidence records.
These two are the building blocks of the code-evidence-capture built-in
recipe — read its source under src/pretorin/recipes/_recipes/code-evidence-capture/
for a real-world usage pattern.
What Recipe Scripts Should Not Do
- Don’t bypass
ctx.api_clientto talk to the platform via raw HTTP. You’ll skip the auth, retry, and error-handling logic the client provides. - Don’t construct
audit_metadatafrom scratch. Usebuild_recipe_metadata/build_recipe_metadata_from_contextso the shape stays consistent. - Don’t call
start_recipefrom inside a script. The recipe context is already open — that’s how the script got invoked. Nesting is forbidden. - Don’t assume
ctx.system_idis set. If your recipe requires a system, raise early with a clear message rather than passingNonethrough to the API.
Testing Recipes
Recipes are real Python modules — test them like any other Python code. The
scaffolder drops a tests/test_recipe.py stub when you run
pretorin recipe new <id>; this page covers what to put in it.
Three Layers Worth Testing
A recipe has three layers and each rewards a different test style:
- Pure helpers inside
scripts/— redaction, normalization, parsers. Plain unit tests with no fixtures. Fastest feedback loop; most coverage per line of test code. runagainst a fakectx— the script’s main entry point. Mockctx.api_clientso you don’t hit the network.- End-to-end through the recipe runner — load the recipe, call its script through the runner, assert the result. Slower but proves the manifest, the importlib-based dispatch, and the script all line up.
Unit-Testing Helpers
If you’ve factored out helpers into scripts/redact.py or
scripts/normalize.py, import them directly:
# tests/test_helpers.py
from scripts.redact import redact_aws_keys
def test_redact_aws_keys_replaces_full_key() -> None:
text = "AKIAIOSFODNN7EXAMPLE"
redacted = redact_aws_keys(text)
assert "AKIA" not in redacted
assert "[REDACTED:AWS_KEY]" in redacted
The recipe runner adds the scripts/ directory to sys.path. In tests,
make sure your pytest.ini or pyproject.toml does the same:
[tool.pytest.ini_options]
pythonpath = ["scripts"]
Testing run with a Fake ctx
The script’s run function takes a ctx argument typed as
Any (loose intentionally — see Script contract).
A MagicMock with AsyncMock for the I/O methods is enough:
# tests/test_run.py
from unittest.mock import AsyncMock, MagicMock
import pytest
from scripts.run_scan import run
@pytest.mark.asyncio
async def test_run_returns_summary_for_no_rules() -> None:
ctx = MagicMock()
ctx.system_id = "sys-1"
ctx.api_client = MagicMock()
ctx.api_client.get_test_manifest = AsyncMock(
return_value={"applicable_stigs": []}
)
result = await run(ctx, stig_id="EMPTY_STIG")
assert result["stig_id"] == "EMPTY_STIG"
assert result["summary"]["total"] == 0
The four scanner recipe tests in pretorin-cli’s test suite use exactly
this shape — patch get_test_manifest, call run, assert on the
returned summary.
End-to-End Through the Runner
The strongest test exercises the full path: registry loads the manifest,
runner imports the script, script runs against a fake API client. This
is what tests/recipes/test_code_evidence_capture.py does for the
code-evidence-capture recipe and it’s the regression-test pattern to
copy.
Sketch:
import pytest
from pretorin.recipes import loader as loader_module
from pretorin.recipes.loader import clear_cache
from pretorin.recipes.registry import RecipeRegistry
from pretorin.recipes.runner import RecipeScriptContext, run_script
from unittest.mock import AsyncMock, MagicMock
@pytest.fixture(autouse=True)
def _isolate(tmp_path, monkeypatch):
clear_cache()
monkeypatch.setattr(loader_module, "_user_recipes_root", lambda: tmp_path / "u")
monkeypatch.setattr(loader_module, "_project_recipes_root", lambda start=None: None)
@pytest.mark.asyncio
async def test_my_recipe_end_to_end() -> None:
registry = RecipeRegistry()
entry = registry.get("my-recipe")
assert entry is not None
api_client = MagicMock()
api_client.create_evidence = AsyncMock(return_value={"id": "ev-1"})
ctx = RecipeScriptContext(
system_id="sys-1",
framework_id="nist-800-53-r5",
api_client=api_client,
logger=MagicMock(),
recipe_id="my-recipe",
recipe_version="0.1.0",
recipe_context_id="ctx-test",
)
result = await run_script(
recipe=entry.active,
script_name="capture",
ctx=ctx,
params={"control_id": "ac-2"},
)
assert result["evidence_id"] == "ev-1"
For a community recipe outside the pretorin source tree, point the loader at your recipe’s directory:
monkeypatch.setattr(loader_module, "_user_recipes_root", lambda: my_recipe_parent)
Run It Locally
Before wiring the recipe into an agent, exercise it directly:
pretorin recipe run my-recipe --param key=value --param limit=20
pretorin recipe run loads the recipe through the registry (or --path for
a not-yet-registered directory), opens a recipe execution context, calls the
script, prints the return value, and closes the context. It bypasses the MCP
boundary, so:
- Use it for fast iteration on the script itself.
- Pure transformation recipes (return data, don’t write to the platform) work end-to-end.
- Recipes that do write through
ctx.api_clientneed explicitaudit_metadataon each call — the MCP boundary stamps automatically; this command does not. See Writer tools.
--no-context skips opening the execution context for recipes that don’t
need it.
Validate as a Smoke Test
pretorin recipe validate <id> runs the manifest schema check, the script
existence check, and the description-quality check. Add it to your CI as
a shell-out smoke test:
- name: Validate recipes
run: |
pretorin recipe validate my-recipe
pretorin recipe validate my-other-recipe
This catches “you renamed the script and forgot to update the manifest” faster than any pytest assertion will.
What Not to Test
- Don’t test the platform API. Your recipe is an adapter; testing
what
create_evidencedoes is pretorin’s job, not yours. Mock the client. - Don’t test pydantic validation of the manifest. That’s already
covered by pretorin’s loader tests. If your manifest is malformed,
pretorin recipe validatewill tell you. - Don’t test redaction patterns. Use
pretorin.evidence.redact’s helpers and trust them.
Publishing Recipes
Recipes can ship at three tiers. The tier is set by the loader from the recipe’s source path, not by what the manifest declares. Where you put the recipe directory determines who can run it and how.
Three Distribution Models
1. Personal — User Folder
~/.pretorin/recipes/<id>/
Drop a recipe directory there and pretorin recipe list shows it
immediately. Loaded as tier: community. No further setup.
Use this when:
- You’re prototyping a recipe.
- The recipe encodes a personal workflow no one else needs.
- You’re working through the 10-minute walkthrough.
The user folder isn’t synced anywhere — it lives on your machine.
2. Team — Project Folder
<repo>/.pretorin/recipes/<id>/
Checked into your team’s compliance repo (the same repo with pretorin.yaml
or your team’s CLAUDE.md). The loader walks up from CWD looking for a
.pretorin/recipes/ directory, so any teammate working in the repo gets
the recipes automatically.
Use this when:
- The recipe encodes a team-specific procedure (e.g., “pull our internal IAM audit log endpoint”).
- You want your CI to validate the recipes alongside the rest of the compliance repo.
- The recipe is too domain-specific to belong upstream but everyone on the team needs it.
Loaded as tier: community. The project folder has higher precedence
than the user folder, so a team-shared recipe shadows a teammate’s
personal copy with the same id.
3. Upstream — First-Party in pretorin-cli
src/pretorin/recipes/_recipes/<id>/
Forced to tier: official by the loader. Distributed with every
pretorin-cli install.
Use this when:
- The recipe is broadly useful to anyone running pretorin (a new scanner wrapper, a generic capture pattern).
- You’re willing to maintain it — official recipes get tested in CI and block releases on regressions.
- The procedure is stable enough that a SemVer bump with backwards- incompatible changes would be unusual.
How to Submit a First-Party Recipe
-
Open an issue first. Describe what the recipe does and why it belongs in the upstream set rather than as a community recipe. The first-party set is intentionally small — it’s a curation surface, not a catch-all.
-
Scaffold under
_recipes/— clone pretorin-cli and create the recipe directory:pretorin recipe new my-new-scanner --location builtinThis drops the recipe under
src/pretorin/recipes/_recipes/<id>/with the right structure. -
Set
tier: officialin the manifest. The loader will override from the source path anyway, but it documents intent. -
Add a smoke test. Every built-in recipe has at least one test under
tests/recipes/that loads it through the registry and verifies the basic shape. Copy the pattern fromtests/recipes/test_builtin_scanner_recipes.py. -
Run quality gates locally:
pretorin recipe validate my-new-scanner pytest tests/recipes/ ./tools/check.sh quick -
PR the recipe. Include in the description: what the recipe does, when an agent should pick it (your
use_whentext is a good start), and what scanners or platform APIs it depends on. Reference the issue from step 1. -
Maintenance commitment. Once merged, the recipe ships with every pretorin-cli release. Be prepared to respond to issues against it.
How to Share a Community Recipe
There’s no central registry yet (pretorin’s recipe install <pkg> is
v1.5). For now, share a community recipe by:
- Posting the recipe directory in a gist or repo. Anyone can clone
it into their
~/.pretorin/recipes/or<repo>/.pretorin/recipes/and use it. - Opening a PR against your team’s compliance repo. The recipe lands
under
<repo>/.pretorin/recipes/<id>/and is loaded automatically by every teammate.
When you publish a community recipe, fill out:
license— required for anything you share publicly. SPDX identifier (Apache-2.0,MIT, etc.).author— your name or your team’s name. Stamped in the audit metadata of every evidence record the recipe writes.description— clear enough that someone else’s agent can decide whether to pick it without needing to read your team’s wiki.
Tier and Trust
The calling agent sees tier on every recipe in list_recipes
output. v1 doesn’t gate execution by tier — a community recipe runs
just like an official one. What tier does is:
- Audit signal. Every evidence record stamped by a community recipe carries the recipe id, version, and author. A reviewer can trace which recipes contributed to a system’s evidence set.
- Selection signal. When two recipes both fit a task, the agent
prefers the official one unless the community one’s
descriptionmakes a stronger case.
partner tier is reserved for recipes shipped via installed Python
packages (deferred to v1.5). The shape is: a Python package declares an
entry point pointing at a recipe directory inside the package; the
loader picks it up at install time.
Versioning Your Recipe
Bump version in the manifest when:
- The recipe’s behavior changes in a way that would surprise a previous consumer (different output shape, different side effects, different redaction rules).
- A bug fix changes results materially.
Don’t bump for cosmetic edits to the body or doc-only changes. Recipe version stamps every evidence record, so a version bump means the audit trail reflects “results from a different procedure.”
recipe_schema_version is independent — it tracks the frontmatter shape,
not the recipe’s behavior. Most recipes pin this to "1.0" and never
touch it.
Workflows
Workflows sit one layer above recipes. A workflow is a playbook the calling agent reads to learn how to iterate items in a domain (one control, all pending scope questions, the entire campaign). Recipes describe what to do per item; workflows describe how to walk the items.
Three-layer routing model:
engagement (deterministic Python rules)
→ workflow (markdown playbook the calling agent reads)
→ recipe (calling agent picks per item from the menu)
The engagement layer (start_task) lands later — see the
roadmap. v1 ships the workflow registry and the per-workflow playbook
markdown so the agent can navigate manually.
What Ships in v1
Four built-in workflows:
| ID | Iterates over | Pick when |
|---|---|---|
single-control | one control | The user names exactly one control id and the work fits in a single focused pass. |
scope-question | scope questionnaire items | The user references the scope questionnaire or scope is the active workflow-state blocker. |
policy-question | policy questionnaire items | The user references an org policy questionnaire or policy is the active blocker. |
campaign | many controls (server-side) | Bulk control work — drafting narratives or capturing evidence for a family or framework. |
Browse them:
pretorin recipe list # for recipes (CLI)
There’s no pretorin workflow list CLI yet — workflows are discovered
through MCP only:
list_workflows— summary metadata for every loaded workflow.get_workflow(workflow_id)— full manifest plus the markdown body.
How a Workflow’s Body Looks
Every workflow body has the same shape: a brief intent statement, a description of the iteration shape, a step-by-step block, and a “what to avoid” closing section. Read one of the built-ins as a template:
cat src/pretorin/workflows_lib/_workflows/single-control/workflow.md
The frontmatter declares:
| Field | Notes |
|---|---|
id | kebab-case, globally unique |
version | SemVer-ish |
name | display name |
description | ≥ 50 chars, what the engagement layer matches against |
use_when | ≥ 30 chars, explicit trigger guidance |
produces | evidence / narrative / answers / mixed |
iterates_over | single_control / scope_questions / policy_questions / campaign_items |
recipes_commonly_used | hint list of recipe ids the agent often picks |
Why Workflows Matter
Without workflows, the calling agent would freelance the iteration pattern for every task. That’s drift-prone — different agents hit the same questionnaire and follow different orders, producing inconsistent audit trails. The workflow body fixes the pattern: load pending items, filter, iterate, pick a recipe per item, submit through the audit boundary, optionally trigger review.
recipes_commonly_used is a hint, not a binding. The agent reads
list_recipes(system_id=...) at runtime and picks per-item by matching
use_when strings against recipes whose required sources are connected.
When no recipe fits, the workflow surfaces a structured recipe_gap
instead of writing directly.
Server-Side vs Calling-Agent Iteration
Three of the four workflows are calling-agent iteration: the agent loops items in its own context window, calling MCP tools per item. Fine for small sets (one control, ~50 questionnaire items).
campaign is server-side iteration: pretorin’s own CodexAgent walks
items inside pretorin, calling the same recipe surface. The calling
agent kicks off the campaign and observes status — it doesn’t iterate
items in its own context. This is what makes thousand-control campaigns
tractable without overwhelming the calling agent’s context window.
Authoring a New Workflow
v1 doesn’t ship a workflow scaffolder — workflows are first-party only. If you need a new iteration shape, open an issue describing:
- What domain it iterates (controls? questions? something else?).
- Why the existing four don’t fit.
- The recipes the workflow would commonly use.
Community workflows land in v1.5 once the engagement layer is in place and the routing rules can include community contributions safely.
What’s Already Wired
- Engagement layer (
start_task) — picks the workflow from the user’s prompt entities. See Engagement Layer. - Capture preflight —
start_taskreturnssuggested_capture_planand workflows can refresh it withcheck_sources. Evidence and narrative writes then proceed through recipe contexts.
Roadmap
- Richer recipe execution — add more first-party and community recipes for operational systems such as GitHub, Kubernetes, and eMASS.
- Community workflows — third loader path, scaffolder, validator. v1.5.
Engagement Layer
The engagement layer is pretorin’s routing boundary. When the user
says “draft AC-2 for system X” or “answer my scope questionnaire” or
“work through the AC family”, the calling agent’s first move is
start_task. Pretorin picks the workflow; the agent then
loads the workflow body and follows it.
This is the third layer in the routing model:
engagement ← start_task (deterministic Python rules)
workflow ← get_workflow(selected) → markdown playbook
recipe ← list_recipes / start_recipe
Recipes are the leaf — what to do per item. Workflows are the trunk — how to iterate items. Engagement is the root — what kind of work we’re doing in the first place.
Why a Routing Layer
Without engagement, the calling agent guesses. Pattern-matching on nouns sends the agent into evidence/narrative write tools the moment the user says “AC-2”, which produces wrong-framework writes when the user wasn’t explicit and silently-cross-system writes when the active context shifted. The audit chain breaks.
The engagement layer fixes this with deterministic rules that run in pretorin (no LLM here). The calling agent extracts entities; the rules pick a workflow; the response carries the platform read-state the workflow needs. One round-trip, one routing decision, no drift.
What start_task Does
Three things:
- Validates the entities the calling agent extracted. Hallucinated control ids, unknown frameworks, unresolvable system names — these fail loud as MCP errors. The calling agent surfaces the error and asks the user to clarify.
- Cross-checks coherence. If the named control exists in some
framework but not the one the user named, that’s an ambiguity. If
the resolved system doesn’t match the active CLI context, that’s
ambiguity too. The response is
ambiguous: truewith a reason — the calling agent surfaces it before any writes. - Picks a workflow and seeds capture preflight. The rule cascade
(in priority order):
intent_verb == "inspect_status"→ no workflow, just inspect output.intent_verb == "campaign"→ campaign.- scope question ids OR (intent=answer AND pending scope) → scope-question.
- policy question ids OR (intent=answer AND pending policy) → policy-question.
- exactly one control id → single-control.
- multiple control ids → campaign with control filter.
- framework set, no controls → campaign over the framework.
- else → ambiguous; ask the user.
The rule_matched field on the response records which rule fired so
the audit trail captures the routing decision.
For evidence-producing workflows, start_task also returns
suggested_capture_plan: source kinds, connected-source status,
candidate recipes, selected recipe ids, and structured recipe_gap
entries. The calling agent presents this plan before opening recipe
contexts or writing evidence/narratives.
Entity Shape
The calling agent’s LLM extracts:
{
"intent_verb": "work_on" | "collect_evidence" | "draft_narrative"
| "answer" | "campaign" | "inspect_status",
"raw_prompt": "<user's verbatim prompt>",
"system_id": "<id or name, or None>",
"framework_id": "<id, or None>",
"control_ids": ["ac-2", "ac-3"],
"scope_question_ids": [],
"policy_question_ids": [],
}
raw_prompt is audit-only — pretorin doesn’t parse it. Everything
else either resolves cleanly or fails the cross-check.
Inspect Bundle
When the call succeeds, the response carries a bundled snapshot of the platform state the workflow will need:
workflow_state(per-system stage rollup)compliance_status(overall posture)pending_families(controls that still need work)pending_scope_questions/pending_policy_questionsorg_policies
The calling agent doesn’t have to issue separate reads for each — one round-trip yields the routing decision plus the context the workflow will reference.
Inspect is best-effort: if any one platform call fails, that section
carries an error field but the rest of the payload still populates.
Pass skip_inspect: true when you already have fresh state.
Three Response Shapes
- MCP error — entity validation or cross-check hard failure. The calling agent shows the error and stops.
selected_workflowset,ambiguous: false— routed. Calling agent reads the workflow body and follows it.ambiguous: truewithambiguity_reason— coherence problem. Calling agent surfaces the reason to the user, gets clarification, and retries with disambiguated entities.
There’s no fourth shape. The router never produces a confidence score or alternatives — the rule either matched or didn’t.
Active System Context
Pass active_system_id (the user’s CLI context system) so the cross-
check catches cross-system writes. When the resolved system doesn’t
match, the response is ambiguous regardless of what the rules would
say. This is the small extra friction that eliminates the silent
wrong-system-write class of error.
Where the Code Lives
src/pretorin/engagement/entities.py—EngagementEntitiespydantic model.src/pretorin/engagement/selection.py—EngagementSelectionresponse model.src/pretorin/engagement/rules.py— pure-function rule cascade.src/pretorin/engagement/cross_check.py— platform-state coherence checks.src/pretorin/engagement/inspect.py— bundles platform reads into the response.src/pretorin/mcp/handlers/engagement.py— thestart_taskMCP handler.
The rule cascade is testable in pure isolation — same inputs always produce the same output. Drift impossible by construction.
Worked Example: a Community Recipe
This walkthrough builds a community recipe end-to-end, the same way you would. The recipe captures the most recent N entries from a structured audit log file as evidence for an access-control review.
The recipe doesn’t ship with pretorin-cli — it’s a teaching artifact.
Drop it under ~/.pretorin/recipes/audit-log-capture/ to actually run
it; the files are reproduced below for reference.
What This Recipe Does
The audit team needs evidence that an admin’s recent actions are being logged. They have a structured log file (one JSON event per line). The recipe:
- Reads the last N entries from the log.
- Filters to events matching a username.
- Composes a markdown evidence body with the events as a code block.
- Returns the composed text to the calling agent so the agent can hand
it to
create_evidence.
The recipe doesn’t write evidence itself — it returns structured data the agent submits through the MCP write boundary. That’s where audit metadata gets stamped automatically.
Directory Layout
~/.pretorin/recipes/audit-log-capture/
├── recipe.md
├── README.md
└── scripts/
└── capture.py
recipe.md
---
id: audit-log-capture
version: 0.1.0
name: "Audit Log Capture"
description: "Capture the most recent admin events from a JSONL audit log and return a formatted markdown body for evidence submission."
use_when: "The auditor needs evidence that admin actions are logged. You have a JSONL audit log file path and a username to filter on."
produces: evidence
author: "Example Team"
license: Apache-2.0
attests:
- { control: AU-2, framework: nist-800-53-r5 }
- { control: AU-3, framework: nist-800-53-r5 }
params:
log_path:
type: string
description: "Absolute path to the JSONL audit log file"
required: true
username:
type: string
description: "Admin username to filter events for"
required: true
limit:
type: integer
description: "Maximum number of events to include"
default: 20
scripts:
capture:
path: scripts/capture.py
description: "Read the audit log, filter by username, return composed markdown."
params:
log_path:
type: string
description: "Absolute path to JSONL log"
required: true
username:
type: string
description: "Admin username"
required: true
limit:
type: integer
description: "Max events"
default: 20
---
# Audit Log Capture
Reads the tail of a JSONL audit log, filters to events for one admin
user, and returns a composed markdown body the calling agent can submit
as a configuration evidence record.
The agent should attach the result to the relevant `AU-2` / `AU-3`
implementation narrative for the system.
scripts/capture.py
"""Capture recent audit events for a specific admin user."""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from pretorin.evidence.markdown import compose
async def run(
ctx: Any,
*,
log_path: str,
username: str,
limit: int = 20,
) -> dict[str, Any]:
"""Read tail of JSONL log, filter to one user, compose evidence body."""
path = Path(log_path)
if not path.is_file():
raise FileNotFoundError(f"audit log not found: {log_path}")
matched: list[dict[str, Any]] = []
for raw in path.read_text(encoding="utf-8").splitlines():
if not raw.strip():
continue
try:
event = json.loads(raw)
except json.JSONDecodeError:
continue
if event.get("user") == username:
matched.append(event)
if len(matched) >= limit:
break
snippet = "\n".join(json.dumps(e, sort_keys=True) for e in matched)
body = compose(
prose=(
f"The {len(matched)} most recent audit events for user "
f"{username!r} from {path.name}. Each line is one structured "
"event (timestamp, action, target, source IP)."
),
snippet=snippet,
snippet_lang="json",
file_path=str(path),
)
return {
"username": username,
"event_count": len(matched),
"evidence_body": body,
}
README.md
# audit-log-capture
A community recipe that captures admin audit events as markdown evidence.
## Try it
1. Drop this directory under ~/.pretorin/recipes/audit-log-capture/
2. Run `pretorin recipe validate audit-log-capture`
3. From your AI agent (Claude Code, Codex CLI), ask:
> "Capture the last 20 audit events for admin alice from /var/log/audit.jsonl
> as evidence for AU-2."
Walking Through It
Why split into manifest + script
Everything inside the frontmatter is what the calling agent reads to
decide whether to use the recipe. Everything in scripts/capture.py is
how the work happens. Keep the description sharp — the agent picks based
on it.
Why use compose from pretorin.evidence.markdown
compose produces an audit-grade markdown body: prose explaining the
context, a fenced code block with the snippet, an italic provenance
footer with the file path and timestamp. Doing this by hand drifts; using
the helper keeps every evidence record consistent.
Why no create_evidence call
The recipe returns the composed body and lets the calling agent submit it
via create_evidence. This is the right shape for two reasons:
- Audit metadata gets stamped at the MCP write boundary. The recipe
context is open in the calling agent’s session; routing through MCP
means the handler reads the context and stamps
producer_kind="recipe"automatically. - The agent stays in the loop. The agent can review the composed body, ask the user to confirm before submitting, or attach extra metadata it pulled from elsewhere.
A recipe that takes raw input and produces structured output the agent
hands to a writer tool is the most useful shape. Recipes that perform
their own writes are sometimes appropriate (the scanner recipes do, via
submit_test_results) but the default should be: return data, let the
agent submit.
How the agent invokes it
The MCP tool name is recipe_audit_log_capture__capture (the
hyphens in the recipe id become underscores; the script name is the
suffix after __).
The agent’s call sequence:
start_recipe(id="audit-log-capture", version="0.1.0",
params={"log_path": "/var/log/audit.jsonl",
"username": "alice", "limit": 20})
→ returns context_id
recipe_audit_log_capture__capture(
log_path="/var/log/audit.jsonl",
username="alice",
limit=20,
)
→ returns {"username": "alice", "event_count": 20, "evidence_body": "..."}
create_evidence(
system_id="...",
control_id="au-2",
framework_id="nist-800-53-r5",
name="Recent admin audit events for alice",
evidence_type="configuration",
description="Recent admin audit events were captured for alice.",
artifact_content=<the evidence_body from the previous call>,
source_excerpt=<the log lines used to compose the evidence>,
capture_method="repository_file_read",
recipe_context_id=<context_id>,
)
→ platform stamps producer_kind="recipe", producer_id="audit-log-capture",
producer_version="0.1.0"
end_recipe(context_id=<context_id>, status="pass")
What the agent should not do
The recipe doesn’t include a submit script that calls
create_evidence directly. Why: every evidence record submitted from
inside the recipe context picks up audit metadata at the MCP boundary;
moving the write into the script would require the script to build
metadata itself, which is one more place for the audit trail to drift.
When in doubt, return data, let the agent write.
Supported Frameworks
Pretorin provides access to 26 compliance frameworks and profiles spanning federal, contractor, defense industrial base, intelligence community, regulatory, and industry-specific compliance requirements.
Representative Frameworks
The table below highlights a representative subset of commonly used frameworks in Pretorin. Always call pretorin frameworks list to get the current catalog from the API for your environment. Control counts reflect the full catalog (base controls plus enhancements) as exposed by the platform.
| ID | Title | Version | Tier | Families | Controls |
|---|---|---|---|---|---|
nist-800-53-r5 | NIST SP 800-53 Rev 5 | 5.2.0 | tier1_essential | 20 | 1150 |
nist-800-171-r3 | NIST SP 800-171 Revision 3 | 1.0.0 | tier1_essential | 17 | 97 |
fedramp-low | FedRAMP Rev 5 Low Baseline | fedramp2.1.0-oscal1.0.4 | tier1_essential | 18 | 156 |
fedramp-moderate | FedRAMP Rev 5 Moderate Baseline | fedramp2.1.0-oscal1.0.4 | tier1_essential | 18 | 323 |
fedramp-high | FedRAMP Rev 5 High Baseline | fedramp2.1.0-oscal1.0.4 | tier1_essential | 18 | 410 |
cmmc-l1 | CMMC 2.0 Level 1 (Foundational) | 2.0 | tier1_essential | 6 | 17 |
cmmc-l2 | CMMC 2.0 Level 2 (Advanced) | 2.0 | tier1_essential | 14 | 110 |
cmmc-l3 | CMMC 2.0 Level 3 (Expert) | 2.0 | tier1_essential | 10 | 24 |
Framework Tiers
Each framework has a tier classification displayed in the pretorin frameworks list output:
| Tier | Description |
|---|---|
| tier1_essential | Core frameworks most teams encounter first: NIST 800-53, NIST 800-171, the FedRAMP baselines, and all three CMMC levels. |
| tier2_important | Sector-specific and adjacent baselines: DoD Cloud SRG / On-Prem, FIPS 140-3, GDPR, HIPAA, ICD-503, IoT Federal, ISO 27001, ISO 42001, MITRE ATLAS, NIST 800-218, NSS-IC, OT/ICS, PCI-DSS 4.0, and SOC 2. |
Framework Relationships
Understanding how frameworks relate helps with cross-compliance:
NIST 800-53 Rev 5 (full catalog including enhancements, ~1150 controls)
├── FedRAMP Low/Moderate/High (800-53 subset + cloud requirements)
├── DoD Cloud IL2/IL4/IL5 + DoD On-Prem (FedRAMP + DoD additions)
├── NIST 800-171 Rev 3 (800-53 subset for CUI in non-federal systems)
│ └── CMMC Level 2 (maps to 800-171 requirements)
└── CMMC Level 3 (advanced controls beyond 800-171)
If an organization is already compliant with a parent framework, many child framework controls are already satisfied.
NIST SP 800-53 Rev 5
The foundational catalog for federal information systems. Includes 20 control families covering all aspects of information security. All other US government frameworks derive from it. The platform exposes the full catalog (base controls plus enhancements), which pretorin frameworks list reports as ~1150 controls.
Target audience: Federal agencies
NIST SP 800-171 Rev 3
Protects Controlled Unclassified Information (CUI) in non-federal systems. A focused subset of 800-53 with 97 requirements in the platform’s catalog.
Target audience: Federal contractors, universities, and other non-federal entities handling CUI under DFARS 252.204-7012 or similar requirements.
FedRAMP
Based on NIST 800-53 with additional cloud-specific requirements. Required for cloud services used by federal agencies.
Impact levels:
| Level | ID | Controls | Use When |
|---|---|---|---|
| Low | fedramp-low | 156 | Public, non-sensitive data. Limited adverse effect from loss. |
| Moderate | fedramp-moderate | 323 | CUI, PII, sensitive data. Serious adverse effect from loss. Most common level. |
| High | fedramp-high | 410 | Life-safety, financial, law enforcement data. Severe/catastrophic effect from loss. |
Target audience: Cloud service providers to government
CMMC 2.0
Cybersecurity Maturity Model Certification for defense contractors. Required by DoD contracts.
| Level | ID | Controls | Use When |
|---|---|---|---|
| Level 1 | cmmc-l1 | 17 | Handles only Federal Contract Information (FCI). Basic cyber hygiene. |
| Level 2 | cmmc-l2 | 110 | Handles CUI. Aligns with NIST 800-171. Most defense contractors need this. |
| Level 3 | cmmc-l3 | 24 | Highest sensitivity CUI. Advanced practices on top of Level 2. |
Target audience: Defense industrial base organizations
Note: CMMC Level 3 controls are in addition to Level 2. An organization at Level 3 must also satisfy all Level 2 controls.
Custom and Forked Frameworks
If your organization needs to track a framework that isn’t in the built-in catalog (e.g., an internal control set, a tailored ISO/SOC 2 mapping, an industry-specific regulation), you can author one yourself or fork an existing Pretorin-managed framework. The pretorin frameworks group exposes the full revision lifecycle:
- Author from scratch —
init-custom,validate-custom,upload-custom - Convert from OSCAL or 12 known custom catalog shapes —
build-custom - Fork an existing framework —
fork-framework,rebase-fork - Inspect drafts —
revisions - Round-trip back to OSCAL —
export-oscal
See the Custom Frameworks guide for the end-to-end workflow.
See Framework Selection Guide for help choosing the right framework.
Control ID Formats
Correct ID formatting is critical. The Pretorin API returns errors on malformed IDs. When unsure, discover IDs first with pretorin frameworks families <id> or pretorin frameworks controls <id>.
NIST 800-53 Rev 5 / FedRAMP
Framework IDs: nist-800-53-r5, fedramp-low, fedramp-moderate, fedramp-high
Family IDs
Family IDs are lowercase slugs, not short codes:
| Correct | Incorrect |
|---|---|
access-control | ac |
audit-and-accountability | au |
identification-and-authentication | ia |
system-and-communications-protection | sc |
configuration-management | cm |
incident-response | ir |
risk-assessment | ra |
Control IDs
Control IDs are zero-padded with a hyphen:
| Correct | Incorrect |
|---|---|
ac-01 | ac-1, AC-1, ac1 |
ac-02 | ac-2, AC-2, ac2 |
au-02 | au-2, AU-2 |
sc-07 | sc-7, SC-7 |
Enhancement IDs append a dot-suffix or parenthetical suffix:
| Format | Example |
|---|---|
| Dot notation | ac-02.1 |
| Parenthetical | ac-02(1) |
CMMC 2.0
Framework IDs: cmmc-l1, cmmc-l2, cmmc-l3
Family IDs
CMMC family IDs include a level suffix:
| Correct | Incorrect |
|---|---|
access-control-level-1 | access-control, ac |
access-control-level-2 | access-control, ac-l2 |
incident-response-level-2 | incident-response, ir |
system-and-communications-protection-level-3 | sc, sc-l3 |
Control IDs
CMMC control IDs use dotted notation with a level prefix and are case-sensitive:
| Correct | Incorrect |
|---|---|
AC.L2-3.1.1 | ac-01, 3.1.1 |
SC.L3-3.13.2 | sc-07, 3.13.2 |
AC.L1-3.1.22 | ac.l1-3.1.22 |
Use uppercase for the family prefix (e.g., AC, not ac).
NIST 800-171 Rev 3
Framework ID: nist-800-171-r3
Family IDs
Family IDs use the same lowercase slug convention as NIST 800-53:
| Correct | Incorrect |
|---|---|
access-control | ac, 3.1 |
incident-response | ir, 3.6 |
identification-and-authentication | ia, 3.5 |
Control IDs
Control IDs use dotted notation with leading zeros:
| Correct | Incorrect |
|---|---|
03.01.01 | 3.1.1, ac-01 |
03.01.02 | 3.1.2, ac-02 |
03.13.01 | 3.13.1, sc-01 |
SOC 2
Framework ID: soc2
Family IDs
SOC 2 family IDs use the Trust Services Criteria code (uppercase, no slug expansion):
| Correct | Incorrect |
|---|---|
CC6 | common-criteria-6, cc6, cc-6 |
CC1 | control-environment, cc1 |
Control IDs
SOC 2 control IDs use dotted notation under the family code:
| Correct | Incorrect |
|---|---|
CC6.1 | cc-06.1, cc6-1, 6.1 |
CC6.2 | cc-06.2, cc6-2, 6.2 |
CC1.1 | cc-01.1, cc1-1, 1.1 |
SOC 2 IDs are case-sensitive — keep the family code uppercase.
Auto-Normalization
The CLI and MCP tools automatically normalize NIST 800-53 and FedRAMP control IDs: uppercase is lowered and single-digit numbers are zero-padded. For example, AC-2 becomes ac-02 and SC-7.1 becomes sc-07.1. CMMC, NIST 800-171, and SOC 2 IDs are passed through unchanged — use the exact format shown above.
Discovery Workflow
When a user provides an informal control reference (e.g., “AC-2” or “access control”):
- Call
pretorin frameworks families <framework_id>to find the correct family slug - Call
pretorin frameworks controls <framework_id> --family <family_slug>to find the correct control ID - Use the discovered ID in subsequent calls
Quick Reference
| Framework | Family Format | Control Format | Example |
|---|---|---|---|
| NIST 800-53 | access-control | ac-01 | pretorin frameworks control nist-800-53-r5 ac-02 |
| FedRAMP | access-control | ac-01 | pretorin frameworks control fedramp-moderate ac-02 |
| CMMC | access-control-level-2 | AC.L2-3.1.1 | pretorin frameworks control cmmc-l2 AC.L2-3.1.1 |
| 800-171 | access-control | 03.01.01 | pretorin frameworks control nist-800-171-r3 03.01.01 |
| SOC 2 | CC6 | CC6.1 | pretorin frameworks control soc2 CC6.1 |
Framework Selection Guide
Use this decision tree to identify the right compliance framework for your situation.
Decision Tree
1. Federal Agency (US Government)
Use: NIST 800-53 Rev 5 (nist-800-53-r5)
The foundational catalog for federal information systems. All other US government frameworks derive from it. Spans 20 control families covering all aspects of information security; the platform exposes the full catalog (base controls plus enhancements), which pretorin frameworks list reports as ~1150 controls. Use this when the organization IS a federal agency and needs the full control catalog.
2. Federal Contractor Handling CUI
Use: NIST 800-171 Rev 3 (nist-800-171-r3)
Protects Controlled Unclassified Information (CUI) in non-federal systems. A focused subset of 800-53 with 97 requirements in the platform’s catalog. Use this when the organization is a contractor, university, or other non-federal entity that handles CUI under DFARS 252.204-7012 or similar requirements.
3. Cloud Service Provider to Government
Use: FedRAMP (fedramp-low, fedramp-moderate, fedramp-high)
Based on NIST 800-53 with additional cloud-specific requirements. Required for cloud services used by federal agencies.
| Level | ID | Controls | Use When |
|---|---|---|---|
| Low | fedramp-low | 156 | Public, non-sensitive data. Loss would have limited adverse effect. |
| Moderate | fedramp-moderate | 323 | CUI, PII, sensitive but not critical data. Loss would have serious adverse effect. Most common level. |
| High | fedramp-high | 410 | Life-safety, financial, law enforcement, or emergency services data. Loss would have severe or catastrophic effect. |
When unsure, FedRAMP Moderate is the most common starting point for cloud services handling government data.
4. Defense Industrial Base (DIB)
Use: CMMC (cmmc-l1, cmmc-l2, cmmc-l3)
Cybersecurity Maturity Model Certification for defense contractors. Required by DoD contracts.
| Level | ID | Controls | Use When |
|---|---|---|---|
| Level 1 | cmmc-l1 | 17 | Handles only Federal Contract Information (FCI). Basic cyber hygiene. |
| Level 2 | cmmc-l2 | 110 | Handles CUI. Aligns with NIST 800-171. Most defense contractors need this. |
| Level 3 | cmmc-l3 | 24 | Highest sensitivity CUI. Advanced/progressive practices on top of Level 2. |
Note: CMMC Level 3 controls are in addition to Level 2.
5. None of the above fits — bring your own framework
If the built-in catalog doesn’t cover your obligation (e.g., an internal control set, a tailored mapping, an industry-specific regulation), you can author a custom framework or fork an existing one. See the Custom Frameworks guide for the pretorin frameworks init-custom / build-custom / upload-custom / fork-framework workflow.
Quick Reference
| Situation | Framework | ID |
|---|---|---|
| We’re a federal agency | NIST 800-53 | nist-800-53-r5 |
| We handle CUI as a contractor | NIST 800-171 | nist-800-171-r3 |
| We’re a cloud service for government | FedRAMP | fedramp-moderate |
| We have a DoD contract | CMMC | cmmc-l2 |
| We need to handle both CUI and cloud | FedRAMP + 800-171 | Start with fedramp-moderate |
| We’re not sure yet | Start with NIST 800-53 | nist-800-53-r5 |
| Our framework isn’t in the catalog | Author or fork your own | See Custom Frameworks |
Using AI Context for Selection
Call get_framework (MCP) or pretorin frameworks get <id> (CLI) to get AI context including purpose, target audience, regulatory context, scope, and key concepts. This helps confirm whether a framework is the right fit.
Custom Frameworks
The pretorin frameworks command group supports authoring, validating, and uploading custom and forked compliance frameworks through the platform’s revision-lifecycle endpoints.
The canonical artifact is unified.json. _index.json is not an upload format — it’s an internal index file used elsewhere in the data pipeline, but the platform’s revision lifecycle expects the full unified.json.
End-to-end workflow
init-custom ──► (edit) ──► validate-custom ──► upload-custom [--publish] ──► revisions
│
build-custom ◄────── (OSCAL or custom catalog as input) ──┘
Starting from scratch
Scaffold a minimal valid unified.json:
pretorin frameworks init-custom acme-soc2-tailored
# → writes unified.json with one sample family + one sample control
Edit the file, fill in your metadata, families, and controls, then run a local pre-flight check:
pretorin frameworks validate-custom unified.json
The bundled JSON Schema validator catches structural errors fast. The platform runs the authoritative validator on upload — additional issues may surface there.
Starting from OSCAL
Already have an OSCAL catalog? Convert it to unified.json:
pretorin frameworks build-custom my-oscal-catalog.json -f acme-iso27001 -o unified.json
The CLI auto-detects the input shape. OSCAL → unified preserves the _oscal blocks for lossless regeneration; you can round-trip back via export-oscal.
Starting from a custom catalog
Many compliance catalogs ship in custom (non-OSCAL) JSON shapes — control_families + controls, CIS-style nested safeguards, ISO control_themes, PCI-DSS, CSA-CCM domains, NIST AI RMF governance requirements, FIPS 140-3, DISA STIG wrappers, MITRE ATLAS, and more.
build-custom recognizes 12 known custom shapes and normalizes them all to unified.json:
pretorin frameworks build-custom catalog.json -f acme-soc2 -o unified.json
If the input shape isn’t recognized, the CLI tells you which shapes are supported. Use init-custom to scaffold instead and copy your data over manually.
Uploading
Upload a draft revision to the platform:
pretorin frameworks upload-custom unified.json
The platform validates synchronously. On a validation failure (HTTP 400) the CLI renders the platform’s structured validation_report as a readable table — you’ll see exact paths and messages for what to fix.
To upload and publish in one step:
pretorin frameworks upload-custom unified.json --publish
You can override the framework ID baked into the artifact and add a version label:
pretorin frameworks upload-custom unified.json -f acme-soc2-v2 -v "2026-Q1"
Linked forks
Fork a Pretorin-managed framework into your own draft. The platform records the lineage so you can rebase later when upstream advances.
pretorin frameworks fork-framework nist-800-53-r5 acme-nist-tailored
pretorin frameworks fork-framework fedramp-moderate acme-fedramp-mod -v initial
The fork starts as a draft anchored on the upstream’s current revision. Edit the resulting unified.json (export it from the platform UI or use revisions to find the draft), then re-upload via upload-custom.
Rebasing a fork
When upstream has advanced and you want to bring your fork forward:
pretorin frameworks rebase-fork acme-nist-tailored
The platform creates a fresh draft anchored on the latest upstream. You resolve any divergence locally and re-upload.
Listing revisions
See all drafts and published revisions for a framework:
pretorin frameworks revisions acme-nist-tailored
Exporting OSCAL
Regenerate an OSCAL catalog from a unified artifact:
pretorin frameworks export-oscal unified.json -o catalog.json
When the unified artifact retains the _oscal blocks (i.e., it was originally converted from OSCAL via build-custom), regeneration is lossless — props, parts, links, and back-matter are restored verbatim.
Command reference
| Command | Talks to platform? | Purpose |
|---|---|---|
init-custom <id> [-t title] [-o path] [--force] | No | Scaffold a minimal valid unified.json |
validate-custom <path> | No | Local JSON Schema pre-flight |
build-custom <input> -f <id> [-o path] [--force] | No | Normalize OSCAL / custom catalog → unified.json |
upload-custom <path> [-f id] [-v label] [--publish] | Yes | Upload draft revision; optionally publish |
fork-framework <upstream_id> <new_id> [-v label] | Yes | Create linked-fork draft |
rebase-fork <id> [-v label] | Yes | Create rebase draft against latest upstream |
revisions <id> | Yes | List drafts + published revisions |
export-oscal <path> [-o path] [--force] | No | Regenerate OSCAL catalog from unified.json |
All commands respect the global --json flag for machine-readable output.
Notes for tool authors
The vendored conversion and validation primitives are exposed at pretorin.frameworks and can be imported directly:
from pretorin.frameworks import (
custom_to_unified,
oscal_to_unified,
unified_to_oscal,
)
from pretorin.frameworks.validate import validate_unified
from pretorin.frameworks.templates import minimal_unified
These are pure-data functions — no I/O, no platform calls. Good for embedding in CI pipelines, agent tools, or your own automation.
Narrative & Evidence Workflow
This is the core workflow for updating control implementations on the platform. Follow this sequence for any control update.
Workflow Steps
1. Resolve the Target
Identify the system_id, control_id, and framework_id for your update. Set the active context:
pretorin context set --system "My Application" --framework fedramp-moderate
2. Read Current State
Before making changes, understand what’s already there:
# Get full control context (requirements + current implementation)
pretorin control context ac-02 --framework-id fedramp-moderate
# Via MCP: get_control_context
# Get current narrative
pretorin narrative get ac-02 fedramp-moderate
# Search existing evidence
pretorin evidence search --control-id ac-02 --framework-id fedramp-moderate
# List existing issues
pretorin issues list ac-02 fedramp-moderate
3. Collect Observable Facts
Search your codebase and connected systems for evidence. Only document what is directly observable — never assume or fabricate implementation details.
Treat existing Pretorin narratives, issues, and status fields as a starting point, not proof that a control gap exists. Before writing a narrative update or issue, inspect the relevant implementation in the workspace and connected systems. If those sources show stronger implementation than the current platform record, update the narrative to reflect the observed implementation and record any remaining evidence gap as an issue.
4. Draft Updates
Prepare three types of updates:
Narrative — How the control is implemented. Narratives describe observed implementation only; do not include gap lists, missing-information placeholders, or remediation backlog.
Evidence — Specific artifacts demonstrating implementation (config files, code, policies). Evidence describes the artifact and what it supports only. Use bold section labels with spacing instead of Markdown headings.
Issues — Unresolved items requiring manual follow-up:
Gap: Missing MFA enforcement evidence
Observed: TOTP library imported in auth module
Missing: MFA policy enforcement configuration
Why missing: IdP admin console not accessible via codebase
Manual next step: Screenshot MFA policy from Azure AD admin portal
5. Push Updates
# Push a single narrative file
pretorin narrative push-file ac-02 fedramp-moderate "My Application" narrative-ac02.md
# Upsert evidence (finds or creates, then links)
pretorin evidence upsert ac-02 fedramp-moderate \
--name "RBAC Configuration" \
--description "Role mapping in IdP" \
--artifact-content "**Evidence**\n\n- Role mapping is enforced in the IdP export." \
--type configuration
# Cadenced evidence with audit-sufficiency metadata
pretorin evidence upsert ac-02 fedramp-moderate \
--name "Quarterly Access Review" \
--description "Output of quarterly access review query" \
--artifact-content "**Evidence**\n\n- Quarterly access review query output is attached as Markdown." \
--type attestation \
--coverage-start 2026-01-01 --coverage-end 2026-03-31 \
--capture-query "SELECT user_id, last_login FROM users WHERE ..." \
--cadence-days 90
# Add issues
pretorin issues add ac-02 fedramp-moderate \
--content "Gap: Missing MFA evidence..."
# Start/reopen implementation authoring
pretorin control status ac-02 in_progress \
--framework-id fedramp-moderate
CLI and MCP callers may only set in_progress. Stage-for-approval, approval, and not-applicable decisions happen in the Pretorin UI by a human.
Read-Only Draft Workflow
When you want AI drafts before any platform writes:
- Resolve scope (system, control, framework)
- Read current state (context, narrative, evidence, issues)
- Generate drafts via
pretorin agent run --skill narrative-generationor the MCPgenerate_control_artifactstool - Review the draft — clearly separate candidate narrative, evidence recommendations, and issue drafts
- Only push to the platform after explicit approval
Markdown Quality Rules
All narratives and evidence must pass markdown quality validation:
Narratives
- No markdown headings (
#,##, etc.) - At least 2 rich markdown elements (code blocks, tables, lists, links)
- At least 1 structural element (code block, table, or list)
- No markdown images
Evidence
- No markdown headings
- At least 1 rich markdown element
- No markdown images
Continuous Compliance & Cadenced Evidence
Evidence created with --cadence-days carries a refresh cadence; the platform stores expires_at = created_at + cadence_days and emits evidence.expiring / evidence.expired monitoring events as the deadline approaches and passes.
To re-affirm that cadenced evidence is still current, prefer validate so the CLI compares the fresh source-material hash before marking current:
pretorin evidence validate <evidence_id>
# If unchanged, records re_verified; if changed, replaces the Markdown artifact
# with a drift note instead of silently marking stale evidence current.
This fails with HTTP 400 if the evidence has no cadence set. The --coverage-start / --coverage-end flags describe the period the evidence content covers (point-in-time if --coverage-end is omitted). The --capture-query flag records the query, filter, or command that produced the artifact — auditors use this for IPE (Information Produced by the Entity) reproducibility.
Linking Evidence to CCI Implementations
To attach evidence to a per-system CCI implementation row (rather than the control as a whole), use link-cci:
pretorin evidence link-cci <evidence_id> <cci_implementation_uuid>
The CCI implementation UUID comes from pretorin cci impl <cci_uuid>; the row must already exist on the platform. Add --override-system-mismatch --override-reason "<why>" to permit cross-system attachment.
Evidence Deduplication
pretorin evidence upsert and the MCP create_evidence tool use find-or-create logic by default (dedupe: true):
- Search for an exact match on (name + description + type + control + framework) within the active system scope
- If found, reuse the existing evidence item
- If not found, create a new one
- Ensure the evidence is linked to the specified control
The response indicates whether the evidence was created (new) or reused, along with the match_basis.
Campaign Workflows
Campaigns are the recommended way to run bulk compliance operations across multiple controls, policies, or scope questions. They replace manual one-at-a-time updates with a coordinated prepare-claim-propose-apply lifecycle.
When to Use Campaigns
- Initial control implementation — Draft narratives and evidence for an entire control family
- Fixing review findings — Address issues flagged by family or policy reviews
- Answering questionnaires — Bulk-answer policy or scope questions
- Issue remediation — Fix controls flagged by platform issues
Campaign Lifecycle
Prepare → Claim → Draft → Propose → Apply
-
Prepare — Snapshot platform state and create a checkpoint file. This captures the current state of all target items so the campaign works from a consistent baseline.
-
Claim — Lease items for drafting. TTL-based leases prevent concurrent editing when multiple agents are working in parallel.
-
Draft — For each claimed item, get full context (control requirements, current state, guidance) and produce a draft.
-
Propose — Submit drafts as proposals without writing to the platform. This provides a review opportunity before any changes are persisted.
-
Apply — Push all accepted proposals to the platform as a single operation.
External Agent Pattern
Campaigns are designed for external agents (Claude Code, Codex, Cursor, etc.) operating through MCP:
Agent A: prepare_campaign → claim_campaign_items → get_campaign_item_context → submit_campaign_proposal
Agent B: claim_campaign_items → get_campaign_item_context → submit_campaign_proposal
...
Coordinator: get_campaign_status → apply_campaign
The checkpoint file enables independent agent execution. Agents can claim non-overlapping items and work in parallel.
CLI Usage
Control Campaign
# Draft narratives for the Access Control family
pretorin campaign controls --mode initial --family AC \
--system "My System" --framework-id fedramp-moderate
# Fix controls flagged by open issues
pretorin campaign controls --mode issues-fix --all-open-issues \
--system "My System" --framework-id fedramp-moderate
# Fix controls flagged by review
pretorin campaign controls --mode review-fix --family AC --review-job <job-id> \
--system "My System" --framework-id fedramp-moderate
# Auto-apply after completion
pretorin campaign controls --mode initial --family AC --apply \
--system "My System" --framework-id fedramp-moderate
Policy Campaign
# Answer all incomplete policy questions
pretorin campaign policy --mode answer --all-incomplete
# Fix review findings for a specific policy
pretorin campaign policy --mode review-fix --policies <policy-id>
Scope Campaign
pretorin campaign scope --mode answer \
--system "My System" --framework-id fedramp-moderate
Check Status
pretorin campaign status --checkpoint .pretorin/campaign-checkpoint.json
MCP Tool Sequence
For AI agents working through MCP:
get_workflow_state— Understand what needs workget_pending_families— Identify target familiesprepare_campaign— Create the campaignclaim_campaign_items— Claim itemsget_campaign_item_context— Get context per itemsubmit_campaign_proposal— Submit draftsget_campaign_status— Review progressapply_campaign— Push to platform
Policy & Scope Questionnaires
Pretorin uses questionnaire workflows to capture organizational policy information and system scope details. Both follow a similar lifecycle: answer questions, generate documents, review, and iterate.
Policy Questionnaire Workflow
Organization policies (e.g., Access Control Policy, Incident Response Policy) are defined at the org level and apply across systems.
1. List Available Policies
pretorin policy list
Or via MCP: list_org_policies
2. View Current State
# Show questionnaire state and saved review findings
pretorin policy show --policy <policy-id-or-name>
Or via MCP:
get_pending_policy_questions # lightweight — only unanswered
get_policy_question_detail # guidance and examples per question
3. Answer Questions
Via CLI — Draft answers from your workspace:
# Preview proposed answers
pretorin policy populate --policy <policy-id>
# Apply answers to the platform
pretorin policy populate --policy <policy-id> --apply
Via MCP — Answer individually for precise control:
answer_policy_question(policy_id, question_id, answer)
Or batch-update multiple answers:
patch_org_policy_qa(policy_id, updates=[{question_id, answer}, ...])
4. Generate Policy Document
Once questions are answered, trigger AI document generation:
trigger_policy_generation(policy_id)
5. Review
Trigger an AI review of the policy:
trigger_policy_review(policy_id)
get_policy_review_results(policy_id) # poll for results
Review results include findings with severity levels, affected sections, and recommended fixes.
6. Track Status
get_policy_workflow_state(policy_id)
get_policy_analytics(policy_id)
Scope Questionnaire Workflow
Scope questionnaires are system+framework specific. They define what’s in scope, what’s excluded, and system boundary details.
1. View Current State
# Show scope questionnaire state and review findings
pretorin scope show --system "My System" --framework-id fedramp-moderate
Or via MCP:
get_pending_scope_questions(system_id, framework_id)
get_scope_question_detail(system_id, framework_id, question_id)
2. Answer Questions
Via CLI — Draft answers from your workspace:
# Preview proposed answers
pretorin scope populate --system "My System" --framework-id fedramp-moderate
# Apply answers to the platform
pretorin scope populate --system "My System" --framework-id fedramp-moderate --apply
Via MCP — Answer individually:
answer_scope_question(system_id, framework_id, question_id, answer)
Or batch-update:
patch_scope_qa(system_id, framework_id, updates=[{question_id, answer}, ...])
3. Generate Scope Document
trigger_scope_generation(system_id, framework_id)
4. Review
trigger_scope_review(system_id, framework_id)
get_scope_review_results(system_id, framework_id)
5. View Full Scope
get_scope(system_id, framework_id)
Returns scope narrative, excluded controls, and Q&A responses.
Bulk Questionnaire Campaigns
For answering many questions at once, use campaigns:
# Answer all incomplete policy questions
pretorin campaign policy --mode answer --all-incomplete
# Answer scope questions
pretorin campaign scope --mode answer --system "My System" --framework-id fedramp-moderate
# Fix review findings
pretorin campaign policy --mode review-fix --policies <policy-id>
See Campaign Workflows for details on the campaign lifecycle.
Vendor Inheritance
Many compliance controls are partially or fully satisfied by external providers (cloud platforms, SaaS tools, managed services). Pretorin tracks these inheritance relationships and keeps inherited narratives in sync with vendor documentation.
Concepts
- Vendor — An external provider or internal shared service (CSP, SaaS, managed service, internal)
- Responsibility edge — A link between a control and a vendor indicating the control is inherited or shared
- Stale edge — A responsibility edge where the source narrative has changed but the inherited control hasn’t been updated
Workflow
1. Create Vendor Entities
pretorin vendor create "AWS GovCloud" --type csp \
--description "Primary cloud infrastructure" \
--authorization-level "FedRAMP High P-ATO"
pretorin vendor create "Okta" --type saas \
--description "Identity and access management"
2. Upload Vendor Documentation
pretorin vendor upload-doc <vendor_id> ./aws-crm.pdf \
--name "AWS Customer Responsibility Matrix" \
--attestation-type vendor_provided
pretorin vendor upload-doc <vendor_id> ./okta-soc2.pdf \
--name "Okta SOC 2 Type II Report" \
--attestation-type third_party_attestation
3. Set Control Responsibility
Via MCP tools:
set_control_responsibility(
system_id,
control_id,
framework_id,
responsibility_mode, # "inherited" or "shared"
source_type, # "provider", "internal", or "hybrid"
vendor_id, # optional — vendor providing the inherited control
)
Responsibility modes:
- inherited — Fully satisfied by the vendor
- shared — Partially satisfied; your system handles the remainder
4. Generate Inheritance Narratives
generate_inheritance_narrative(system_id, control_id, framework_id)
AI generates a narrative grounded in the vendor’s uploaded documentation (resolved via the responsibility edge), explaining how the vendor satisfies the control requirements.
5. Monitor Staleness
Over time, vendor documentation or source narratives may be updated. Check for stale inheritance:
get_stale_edges(system_id)
Returns controls where the source has changed but the inherited narrative hasn’t been refreshed.
6. Sync Stale Edges
sync_stale_edges(system_id)
Bulk updates inherited controls by regenerating narratives from the latest source.
Linking Evidence to Vendors
link_evidence_to_vendor(evidence_id, vendor_id, attestation_type)
Attestation types: self_attested, third_party_attestation, vendor_provided
Gap Analysis Workflow
A systematic approach to assessing a codebase against a compliance framework’s controls.
Step 1: Scope the Assessment
Determine which framework and control families to assess.
# List frameworks if not specified
pretorin frameworks list
# List control families for the chosen framework
pretorin frameworks families fedramp-moderate
Not all families will have code evidence. Prioritize based on evidence likelihood.
Step 2: Prioritize Control Families
High Priority (Direct Code Evidence)
These families typically have strong evidence in source code:
| Family | What to Search For |
|---|---|
| Access Control (AC) | Authentication systems, RBAC/ABAC, session management, user provisioning |
| Audit & Accountability (AU) | Logging frameworks, audit trails, log retention, structured logging |
| Identification & Authentication (IA) | Login flows, MFA, password hashing, credential storage, OAuth/SAML |
| System & Communications Protection (SC) | TLS config, encryption, network boundaries, CORS, API security |
| Configuration Management (CM) | Config files, env handling, version pinning, baseline settings, IaC |
Medium Priority (Mixed Code/Policy)
| Family | What to Search For |
|---|---|
| System Acquisition (SA) | Secure development practices, dependency management, SAST/DAST configs |
| System Integrity (SI) | Input validation, error handling, malware protection configs |
| Assessment (CA) | Security testing configs, vulnerability scanning, CI/CD security gates |
Lower Priority (Mostly Policy)
Primarily documentation-based, unlikely to have code evidence:
- Awareness & Training (AT)
- Planning (PL)
- Personnel Security (PS)
- Physical Protection (PE)
- Program Management (PM)
Step 3: Collect Evidence
For each high-priority family:
-
List controls filtered by family:
pretorin frameworks controls fedramp-moderate --family access-control -
For each relevant control, get AI guidance:
pretorin frameworks control fedramp-moderate ac-02References and AI guidance are shown by default. The
ai_guidancefield provides evidence expectations, implementation considerations, and common failures. Use--briefto show only the basic info panel. -
Search the codebase using guidance-informed patterns:
File patterns:
**/auth/** **/users/** **/accounts/**
**/logging/** **/audit/** **/security/**
**/config/** **/settings/** **/crypto/**
**/identity/** **/iam/** **/rbac/**
**/middleware/** **/terraform/** **/k8s/**
Keyword patterns:
authenticate, authorize, permission, role, session
log, audit, event, trace, record
encrypt, tls, ssl, https, certificate
config, setting, baseline, default
password, credential, hash, mfa, token
- For each piece of evidence, note the file path, line numbers, and what it demonstrates.
Step 4: Assess Implementation Status
For each control, assign a status:
| Status | Criteria |
|---|---|
| Implemented | Full requirements met with clear code evidence |
| Partial | Some requirements met, others missing or incomplete |
| Planned | Architecture supports it but feature not built yet |
| Not Applicable | Control doesn’t apply to this component |
| Gap | Control requirements not addressed at all |
Use ai_guidance.common_failures to calibrate your assessment — if the codebase exhibits a known failure pattern, it’s likely a gap or partial implementation.
Step 5: Produce the Report
Structure the gap analysis output as:
Summary
- Framework assessed and total controls in scope
- Counts by status (implemented, partial, planned, not applicable, gap)
- Overall compliance posture assessment
Family-by-Family Findings
For each assessed family:
- Family name and total controls
- Status breakdown
- Key findings with evidence references
- Gaps with remediation recommendations
Priority Remediation Items
Rank gaps by:
- Controls with the highest security impact
- Controls that are prerequisites for other controls (check related controls)
- Controls that are easiest to implement (quick wins)
Evidence Summary
For each assessed control:
- Control ID and title
- Implementation status
- Evidence file paths and descriptions
- Recommendations if partial or gap
Example Output
See the example gap analysis for a complete sample report.
Tips
- Start broad (family level) and drill into specific controls where evidence exists
- Use
pretorin frameworks control <fw> <ctrl>for AI guidance — it provides the richest context (references are included by default; use--briefto skip them) - Check related controls to identify dependencies
- For infrastructure evidence, look at Terraform, CloudFormation, Dockerfiles, Helm charts, and CI/CD configs
- For application evidence, focus on auth, logging, crypto, and configuration code
Example: Gap Analysis Report
This example shows a gap analysis for a hypothetical web application assessed against FedRAMP Moderate.
Gap Analysis: Acme Web Platform — FedRAMP Moderate
Summary
| Metric | Value |
|---|---|
| Framework | FedRAMP Rev 5 Moderate (fedramp-moderate) |
| Component | Acme Web Platform |
| Families Assessed | 5 of 18 (high-priority code-evidenced families) |
| Controls in Scope | 47 |
| Implemented | 18 (38%) |
| Partial | 14 (30%) |
| Planned | 3 (6%) |
| Not Applicable | 4 (9%) |
| Gap | 8 (17%) |
Overall Posture: Partial compliance. Strong authentication and logging foundations, but gaps in account lifecycle management, boundary protection, and baseline configuration documentation.
Access Control (AC) — 12 controls assessed
Status: 5 implemented, 4 partial, 1 planned, 2 gap
Key Findings:
- AC-02 (Account Management) — Partial. User creation with role assignment exists in
src/auth/users.py:45-72, but no account expiration, dormant account handling, or manager approval workflow. - AC-03 (Access Enforcement) — Implemented. RBAC middleware in
src/middleware/auth.py:12-38enforces role-based access on all API routes. - AC-07 (Unsuccessful Logon Attempts) — Implemented. Account lockout after 5 failed attempts in
src/auth/login.py:89-105. - AC-17 (Remote Access) — Gap. No VPN or remote access controls documented.
Recommendations:
- Add account expiration and dormant account cleanup (addresses AC-02 gaps)
- Implement remote access policy and controls for administrative access (addresses AC-17)
Audit & Accountability (AU) — 8 controls assessed
Status: 5 implemented, 2 partial, 1 gap
Key Findings:
- AU-02 (Audit Events) — Implemented. Structured JSON logging for auth events, data access, and admin actions.
- AU-03 (Content of Audit Records) — Implemented. Logs include timestamp, user ID, action, outcome, and source IP.
- AU-06 (Audit Record Review) — Gap. No automated log review or alerting configured.
Recommendations:
- Configure CloudWatch alarms for security events (addresses AU-06)
- Add log review procedures and alerting rules
System & Communications Protection (SC) — 10 controls assessed
Status: 2 implemented, 4 partial, 2 planned, 2 not applicable
Key Findings:
- SC-07 (Boundary Protection) — Partial. TLS 1.3 and CORS configured, but security groups allow broad ingress.
- SC-08 (Transmission Confidentiality) — Implemented. All traffic encrypted via TLS 1.3 with HSTS.
- SC-28 (Protection of Information at Rest) — Planned. Database encryption not yet enabled.
Priority Remediation
| Priority | Control | Gap | Effort |
|---|---|---|---|
| 1 | SC-28 | Enable RDS encryption at rest | Low — Terraform change |
| 2 | AU-06 | Add CloudWatch alerting for security events | Medium — alerting rules |
| 3 | AC-02 | Account lifecycle management | Medium — new feature |
| 4 | CM-02/CM-06 | Baseline configuration documentation | Medium — documentation |
| 5 | AC-17 | Remote access controls for admin access | High — new infrastructure |
Artifact Generation
Compliance artifacts are structured JSON documents that describe how a specific control is implemented within a component.
Generating Artifacts
Via Agent
pretorin agent run --skill evidence-collection "Generate artifact for AC-02 in my system"
Via MCP
Use the generate_control_artifacts tool for read-only AI drafts.
Submit to Platform
pretorin frameworks submit-artifact artifact.json
Artifact Schema
{
"framework_id": "fedramp-moderate",
"control_id": "ac-02",
"component": {
"component_id": "my-application",
"title": "My Application",
"description": "A web application that handles user data",
"type": "software",
"control_implementations": [
{
"control_id": "ac-02",
"description": "2-3 sentence narrative explaining HOW the control is implemented",
"implementation_status": "implemented",
"responsible_roles": ["System Administrator", "Security Team"],
"evidence": [
{
"description": "What this evidence demonstrates",
"file_path": "src/auth/users.py",
"line_numbers": "45-72",
"code_snippet": "def create_user(username, role):\n ..."
}
],
"remarks": "Optional additional context"
}
]
},
"confidence": "high"
}
See Artifact Schema Reference for the full field documentation.
Implementation Status Values
| Status | Criteria |
|---|---|
implemented | Fully implemented and operational. Clear, direct code evidence. |
partial | Some aspects implemented, others pending. |
planned | Not yet implemented but scheduled. Architecture supports it. |
not-applicable | Control doesn’t apply to this component. |
Confidence Levels
| Level | Criteria |
|---|---|
high | Clear, direct evidence in code. Specific file paths and line numbers. |
medium | Reasonable evidence with some inference required. |
low | Limited evidence. Significant assumptions made. |
Evidence Quality
Good evidence shows HOW a control is implemented with specifics. Weak evidence merely shows that relevant code exists.
Good:
User creation requires role assignment and manager approval via the
create_user()function which validates roles against an allowlist and triggers an approval workflow.
Weak:
Has a User class in the models file.
Guidelines
- Call
pretorin frameworks control <fw> <ctrl>first — the AI guidance describes exactly what evidence assessors expect - Include specific file paths and line numbers
- Keep code snippets brief (under 10 lines)
- Focus on the most relevant evidence, not exhaustive listing
- Describe what the evidence demonstrates in relation to the control requirement
Example: Good Artifact
{
"framework_id": "fedramp-moderate",
"control_id": "ac-02",
"component": {
"component_id": "acme-web-platform",
"title": "Acme Web Platform",
"description": "A web application with multi-tenant user management",
"type": "software",
"control_implementations": [
{
"control_id": "ac-02",
"description": "The application implements account management through a provisioning system that requires role assignment during user creation, enforces manager approval for elevated roles, and automatically disables accounts after 90 days of inactivity.",
"implementation_status": "implemented",
"responsible_roles": ["System Administrator", "Security Team", "Team Managers"],
"evidence": [
{
"description": "User creation requires role assignment and manager approval for admin roles",
"file_path": "src/users/provisioning.py",
"line_numbers": "45-72",
"code_snippet": "def create_user(username, role, manager_id):\n validate_role(role)\n if role in ELEVATED_ROLES:\n require_approval(manager_id)\n user = User.create(username=username, role=role)"
},
{
"description": "Automated dormant account detection and deactivation after 90 days",
"file_path": "src/users/lifecycle.py",
"line_numbers": "120-145",
"code_snippet": "def check_dormant_accounts():\n threshold = datetime.utcnow() - timedelta(days=90)\n dormant = User.query.filter(User.last_login < threshold)"
}
],
"remarks": "Account removal via soft delete to maintain audit trail."
}
]
},
"confidence": "high"
}
Example: Partial Implementation
{
"framework_id": "fedramp-moderate",
"control_id": "sc-07",
"component": {
"component_id": "acme-web-platform",
"title": "Acme Web Platform",
"description": "A web application with multi-tenant user management",
"type": "software",
"control_implementations": [
{
"control_id": "sc-07",
"description": "TLS 1.3 enforced and CORS restricted to specific origins. However, security group ingress allows broad access from 0.0.0.0/0 on port 443, and no WAF is configured.",
"implementation_status": "partial",
"responsible_roles": ["System Administrator", "DevOps Team"],
"evidence": [
{
"description": "CORS restricted to application origins only",
"file_path": "src/api/middleware.py",
"line_numbers": "8-15",
"code_snippet": "app.add_middleware(\n CORSMiddleware,\n allow_origins=['https://app.acme.com'])"
},
{
"description": "Security group allows unrestricted ingress — overly permissive",
"file_path": "terraform/security.tf",
"line_numbers": "12-25",
"code_snippet": "ingress {\n from_port = 443\n cidr_blocks = [\"0.0.0.0/0\"]\n}"
}
],
"remarks": "Recommend restricting security group ingress and adding WAF."
}
]
},
"confidence": "medium"
}
Asset Inventory & System Spec
Auditors require five “system spec” artifacts: an asset inventory plus four snapshot kinds (data flow, network topology, threat model, hardware/software baseline). The platform exposes these as typed entities so the inventory can evolve over time and each snapshot can be attested independently.
This page covers the CLI / MCP surface for the asset inventory specifically. The four snapshot kinds are authored in the platform UI today; toggling them required/optional is the only CLI touchpoint.
CLI commands
All commands live under pretorin scope artifacts. They wrap the public
/api/v1/public/systems/{id}/spec/* endpoints and require a token with the
system_spec.read (reads) or system_spec.write (writes) scope.
# 1. List the 5 artifact kinds with their required / toggle / attest state.
pretorin scope artifacts list
# 2. Inspect the current asset inventory (or replay history).
pretorin scope artifacts inventory show
pretorin scope artifacts inventory show --as-of 2026-04-01T00:00:00Z
# 3. Upload a CSV.
# The CLI fetches the current platform inventory first, classifies your CSV
# rows into added / modified / decommissioned, shows a diff preview, and
# posts a single diff.
pretorin scope artifacts inventory upload assets.csv
# 4. Scan a source and apply the resulting diff.
pretorin scope artifacts inventory scan aws # live AWS account
pretorin scope artifacts inventory scan azure # live Azure subscription
pretorin scope artifacts inventory scan k8s # live K8s via kubectl
pretorin scope artifacts inventory scan iac-workspace # local .tf / k8s YAML files
pretorin scope artifacts inventory scan aws --dry-run # show diff without applying
# 5. Toggle an artifact kind required/optional.
# Rationale is required when toggling off.
pretorin scope artifacts toggle threat_model --optional \
--rationale "single-tenant scope; threat model lives in linked vendor SSP"
Scan sources
Each inventory scan <source> runs a built-in recipe that lives under
src/pretorin/recipes/_recipes/asset-inventory-<source>/:
| Source | Recipe | What it reads |
|---|---|---|
aws | asset-inventory-aws-baseline | Live AWS API (boto3) — EC2 instances in v1 |
azure | asset-inventory-azure-baseline | Live Azure Resource Manager — Compute VMs in v1 |
k8s | asset-inventory-k8s-baseline | kubectl get against the active context — nodes + Deployment/StatefulSet/DaemonSet |
iac-workspace | asset-inventory-iac-workspace | Static parse of .tf, .tf.json, K8s YAML, and cloudformation.{json,yaml} files in the cwd |
The iac-workspace recipe is the generalized “look at the IaC checked into
this repo” path — it does not call any cloud API and does not require any
cloud credentials. Use it when you want the inventory to match the desired
state in source control rather than current cloud state.
Adding a new source means adding a new recipe directory and updating
SCAN_SOURCE_TO_RECIPE_ID in src/pretorin/spec.py. Community recipes can
live under ~/.pretorin/recipes/ and override built-ins by id.
Decommission semantics
The diff endpoint never silently revives a decommissioned asset. If you
upload a CSV (or scan) that contains an external_id matching a
previously-decommissioned row, the platform returns an outcome: "not_found"
item with a message telling you to re-activate via the UI rather than re-scan.
The CLI surfaces this clearly in the diff response — look for the yellow
“Some rows did not apply cleanly” block.
MCP tools
Three tools mirror the read + diff endpoints for AI agents:
list_artifact_requirements(system_id)— wraps the kinds endpoint.get_asset_inventory(system_id, as_of?)— wraps the inventory read.submit_asset_inventory_diff(system_id, recipe_id, added?, modified?, decommissioned?, idempotency_key?, recipe_context_id?)— posts the diff.recipe_idis a free-form string (the platform recordscli:<recipe_id>as per-row provenance).idempotency_keydefaults tosha256(system_id, recipe_id, scan_timestamp)[:32]; pass your own when replaying a scan.recipe_context_idis optional — set it when the diff is being produced inside an active recipe context opened viastart_recipe.
The diff endpoint accepts recipe_context_id cleanly but does not require
it, unlike the create_evidence write surface. There’s no 11-field audit
metadata envelope required for inventory diffs.
Cross-Framework Mapping
Map controls across related frameworks to identify overlaps, reduce duplicate work, and understand framework relationships.
When to Use Cross-Framework Mapping
- Dual compliance — Organization needs FedRAMP + CMMC. Map overlapping controls to avoid duplicate work.
- Framework migration — Moving from 800-171 to FedRAMP. Identify which controls already satisfy FedRAMP requirements.
- Gap identification — Already compliant with 800-53 and need CMMC. Find the delta.
- Audit preparation — Show auditors how controls in one framework map to another.
Workflow
Step 1: Start with the Source Control
Query the control with references to discover relationships:
pretorin frameworks control nist-800-53-r5 ac-02
References are shown by default. The Related Controls field reveals connections to other controls and frameworks.
Step 2: Build the Mapping
Look up the equivalent control in each target framework:
| Framework | Control ID | Title |
|---|---|---|
| NIST 800-53 Rev 5 | ac-02 | Account Management |
| FedRAMP Moderate | ac-02 | Account Management |
| NIST 800-171 Rev 3 | 03.01.01 | Account Management |
| CMMC Level 2 | AC.L2-3.1.1 | Authorized Access Control |
Step 3: Compare Requirements
Get details for each framework’s version of the control:
pretorin frameworks control nist-800-53-r5 ac-02
pretorin frameworks control fedramp-moderate ac-02
pretorin frameworks control nist-800-171-r3 03.01.01
pretorin frameworks control cmmc-l2 AC.L2-3.1.1
Compare what each framework emphasizes. For Account Management:
- NIST 800-53 — Full control with 13 enhancements. Covers account types, conditions, authorized users, managers, CRUD, monitoring, and atypical usage.
- FedRAMP Moderate — Same base control with FedRAMP-specific parameter values (e.g., specific timeframes for disabling inactive accounts).
- NIST 800-171 — Streamlined from 800-53. Core requirements: defining types, assigning managers, establishing conditions, authorizing access, monitoring.
- CMMC Level 2 — Maps directly to 800-171 03.01.01. Same core requirements framed as maturity practices.
Step 4: Identify Gaps and Overlaps
NIST 800-53 AC-02 (most comprehensive)
├── Includes all FedRAMP Moderate AC-02 requirements ✓
├── Includes all NIST 800-171 03.01.01 requirements ✓
└── Includes all CMMC L2 AC.L2-3.1.1 requirements ✓
FedRAMP Moderate AC-02
├── Satisfies NIST 800-171 03.01.01 ✓
└── Satisfies CMMC L2 AC.L2-3.1.1 ✓
NIST 800-171 03.01.01
└── Satisfies CMMC L2 AC.L2-3.1.1 ✓
Key insight: Compliance with a parent framework generally satisfies the child framework’s corresponding control. Always verify with pretorin frameworks control <fw> <ctrl> to check for framework-specific parameters or additional requirements (references are included by default).
Using MCP for Cross-Framework Mapping
With an MCP-connected AI agent, ask questions like:
“Map Account Management controls across NIST 800-53, FedRAMP Moderate, and CMMC Level 2. Show me the overlaps and any unique requirements.”
The agent will use get_control and get_control_references to discover and compare related controls across frameworks.
STIG Compliance Scanning
Pretorin integrates STIG (Security Technical Implementation Guide) scanning to verify technical control implementations. The scanning workflow connects NIST 800-53 controls to specific technical checks via the CCI (Control Correlation Identifier) chain.
Traceability Chain
NIST 800-53 Control → CCIs → SRGs → STIG Rules → Scanner Results
- CCI — Control Correlation Identifier: bridges a control requirement to testable items
- SRG — Security Requirements Guide: technology-neutral security requirements
- STIG Rule — Technology-specific check with detailed test and fix procedures
Browse the Chain
Find Applicable STIGs
# Show STIGs applicable to your system
pretorin stig applicable --system "My System"
# AI-infer STIGs from system profile
pretorin stig infer --system "My System"
Explore the Traceability
# Full chain from a NIST control to STIG rules
pretorin cci chain ac-2 --system "My System"
# Browse CCIs for a control
pretorin cci list --control ac-2
# See what a specific CCI requires
pretorin cci show CCI-000015
# Browse STIG rules
pretorin stig rules <stig_id> --severity cat_i
Scanning Workflow
Scanning is driven by recipes that the calling AI agent invokes through MCP.
Each scanner ships as a built-in recipe (inspec-baseline, openscap-baseline,
cloud-aws-baseline, cloud-azure-baseline, manual-attestation).
1. Discover Available Recipes
pretorin recipe list
pretorin recipe show inspec-baseline
2. Review Test Manifest
The agent uses get_test_manifest (MCP) to see which STIGs and rules
apply to a system before running a scan. From the CLI you can browse the
relationships directly:
pretorin stig applicable --system "My System"
pretorin cci chain ac-2 --system "My System"
3. Ask the Agent to Run the Scan
Inside Claude Code, Codex CLI, or pretorin agent run, ask:
“Run an inspec-baseline scan against
RHEL_9_STIGon this system.”
The agent will open a recipe context, call the recipe’s run_scan script,
and submit results through submit_test_results. There is no
direct CLI command for executing a scan — the recipe layer is the
contract surface.
4. Submit Results Manually
If you have raw scanner output and want to upload it without running through a recipe, push it directly via MCP:
submit_test_results(system_id, results)
5. Attach Evidence to a Failing Rule
When a rule fails, attach remediation proof, mitigating-control documentation, or waiver-justification artifacts to the rule’s per-system workflow row. The workflow row is lazy-created on first attachment.
# Create the evidence
pretorin evidence upsert ac-02 fedramp-moderate \
--name "RHEL hardening playbook output" \
--description "Ansible run output applying CAT-I remediations" \
--artifact-content "**Evidence**\n\n- Ansible run output applying CAT-I remediations." \
--type configuration
# Link it to the STIG rule by catalog rule UUID
pretorin evidence link-stig <evidence_id> <stig_rule_uuid>
Add --override-system-mismatch --override-reason "<why>" to permit
cross-system attachment when the evidence belongs to a different system
than the active context.
MCP Tools for STIG/CCI
| Tool | Description |
|---|---|
list_stigs | List benchmarks with filters |
get_stig | Benchmark detail |
list_stig_rules | Rules with severity/CCI filters |
get_stig_rule | Full rule: check text, fix text, CCIs |
list_ccis | CCIs with control filter |
get_cci | CCI detail with linked rules |
get_cci_chain | Full traceability chain |
get_cci_status | CCI compliance rollup |
get_cci_implementation | Per-system CCI implementation row detail |
get_stig_applicability | Applicable STIGs for a system |
infer_stigs | AI-infer applicable STIGs |
get_test_manifest | Test manifest for a system |
submit_test_results | Upload scan results |
link_evidence_to_cci_implementation | Attach evidence to a per-system CCI row |
link_evidence_to_stig_rule_workflow | Attach evidence to a STIG rule workflow row |
Environment Variables
Environment variables override stored configuration values.
Authentication & API
| Variable | Description | Default |
|---|---|---|
PRETORIN_API_KEY | API key for platform access. Overrides api_key in config file. | — |
PRETORIN_PLATFORM_API_BASE_URL | Platform REST API base URL | https://platform.pretorin.com/api/v1/public |
PRETORIN_API_BASE_URL | Backward-compatible alias for PRETORIN_PLATFORM_API_BASE_URL | — |
PRETORIN_MODEL_API_BASE_URL | Model API URL for agent runtime | https://platform.pretorin.com/api/v1/public/model |
Context
| Variable | Description | Default |
|---|---|---|
PRETORIN_SYSTEM_ID | Active system ID. Overrides the system set via pretorin context set. | — |
PRETORIN_FRAMEWORK_ID | Active framework ID. Overrides the framework set via pretorin context set. | — |
Agent Runtime
| Variable | Description | Default |
|---|---|---|
OPENAI_API_KEY | Model key override for agent runtime. Takes precedence over stored Pretorin login key. | — |
OPENAI_BASE_URL | Base URL for the model API endpoint. Overrides openai_base_url in config file. | — |
OPENAI_MODEL | Model name for the agent runtime. | gpt-4o |
Source Attestation
| Variable | Description | Default |
|---|---|---|
PRETORIN_SOURCE_PROVIDERS | JSON array of source provider configurations. Overrides source_providers in config file. | — |
PRETORIN_SOURCE_MANIFEST | JSON string or file path to a source manifest. Falls back to .pretorin/source-manifest.json in the git repo root, then ~/.pretorin/source-manifest-{system_id}.json, then the source_manifest config key. | — |
Behavior
| Variable | Description | Default |
|---|---|---|
PRETORIN_DISABLE_UPDATE_CHECK | Set to a truthy value (1, true, yes, on) to disable passive update notifications. | — |
PRETORIN_LOG_LEVEL | Logging level (DEBUG, INFO, WARNING, ERROR) | WARNING |
PRETORIN_MCP_TELEMETRY_DISABLED | Set to any non-empty value to suppress the PRETORIN_TELEMETRY_EVENT JSON lines that pretorin mcp-serve emits on stderr for tool-routing observability. | — |
Precedence
For the API key:
PRETORIN_API_KEYenvironment variable (highest)api_keyin~/.pretorin/config.json
For the platform API URL:
PRETORIN_PLATFORM_API_BASE_URLenvironment variable (highest)PRETORIN_API_BASE_URLenvironment variable (legacy alias)platform_api_base_urlin~/.pretorin/config.jsonapi_base_urlin~/.pretorin/config.json(legacy)https://platform.pretorin.com/api/v1/publicdefault
For the model key (agent runtime):
OPENAI_API_KEYenvironment variable (highest)config.api_key(frompretorin login)config.openai_api_key
For the model name:
OPENAI_MODELenvironment variable (highest)openai_modelin~/.pretorin/config.json- Org AI settings from the platform (cached)
gpt-4odefault
For the source manifest:
PRETORIN_SOURCE_MANIFESTenvironment variable (highest) — JSON string or file path.pretorin/source-manifest.jsonin the git repo root~/.pretorin/source-manifest-{system_id}.jsonsource_manifestkey in~/.pretorin/config.json
CI/CD Example
export PRETORIN_API_KEY=pretorin_your_key_here
export PRETORIN_DISABLE_UPDATE_CHECK=1
export PRETORIN_SYSTEM_ID=your_system_id
pretorin frameworks list
pretorin evidence push
Artifact Schema Reference
Complete field reference for compliance artifact JSON documents.
Top-Level Fields
| Field | Type | Required | Description |
|---|---|---|---|
framework_id | string | Yes | The compliance framework (e.g., fedramp-moderate, nist-800-53-r5) |
control_id | string | Yes | The control being addressed (e.g., ac-02, au-02) |
component | object | Yes | The system component being assessed |
confidence | string | Yes | Confidence in the analysis: high, medium, or low |
Component Fields
| Field | Type | Required | Description |
|---|---|---|---|
component_id | string | Yes | Source identifier (repository name, package name) |
title | string | Yes | Human-readable component name |
description | string | Yes | Brief description of what the component does |
type | string | Yes | One of: software, hardware, service, policy, process |
control_implementations | array | Yes | How the control is implemented |
Control Implementation Fields
| Field | Type | Required | Description |
|---|---|---|---|
control_id | string | Yes | Must match parent control_id |
description | string | Yes | 2-3 sentence narrative of HOW the control is implemented |
implementation_status | string | Yes | implemented, partial, planned, or not-applicable |
responsible_roles | array | No | Roles responsible (default: ["System Administrator"]) |
evidence | array | No | Supporting evidence items |
remarks | string | No | Additional notes or caveats |
Evidence Fields
| Field | Type | Required | Description |
|---|---|---|---|
description | string | Yes | Narrative of what this evidence shows |
file_path | string | No | Path to the source file |
line_numbers | string | No | Line range (e.g., "10-25") |
code_snippet | string | No | Relevant code excerpt (keep under 10 lines) |
Implementation Status Definitions
| Status | Definition |
|---|---|
implemented | Control is fully implemented and operational. Clear, direct evidence exists in the codebase. |
partial | Some aspects are implemented, others are pending. Example: user CRUD exists but no account expiration or manager approval. |
planned | Not yet implemented but scheduled. The architecture supports it but the feature isn’t built. |
not-applicable | Control doesn’t apply to this component. Example: a pure API service with no user accounts doesn’t need account management controls. |
Confidence Levels
| Level | Definition |
|---|---|
high | Clear, direct evidence in code. Well-documented implementations with specific file paths and line numbers. |
medium | Reasonable evidence but some inference required. The implementation likely satisfies the control but some aspects aren’t explicitly documented. |
low | Limited evidence. Significant assumptions made. The codebase has relevant code but the connection to the control requirement is indirect. |
Evidence Attestation
The Pretorin platform can sign each evidence record with a DSSE envelope wrapping an in-toto Statement v1, per ADR 0003 — Evidence DSSE Attestation Envelope. This page covers how to fetch and independently verify those envelopes from the CLI or any compliant DSSE verifier.
Beta surface. Attestation is gated by the platform-side
EVIDENCE_ATTESTATION_MODEflag (off|shadow|dual|primary). The CLI commands return a friendly “no attestation available” message until your deployment enables the surface (dualorprimary).
Why DSSE attestation matters
The evidence record itself is mutable on the platform side (status transitions, lifecycle updates, recipe re-runs). The DSSE envelope is the immutable, signed snapshot that audit packages reference. With it:
- Auditors can verify offline that a piece of evidence as presented matches what the platform observed at attestation time.
- CI pipelines can gate releases on a verifier returning exit 0 over the evidence used in the bundle.
- Tooling downstream of the platform (cosign, in-toto verifiers) can consume the envelope without trusting the API.
CLI commands
Fetch the envelope
# Pretty summary
pretorin evidence attestation get ev-abc123
# Raw DSSE envelope JSON — pipe to any DSSE verifier
pretorin evidence attestation get ev-abc123 --json
# Lineage view: every prior signing of this evidence (newest first)
pretorin evidence attestation get ev-abc123 --lineage
pretorin evidence attestation get ev-abc123 --lineage --include-archived
get returns the latest completed envelope by default. Each evidence row may have multiple historical attestations (after a key rotation, after a content edit, etc.); --lineage surfaces all of them.
Verify the signature
# Default: verify against the prod-tier key registry
pretorin evidence attestation verify ev-abc123
# Other environments (staging, dev)
pretorin evidence attestation verify ev-abc123 --env staging
# Pin a specific signing key — extra safety check
pretorin evidence attestation verify ev-abc123 \
--key-fingerprint 8b4c2e...64-hex-chars
verify exits 0 on success and 1 on failure. With --json the CLI emits a structured result:
{
"evidence_id": "ev-abc123",
"ok": true,
"reason": null,
"fingerprint": "8b4c2e...",
"attested_at": "2026-05-27T00:00:00+00:00",
"expected_env": "prod"
}
What the verifier actually checks
The CLI verifier is a direct port of the platform’s reference implementation, so client and server agree byte-for-byte on validity. Six checks run, in order:
- Envelope shape.
payloadTypemust beapplication/vnd.in-toto+json; at least one signature must be present. - Payload decode. The base64-encoded
payloadmust decode to JSON. - Signature. The signature is over the DSSE PAE bytes (
"DSSEv1 LEN(type) type LEN(payload) payload"), not the canonical JSON Statement bytes directly. The verifier reconstructs the PAE and runs ECDSA P-256 + SHA-256 against it. - Trust root. The public key comes from
GET /api/v1/public/keys. The verifier matches the envelope’ssignatures[].keyidto a registry entry by SHA-256 fingerprint of the DER SPKI. Thepublic_key_pemfield embedded on the envelope row is never used as the trust root — it’s there for offline human inspection only. - Key validity. The matched key must be inside its
valid_from/valid_untilwindow atattested_at, not revoked beforeattested_at, and have anenvironment_labelmatching--env. Prod keys do not verify staging envelopes and vice versa. - Statement shape.
_typemust behttps://in-toto.io/Statement/v1,predicateTypemust be in the accepted set (default:https://pretorin.com/attestations/evidence/v1), and the subject must carry a non-empty SHA-256 digest.
Any failed check returns a structured reason that maps to one of the platform’s failure classes (shape, signature_mismatch, key_untrusted, other).
Verifying with cosign
The DSSE envelopes are spec-compliant, so any DSSE-aware verifier works. To verify with cosign:
# 1. Fetch the envelope.
pretorin evidence attestation get ev-abc123 --json > attestation.dsse.json
# 2. Pull the matching public key from the registry.
PUBKEY_FP=$(jq -r .signatures[0].keyid attestation.dsse.json)
pretorin --json evidence attestation get ev-abc123 \
| jq -r .signatures[0].keyid # double-check the fingerprint matches
# 3. Verify with cosign. Use the PEM from `GET /api/v1/public/keys` — the
# CLI's own `verify` command does this lookup for you, but for cosign
# you fetch the registry entry yourself.
cosign verify-blob-attestation \
--insecure-ignore-tlog \
--key pretorin-prod.pem \
--signature attestation.dsse.json
CI integration
A common pattern is to gate a release on every evidence record in the bundle having a verifiable attestation:
#!/usr/bin/env bash
set -euo pipefail
EVIDENCE_IDS=( $(cat evidence-bundle.txt) )
for id in "${EVIDENCE_IDS[@]}"; do
if ! pretorin evidence attestation verify "$id" --env prod >/dev/null 2>&1; then
echo "::error::Attestation verification failed for $id"
exit 1
fi
done
echo "All ${#EVIDENCE_IDS[@]} evidence records have valid attestations."
MCP integration
External AI agents (Claude Code, Codex CLI, custom MCP clients) can call get_evidence_attestation to fetch the envelope as JSON:
// MCP tool call
{
"tool": "get_evidence_attestation",
"arguments": {
"evidence_id": "ev-abc123",
"include_lineage": true,
"include_archived": false
}
}
The response is a structured { evidence_id, attestation, lineage? } payload. When the platform attestation surface is disabled or the row has no envelope yet, the tool returns a structured attestation_unavailable error rather than an opaque HTTP 404, so the calling agent can react appropriately.
Predicate body — what’s actually signed
The Pretorin v1 predicate (https://pretorin.com/attestations/evidence/v1) wraps the 12-field audit metadata baseline that lands on every evidence row at write time:
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "ev-abc123",
"digest": { "sha256": "..." }
}
],
"predicateType": "https://pretorin.com/attestations/evidence/v1",
"predicate": {
"predicate_schema_version": "v1",
"evidence_id": "ev-abc123",
"kind": "configuration",
"captured_at": "2026-05-27T00:00:00Z",
"source_uri": "file://./terraform/main.tf",
"source_label": "Terraform IaC",
"producer_kind": "recipe",
// ... plus the rest of the audit_metadata contract
}
}
The subject digest is computed over the evidence body bytes; verifying the digest alongside the signature is what lets an auditor confirm the evidence content hasn’t changed since attestation.
See also
- Evidence Commands — the full
pretorin evidencesurface. - MCP Tool Reference — the
get_evidence_attestationMCP tool. - ADR 0003 (in the platform monorepo) — the architecture decision and threat model.
Contributing
Thank you for your interest in contributing to the Pretorin CLI!
We welcome contributions to the CLI, MCP server, docs, scanners, developer workflows, and local tooling. This repository is open source under Apache-2.0, while Pretorin-hosted platform services, authenticated API access, and account-scoped data are governed separately by the applicable platform terms.
Scope
Good fits for this repository:
- CLI commands and output improvements
- MCP tools, prompts, and local agent integrations
- Scanner integrations and developer workflow automation
- Documentation, examples, and tests
Out of scope for public contributions:
- Customer data, exported platform data, or private operational runbooks
- Secrets, internal credentials, or private environment details
- Changes that imply trademark rights or suggest an unofficial fork is an official Pretorin service
For brand usage guidance, see Trademarks and Service Terms.
Getting Started
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/pretorin-cli.git cd pretorin-cli - Install development dependencies:
uv pip install -e ".[dev]"
Development Workflow
Running Tests
pytest
Integration tests require an API key and are marked with @pytest.mark.integration:
pytest -m integration
Integration tests require a valid API key tied to an account that has accepted the platform terms.
Type Checking
mypy src/pretorin
Linting
ruff check src/pretorin
ruff format src/pretorin
Full CI Check
Run the same checks as the CI pipeline:
ruff check src/pretorin && ruff format --check src/pretorin && mypy src/pretorin && pytest
Submitting Changes
- Create a feature branch from
main - Make your changes
- Ensure tests pass and code is properly formatted
- Add a sign-off to each commit with
git commit -s - Submit a pull request
By submitting a contribution, you certify that:
- You have the right to submit the code, docs, or other materials.
- Your contribution may be distributed under the Apache License, Version 2.0.
- You are not including confidential information, customer data, or material that is governed by separate platform terms.
Code Style
- Follow PEP 8 guidelines
- Use type hints for all function signatures
- Write docstrings for public functions and classes
- Keep functions focused and small
CI Pipeline
The CI pipeline runs on Python 3.10, 3.11, and 3.12:
- Lint — Ruff check + format
- Audit — pip-audit (dependency vulnerability scan)
- Type check — mypy strict mode
- Test — pytest
Legal and Platform Boundaries
- The source code in this repository is licensed under Apache-2.0.
- The Pretorin name, logos, and other brand assets remain subject to trademark rights and are not licensed for reuse except for nominative/reference use. See Trademarks and Service Terms.
- Access to Pretorin-hosted APIs, services, and account-scoped data is authenticated and governed by separate platform terms.
Reporting Issues
Use GitHub Issues to report bugs or request features. Include:
- Clear description of the issue
- Steps to reproduce (for bugs)
- Expected vs actual behavior
- CLI version (
pretorin version)
Questions?
- API documentation: platform.pretorin.com/api/docs
- Platform: platform.pretorin.com
Trademarks and Service Terms
Pretorin, the Pretorin logo, and related brand assets are trademarks or registered trademarks of Pretorin, Inc.
The Apache-2.0 license for this repository covers the source code and documentation in this repo. It does not grant permission to use Pretorin trademarks, logos, or branding for derivative products or services in a way that suggests sponsorship, endorsement, or official status.
Permitted uses generally include truthful, referential statements such as:
- Saying that your project is based on or compatible with Pretorin CLI
- Linking to this repository or to Pretorin documentation
- Describing changes you made in a fork, as long as you do not imply the fork is an official Pretorin release or hosted service
Not permitted without separate permission:
- Shipping a fork under the Pretorin name as if it were the official product
- Reusing Pretorin logos, trade dress, or marketing assets for another hosted service
- Suggesting endorsement, partnership, certification, or official support where none exists
Access to Pretorin-hosted platform services, APIs, and any account-scoped data returned by those services is governed by the applicable platform terms and account agreements, which are separate from the open-source license for this repository.
Changelog
All notable changes to the Pretorin CLI are documented here. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
0.22.14 - 2026-05-29
Fixed
pretorin updateno longer trusts a stale “already latest” check as final: no-argument updates still check PyPI for user-facing context, but they now run the installer when that check reports the current version. This lets uv/pipx/pip confirm with a refreshed/no-cache install path instead of exiting early on stale CDN metadata, while avoiding downgrades when the installed version is newer than PyPI’s latest.- PyPI-confirmed uv updates use an exact refreshed version: when the update check sees a newer version, uv-managed installs now run
uv tool install --force --refresh pretorin==<version>instead ofpretorin@latest. If verification still sees the old version, the manual recovery hint also names that exact refreshed command.
0.22.13 - 2026-05-29
Fixed
pretorin updaterefreshes uv’s package index for latest installs: uv-managed no-argument updates now runuv tool install --force --refresh pretorin@latest, keeping uv as the resolver while forcing it past stale cached index data. This prevents the observed one-version-at-a-time upgrade path where a fresh0.22.12release first resolved only to0.22.11.
0.22.12 - 2026-05-29
Fixed
pretorin updaterestores latest/current feedback without reintroducing uv pinning: no-argument updates check PyPI first and print either “already on the latest version” or the available upgrade, but still dispatch uv’s unpinnedpretorin@latestinstall path so the installer resolves against its own index view. Failed version checks now fall back to attempting the installer update instead of blocking the user.- pipless venvs can update through uv: uv-created virtualenvs, plus other current Python environments that do not have pip but do have uv on PATH, now route
pretorin updatethroughuv pip install --python ... --upgrade --refresh pretorininstead ofpython -m pip. The installer subprocess also preserves detected uv/pipx tool homes for custom tool directories. pretorin updateavoids local import shadowing: installer and verification subprocesses now run from the active venv root (or home directory fallback) and stripPYTHONPATH/PYTHONHOME, preventing untrusted working-directory files such aspip.pyorpretorin.pyfrom shadowing the real packages during self-update.
0.22.11 - 2026-05-29
Changed
- Evidence and narrative guidance plus write validation now keep gaps, missing evidence, ambiguity, and remediation work out of artifact text and record them only as control issues.
- Evidence Markdown now normalizes headings to report-safe bold section labels, with
pretorin evidence format-markdownavailable for file/stdin reformatting.
0.22.10 - 2026-05-29
Added
- Control issues workflow: Added the first-class
pretorin issuesCLI, matching MCP/agent issue tools, local issue writer/sync support, and issue-driven campaign targeting withissues-fixplus--all-open-issuesselectors.
Changed
- Legacy
notescommands and tools remain compatibility aliases while docs, prompts, receipts, and campaign generation now prefer issue terminology for durable gaps and remediation work. Issue and note resolution requests also percent-encode path IDs and require explicit resolution justifications.
0.22.9 - 2026-05-28
Fixed
- MCP recipe-context audit trail hardening (#958, #959, #963, #964):
get_control_implementationnow reports the canonical narrative source, note writes require a dedicatedcontrol-note-attestationrecipe context, narrative writes reject evidence-only or cross-control contexts, and workspace-capture markdown artifacts no longer get wrapped in an extra code fence that breaks nested fences.
0.22.8 - 2026-05-27
Added
- Evidence DSSE attestation: get/verify CLI + MCP (#150): New
pretorin evidence attestation getandpretorin evidence attestation verifysubcommands surface the platform’s DSSE in-toto attestation envelopes (ADR 0003) to auditors and CI pipelines. The verifier independently checks the ECDSA P-256 + SHA-256 signature over the DSSE PAE bytes, resolves the signing key throughGET /api/v1/public/keysrather than trusting any embedded PEM, and honors key validity windows, revocation, and environment labels — exit 0 on success, 1 with a reason on failure. The matchingget_evidence_attestationMCP tool lets external agents fetch the envelope (plus an optional lineage view) for any evidence record. Newcryptography>=42.0.0runtime dependency.
0.22.7 - 2026-05-26
Added
- Scoped evidence RAG search (#148):
search_evidencenow accepts a natural-language query across the CLI, MCP handler, and agent tool surface. Query mode searches attached evidence plus scoped reusable unattached evidence, including policy documents, before agents create new evidence.
Changed
- Agent and workflow guidance now tell control-update flows to search existing evidence semantically, link relevant unattached evidence, and cite those evidence IDs in updated narratives.
0.22.6 - 2026-05-23
Changed
- Automated maintenance + documentation sync (#147): lint/type-check fixes, test coverage and dead-code cleanups, dependency vulnerability patches, and version/registration consistency tweaks across the codebase. Doc sources, llms.txt manifests, and the rebuilt mdBook output were re-synced against the current CLI/MCP/agent surface, including the system-spec workflow entry, STIG/CCI tooling tables, and SOC 2 control-ID format notes. No behavior changes for end users.
0.22.5 - 2026-05-22
Fixed
- System-spec evidence type parity (#145): the CLI now accepts the platform’s five
system_spec_*evidence types (system_spec_inventory_attestation,system_spec_boundary_diagram,system_spec_network_dfd,system_spec_ppsm, andsystem_spec_interconnection) across evidence validation, MCP/agent prompts, audit metadata source-type defaults, and CLI error/help output. This prevents system-spec snapshot evidence returned by the platform from being rejected or hidden by the CLI.
0.22.4 - 2026-05-22
Fixed
- MCP
resolve_control_noteno longer 400’s Claude-based clients: the tool’s input schema declared a top-levelallOfto express “resolution_note is required when is_resolved is true”. Claude’s API rejectsanyOf/oneOf/allOfat the top level of toolinput_schemas, so every Claude Code / Claude Desktop request against any pretorin MCP tool failed before reaching the handler. The conditional requirement now lives in the handler — the constraint is preserved, and the schema is Claude-API compatible. pretorin updatedetects uv/pipx installs outside the default folders: the installer detector now reads uv’suv-receipt.tomland pipx’spipx_metadata.jsonfrom the running venv before falling back to path heuristics. This keeps custom uv/pipx tool installs from falling through topython -m pip, which fails in tool venvs that intentionally omit pip.- Update notices point at
pretorin update: passive CLI/MCP status prompts no longer hardcodepip install --upgrade pretorin, so uv, pipx, and pip users all get the same installer-aware upgrade path.
0.22.3 - 2026-05-22
Fixed
pretorin updateno longer fails right after a fresh release: previous design pre-resolved the latest version via PyPI’s JSON metadata API and passed it to uv as a strict==X.Y.Zpin. The JSON API can return a version moments before uv’s simple-index resolver sees it, so the pinned install failed with “No solution found.” Nowpretorin updatedispatchesuv tool install --force pretorin@latestdirectly and lets uv be the single source of truth.- Explicit-version updates use
--refresh:pretorin update X.Y.Zpasses--refreshto uv (and--no-cache-dirto pip/pipx) so the installer re-fetches the index before resolving.
Removed
- JSON-API pre-resolution + post-install verify dance:
pretorin updateno longer pre-resolves the target version or re-spawns Python after the install to verify. The installer’s exit code is the source of truth.
0.22.2 - 2026-05-21
Fixed
- Legacy agent — OpenAI strict-mode tool schemas (#136 bug 1): 20 platform tool definitions in
pretorin.agent.toolsdeclared optional parameters inpropertieswithout listing them inrequired. OpenAI’s strict-mode function-calling validator rejected the entiretoolsarray before any model turn. Added_to_strict_schemawhich normalizes schemas at the SDK boundary: every property gets added torequired, and optional properties become nullable unions (["string", "null"]). - Codex agent — unhelpful “Connection lost” error (#136 bug 2):
pretorin agent run(Codex runtime) was swallowing the exception class and chained cause. Now prints the exception class,caused bychain, and active runtime context (model + base_url) so the operator can tell which connection failed; same diagnostic block also wired into the legacy runtime.
0.22.1 - 2026-05-21
Fixed
inventory showalways reported empty (#133 follow-up): the CLI read the response underpayload["assets"]but the platform returns asset rows under"items". Same bug causedinventory scanto misclassify every row asadded(it diffed against an empty existing inventory). Both paths now readpayload["items"].artifacts togglealways 422’d (#133 follow-up): the client posted{"optional": ...}but the server’s PATCH schema is keyed ontoggled_off. Renamed the wire field while keeping the user-facing--optional/--requiredflag unchanged. Theartifacts listrenderer now reads eithertoggled_offor legacyoptionaldefensively.
0.22.0 - 2026-05-21
Added
- System spec CLI + MCP surface (#133): new
pretorin scope artifacts ...command group wraps the public/api/v1/public/systems/{id}/spec/*endpoints from monorepo PR #859. Operators canartifacts list,inventory show [--as-of T],inventory upload <csv>,inventory scan <source>, andartifacts toggle <kind> --optional --rationale "...". Three matching MCP tools (list_artifact_requirements,get_asset_inventory,submit_asset_inventory_diff) expose the same surface to AI agents. The diff endpoint acceptsrecipe_context_idbut does not require it — the 11-field audit-metadata envelope is reserved for evidence writes. - Four asset-inventory recipes:
asset-inventory-aws-baseline(live EC2 via boto3),asset-inventory-azure-baseline(live Compute VMs via azure-mgmt-compute),asset-inventory-k8s-baseline(kubectl-driven enumeration of nodes + Deployment/StatefulSet/DaemonSet), andasset-inventory-iac-workspace(static parse of.tf/.tf.json/ K8s YAML / CloudFormation files in the cwd — no cloud credentials required). All four ship astier: official.
0.21.4 - 2026-05-19
Fixed
- MCP start-task routing and capture preflight (#126, #127):
inspect_statusnow returns a bounded no-workflow status bundle without running the full routing cross-check, and platform validation outages now surface as structured upstream errors instead of false “not found” messages. - AI-guidance evidence expectations (#127):
start_task.suggested_capture_plannow falls back from control context toget_control(...).ai_guidance.evidence_expectations, so enriched controls such as AU-04 retain their recipe preflight plan even when the system control-context endpoint is unavailable.
Changed
- Workspace capture fallback (#127):
workspace-captureis now the generic workspace evaluation/capture fallback for broad or unclassified evidence expectations, and capture-plan metadata identifies whether a recipe came from an expectation match or the fallback path.
Removed
- Legacy document requirements API: removed the obsolete
get_document_requirementsclient/MCP surface andpretorin frameworks documentscommand. Evidence requirements are derived from AI guidance.
0.21.3 - 2026-05-19
Fixed
pretorin updateworks on uv tool and pipx installs: the update command now detects howpretorinwas installed by inspectingsys.executableand dispatches touv tool upgrade pretorinorpipx upgrade pretorinwhen appropriate. Previously it always shelled out topython -m pip install --upgrade, which fails withNo module named pipon recentuvversions because tool venvs no longer ship pip. Pinned upgrades (pretorin update X.Y.Z) route touv tool install --force/pipx install --forceso they work on isolated tool venvs too. Failure paths and the post-upgrade “ran but version unchanged” hint now name the right installer.
0.21.2 - 2026-05-18
Changed
- MCP recipe-required telemetry (#121): evidence and narrative producer guardrails now emit a
PRETORIN_TELEMETRY_EVENTwithevent_type="recipe_required"and non-content shape metadata, letting operators compute the combined workflow/recipe bypass rate for the post-v0.21 trigger watch.
0.21.1 - 2026-05-16
Maintenance
- Automated maintenance + documentation sync pass (#122): lint/type-check fixes, test coverage improvements, dead-code removal, dependency vulnerability patches, version/registration consistency, and a repository-wide doc resync against the v0.21 surface (CLI/MCP/agent references, llms.txt manifests, and a fresh mdBook rebuild).
0.21.0 - 2026-05-15
Added
- Recipe/source MCP producer surface (#118): recipes can declare
requires.sources, MCP exposeslist_connected_sourcesandcheck_sources,start_taskreturnssuggested_capture_plan, andlist_recipes(system_id=...)filters to source-eligible recipes while failing open on older platform deployments. - Narrative recipe support (#118):
start_recipeacceptsevidence_ids,update_narrativerequires a narrative-producing recipe context with cited evidence ids, and the built-inevidence-narrative-composerecipe provides the canonical narrative path. - Workspace capture floor recipe (#118):
workspace-capturegeneralizes code capture for readable workspace files such as runbooks, policy drafts, scripts, configs, and exported reports.
Changed
- Recipe-only MCP writes (#118): MCP
create_evidence,create_evidence_batch, andupdate_narrativenow reject agent writes withoutrecipe_context_idusing a structuredrecipe_requirederror.
0.20.1 - 2026-05-15
Fixed
- Control note resolution parity (#760): MCP, CLI, and built-in agent note-resolution tools now expose and forward
resolution_note, matching the platform UI’s audit-trail requirement for closing notes.pretorin notes resolveaccepts--resolution-note/--justification, and local validation prevents closing a note without a justification.
0.20.0 - 2026-05-14
Changed
- MCP tool prefix dropped (#113, phase 3): every server-side tool name lost its leading
pretorin_. Hosts seemcp__pretorin__check_contextinstead ofmcp__pretorin__pretorin_check_context. Recipe-script tools follow the same rule (recipe_<id>__<script>instead ofpretorin_recipe_<id>__<script>). Breaking change for any agent that hardcoded the old names — re-install the bundled skill (pretorin skill install) or update local references. Tier metadata, the intent-verb map, and the workflow-body schema-bundling regex all moved with the rename. The handler function names (handle_create_evidence, etc.) are unchanged — this only affects the wire-level tool identifier.
Added
- Cross-harness MCP tool surface (#113, phases 0-2): the MCP server now ships a small set of cross-harness discovery + grounding tools so Cursor, Codex, vanilla Agents SDK, and any other client can ground a session without depending on the
initializeinstructions block.check_context— cheap, unauthenticated probe. Returns{connected, active_system, active_framework_id, suggested_next, pending_attention}with a deterministic next-step hint. Call once at session start.list_tools— compact catalog. One short record per tool (name,purpose,tier,requires_workflow) plus tier counts. Cross-harness alternative to fetching every tool’s full schema just to browse. Tiers:default,reference,workflow,recipe.get_instructions— callable mirror of the server’sinstructionsblock, for harnesses that don’t render it.- Errors-as-instructions: write tools that fail because there’s no active routing context now return a structured
{error: "workflow_required", message, routing_hint}payload (stillisError=true) instead of plain-text errors.routing_hint.suggested_intent_verbtells the agent the exactstart_taskcall to make. Backed by a newWorkflowRoutingErrorexception class. - Workflow schema bundling:
get_workflownow bundlesrequired_tool_schemas— the full MCPTooldefinitions for every tool the workflow body references. One round trip equips the agent. - Telemetry: structured single-line JSON events emitted on stderr (
PRETORIN_TELEMETRY_EVENT {...}) on successfulstart_taskand onWorkflowRoutingErrorraises. Feeds the phase-4 trigger decision in the RFC. Opt out withPRETORIN_MCP_TELEMETRY_DISABLED=1. pretorin mcp-smoke-testcommand: end-to-end harness that exercises every new behavior in-process — useful for verifying an install or PR.
0.19.0 - 2026-05-13
Added
- Markdown evidence artifacts and structured provenance (#112): JSON evidence writes now send short
descriptionsummaries plus standalone Markdownartifact_content, with source/capture context inaudit_metadata(source_label,source_locator,source_excerpt,content_hash,capture_method, and related fields). Batch evidence follows the same per-item contract. Addedpretorin evidence validateto compare fresh source-material hashes before re-verifying; drifted sources update the existing evidence artifact with adrift_noteinstead of silently callingmark-current.
0.18.2 - 2026-05-09
Maintenance
- Automated maintenance + documentation sync pass (#111): lint/type-check fixes, test coverage improvements, dead-code removal, dependency vulnerability patches, version/registration consistency, and a repository-wide doc resync against the v0.18 surface (CLI/MCP/agent references, llms.txt manifests, and a fresh mdBook rebuild).
0.18.1 - 2026-05-09
Added
- Continuous compliance —
--cadence-daysflag andmark-currentcommand (#108 PR B):pretorin evidence upsertaccepts--cadence-days <int>to opt new evidence into a refresh cadence; the platform then computesexpires_atserver-side and includes the row in the daily freshness sweep. Newpretorin evidence mark-current <id>subcommand re-affirms that evidence is still current — bumpsexpires_atby the cadence, transitionsexpired→valid, writes are_verifiedlineage row, and auto-resolves any openevidence.expiring/evidence.expiredmonitoring events.EvidenceCreatecarries the newrefresh_cadence_daysfield.PretorianClient.mark_evidence_current()is the corresponding API client method.
0.18.0 - 2026-05-08
Added
- Auditor sufficiency fields on evidence writes (#108):
pretorin evidence upsertgains--coverage-start,--coverage-end, and--capture-queryflags so callers can populate the new auditor sufficiency columns. The MCPcreate_evidencetool accepts the same arguments.EvidenceCreateandEvidenceBatchItemCreatenow carrydata_coverage_start_at,data_coverage_end_at, andcapture_query. Pairs with the platform-side schema; auditors get clear answers to the seven sufficiency questions (source-system, capture-vs-coverage timestamps, producer authority, capture context, in-scope binding, control mapping, reliability) without walking attestation chains.
0.17.8 - 2026-05-08
Fixed
- Evidence audit metadata serialization:
pretorin evidence upsertand MCP evidence writes now serializeaudit_metadata.captured_atusing Pydantic JSON mode before handing payloads tohttpx. Previously, recipe/agent-stamped evidence failed locally withTypeError: Object of type datetime is not JSON serializablebefore the platform request was sent. - Source verification JSON safety: evidence create and batch-create now normalize source-verification snapshots to JSON primitives, so attested contexts with datetime values do not break evidence writes.
0.17.7 - 2026-05-07
Fixed
- MCP recipe-script context resolution (#104): scanner recipes invoked over MCP (
manual-attestation,inspec-baseline,openscap-baseline,cloud-aws-baseline,cloud-azure-baseline) now correctly receive the activesystem_id/framework_id. The dispatcher previously read these fromPretorianClientinstead ofConfig, so every script ran withctx.system_id == Noneand the platform returnedSystem not found. As a bonus,PRETORIN_SYSTEM_ID/PRETORIN_FRAMEWORK_IDenv-var overrides now flow through end-to-end. - Recipe import error in scope/policy questionnaire redactors (#103):
scope-q-answerandpolicy-q-answerno longer fail at import withcannot import name 'redact_secrets'. Both scripts now use the publicredact()helper frompretorin.evidence.redactand unpack the(str, RedactionResult)return shape.
Documentation
- Customer-managed air-gapped install guide: new page walking operators of customer-managed / air-gapped Pretorin platform deployments through pointing the CLI at their private platform — non-secret platform validation (smoke test, embedding readiness, AI provider checks), CLI configuration via
PRETORIN_PLATFORM_API_BASE_URL/pretorin login --base-url, and tenant-scoped CLI smoke tests. Linked from the configuration reference. See Customer-managed air-gapped installs.
0.17.6 - 2026-05-06
Added
- Risk-management CLI + MCP surface (#100): you can now populate a system’s risk register directly from the CLI or from any MCP-connected agent — list, create, seed from library templates, update with mitigation, link controls/evidence/vendors as artifacts, and refresh the AI-generated summary. End-to-end wrappers around the platform’s public
/systems/{system_id}/risks*endpoints. Newpretorin riskcommand group:list,show,create,seed,update,refresh-summary,link add/link rm, andlibrary list. Matching MCP tools:list_risks,get_risk,create_risk,seed_risks,update_risk,link_risk_artifact,unlink_risk_artifact,refresh_risk_summary,list_risk_library. Tool descriptions encode workflow gotchas — risks are system-scoped, control auto-link is opt-in (requiresframework_id+ matching ControlImplementation rows), mitigation is recorded viaupdate_risk(no separate /mitigate endpoint), and AI summary refresh is best-effort.
0.17.5 - 2026-05-06
Fixed
pretorin cci implpanel now surfaces the impl row id (theidfield in the platform response) so agents can chain directly intoevidence link-cciwithout re-querying.- Panel header now displays the CCI human label (
CCI-000007) by reading the platform’scci_identifierfield. The earlier code read a non-existentcci_uuidfield and silently fell back to the URL arg. - Removed dead-code rendering loop for
emass_*fields that the platform does not return.
0.17.4 - 2026-05-06
Added
- CCI implementation read endpoint (#97):
pretorin cci impl <cci_uuid>and MCP toolget_cci_implementationwrap the new platformGET /systems/{system_id}/cci-implementations/{cci_uuid}endpoint, returning the live per-system impl row. - Evidence link target-type extensions (#97): new sibling commands
pretorin evidence link-cciandpretorin evidence link-stigplus MCP toolslink_evidence_to_cci_implementationandlink_evidence_to_stig_rule_workflow. Both honor the platform’soverride_system_mismatch+override_reasongate; the STIG variant lazy-creates the workflow row when none exists. - Agent guidance on STIG-to-CCI traceability: SKILL.md and the
single-controlworkflow playbook clarify that the STIG-rule → CCI relationship is catalog-level (DISA-defined). Useget_cci_chain(nist_control_id, system_id)for “what tests this CCI on this system.”
0.17.3 - 2026-05-05
Fixed
- Scope and policy generation MCP tools now request AI review in the same durable generation job by default, matching the platform workflow while preserving an
include_review=falseopt-out.
0.17.2 - 2026-05-02
Documentation
- Repository-wide documentation sync to current v0.17 surfaces: README recipes table, getting-started, CLI/MCP reference, frameworks selection + custom-framework authoring, recipes/workflows, agent overview, env-vars reference, llms.txt manifests, and a fresh mdBook rebuild.
Fixed
- Test isolation:
test_install_default_writes_to_all_known_agentsnow performs filesystem assertions inside thePath.home()patch context so CI runs do not depend on the runner’s real home directory.
0.17.1 - 2026-04-30
Added
- Custom framework authoring CLI (#90): end-to-end build / validate / upload workflow around the platform’s
unified.jsonrevision-lifecycle endpoints. Newpretorin frameworkscommands:init-custom,validate-custom,build-custom,upload-custom(--publishto ship immediately),fork-framework,rebase-fork,revisions,export-oscal. - Vendored unified-framework toolchain at
pretorin.frameworks: bundled JSON Schema validator, OSCAL ↔ unified converters with lossless round-trip, and the 12-format custom-catalog converter ported from the monorepodata/tools/. - Framework revision lifecycle client methods on
PretorianClient:create_custom_draft,publish_draft,fork_framework,create_rebase_draft,list_revisions. Structuredvalidation_reportis preserved throughPretorianClientError.detailson 400. jsonschema>=4.0.0added as a runtime dependency.
Documentation
- New page covering the full custom-framework workflow: Custom frameworks.
0.17.0 - 2026-04-30
Added
- Recipe extensibility system (RFC 0001): full implementation of the three-layer routing model — engagement → workflow → recipe. Calling AI agents now route through deterministic Python rules to a workflow playbook, then pick recipes per item from a discoverable menu instead of freelancing.
start_taskMCP tool: pure-function rule cascade over agent-extracted entities. Cross-checks against platform state (hallucinated control ids → hard error; wrong-framework / cross-system writes → ambiguous response). Bundles inspect summary into the response.- Workflow registry + 4 built-in playbooks:
single-control,scope-question,policy-question,campaign.list_workflowsandget_workflowMCP tools. - Recipe registry + 8 built-in recipes:
code-evidence-capture,inspec-baseline,openscap-baseline,cloud-aws-baseline,cloud-azure-baseline,manual-attestation,scope-q-answer,policy-q-answer. - Recipe authoring surface:
pretorin recipe list / show / new / validate / runCLI commands. Four loader paths with clear precedence: explicit > project > user > built-in. Per-script MCP tools auto-registered asrecipe_<safe_id>__<script>. - Recipe execution context:
start_recipe/end_recipe; every platform write inside the context auto-stampsproducer_kind="recipe", recipe id, and recipe version. - Audit-trail metadata:
EvidenceAuditMetadatais stamped on every CLI / agent / MCP / campaign-apply evidence write. Build helpers atpretorin.evidence.audit_metadataare the single construction surface. - Recipe selection on every drafting call:
draft_control_artifactsconsults the recipe registry before falling through to freelance. The decision is recorded asRecipeSelectionon the response. pretorin.evidence.redact+pretorin.evidence.markdown: shared primitives for secret redaction and audit-grade markdown composition.- Bundled
pretorinskill v0.17.0: teaches the calling agent about the routing model. New “Engagement (Routing)” section flagsstart_taskas the FIRST call. - Authoring docs at
docs/src/recipes/: index, manifest reference, script contract, writer tools, testing, publishing, workflows, engagement, worked example.
Changed (BREAKING)
pretorin scanCLI command removed. All scanner functionality moved to recipes. Migrate topretorin recipe run <recipe-id>(e.g.,pretorin recipe run inspec-baseline --param stig_id=RHEL_9_STIG) or invoke via MCP.ScanOrchestratorremoved. Manifest fetch + rule filter + summary helpers extracted topretorin.scanners.manifestand shared across scanner recipes.
Removed
src/pretorin/cli/scan.pyandsrc/pretorin/scanners/orchestrator.py.- The deprecated
rejected_invalid_typecampaign-apply telemetry counter (deprecated in 0.16.0).
0.16.3 - 2026-04-26
Fixed
- CCI chain test fix:
test_cci_chain_with_system_statusnow correctly mocksresolve_execution_contextso CCI status rendering is exercised. No production code changes.
0.16.2 - 2026-04-21
Fixed
pretorin campaign controls --familycase-insensitive resolution (#84):--family cc6now resolves to canonicalCC6before hitting the backend. Unknown families raise a structured error listing available families and pointing atpretorin frameworks families <framework-id>. Same fix applied toprepare_campaignMCP handler.
0.16.1 - 2026-04-21
Added
- Gap questions for policy and scope Q&A: MCP tool descriptions guide agents through answer-first workflow with structured gap questions for organizational knowledge gaps.
0.16.0 - 2026-04-21
Changed (BREAKING)
evidence_typeis now required on every CLI, MCP, agent, and workflow write path (#79). CLI paths hard-error when the user omits-t/--type; every other path runs a client-side normalizer before submission.
Added
- Evidence provenance fields: CLI sends
code_file_path,code_line_numbers,code_snippet,code_repository,code_commit_hashon all evidence creation paths. Auditors can trace evidence to source files and commits. - Source verification mapping: Attested source identities mapped to platform’s
SourceVerificationPayloadwithsource_typeandsource_role. pretorin evidence upload: Upload files (screenshots, PDFs, configs) as evidence with SHA-256 integrity verification.upload_evidenceMCP tool: Agents and recipes can upload evidence files via MCP.- File reference validation: Campaign apply reads actual file content as canonical snippet, validates paths and line ranges.
- Code provenance on local evidence: Frontmatter supports code_* fields for local evidence create and push.
pretorin.evidence.typesmodule: canonical 13-type enum, AI-drift alias map, andnormalize_evidence_type()with fuzzy matching.
Changed
- Evidence models include code provenance fields. Campaign extracts
code_*andrelevance_notesfrom AI recommendations. upsert_evidence()creates enriched evidence as new record when provenance fields are provided.- AI generation prompt requests code file paths and line numbers in evidence recommendations.
Fixed
- SOC2 campaign batches with non-canonical
evidence_typestrings now succeed end-to-end via the normalizer. - Non-campaign write paths can no longer silently tag missing-type evidence as
policy_document.
0.15.5 - 2026-04-20
Fixed
- Campaign
--applyruns no longer flood the evidence locker with AI-authored summaries typed aspolicy_document(issue #77). The pipeline now wiresrecommended_notesthrough to the platform as real gap notes, rejects evidence recommendations with missing or invalidevidence_type(turning them into synthesized gap notes), and emits a structuredcampaign.apply.controltelemetry line for post-ship measurement. - Partial failures in the per-control notes write now raise
PretorianClientErrorwith the failing indexes, mirroring the existing evidence-batch behavior so checkpoint resumes are idempotent. - Evidence batch result mapping now aligns offsets to the original recommendation index via the accepted-items list and asserts length match, fixing a latent index-drift bug that appeared once any recommendation was rejected mid-loop.
- Completion note now fires when all pending work has landed across runs, not only when something new was written in the current run.
Changed
evidence_typeis now required onEvidenceBatchItemCreate. The campaign batch write path no longer silently tags missing types aspolicy_document; pydantic validation raises instead. Other evidence write paths (CLI, MCP, direct API) keep their existing defaults.- Agent drafting prompts (
_build_generation_task,_draft_control_fix,_WORKFLOW_GUARDRAILS, codex system prompt,[[PRETORIN_TODO]]template) now list every valid evidence type verbatim and state that an emptyevidence_recommendationslist is a valid result — gaps belong inrecommended_notes. _WORKFLOW_GUARDRAILSmerged in the evidence-collection skill’s “concrete, auditable artifacts” language so narrative-generation skill callers inherit the same rules.
0.15.4 - 2026-04-18
Changed
- Updated 6 dependencies to resolve 7 known vulnerabilities (cryptography, pygments, pyjwt, pytest, python-multipart, requests)
- Added CLAUDE.md and AGENTS.md for AI agent context
0.15.3 - 2026-04-18
Fixed
pretorin updatenow checks PyPI before running pip, skipping reinstall when already currentpretorin updateverifies the installed version after pip runs, detecting silent failures in pipx/uv-managed environments
Added
pretorin update [VERSION]accepts an optional version argument to install a specific release
0.15.2 - 2026-04-18
Changed
- Documentation sync: rebuilt all docs to match current codebase
0.15.1 - 2026-04-17
Added
pretorin evidence delete <evidence-id>command with--yesflag for non-interactive workflows- MCP tool
delete_evidencefor programmatic evidence deletion within system scope - API client method
delete_evidencefor the public DELETE endpoint
0.15.0 - 2026-04-16
Added
- Source manifest requirement policy: declare which external sources a system expects and gate compliance writes on their presence
pretorin context manifestcommand for viewing the resolved manifest and evaluating it against detected sources- Manifest loading from four layered sources: env var, repo-local
.pretorin/source-manifest.json, per-system user config, or inline config key - Family-level source requirements with three requirement levels (required/recommended/optional) and write blocking on missing required sources
- Manifest evaluation results in write provenance (
manifest_statusandmissing_required_sourcesfields)
Changed
_enforce_source_attestationnow evaluates manifest requirements after the existing MISMATCH checkresolve_execution_contextandbuild_write_provenanceaccept optionalcontrol_idfor family-level manifest enforcement
0.14.0 - 2026-04-10
Changed
- MCP and agent write workflows now treat the active CLI context as a strict execution boundary by default, with an explicit
allow_scope_overrideescape hatch for intentional cross-scope writes - Control-scoped MCP and agent workflows now route through one shared scope-validation path so exact control lookup happens in the resolved framework before any write proceeds
- Agent guidance now tells built-in workflows to resolve an exact user-supplied control in the active framework before doing broader discovery
pretorin mcp-servenow emits a non-blocking stderr update prompt when a newer CLI release is available, so MCP-only users can discover upgrades without interrupting active tool calls
Fixed
apply_campaignnow reportsapply: trueafter a successful apply run and persists that state back to the checkpoint summary- Stored active context and campaign checkpoints are now validated against the current API environment before campaign reads or writes proceed
- Control-scoped MCP and agent updates now refuse silent remaps like
cm-04.02to a different control when the exact control does not resolve in the active framework
Added
get_cli_statusand thestatus://cliMCP resource expose local CLI version, update availability, and upgrade guidance to MCP hosts and agents
0.13.1 - 2026-04-07
Added
get_stigMCP tool for STIG benchmark detailget_cci_chainMCP tool for full Control → CCI → SRG → STIG rule traceability
0.13.0 - 2026-04-07
Added
- Complete STIG/CCI MCP tools:
list_stigs,get_stig,list_stig_rules,get_stig_rule,list_ccis,get_cci,get_cci_chain,get_cci_status,get_stig_applicability,infer_stigs,get_test_manifest,submit_test_results - STIG/CCI agent tools for OpenAI Agents SDK
pretorin stigCLI group:list,show,rules,applicable,inferpretorin cciCLI group:list,show,chainpretorin scanCLI group:doctor,manifest,run,results- Scanner orchestration module with support for OpenSCAP, InSpec, AWS/Azure Cloud Scanners, and Manual review
0.12.0 - 2026-04-04
Added
- Vendor management CLI:
pretorin vendor list/create/get/update/delete/upload-doc/list-docs - MCP vendor tools:
list_vendors,create_vendor,get_vendor,update_vendor,delete_vendor,upload_vendor_document,list_vendor_documents,link_evidence_to_vendor - Inheritance/responsibility MCP tools:
set_control_responsibility,get_control_responsibility,remove_control_responsibility,generate_inheritance_narrative,get_stale_edges,sync_stale_edges
0.11.0 - 2026-04-02
Added
- Campaign CLI:
pretorin campaign controls/policy/scope/status - Campaign MCP tools:
prepare_campaign,claim_campaign_items,get_campaign_item_context,submit_campaign_proposal,apply_campaign,get_campaign_status - External-agent-first campaign pattern with checkpoint persistence and lease-based concurrency
- Campaign builtin executor for local execution
0.10.0 - 2026-03-28
Added
- Workflow state and analytics MCP tools:
get_workflow_state,get_analytics_summary,get_family_analytics,get_policy_analytics - Family operations MCP tools:
get_pending_families,get_family_bundle,trigger_family_review,get_family_review_results - Policy workflow MCP tools:
get_pending_policy_questions,get_policy_question_detail,answer_policy_question,get_policy_workflow_state,trigger_policy_generation,trigger_policy_review,get_policy_review_results - Scope workflow MCP tools:
get_pending_scope_questions,get_scope_question_detail,answer_scope_question,trigger_scope_generation,trigger_scope_review,get_scope_review_results - ExecutionScope for thread-safe parallel agent execution
0.9.7 - 2026-03-25
Fixed
- Aligned CLI control status validation with the platform status enum set used by that release
- Aligned MCP control status validation with the live platform status enum set to match public API behavior
- Synced package version metadata and release notes so PyPI builds publish a consistent CLI version
Changed
- Updated CLI and MCP coverage tests to reflect the platform control status contract used by public control workflows
0.8.7 - 2026-03-23
Added
- MCP questionnaire tooling for scope and organization policy workflows
Changed
- MCP documentation now reflects the full 29-tool surface, including batch evidence support
0.8.6 - 2026-03-23
Added
pretorin context show --quietfor compact shell-friendly context checkspretorin context show --checkto fail fast when stored scope is missing, stale, or unverified
Changed
context showcaches the last known system name so offline and stale context output stays human-friendly
Fixed
context showvalidates stored context against the platform instead of silently treating deleted systems as active
0.8.5 - 2026-03-23
Fixed
- Reset active system/framework context when logging into a different API endpoint or with a different API key
- Model API base URL now follows the configured platform public API endpoint during login
scope populate --json --applyandpolicy populate --json --applynow persist questionnaire updates- Larger Codex subprocess line buffer for policy questionnaire responses
0.8.0 - 2026-03-07
Added
- MCP
generate_control_artifactsfor read-only AI drafting of control narratives and evidence-gap assessments - Shared AI drafting workflow helper for structured MCP/CLI parity
Changed
- MCP system-scoped tools now resolve friendly system names the same way the CLI does
- Codex Desktop MCP configuration can be pinned to the UV-managed Pretorin wrapper
0.7.0 - 2026-03-07
Fixed
- Control implementation parsing tolerant of
notes: nulldeployments - Compatibility fallback for control note reads when
/notesendpoint returns405 - Compatibility fallback for evidence search on system-scoped evidence routes
- Agent
--no-streamcrash on literal[[PRETORIN_TODO]]blocks
Changed
- MCP and legacy agent evidence search tools accept optional
system_idcontext
0.6.1 - 2026-03-05
Fixed
- Added required MCP registry ownership marker for PyPI validation
0.6.0 - 2026-03-05
Added
- Shared markdown quality validator for auditor-readable artifacts
- Dedicated tests for markdown quality guardrails
- CLI/MCP/agent parity for reading notes via dedicated endpoint
Changed
- Narrative and evidence update flows enforce markdown quality checks before push/upsert
- Agent prompts require auditor-ready markdown (lists/tables/code/links)
- Source tagging normalized to
cliacross write paths
Removed
- Markdown image usage from narrative/evidence authoring contract (temporarily)
0.5.4 - 2026-03-05
Added
pretorin narrative getto read current control narrativespretorin notes listandpretorin notes addfor control-note managementpretorin evidence searchfor platform evidence visibilitypretorin evidence upsertfor find-or-create evidence with control linking- Shared compliance workflow helpers (system resolution, evidence dedupe/upsert, TODO blocks, gap notes)
- MCP
get_control_notestool
Changed
create_evidencenow upserts by default (dedupe: true)pretorin evidence pushuses find-or-create upsert logic- Agent skill prompts include no-hallucination guidance and gap note format
Removed
- Automatic control status updates from CLI evidence push workflow
0.5.3 - 2026-03-02
Fixed
- CI lint failure formatting
- CLI model key precedence:
OPENAI_API_KEY→config.api_key→config.openai_api_key
0.5.2 - 2026-02-27
Fixed
- Rich markup
MarkupErrorcrash in login flow - Evidence type mismatch (
documentation→policy_document) - CMMC control ID casing preserved (no longer incorrectly lowercased)
monitoring pushchecks active context before requiring--systempretorin loginskips prompt when already authenticated- Demo script
--jsonflag position and stdin handling
Changed
- Default evidence type changed to
policy_document - Valid evidence types aligned with API
- Added
.pretorin/andevidence/to.gitignore
0.5.0 - 2026-02-27
Added
- Context management (
context list/set/show/clear) - Evidence commands (
evidence create/list/push/search/upsert) - Narrative push (
narrative push) - Monitoring events (
monitoring push) - Codex agent runtime (
agent runwith skills,agent doctor/install/version/skills) - Agent MCP management (
agent mcp-list/mcp-add/mcp-remove) - Code review (
review run/status) - 14 new MCP tools for system, evidence, narrative, monitoring, notes, and control operations
- Control ID normalization (zero-padding)
- Interactive demo walkthrough script
- Beta messaging across CLI, MCP, and README
Changed
- Platform API base URL changed to
/api/v1/public - Evidence and linking scoped to system
update_control_status()changed from PATCH to POST
Removed
pretorin narrative generate— usepretorin agent run --skill narrative-generationpretorin_generate_narrativeMCP tool
Security
- MCP mutation handler parameter validation
- Client-side enum validation
- Path traversal protection in evidence writer
- TOML injection prevention in Codex config writer
- Connection error URL display
0.2.0 - 2026-02-06
Added
--jsonflag for machine-readable outputpretorin frameworks family/metadata/submit-artifactcommands- Full AI Guidance rendering on control detail view
.mcp.jsonfor Claude Code auto-discovery- Usage examples in command docstrings
Changed
- Control references shown by default (replaced
--referenceswith--brief) - Default controls limit changed to 0 (show all)
0.1.0 - 2025-02-03
Added
- Initial public release
- CLI commands for browsing compliance frameworks
- Authentication commands (login, logout, whoami)
- Configuration management
- MCP server with 7 tools and analysis resources
- Self-update functionality
- Rich terminal output with Rome-bot mascot
- Docker support
- GitHub Actions CI/CD
- Integration test suite
Supported Frameworks
- NIST SP 800-53 Rev 5
- NIST SP 800-171 Rev 2/3
- FedRAMP (Low, Moderate, High)
- CMMC Level 1, 2, and 3