Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Campaign workflow

A Campaign is local orchestration around the existing Pretorin workflow, Plan, MCP, and platform surfaces. Use it when a bounded set is too large for one agent session—for example an entire control family or framework.

CLI campaign start --dry-run OR MCP check_campaign_runtime
  -> local execution-dependency gate (before external reads or local writes)
  -> for MCP, launch_ready=true -> preview_campaign
  -> ordinary Pretorin source preflight (once for the target workspace and scope)
      -> frozen resolver verdicts + shared agent source access + active recipe pins
  -> local draft parent Campaign Plan + deterministic child assignments
  -> CLI confirmation OR MCP start_campaign(plan ID + digest + confirmed=true)
      -> recheck execution dependencies
      -> embedded Hatchet dispatch
          -> one specific work_on task per item
              -> selected workflow phases + child-authored actions and recipes
              -> read-only preflight snapshot + the interactive agent's source access + pinned recipes
              -> existing typed MCP platform writes
              -> existing platform review only when explicitly configured
      -> deterministic local aggregate + platform review handoff

check_campaign_runtime reports execution and observer dependencies, selected agent and embedded Hatchet runtimes, blocking failures, and native setup that may be deferred until confirmed start. It never contacts the platform, downloads or installs software, reserves an idempotency key, or writes a Plan. For a configured or PATH agent executable, the check freezes its resolved path and content identity without launching it; version and capability validation are reported separately as deferred_validation and occur only after explicit start confirmation. When it returns launch_ready=false, stop. Apply its remediation outside MCP, restart the server, and check again before preview.

Pretorin does not run a Campaign-specific LLM. Each isolated child session uses the Codex or OpenCode harness selected through the shared agent configuration. Recipes and workflows are markdown playbooks that agent reads; they are not server-side runtimes.

Authority boundaries

The shared transport-neutral coordinator creates the local parent Plan and freezes Campaign type, selector, ordered item/objective roster, harness/model/provider/reasoning effort, the Codex model endpoint or effective OpenAI/Anthropic OpenCode provider endpoint, exact executable source, managed status, and SHA-256 identity, plus the maintained version when known, Hatchet engine/SDK version, concurrency and retry settings, publication policy, and review policy. The CLI and MCP adapters both ask the coordinator to prepare the ordinary Pretorin preflight once and freeze its resolver verdicts, active recipe pins, and content digest on the Campaign. Before dispatch the coordinator creates or strictly reconciles one deterministic child identity per item and binds its exact scope, objective roster, required outcomes, publication policy, safety boundary, and replay-safe logical write identities. It does not supply a Campaign-specific execution sequence. The selected workflow supplies semantic Plan phases; the child adds concrete actions and recipe selections, then activates the result as the stable retry contract. Bounded Campaign state tracks attempts, Hatchet correlation IDs, process facts, resource receipts, and aggregate progress.

CLI/MCP adapter fields are excluded from that semantic definition. In particular, MCP’s durable preview idempotency key lives only in a sidecar reservation; it cannot change Campaign identity, Plans, effects, or the confirmation digest. All new parent/child creation and transitions use the surface-neutral campaign-coordinator actor and v2 launch contract.

The portable reasoning-effort values are low, medium, and high. An explicit campaign start --reasoning-effort wins over the selected harness’s saved setting; if neither is present, the provider/harness default is used. Once prepared, the effective optional value is part of the frozen assignment, so retry and resume cannot follow a later configuration change. Codex consumes the setting natively. OpenCode consumes it as --variant; each attempt checks the exact authenticated model metadata first and rejects an unsupported portable variant instead of silently falling back.

The existing platform remains authoritative for evidence, mappings, narratives, objective implementations, Issues, review jobs/findings, and human approval. The local store never copies those artifact bodies and cannot approve a control. No platform Campaign API, Campaign database model, shared Plan repository, or Campaign-specific UI is required.

Execution contract

Hatchet assigns one frozen item to an isolated process for the selected harness. The worker prompt is deliberately small: it states the specific task, provides start_task entities with intent_verb="work_on" and the exact item scope, then directs the child to fetch the compact selected workflow without repeating tool schemas already registered by its MCP harness. The resulting guidance payload stays under 800 words. The trusted runtime injects the parent Plan and Campaign context before profile validation; those bookkeeping fields are not instructions the child must reproduce.

The selected MCP workflow defines domain guidance and the semantic Plan phase order. The child owns concrete actions within those phases, reads, tools, and recipe choices, then advances that Plan and publishes through existing typed Plan-scoped writers. Every selected recipe must earn its exact lifecycle receipt before its step can complete; no minimum artifact count is imposed. A pass requires an observed recipe script or producer write, while an unavailable action can end needs_input without synthetic evidence. For a control pass, the required result includes an authoritative evidence mapping, one truthful disposition and working narrative for every frozen assessment objective, and any explicitly authorized review handoff. The worker may approve a grounded assessment-objective leaf after the Campaign publication and evidence gates pass; it never grants parent-control approval. The child uses ordinary evidence tools to establish the relationships; at complete_plan, the server re-reads authoritative coverage and atomically stores the verified mapping as a top-level Plan outcome. The workflow mapping phase remains named and ordered, but the Campaign does not trust a child-supplied mapping payload.

Campaign completion validates the frozen scope, terminal child Plan, required persisted outcomes, idempotent/reconciled writes, and publication policy. It does not require a coordinator-authored milestone shell or compare the run to a prescribed MCP method. This keeps retry and audit guarantees without turning the Campaign into a second workflow engine.

The worker MCP profile exposes ordinary platform reads across Campaign types and scopes under the platform credential’s authorization, including reusable evidence search. It validates the current attempt and keeps child Plan, recipe execution, Campaign process records, and typed writes bound to the assignment. Campaign-only Issue and evidence inspectors still address the assigned item. It withholds Campaign finalization, generic proposal/apply, destructive evidence operations, and human approval. Workflow-owned completion criteria remain authoritative, while the child authors the Plan that satisfies them. The selected harness receives one ephemeral home/config, the assigned Pretorin MCP server only, a read-only workspace, and no edit/write, web, or delegated-task tools. OpenCode denies its native shell; Codex permits sandboxed read-only commands whose environment excludes all model, platform, and source credentials.

Model-provider credentials, the Pretorin platform key, and evidence-source credentials are separate trust domains. Source values are resolved fresh for the exact system/framework attempt only when its authoritative preflight artifact authorizes that source; credential values are not copied into Plans, Campaign records, harness config, or observer events.

Preflight is one shared input to the work, not a per-child Campaign phase. The coordinator prepares it through the same implementation used before an interactive agent task. Each child and retry receives a private read-only copy; it cannot verify, refresh, mutate, reprovision, or record preflight again. Campaign preview and the child’s get_preflight distinguish host readiness from worker acquisition for each source kind. The child’s native read tools can inspect machine-verified frozen workspace bindings inside the project root. Native reads do not redact content or establish evidence provenance by themselves. Host CLI probes and platform feature bindings are not implicitly available to the child; a pinned source recipe is a candidate until its exact resolver coverage is known. Platform evidence search is a separate path. These availability verdicts inform the best-effort assessment but do not act as an objective readiness gate. An operator may separately request a launch gate for named source kinds (--require-source-kinds in CLI or required_source_kinds in MCP preview). Each named kind must be ready in the frozen preflight; a blocked gate prevents launch and calls for a new preview after access is restored. This launch gate still does not prove that an objective has qualifying evidence. Recipe IDs must be trusted package built-ins, and a selected recipe must match the exact active content pin. No source is a valid process condition. The child uses normal MCP guidance to decide which available pinned recipes fit the assignment; the coordinator does not mandate a particular fallback. An attempt may truthfully produce no evidence, and no runnable source remains a valid specific limitation:

  • grounded requires persisted platform evidence;
  • gap requires an authoritative exact-scope, nonterminal control_gap Issue plus either pre-existing scoped evidence or a server-verified workspace path, bounded line range, and whole-file SHA-256; free-form observation prose is insufficient. An existing Issue that already represents the deficiency is reused, and no same-child Issue-writer receipt is required;
  • needs_input requires a coverage limitation or evidence request and is not itself an execution failure; and
  • an evidence request remains a next action, never an evidence artifact.

Durability and replay

Embedded Hatchet owns dispatch, per-Campaign concurrency, retry/backoff, cancellation, and run IDs. Local code does not add another queue or concurrency limiter. Duplicate delivery of a succeeded item returns its saved state without starting an agent.

Parent and child Plan IDs are the recovery identities. Retry and restart reuse the same deterministic child Plan. Resume adopts a persisted non-terminal Hatchet run when one exists and submits only work without a live run; an explicit resume from completed_with_errors reopens failed children only. The frozen harness/model and exact runtime source/version/identity are revalidated on each attempt, so configuration or PATH changes cannot redirect an existing Campaign. The preflight snapshot is reused verbatim across retry and restart; later canonical preflight changes apply only to newly prepared work. Resume authenticates the frozen Campaign and complete parent/child Plan hierarchy before it reopens Plans, reconciles orphan attempts, installs a runtime, or dispatches anything. Logical platform-write identities make a committed response loss replay-safe, and local finalization is atomic and exactly once. A cancellation command first persists the request; a live worker may acknowledge the terminal state only after Hatchet stops outstanding runs. Recovery is supported on the same host; multi-host execution is deferred until Plans are shared.

An OpenCode process that exits successfully with an active child Plan gets one same-session continuation inside its current attempt. The continuation reads the Plan and addresses unfinished steps; it must still complete the Plan under the normal server gates. A failed or incomplete continuation fails that attempt and does not add an implicit Hatchet retry.

Campaign state remains on schema v2, while new preparation journals use schema v3 and new Campaigns use launch contract v2. Launch contract v2 is a deliberate execution clean break from coordinator-authored child step shells and step-scoped typed-write identities: launch-contract-v1 Campaigns remain readable history (including status and terminal cancellation) but cannot be resumed. Start a new Campaign to use the child-owned Plan contract. State schema v2 freezes resolved system/framework IDs, coordinator and launch-contract versions, roster, hierarchy, template and effect-policy hashes, exact authorized effects, the launch-definition SHA-256, and durable confirmation time. CLI and MCP reject v0.29.3 Plan-backed state with campaign_state_version_unsupported; listing skips and counts it. This does not affect the separate deprecated checkpoint records and compatibility tools.

Observe and hand off

campaign status <campaign-plan-id> reports persisted execution, assessment, evidence-requirement coverage from each child Plan’s server-verified completion outcome, and last-recorded review aggregates without querying the platform. Coverage reports active requirements as covered or uncovered and counts intentionally unbound evidence separately; it never implies objective or control approval. Partial aggregates are labeled as known coverage. Pending, loading, or unavailable mappings are explicit instead of appearing as zero requirements. Legacy mapping records without the current authority-verification marker remain readable, but their coverage is reported as unavailable rather than trusted. campaign watch <campaign-plan-id> is a read-only projection that additionally refreshes recorded queued/running review jobs and overlays their live state without mutating the Campaign record. It keeps execution, assessment, evidence-requirement coverage, and review separate while showing Plan steps, attempt and Hatchet IDs, recent retained MCP calls, objective-disposition progress, shared preflight context, recipes, safe resource IDs, and platform review identity. Press q to detach without cancellation.

The tool_activity observer field uses retained child Plan MCP signals. A separate OpenCode attempt summary records only terminal native file, shell, and web tool outcomes by category; it does not include commands, paths, arguments, outputs, or model text. These native outcomes are diagnostic, can never establish which source record was read, and do not count as persisted evidence or objective proof.

get_campaign returns the same persisted projection in an MCP-safe bounded form: immutable item pages default to 10 and cap at 20; Campaign-list pages default to 20 and cap at 50. Its execution, assessment, verified-coverage, and review fields match the overlapping CLI fields exactly. Local get/list/cancel continue to work during a platform auth or consent outage; preview/start/resume still require current platform and frozen-authority validation.

Every MCP response for one Campaign includes the exact same-host watch command and a version-matched registry fallback:

pretorin campaign watch <campaign-plan-id>
uvx --from "pretorin==0.29.18" pretorin campaign watch <campaign-plan-id>

The MCP server never runs these strings or streams a terminal over JSON-RPC. The operator launches one on the MCP server’s host; q safely detaches.

After automated work finishes, continue review in the existing Pretorin control and review experience. A completed Campaign says that its declared process ran; it does not say a human approved the controls.

See Campaign CLI for commands, runtime management, and the legacy checkpoint migration.