Preflight
Preflight is how Pretorin verifies that the host is connected to the sources a framework needs before evidence work begins. The platform recommends canonical source kinds per framework, but it cannot verify whether any of them are reachable from where you are working — only the CLI host can. Preflight is that CLI-local verification layer, and its verdict is the single source of truth for source availability (it replaces the platform connection registry).
The model
A recommended source kind (e.g. code_repository, cloud_control_plane)
maps to a collection of resolvers, not a single one. Each resolver is a
concrete, host-local way to reach part of the evidence story:
Resolver type | Verifies | Example params |
|---|---|---|
workspace_path | a path (and optional marker) exists | {path: /infra, marker: "*.tf"} |
cli_tool | a CLI is present/authenticated | {name: gh, probe: "gh auth status"} |
command | a generic probe exits 0 | {probe: "curl -fsS https://host/health"} |
manual / attested | nothing — user-asserted | {identity: "SOC2-2026-Q1"} |
mcp / connected_api / pretorin_feature | a declared probe, else unverified | {probe: "..."} |
Resolver type and params are open — custom types work, and an unknown
type with a declared probe is simply run (the registry fails open). A resolver
may also declare capabilities, matched against a recipe’s
requires.sources[].capabilities so the executor requires only the resolver(s)
a recipe touches.
Status vocabulary
Each resolver verifies to one of: connected (machine-verified), degraded
(reachable but stale/partial), missing (probe ran, not reachable), attested
(user-asserted, never silently “connected”), or unverified (no probe yet).
These roll up per kind:
ready— every bound resolver is up; the whole evidence story is reachable.degraded— some up, some not; partial story.missing— resolvers bound and verified, none reachable.unverified— resolvers bound but not probed yet.unmapped— a recommended kind with no resolvers bound.
A Pretorin Physical Security Policy is a policy and applicability record. It
does not supply badge logs, visitor records, door events, or facility operating
records. If an older local artifact bound that policy under
physical_access_system, Pretorin moves the binding to document_repository
with only policy_applicability capability when the mutable artifact is loaded
or saved. The former generic API-authentication verdict is cleared; a fresh
probe must read that policy’s mappings. physical_access_system remains
unmapped unless a separate operating-record source is bound and verified.
Previously frozen Campaign snapshots retain their historical bytes and are
never silently rewritten.
Two grains of availability
- Control grain — the per-kind rollup answers “is the whole evidence story present?”
- Executor grain —
start_recipeonly requires the specific resolver(s) a recipe touches (kind + optional capability), so a degraded kind never blocks a recipe that doesn’t need the down resolver.
How availability is decided
The verdict drives every availability decision:
list_recipes/ the capture plan hide recipes whose required kinds are verified missing; unmapped/unverified kinds fail open (shown asunknown— a soft “verify before capture”, never a hard “not connected”).start_reciperefuses to open a context when a required kind is verified missing, unless you passforce=true.
Commands
pretorin preflight init # bind sensible local defaults, verify by default
pretorin preflight show # read the verdict for the active scope
pretorin preflight verify # probe every bound resolver, refresh status
pretorin preflight prune # preview stale/duplicate resolver cleanup
pretorin preflight prune --apply # persist safe removals
pretorin preflight bind <kind> --type <type> [--param k=v ...] \
[--probe "<cmd>"] [--capability <cap> ...] [--recommended] \
[--constraint "<usage note>"] [--scope k=v ...] [--env-key NAME ...]
pretorin preflight init is the low-friction setup path for a fresh machine:
it canonicalizes linked Git worktrees to the primary checkout, detects common
local tools (gh, az, aws, kubectl) and local docs/policy folders, then
binds those resolvers. GitHub probes are pinned to the repository identity when
it can be derived safely, and Kubernetes probes are pinned to the discovered
context. Disposable worktree paths are not added. An explicit
source_providers configuration gates Azure, AWS, and Google Cloud host
discovery so an out-of-scope CLI on PATH does not create a binding. It skips
existing mappings unless you pass --replace, and it verifies by default
(--no-verify just writes the mappings).
pretorin preflight prune is dry-run by default. It proposes removal of
bindings tied to missing or known-ephemeral workspaces and collapses semantic
duplicates, retaining the richest constraints and freshest recorded verdict.
Use --apply to persist those safe removals and --scope <kind> to inspect
only one source kind. Provider-scope mismatches and bindings without a
currently connected result are advisory findings; prune never removes them
automatically.
--system / --framework default to the active context
(pretorin context set). The agent-facing MCP tools are get_preflight,
verify_preflight, and update_preflight.
Use repeatable --env-key NAME when a source command needs an environment
variable that is also a model-provider credential, for example
--env-key ANTHROPIC_API_KEY. Only names are saved in the preflight artifact;
values remain in the invoking host environment. A fresh, machine-verified
binding grants that key to a Campaign child even when it uses a different
model provider. Unverified or merely attested bindings cannot grant these
credentials. Pretorin Campaign authority variables cannot be granted. Run
pretorin preflight verify after binding.
--constraint records a human/agent-readable usage note on the binding.
--scope k=v (repeatable) pins a structured usage scope — for example
--scope subscription=sub-prod --scope region=westus2. Scope entries become
recipe param defaults: when a recipe declares a param with the same name,
start_recipe and pretorin recipe run fill it from the matching binding
unless the caller passes an explicit value. The applied defaults are reported
back as source_params. Scope never crosses cloud providers — a binding
identifiable as Azure (e.g. the az CLI, or an explicit --scope provider=azure) will not feed defaults into an AWS-kind recipe.
The guided workflow
For an interactive, recommendation-aware setup, run the preflight
workflow: it pulls the framework’s recommended source kinds, diffs them
against what you have mapped, walks you through binding a resolver collection
for each gap, verifies them, and reports ready / degraded / missing. The
artifact persists locally per (system, framework) under
~/.pretorin/preflight/, so later evidence work reads the verdict directly —
re-run pretorin preflight verify if it has gone stale.
Task and Campaign preparation, along with CLI and MCP updates for the same
scope, share one transaction. Concurrent preparation therefore cannot discard
another workspace binding or an explicitly activated recipe.
Over MCP, enter this workflow through the normal routing boundary:
start_task with entities.intent_verb="preflight", the active system_id
and framework_id, and the user’s verbatim prompt. Then load the returned
preflight workflow with get_workflow before calling its preflight and
recipe-discovery tools.
Do not put literal credentials in resolver probes. Secret-shaped strings in resolver params and probe results are redacted before the local artifact is persisted, but probes should rely on the host’s normal auth stores whenever possible.