phax-cli
Skill2 starsChanged 5 months agoApache-2.0View on GitHub
Operate the phax CLI — its concepts, run lifecycle, and the canonical init → plan → run → review → publish flow. Use when driving phax, explaining it to a developer, or scripting against it. Defers to `phax --usage` for the exact command/flag contract.
In this repository16 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- boundariesSkill
- cli-view-layerSkill
- effect-servicesSkill
- find-docsSkill
- infrastructure-adaptersSkill
- model-routingSkill
- observabilitySkill
- phax-decide-planSkill
- phax-decide-reviewSkill
- phax-decide-specSkill
- phax-planningSkill
- phax-reviewSkill
- phax-specSkill
- state-machinesSkill
- validation-boundariesSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 188
When the operator exits, phax asks the session for the revised document, checks it, prints the body diff, and writes and commits the …
- Very specific: line 245
When unsure about any command, read its long_help and example in phax --usage.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
phax CLI skill
This skill is the map, not the territory. For the exact, version-accurate command/flag/argument contract — every command, its flags, args, examples, and help — run:
phax --usage # KDL spec, source of truth, no external dependency
phax --usage-format json # same contract as JSON (needs the `usage` CLI)--usage is generated from the CLI's own command tree, so it never drifts from
the installed binary. Don't memorize or restate flags here — read --usage.
This skill only covers what --usage can't express: the concepts, the run
lifecycle, and how commands fit together.
What phax is
A deterministic, local CLI that drives an AI coding agent (Claude Code by
default; also Mistral Vibe and OpenAI Codex) through isolated, gated phases.
Each phase runs in its own Git worktree, executes the agent, then runs a
gate profile (typecheck, tests, lint, …) with a same-session fix loop —
the agent fixes gate failures in the same context before the phase may commit.
The final phase worktree stays open for human review. phax pushes the branch and
opens a PR only when phax.json sets publish.auto, or when you run phax publish-pr.
Run lifecycle — the command you reach for depends on the state
Runs live in a local registry (~/.phax/runs/), are addressed by a
short-name (e.g. usage-cli), and move through:
created → running → review_open → archived → (prune) gone
↘ failed- created / running — phases executing. After an interruption, continue
with
resume. - failed — a phase failed and the loop stopped. Inspect with
session-info(orenter-phaseto attach to the uncommitted worktree), thenreset-phaseto clear it andresumeto re-run from there. - review_open — all phases committed; the final worktree is open and waiting
for a human. This is where you
enter/shell/opento review, optionallyreview-compliance, thenpublish-prand finallyarchive. - archived — the run folder and worktrees are moved under
~/.phax/archive, and the name stays held.phax prunedeletes the run for real and frees its name and disk space. Archived is no longer terminal: prune is the step that removes it.
Most review commands have a …-last variant that targets the most recent
review_open run, so you can drop the short-name (see --usage).
Canonical end-to-end flow
phax init # scaffold phax.json
# author plan.md → use the `phax-planning` skill for its format (status: Approved)
phax plans lint plan.md # check structure, planned files, run readiness
phax run my-feature --plan plan.md # extract plan + run every phase → review_open
phax enter my-feature # review/iterate in the kept-open agent session
phax publish-pr my-feature # push branch + open a PR (needs gh)
phax archive my-feature # finish
phax prune my-feature # optional: delete the archived run and free its namephax run extracts the plan inline; phax plans lint <plan> checks a plan's
structure, planned files and run readiness without running it. Each phase requests a
model + effort that phax resolves to a concrete provider — inspect routing
under phax agent (see --usage).
Plans that touch .claude/skills/ files need phax run --allow-skill-edits; without it
the preflight refuses (exit 11). phax resume inherits the consent, and the grant is
recorded per phase in security.json (skillEditGrants). See --usage for the flag
contract.
Inside a phase worktree — the phase guard
A phase worktree is a linked Git worktree whose root holds .phax-context/. Run from
anywhere inside one, phax refuses every command that acts on phax state or on an
artifact's lifecycle, before the command runs, and names the main checkout as the place to
run it. That covers run, resume, archive, publish-pr, review-*,
artifact approve/new/decide/…, plans status --apply, and also enter, shell and open.
What still runs inside:
phax brief [path…];phax architecture [path…];- the read-only commands:
validate,ls,path,session-info,completions,plans lint,plans overview,plans status,artifact status,artifact schema,records explain,records status,records list,security status; schema upgrade, which writes only the working tree's local schemas.
The guard has no flag or environment variable to turn it off, and it catches people too:
in phax shell or the kept-open final phase, leave the worktree to run review-compliance
or publish-pr. It is accident-proofing, not a security boundary; the sandbox's write
scope is the boundary.
Gate steps, briefs and records
These are phax.json keys (brief, architecture, assignments, …) rather than commands, so --usage does not show them. The
README (sections Gate report steps, Gate request, Brief provider, Architecture
provider, Plan auditor) holds the exact formats.
"output": "gate-report"on a gate step: the step prints a gate report on stdout, and phax reads the verdict from it, not from the exit code. A checked report carries findings (rule, location, message, related locations, and a guide file the agent reads) and review notes; any finding fails the step, and the findings are what the agent is asked to fix. Review notes fail nothing and go to the review handoff, never the agent. A refused report (reason and remedy) stops the phase with exit 4 and no fix attempt;phax resumeruns the gate again. Each readable report is saved aschecks-attempt-NN.report-SS.json."input": "gate-request"on a gate step: the step gets{$schema, phase, base, terminal, phases}on stdin, the facts it needs to decide what is due now and what a later phase is planned to bring. Each attempt's request is saved aschecks-attempt-NN.request.json;phax records explain <commit> --gatesprints it after its log.brief(commandandpush, both required): the provider answers with a brief report, the rules over some paths and the findings there with their due. It is pushed into a phase's first prompt and pulled withphax brief [path…], which prints the whole report, from inside a phase or from your own checkout.pushchooses what the first prompt lists:"findings"(the findings due in this phase) or"findings-and-rules"(those findings, then the rules over the phase's planned files). A brief never blocks; the gate still decides. Insecuremode the phase agent is grantedphax brief(sourcebriefinsecurity.json). Each brief is recorded asbrief-NN.json;phax records explain <commit> --briefsprints them.architecture(command, required): a provider that answersphax architecture [path…]with an architecture report (bodyplusparts: id, name, description, globs) that phax renders to Markdown. The command lists the assignment bounds after the parts. With none configured, it prints one line telling the agent to read the code and its documentation, followed by the bounds when they are declared, and exits 1. It writes nothing, and a headless plan session is granted it when a provider or bounds are configured.assignments(phax.json only, never the user overlay): the owner's ordered bounds, each apart(an architecture-report part id) orglobsbound with one model and an effort range. The first bound matching any file a phase plans to touch governs it; a departure needs an**Assignment reason:**.phax plans lintand the run's start preflight hold plans to the bounds (exit 11 on a refusal);phax validatechecks the bounds against the routing catalog (exit 2).planAuditor(a provider command): advisory findings forphax plans lint, never during a run.
Artifact lifecycle — specs and plans carry an enforced status
Specs (docs/specs/) and plans (docs/plans/) each carry a status key in
their YAML frontmatter block, drawn from a fixed per-kind set (specs: Draft,
Approved, Abandoned, Completed; plans add Stale). phax enforces the one
gate that matters: only an Approved plan can run — phax run refuses a
Draft, Stale, or retired (Abandoned/Completed) plan, naming the status and
the remedy, before extraction. Extraction itself stays ungated, so you can
still preview a draft's phax-plan.json.
The phax artifact command group inspects and moves lifecycle status through its
legal transitions (see --usage for the exact subcommands and flags):
phax artifact status <path>— report an artifact's kind, current status, and legal transitions. It also prints aQuestions:line when the artifact has question sections: the count, the open questions with their ids, and the arbitrated ones with how many are lifted (Questions: 4 — open 2 (Q3, Q4) · arbitrated 2 (1 lifted)). A headless spec with a valid sidecar always prints it, a plan only when it has questions; a hand-authored §9 that departs from the §9 format prints the first departing line instead, and status still exits 0. A headless sidecar stamped below its format's current shape, or written before$schema, is not compared: theAuthored:line names its stamped shape andphax artifact migrate-documents.phax artifact approve [--by <arbiter>] <path>— theDraft → Approvedgate; run it on a plan underdocs/plans/beforephax run. Approving stampsapproved: { date, baseline }into the frontmatter and writes the artifact's own record file (docs/plans/approvals/<plan file name>.jsonfor plans,docs/specs/approvals/<spec file name>.jsonfor specs).--by operatoror--by machine:<grant>(a kebab-case slug) says who approves; the record file'sapprovedBynames them. From a terminal,--bydefaults to the operator, named as git commits (GIT_COMMITTER_NAME, elseuser.name); with no terminal and no--by, approve refuses with exit 12, so a loop or script must pass--by machine:<grant>. An operator approval with neither name set also refuses with exit 12 (git config user.name). A record written before attribution reads asunattributedand is never rewritten by a read. Re-approving an already-Approvedartifact is legal — it re-records the approval against the current content, the correct way to log an in-place revision (don't hand-edit the stamp). Approving a plan whoseSource-Specis an Approved spec that is unrecorded or edited since its approval is refused with exit 12 — re-approve the spec first.phax artifact stale/reopen— mark a planStale, or reopen anApprovedspec or plan, or aStaleplan, back toDraft. Reopen clears theapprovedstamp, deletes the record file, takes--bylike approve (same terminal default and no-terminal refusal), and writes aReopened-By: machine (<grant>)/operator (<name>)trailer in its commit. Reopening a spec names its bound plans and leaves them unchanged. ADraft,CompletedorAbandonedartifact is refused with exit 12.phax artifact decide [--question <id>] [--doctrine <file>] [--model <m>] [--effort <e>] <path>— decide a Draft spec's or plan's open questions in an interactive Claude Code session (the verdicts form is below). The agent raises the framing questions F1–F5, then presents the open questions; the operator decides. When the operator exits, phax asks the session for the revised document, checks it, prints the body diff, and writes and commits the artifact and its sidecar only after the operator accepts (a declined diff writes nothing and exits 0).--question <id>presents one question alone, open or arbitrated; a new verdict keeps the old one in its history. The flow isstatus → decide → approve, and to revisit a decisionreopen → decide --question <id>. decide needs a terminal (exit 12 without one), a Draft artifact (an Approved one namesphax artifact reopen), and a Claude model; it is refused inside a phase worktree, and never runs inside a run. The doctrine is thephax-decide-specorphax-decide-planskill (a copy under.claude/skills/wins), with--doctrineappended. The approval lock:approverefuses with exit 12 while any question is open, naming the ids andphax artifact decide; a loop cannot approve past an open question. Seedocs/arbitration.md. Verdicts form:phax artifact decide <path> --verdicts <file|-> [--by operator] [--doctrine <file>] [--model <m>] [--effort <e>] [--json]decides from a file of choices a person already made (phax artifact schema verdictsprints its format):{ question, chosen, note }per question,chosenan option id or the reservedother, a note required when the verdict departs from the recommendation. No terminal is needed with--by operator;--by machine:<grant>is refused. One headless writer (defaultclaude-sonnet-5-5atmedium, routed to a provider) records the verdicts; phax checks its answer, setswhy,byandat, commits without asking and leaves the artifact Draft, so read the printed report (or the--jsonobject) beforeapprove.--questionis refused with--verdicts;--jsonand--byneed it.phax artifact abandon/complete— terminal transitions; phax moves the file into the matchingarchive/directory and deletes its record file as part of the transition. Reopen deletes the artifact's record file the same way. No transition touches another artifact's record file.phax artifact migrate-approvals— the one-time upgrade from the old shared ledgers (docs/plans/approvals.json,docs/specs/approvals.json) to per-artifact record files underdocs/plans/approvals/anddocs/specs/approvals/, in one commit. Exits 0 when migrated or when there is nothing to migrate; exits 12, writing nothing, on an unreadable ledger, an entry that is not a live artifact path, an uncommitted change to a path it would write, or an existing record file holding a different record. While a ledger exists, every other approval command exits 12 and names this command.phax artifact migrate-documents— the one-time upgrade of headless sidecars. It rewrites every live spec and plan sidecar (a.jsondirectly underdocs/specs/ordocs/plans/beside its.md) stamped below its format's current shape, or written before$schema, and re-renders its body, keeping the frontmatter byte for byte. A spec question whose rationale opens withDecided by the author on <YYYY-MM-DD>becomes arbitrated, lifted and unattributed; every other question stays open. A plan stamped 0.20.0 lifts with empty question arrays and keeps its body. It refuses (exit 12, nothing written) on an invalid sidecar (a plan stamped 0.17.0–0.19.x stays refused), on a body that is not the sidecar's own rendering (a hand edit would be overwritten), or on an uncommitted change to a path it would write; the remedy is to re-author it headless, or delete its sidecar to demote it to hand-authored. It names every Approved artifact it leaves edited since approval (with its open question ids andphax artifact reopen <path>when it has any, elsephax artifact approve <path>) and every plan it leaves stale withspec-changed, then commits exactly what it wrote in one commit. With nothing to migrate it says so and exits 0. Until it has run,approveandreopenexit 12 and name it;complete,abandonand run completion carry an older sidecar as before. Archived and hand-authored artifacts and approval record files are never touched. The phase guard refuses it inside a phase worktree: run it in the main checkout.
Transitions are validated: an illegal one is refused and names the legal set, and
a terminal status must live under archive/ (status and location must agree). A
loose plan.md outside docs/specs/|docs/plans/ is still gated on status, but
its status line is edited by hand — phax artifact targets repo-tracked
artifacts.
When unsure about any command, read its long_help and example in
phax --usage.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

