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.