Campaigns
pretorin campaign and the seven normal-profile Campaign MCP tools run bounded
compliance work through one shared coordinator. A Campaign is a local parent
Plan; every independently executable
item has a deterministic local child Plan. Embedded Hatchet dispatches those
children, and an isolated Codex process executes each one through the existing
Pretorin MCP tools.
Evidence, mappings, narratives, objective results, Issues, review jobs, and human decisions remain authoritative on the Pretorin platform. Campaign state contains operational identifiers and receipts, not copies of that compliance content. There is no platform Campaign model or Campaign-specific LLM.
First run
Configure Codex, verify its runtime, then start a Campaign. Recipe activation is optional for the baseline best-effort pass, but required before an unattended child may execute a particular recipe:
pretorin agent configure --runtime auto
# Inspect Python dependencies and native runtime support without changing them.
pretorin campaign doctor
# Resolve or install only the managed native components.
pretorin campaign install
# Optional: customize the nonempty recipe set that work preflight will preserve.
# Use the canonical system UUID returned by `pretorin --json context list`.
pretorin recipe activate \
code-evidence-capture workspace-capture preflight-source-capture \
evidence-narrative-compose issue-create \
--system <system-uuid> --framework cmmc-l1
pretorin campaign start initial-pass \
--system <system-uuid> \
--framework cmmc-l1 \
--all-controls
Ordinary preflight verify preserves an already-provisioned active recipe
set. Initial/interim control Campaign preparation additionally ensures the
trusted built-in preflight-source-capture recipe is pinned in the frozen
Campaign snapshot. When a nonempty canonical recipe set omits it, preparation
adds the trusted pin to that snapshot only; it does not rewrite the canonical
preflight. A deliberately empty recipe set, a drifted pin, or a project/user
shadow blocks preparation and requires explicit review and activation before a
new preview. A child cannot activate or repin the recipe after launch. Its pin
permits a capture context, not an evidence claim: verify the actual returned
record and each new artifact’s persisted provenance and exact control/objective
links.
agent configure saves the Codex runtime, model, provider, and reasoning
settings used by both interactive runs and newly prepared Campaigns:
pretorin agent configure \
--runtime auto \
--model gpt-5.6-terra \
--reasoning-effort low
campaign start accepts --model, --model-provider, and
--reasoning-effort low|medium|high. A Campaign inherits Pretorin’s configured
model when no model override is given. Explicit model and reasoning options
override the saved values. When reasoning effort is unset, the provider and
Codex defaults remain in effect.
campaign start checks local execution dependencies and runtime support before
authentication, platform reads, source preflight, or Plan persistence. It then
validates authentication and scope; runs the same ordinary preflight used by
interactive agent tasks exactly once; freezes its resolver verdicts and
first-party recipe pins with the roster; creates or strictly reconciles the
parent plus one deterministic child identity per assignment; displays the
roster, expected writes, and review policy; and asks for one confirmation.
After confirmation it resolves or installs deferred native components,
rechecks execution dependencies, dispatches the work, and opens the read-only
observer. Use --yes for a non-interactive confirmation or --detach to
return after dispatch.
When a scope has never been provisioned, work preflight seeds all runnable
official recipes through the existing provisioning engine. Existing explicit
pins are preserved. An unattended Campaign worker may execute only recipes whose
source, version, and complete executable content hash are pinned for the exact
system/framework. Children never honor later project or user recipe shadowing and
cannot use force to bypass a missing or drifted pin. Each attempt receives a
private, read-only copy of the same frozen preflight artifact; retries do not
rediscover sources, refresh resolver status, or change recipe pins.
If a frozen pin is missing or drifted, review and re-activate the package recipe,
then start a new Campaign; re-activation cannot rewrite an existing snapshot.
Filesystem recipe inputs are confined to the frozen project root. InSpec scans
default to local; a remote target is accepted only when that exact target was
frozen into the assignment by a trusted caller.
Campaign preflight reports host readiness and a worker_availability
projection that mirrors each kind’s and resolver’s verdict in the exact frozen
child snapshot. snapshot_matches_assignment and a zero
source_access_difference_count establish verdict parity only: they do
not guarantee that the child can execute a reader, acquire a record, or
satisfy an assessment objective. Separate worker_*_query_kind_count fields
report bounded Pretorin MCP read paths (including exact fixed-query grants for Azure
and GitHub/Kubernetes), not returned records. Pretorin feature reads appear in
worker_platform_candidate_query_kind_count because the generic feature
probe has not tested the exact record endpoint. The separate
worker_azure_detail_query_binding_count and
worker_provider_detail_query_binding_count fields count only fresh,
versioned exact-record grants, not ordinary first-page list grants. Pinned source-recipe and
capture-recipe counts are candidates until a relevant read and persisted
evidence write succeed. Platform evidence search, including reusable
unattached evidence, is separate from live source access. The preview names
connected kinds without a bounded MCP record path before launch. Campaign
children retain ordinary Codex native tools and can also use the
assignment-bounded Pretorin MCP readers or explicitly configured external MCP
servers. Native and external-MCP reads do not receive Pretorin source-read
receipts; the preview reports routes and configuration, not that a record was
read through any path. A ready or
attested host binding alone proves none of these downstream outcomes.
For an acceptance run that depends on specific source kinds, pass the opt-in
--require-source-kinds gate with a comma-separated list. The preview reports
each selected kind’s frozen preflight status. start requires every selected
kind to be exactly ready; degraded, missing, unverified, and unmapped
block dispatch. New gated Campaigns also require a bounded typed child path for
every connected binding in each selected kind and for every assigned child;
a host probe, generic feature candidate, live recipe, or a path available to
another child does not pass this gate. A missing binding path or snapshot
mismatch blocks dispatch, and rosters above the 64-child verification bound
fail as unverified. The strict source policy and
kind list are both part of the confirmation-bound Campaign definition, and
launch rechecks the same frozen snapshot without refreshing source access.
Historical gated Campaigns retain their frozen minimum-per-kind policy. Neither
policy proves that a relevant record was returned or that evidence was created.
For an exact policy binding that is not mapped to a child control, metadata-only
discovery can safely account for that binding without exposing its content, but
it does not satisfy the child’s minimum readable-source path for the kind.
Each worker attempt starts the exact finalized Pretorin MCP transport before
starting Codex and attests the complete tool
catalog, paginated frozen grant identities, snapshot digest, and frozen
source-key forwarding. This check is metadata-only: it performs no source
content read and creates no source-read receipt. Any mismatch blocks that child
model process.
Omitting the option keeps the ordinary best-effort assessment behavior. For
example:
pretorin campaign start initial-pass \
--system <system-uuid> --framework cmmc-l1 \
--controls AC.L1-3.1.20,IA.L1-3.5.2,PE.L1-3.10.1 \
--require-source-kinds cloud_control_plane,physical_access_system \
--dry-run
An existing stored EvidenceItem PDF may be explicitly offered as a source
read for one selected control with repeatable
--source-evidence-grant CONTROL_ID=EVIDENCE_ID. Preview verifies the same
system, extractable first-page PDF text in a bounded probe, checksum, and
valid grounding status,
then freezes the ID only into that child’s scope. Preview and status show the
grant count and bounded IDs separately from preflight source readiness. A
grant permits inspection; it does not link the artifact to an objective or
prove an operating control. A vendor document ID is not automatically an
EvidenceItem ID, and an unextractable or pending PDF fails the grant check.
The child can use ordinary read-only platform MCP tools under its API credential across systems, controls, and Campaign types. Its assigned item still defines where Plan records, recipes, and compliance writes may be made.
An assigned child can use bounded Pretorin MCP readers for verified workspace
paths, exact Azure and GitHub source queries, explicitly scoped Kubernetes
queries, mapped policy sections, eligible Pretorin-feature records, and
control-linked or explicitly granted artifact content. The child chooses a
frozen binding/query ID, not arbitrary commands or URLs. A Kubernetes host
probe alone grants no namespace or cluster-wide read; those scopes must be
explicitly frozen and verified. A policy section read additionally requires
the exact verified policy ID/template binding, an explicit frozen
policy_control_mappings entry for the assigned framework/control, and the
same mapping on the live policy; example_controls alone grants nothing.
Policy text is not physical operating proof. The readers return locators, capture times,
versions/hashes, redacted content, and whether a response is usable for
grounding. Provider collections with a 26th GitHub sentinel, Kubernetes
continuation, or more than 25 records are incomplete and not grounding-usable;
an exact unique first-page record ID can return a row-specific receipt without
claiming the collection is complete. GitHub issues are bound to the frozen
repository; their first page is a metadata-only index. A fresh preflight can
separately probe and freeze github_issue_detail_v1, which lets a child read
an exact positive numeric issue beyond the first page from that same repository
without a list call. Older list-only snapshots remain first-page-only. The
selected issue needs a substantive, bounded, redacted body and matching frozen
issue URL before it is grounding-usable; a credential-only body cannot ground
evidence. A concrete usable reader response carries a CLI-issued
source_read_receipt_id bound to the child attempt, frozen snapshot, and
returned content. It also projects a copy-ready create_evidence_fields block
containing the exact receipt, source URI, locator, version, capture time,
bounded excerpt, copy-ready artifact body containing that excerpt, and capture
method; copy those fields unchanged into create_evidence. A connected probe,
listing, index, empty result, or incomplete response withholds that block and
does not establish an assessment
objective or authorize a new evidence claim. preflight-source-capture
provides a pinned context for a specific returned record. The server still
validates the receipt, exact excerpt, and artifact body and fills the read’s
provenance before persisting; paraphrased or changed fields fail closed. The
child must still link the artifact to the exact control and supported objective
through ordinary Plan-scoped tools. This local receipt attributes a Pretorin
reader result to a write; it is not an operating-system tamper boundary and
does not judge objective relevance. Reads through an external MCP server do not
yield this Pretorin receipt and require independently truthful provenance.
Review partial and unavailable kinds before confirming a Campaign that depends
on them.
The confirmation authorizes only the Plan-scoped draft writes declared by the Campaign. It never authorizes control approval, risk acceptance, destructive evidence operations, or a human review decision.
That boundary is enforced on Pretorin’s platform-writing surfaces. The assigned
Pretorin MCP catalog and dispatch gate omit objective and control approval
tools. The child itself is an ordinary Codex workspace session: project
instructions, native shell tools, writable workspace access, source environment,
and configured MCP servers remain available. Those native and external MCP
actions are outside Pretorin’s typed source-receipt accounting, so review both
~/.pretorin/mcp.json and project .pretorin-mcp.json before an acceptance run
and configure only servers whose authority is intended.
Use --dry-run to resolve and display the complete draft Plan without installing
runtimes, activating or dispatching agents, or writing platform artifacts:
pretorin campaign start initial-pass \
--system "Sentinel Shield JWIP" \
--framework cmmc-l1 \
--family AC \
--dry-run
For machine-readable output, use the root --json option.
Local CMMC demo
The CMMC demo is the normal Campaign workflow, not a second orchestration
script. Seed the platform demo data, then run the CLI from the clean root of the
local Sentinel Shield clone. The directory in which campaign start runs is
frozen as the parent and child Plan workspace.
DEMOS='cmmc' make -C /path/to/monorepo demo-up
cd /path/to/sentinel-shield-platform
pretorin campaign start initial-pass \
--system "Sentinel Shield JWIP" \
--framework cmmc-l1 \
--controls AC.L1-3.1.1,IA.L1-3.5.2 \
--model gpt-5.6-terra \
--reasoning-effort low \
--yes --detach
pretorin campaign watch <campaign-plan-id>
That two-control scope is the inexpensive workflow smoke test. Replace
--controls with --all-controls for the complete 17-control / 59-objective
run used by the larger CMMC Level 1 demo. Use --dry-run to inspect the frozen
Plan without launching a model or writing platform artifacts. Omitting the
explicit model and reasoning options uses the shared Codex configuration.
Campaign types
CLI names use hyphens; persisted Plan values use underscores.
| CLI type | Stored value | Purpose | Selectors | Platform review |
|---|---|---|---|---|
initial-pass | initial_pass | First best-effort assessment of controls | all controls, family, explicit controls | Not requested unless --review is passed |
interim-pass | interim_pass | Revisit selected controls or review findings | all controls, family, explicit controls, open Issues, review job | Not requested unless --review is passed |
issue-triage | issue_triage | Reconcile existing open Issues and their next actions | open Issues, with optional source/control/family filters | No automatic review request |
evidence-review | evidence_review | Review selected evidence or control evidence coverage | evidence IDs, all controls, family, explicit controls | No automatic review request |
The primary control selectors are mutually exclusive:
# Entire framework
pretorin campaign start initial-pass --system "My System" \
--framework cmmc-l1 --all-controls
# One family
pretorin campaign start initial-pass --system "My System" \
--framework cmmc-l1 --family AC
# Explicit controls
pretorin campaign start interim-pass --system "My System" \
--framework cmmc-l1 --controls AC.L1-3.1.1,IA.L1-3.5.2
# All currently open Issues
pretorin campaign start issue-triage --system "My System" \
--framework cmmc-l1 --all-open-issues
initial, issues-fix, notes-fix, and review-fix remain compatibility
aliases through the 0.29.x release line and will not be removed before 0.30.0.
New scripts should use the four names in the table. initial uses the normal
control selectors; issues-fix and notes-fix require --all-open-issues;
review-fix requires a pinned --review-job and maps to interim-pass.
Lifecycle commands
The Campaign Plan ID printed by start is the durable re-entry handle:
pretorin campaign list
pretorin campaign show <campaign-plan-id>
pretorin campaign status <campaign-plan-id>
pretorin campaign watch <campaign-plan-id>
pretorin campaign resume <campaign-plan-id>
pretorin campaign cancel <campaign-plan-id>
show returns the frozen definition and bounded execution projection. status
reports the locally persisted execution, assessment, child-Plan
evidence-requirement coverage, and last-recorded platform review aggregates; it
does not query the platform. Covered and uncovered counts refer to the active
evidence requirements captured by each child’s server-verified, top-level Plan
completion outcome.
Intentionally unbound evidence is a separate artifact count, and none of these
values imply objective or control approval. Partial aggregates are labeled as
known requirements rather than full-Campaign coverage. Pending or unavailable
mapping outcomes remain explicit instead of appearing as zero requirements;
legacy mapping records without the current authority-verification marker are
also reported as unavailable rather than trusted. watch labels child Plans
not yet loaded in its bounded refresh as loading. watch opens
the full-screen observer and periodically refreshes locally recorded
queued/running review job IDs from the platform. That live review state is a
read-only overlay and is not written back into the Campaign record.
The bounded tool_activity projection counts retained child Plan MCP
signals and may omit calls after Plan compaction. Native Codex activity is not
retained in this projection and does not identify a source kind or prove that a
relevant record was read, evidence was persisted, or an objective was
satisfied. Inspect the evidence and Plan outcomes for those claims.
resume first reconciles and adopts any persisted non-terminal Hatchet runs,
then submits work only for children without a live run. Explicitly resuming a
completed_with_errors Campaign reopens failed items and their failed Plans
only; successful children and their process records remain intact.
cancel durably requests cancellation. A live worker forwards the request to
Hatchet and records the terminal state after outstanding runs stop; orphan
recovery may acknowledge it locally. The command can therefore return before
the Campaign is terminal. It never undoes platform writes that already
committed; use status or watch to observe completion.
status, watch, and resume may omit the ID when exactly one resumable
Campaign exists for the current Git workspace, including when the command runs
from a nested directory. Resumable means queued,
running, or finalizing work, plus a completed_with_errors Campaign whose failed
items still have retry capacity. If several are resumable, Pretorin prints their
IDs and refuses to guess. Completed and cancelled Campaigns require an explicit
ID even for status or watch.
Press q in the observer to detach safely. Detaching never cancels work. Attach
again later with campaign watch <campaign-plan-id>.
MCP parity and TUI handoff
MCP is a second adapter over the same lifecycle, not a separate Campaign
implementation. Equivalent normalized inputs through CLI dry-run or
preview_campaign produce the same v2 Campaign definition, ordered roster,
shared-preflight digest, authorized effects, parent Plan, deterministic child
identities and assignments, and confirmation digest. CLI and MCP then reuse the same activation,
supervisor, resume, cancellation, projection, and error semantics. An MCP-created
Campaign is fully manageable through CLI and a CLI-created draft can be
confirmed through MCP.
The MCP flow is explicitly readiness, preview, then confirm:
- Call
check_campaign_runtime. This read-only inspection makes no platform calls, downloads, installations, idempotency reservations, Campaigns, or Plans. Iflaunch_ready=false, stop and present its structured blocker and remediation. After repair, restart the MCP server and check again. - Only when
launch_ready=true, callpreview_campaignwith a unique 1–200-characteridempotency_key, canonical underscore Campaign type, exact system/framework, and nestedselector. It performs the one shared source preflight, freezes the draft, and returns its Campaign Plan ID, digest, effects, aggregates, and first bounded item page without activation or dispatch. - Present those effects to the user. Only after explicit confirmation call
start_campaignwith the exact Campaign Plan ID, returned digest, andconfirmed=true. It rechecks execution dependencies, never rebuilds the roster or reruns preflight, and returns after ensuring the detached supervisor. - Poll
get_campaign, or run the observer command returned in the response. Useresume_campaignorcancel_campaignwith that exact Plan ID when needed.list_campaignsuses stable cursor pagination for discovery.
The preview idempotency key is stored only in an MCP reservation sidecar. It
does not affect Campaign/Plan identity or the confirmation digest. Retrying the
same normalized preview after its preparation is durably staged returns the
existing Campaign without a second platform/preflight pass; changing inputs
under the same key returns campaign_idempotency_conflict. If the host fails
during the initial external reads before local staging, those read/preflight
calls can repeat on recovery, but the reservation reuses the same Campaign ID
and cannot create a duplicate Campaign. Closing that cross-system crash window
requires upstream transactional/idempotent preparation support.
Every MCP response about one Campaign includes informational observer data:
{
"observer": {
"mode": "same_host_cli",
"command": "pretorin campaign watch <campaign-plan-id>",
"uvx_command": "uvx --from \"pretorin==0.29.22\" pretorin campaign watch <campaign-plan-id>",
"poll_tool": "get_campaign",
"same_host_required": true
}
}
MCP returns those strings but never launches a terminal. Run the ordinary
command when the standard CLI is installed, or use the version-matched base
package uvx alternative for an isolated observer. The terminal must be on
the MCP server’s host: execution and persistence are local-host durable, not a
remote streaming TUI.
get_campaign pages immutable item order with offset/limit (10 by default,
20 maximum). list_campaigns pages stable (created_at, Campaign Plan ID)
order with an opaque cursor (20 by default, 50 maximum). Both can return fewer
rows to remain under the internal 32 KiB response budget. Projections contain
bounded labels/scope, safe identifiers, counts, state, result codes,
timestamps, durability, and separate execution/assessment/verified-coverage/
review axes. Each returned item also summarizes retained child Plan MCP calls,
recent tool outcomes, errors, denials, and safe artifact IDs by attempt; the
top-level tool count covers only the returned page. Plan signals may be compacted
and do not include native Codex steps, token usage, or full transcripts.
Projections omit credentials, artifact and preflight bodies, raw receipts/events/
errors, hidden reasoning, arbitrary agent output, and full Plan prose.
All seven lifecycle tools are available only in the normal MCP profile. Assigned
Campaign workers—including the legacy worker profile—cannot discover or call
them. Local get_campaign, list_campaigns, and cancel_campaign remain
available during a platform authentication or consent outage; preparation,
start, and resume require current authority. An explicit preview/list
project_dir must resolve beneath the MCP startup root or an additional root
configured in PRETORIN_MCP_ALLOWED_PROJECT_ROOTS; filesystem roots,
traversal, symlink escape, and out-of-root Git workspaces are rejected.
What a child does
Every agent attempt receives one specific work_on task. For
an initial CMMC pass, that task names one control and requires the child to
complete that control’s evidence requirements and assigned assessment
objectives. The coordinator freezes the exact system, framework, item,
objective roster, required outcomes, publication policy, safety boundary, and
replay-safe logical write identity policy. It does not prescribe how the child
performs the work.
The task text is intentionally direct: “Complete the initial pass for control
<control> in system <system> under framework <framework>, including its
evidence requirements and assigned assessment objectives.”
In its own MCP session the child calls start_task with the short task and its
scope coordinates. The trusted runtime injects Campaign and parent-Plan
bookkeeping, so the prompt does not ask the model to repeat or manage it. The
child then follows the selected MCP workflow, adds concrete actions and exact
recipe selections to its workflow-owned Plan phases, and activates the Plan.
It chooses its reads and tools; on retry it resumes that Plan and reconciles uncertain writes against
authoritative state.
Completion is outcome-based. The child must stay inside the frozen assignment,
bring evidence relationships and item outcomes to their required persisted
state, use typed Plan-scoped writers safely, publish each assigned objective’s
truthful working narrative and exact evidence roster without approving it, and
publish or verify the parent control narrative against those outcomes. New
initial/interim control Campaigns require a substantive parent narrative even
when no platform review was requested. An all-needs_input, evidence-free
child may use the server-rendered limitation-only form; a grounded parent
narrative must cite its supporting persisted evidence. Whether an existing
parent is kept or replaced is the control workflow’s decision. To keep an
accurate existing parent, the child records preserve_existing=true with an
explicit reason and empty evidence-ID list; completion rechecks the exact
content hash, but readiness remains pending human reconciliation. A conflict
the workflow can’t resolve is reported for human action.
Already-frozen Campaigns keep their original narrative contract.
The child requests platform review
only when the user passed --review. When evidence
mapping is required, complete_plan re-reads authoritative control coverage
and atomically captures the verified mapping as a top-level child Plan outcome;
the child completes its workflow-owned mapping phase but does not supply the
top-level mapping outcome. The Campaign validates
the child Plan’s terminal state, required persisted outcomes, scope, and write
safety; it does not grade an exact tool-call trajectory.
Preflight is informative, not a readiness gate. An unavailable source produces
a visible needs_input outcome and a concrete limitation. It does not fabricate
evidence or automatically create an Issue. grounded requires a persisted
platform evidence ID; gap requires an independently observed deficiency and
an authoritative exact-scope, nonterminal control_gap Issue plus either
pre-existing scoped evidence or a server-verified in-workspace path, bounded
line range, and whole-file SHA-256. Reuse an existing Issue that already
represents the deficiency; create one through the governed admission contract
only when none exists. Completion does not require the current child to have
created that Issue or produced an Issue-writer receipt. Free-form observation
prose and evidence created by the same child are not independent proof.
Evidence requests are next actions, not collected evidence.
The worker prompt contains only the specific task, scoped work_on
start_task entities, and a direction to follow the returned Pretorin
guidance. The selected workflow phases and child-authored actions and recipe
selections govern execution.
State and review
The observer deliberately keeps four axes separate:
| Axis | Values |
|---|---|
| Execution | queued, running, retrying, succeeded, failed, cancelled |
| Assessment | grounded, gap, needs input, mixed, not applicable |
| Evidence requirements | verified covered/uncovered counts from the Plan completion outcome; mapping state is mapped, pending, loading, or unavailable |
| Platform review | not requested, queued, running, succeeded, failed, awaiting human review |
An item can therefore succeed as a process while reporting needs_input, or
finish its automated review while still awaiting a human decision. Campaign
completion never approves its parent control.
The observer shows the parent/child Plan hierarchy, current step, attempts and Hatchet run IDs, objective rollups, the shared preflight context, recent retained MCP calls, artifact counts and safe IDs, and platform review identity. Its activity view is partial: native Codex actions and full transcripts are not retained there. It has no approve/apply action.
Runtime management
Campaigns share the agent subsystem’s Codex resolver and add embedded
Hatchet SDK 1.39.0 plus engine v0.105.16. The default auto policy resolves
an explicitly configured executable first, then a compatible system binary,
then a Pretorin-managed binary. Compatibility includes the maintained minimum
version and required CLI capabilities. system permits only the configured
path or compatible PATH discovery and never downloads. managed ignores
configured and PATH executables and uses only Pretorin’s managed artifact.
Save the policy with pretorin agent configure --runtime auto|system|managed.
Managed components are platform-specific, checksum-verified, and stored under
Pretorin-owned paths. Codex uses ~/.pretorin/bin/; the Hatchet sidecar uses
~/.pretorin/runtimes/hatchet/<version>/<platform>/. Installation
never invokes pip or a global npm command. The standard pretorin package
contains the exact Hatchet SDK and Textual dependencies; the former
campaign-runner extra is a compatibility-only alias. The runtime gate requires
the exact SDK pin before source preflight, idempotency reservation, Plan
persistence, or native-runtime resolution.
pretorin campaign version
pretorin campaign doctor
pretorin campaign install
version reports the Codex source, path, version, and managed status alongside
Hatchet. doctor
checks executable capability/trust, Python dependencies,
configuration isolation, and local-host durability. install resolves Codex
plus Hatchet: it reuses a compatible configured or system binary and downloads
only the managed fallback. It does not mutate the Python environment.
Preparation freezes the concrete model, optional provider label, optional
reasoning effort, Codex model endpoint, and the executable’s version, source, managed status, and
identity digest into the Campaign record. It also records the Hatchet engine/SDK
version and freezes the child workflow, expected outputs, and outcome/safety
criteria. The confirmation and observer show these coordinates. Retry, resume, and every
worker attempt reuse and revalidate them and fail closed when the exact
endpoint, source, identity, or Plan contract is unavailable or changed; changing
the saved model, reasoning effort, model URL, executable override, or
PATH does not redirect an existing Campaign.
Each attempt receives distinct temporary Codex configuration and home state while sharing verified binaries. Credentials travel only through an explicit environment allowlist and are not serialized to Codex configuration, Plan files, Campaign state, or observer events. The assigned preflight artifact is copied into that tree; canonical Plan and Campaign roots are passed explicitly rather than rediscovered from the isolated home. See Environment variables.
The model-provider credential, Pretorin platform API key, and evidence-source credentials serve different purposes. The trusted Codex process receives the selected model-provider credential and the same source environment available to an interactive workspace session, while the assigned Pretorin MCP child receives the current platform key and source variables authorized by the frozen preflight. Project instructions, native shell and workspace tools, and configured MCP servers remain available. The exact system/framework preflight artifact limits Pretorin’s readers, not native Codex access or an external server’s separately declared authority. Source values are resolved fresh on every attempt, so key rotation does not change the Campaign’s frozen runtime or copy a secret into durable state.
Automatic resolver bindings explicitly scoped to another repository are excluded from this work’s preflight view, even when both repositories use the same system/framework. Non-workspace manual and platform bindings remain available, and the other repository’s bindings remain in the canonical index for later work there.
AWS evidence sources currently support direct access/session credentials,
profiles and regions, role assumption, web identity, explicit config/credential
files, and conventional ~/.aws/config and ~/.aws/credentials files. They are
passed only when the scoped preflight artifact authorizes an AWS account or an
AWS cloud_control_plane resolver; the original-home files are converted to
explicit paths before the attempt’s isolated HOME is installed. See the
complete variable list.
Local Plans default to ~/.pretorin/plans/, bounded Campaign records to
~/.pretorin/campaigns/, preflight state to
~/.pretorin/preflight/, and per-Campaign embedded Hatchet data to
~/.pretorin/campaigns/.hatchet/<campaign-plan-id>/. These locations explain
the same-host recovery boundary. Detached supervisors discard raw process
output and retain only bounded, content-free Campaign events; platform artifact
bodies do not live there.
Retry, recovery, and idempotency
Embedded Hatchet is the only queue, concurrency, retry, backoff, cancellation, and run-ID authority. The default is four concurrent items and two retries. Pretorin does not add a second semaphore or polling queue.
A retry or same-host restart reopens the same parent Plan and deterministic child Plans. Successful children are reconciled and skipped. Platform writes use a logical identity derived from the parent Plan, child Plan, structural version, and artifact identity, so replay after a lost response returns the original resource instead of creating a duplicate. The child step is retained as execution attribution, not resource identity. Before a terminal local receipt is replayed, the typed handler revalidates the authoritative platform resource; an uncertain write remains pending or fails closed instead of trusting stale local state. Local aggregate finalization is atomic and happens once.
Execution is intentionally local-host durable. It can resume after the process restarts on the same machine, but it cannot continue while that host is off or migrate to another host. Remote execution is deferred until Plans have a shared persistence contract.
Legacy migration
The old campaign controls|policy|scope, campaign apply, and checkpoint-path
status/watch forms remain deprecated compatibility adapters through the
0.29.x release line. They will not be removed before 0.30.0. They are hidden
from primary help and print a migration warning. The checkpoint execute
adapter has been removed; deterministic mock execution is test-only and has no
CLI or MCP entry point. Use start or resume for Codex execution.
The 0.29.4 lifecycle intentionally advances Plan-backed Campaign and preparation
state to schema v2. CLI and MCP reject v0.29.3 Plan-backed records consistently
with campaign_state_version_unsupported, and listing skips and counts them;
start a new Campaign. This clean break does not remove or change the separate
deprecated checkpoint files/tools.
The child-owned Plan contract uses launch contract v2 and preparation journal schema v3. Launch-contract-v1 Campaign records remain readable for history, status, and terminal cancellation, but they cannot execute or resume because their coordinator-authored step shell and step-scoped typed-write identity are not compatible with this execution contract. Start a new Campaign instead.
| Legacy concept | Replacement |
|---|---|
| Prepare a checkpoint, then execute it | campaign start <type> |
| Checkpoint path as run identity | Campaign Plan ID |
| Local proposal queue | Existing typed MCP writers and platform state |
Generic coordinator apply | Child-owned typed writes after the one bounded authorization at start |
| Local proposal review | Existing platform review and human approval |
controls --mode initial | start initial-pass |
controls --mode issues-fix | start issue-triage |
controls --mode notes-fix | start issue-triage --all-open-issues |
controls --mode review-fix | start interim-pass --review-job ... |
Policy and scope questionnaire bulk work remains available through their domain-specific workflows and commands. Those domains are not silently mapped onto the four control/evidence Campaign types.