Running a plan

Run

phax run --plan plan.md                         # full execution (extracts plan.md, runs every phase)
phax run my-feature --plan plan.md              # set the run short name explicitly
phax run --plan plan.md --dry-run               # preview only — zero side effects
phax run --plan plan.md --allow-dirty           # skip clean-tree guard
phax run --plan plan.md --provider-priority mistral-vibe,claude-code  # override provider priority for this run
phax run --plan plan.md --security unsafe       # override the security mode for this run
phax run --plan plan.md --allow-skill-edits     # let phases edit the .claude/skills files the plan declares

Each phase:

  1. Creates a Git worktree at ~/.phax/worktrees/<short-name>/phase-NN/ on its own branch <run.branch>--phase-NN.
  2. Runs commands.setup inside the worktree.
  3. Builds a prompt from the plan and the previous phase's handoff, sends it to the selected provider's agent (resolved by the routing layer; see Multi-provider model routing).
  4. Runs the gate profile; on failure, resumes the same agent session once and retries.
  5. After passing gates, resumes the agent to produce phase-handoff.md.
  6. Commits with the planned message. If the worktree is clean (no changes), the run stops with a non-zero exit and writes resume-instructions.md — use phax resume to continue from the next phase.
  7. Reconciles the files actually touched against the phase's planned files, writing file-reconciliation.{json,md} to the phase folder. Deviations (unplanned creates/edits, missing planned changes) are injected into the next phase's prompt so the agent sees how the prior phase diverged from its plan; with fileReconciliation.mode: "warn" they are also logged (default report_only only records them).

Each phase gets its own branch (<run.branch>--phase-01, <run.branch>--phase-02, …), chained: phase-01 branches off <run.branch>, phase-N branches off the previous phase's branch. The base <run.branch> stays at the run-start commit. The final phase's branch carries the full commit chain and is the ref to review, merge, or push.

Worktrees from every phase persist on disk for the lifetime of the run and are available for inspection until phax archive is run.

The final phase stays open for review. A review-handoff.md is written to the run folder showing the final phase branch as the review target. When the run reaches review, two optional steps run automatically if enabled in phax.json (both are non-fatal — the run stays review_open if they fail):

  1. Compliance review (review.compliance.enabled) — a non-mutating plan-compliance pass writes its verdict to the run folder, so it can land in the PR body.
  2. Publish (publish.auto) — pushes the final phase branch to the configured remote and opens (or reuses) a pull request; details are recorded in publication.json.

See Compliance review & publishing.

When phax run finishes (or is interrupted), it prints an end-of-run recap to the terminal summarizing the run state, the review target branch, any published PR URL, and the next command to run.

macOS sleep prevention — long-running phax run sessions can be wrapped with caffeinate to prevent macOS from sleeping while phax executes:

caffeinate -ims phax run --plan plan.md

Resume

phax resume <short-name>        # restart from the next pending phase
phax resume <short-name> --yes  # skip confirmation
phax resume <short-name> --yes --provider-priority codex-cli,claude-code  # override provider priority

Resume validates the run state, lock, and worktree before proceeding. It never re-runs committed phases. If the run is review_open, it refuses and points you at phax enter.

Locks

phax writes a lock file at ~/.phax/locks/<short-name>.lock for every active run. If a process dies, the lock can become stale:

phax unlock <short-name>        # remove stale lock
phax unlock <short-name> --force  # remove any lock