The 0.7.0 API is packet-first. The CLI is a convenience layer over these modules.

Packet And Profile APIs

Initialize the profile store:

{:ok, _paths} = PromptRunner.Profile.init()
{:ok, templates} = PromptRunner.Template.list()

Create and inspect profiles:

{:ok, profile} =
  PromptRunner.Profile.create("codex-fast", %{
    "provider" => "codex",
    "model" => "gpt-5.4",
    "reasoning_effort" => "high"
  })

{:ok, _same_profile} = PromptRunner.Profile.load(profile.name)
{:ok, names} = PromptRunner.Profile.list()

Create a packet and add a repo:

{:ok, packet} =
  PromptRunner.Packet.new("demo",
    root: "/tmp",
    profile: "simulated-default",
    prompt_template: "from-adr",
    provider: "simulated",
    model: "simulated-demo",
    recovery: %{
      "resume_attempts" => 2,
      "retry" => %{"max_attempts" => 3, "base_delay_ms" => 0, "max_delay_ms" => 0},
      "repair" => %{"enabled" => true, "max_attempts" => 2}
    }
  )

{:ok, packet} = PromptRunner.Packet.add_repo(packet.root, "app", "/path/to/repo", default: true)

Create a prompt file:

{:ok, _path} =
  PromptRunner.Packets.create_prompt(packet.root, %{
    "id" => "01",
    "phase" => 1,
    "name" => "Capture runtime boundaries",
    "targets" => ["app"],
    "commit" => "docs: add runtime boundaries summary"
  })

The packet's prompt_template is applied automatically. You can also override it per prompt with:

{:ok, _path} =
  PromptRunner.Packets.create_prompt(packet.root, %{
    "id" => "02",
    "phase" => 1,
    "name" => "Create execution checklist",
    "targets" => ["app"],
    "commit" => "docs: add execution checklist",
    "template" => "from-adr"
  })

Inspect packet health:

{:ok, preflight_report} = PromptRunner.preflight(packet.root)
{:ok, doctor_report} = PromptRunner.Packet.doctor(packet.root)
{:ok, preflight_report} = PromptRunner.Packet.preflight(packet.root)
{:ok, explain_report} = PromptRunner.Packet.explain(packet.root)

preflight is the runtime readiness gate that checks packet-local repo paths and git readiness before provider execution.

Planning And Running

{:ok, plan} = PromptRunner.plan(packet.root, interface: :cli)
{:ok, run} = PromptRunner.run(packet.root, interface: :cli)

Useful plan fields:

  • plan.prompts
  • plan.options
  • plan.runtime_store
  • plan.committer
  • plan.state_dir
  • plan.config

Embedded Use

API calls default to an in-memory runtime store plus a no-op committer:

{:ok, run} =
  PromptRunner.run(packet.root,
    provider: :codex,
    model: "gpt-5.4",
    runtime_store: :memory,
    committer: :noop
  )

That keeps embedded use free of surprise filesystem writes and git commits unless you opt in.

For deterministic recovery demos:

{:ok, run} =
  PromptRunner.run(packet.root,
    provider: :simulated,
    runtime_store: :memory,
    committer: :noop
  )

Repair And Status

{:ok, status} = PromptRunner.status(packet.root)
{:ok, repaired_run} = PromptRunner.repair(packet.root, prompt: "01", interface: :cli)

PromptRunner.status/1 returns the packet runtime state from .prompt_runner/state.json.

Deterministic Verification

Run verification without executing prompts:

{:ok, plan} = PromptRunner.plan(packet.root, interface: :cli)
{:ok, reports} = PromptRunner.Verifier.verify(plan)

Or verify one prompt:

prompt = Enum.find(plan.prompts, &(&1.num == "01"))
report = PromptRunner.Verifier.verify_prompt(plan, prompt)

Observer Callbacks

Supported callbacks:

  • on_event
  • on_prompt_started
  • on_prompt_completed
  • on_prompt_failed
  • on_run_completed
{:ok, run} =
  PromptRunner.run(packet.root,
    on_event: fn event -> IO.inspect(event.type) end
  )

PubSub Bridge

callback = PromptRunner.Observer.PubSub.callback(MyApp.PubSub, "prompt_runner:runs")

{:ok, run} =
  PromptRunner.run(packet.root,
    on_event: callback
  )