ProveGate

CLI Reference

provegate / gate commands.

The package installs two equivalent binaries: provegate and gate.

Implemented

gate status

Rebuilds workflow state from the artifact tree (_prds/_readiness/_tasks/_docs by default), writes the snapshot (default _state/prds.json), and prints one line per work item plus panel metrics:

$ gate status
PRD-001  In Progress  readiness=PASS/8.7  tasks=12/45  config-state-locks
Implemented: 0
Latest implemented: —
wrote /repo/_state/prds.json

gate queue [--json]

The scheduling view: READY items sorted by readiness score (with conflict-surface overlap warnings), IN-FLIGHT lock leases (stale-flagged), BLOCKED, and IN-REVIEW. --json emits the machine shape (ready / readyOverlaps / inFlight / blocked / inReview).

gate push

$ gate push
No. Push is yours.
$ echo $?
1

Fully implemented, permanently. The runner has no code path that pushes to a remote.

gate run [--dry-run] [--from-phase=4|5|6|7|merge] PRD-XXX

The deterministic close: builds the gate chain from gates.manifest.json (floor gates + diff-conditional class defaults), executes the PRD's §11 commands through the command-safety allowlist, checks the independent-review artifact schema, the durable-artifacts diff gate, and the operator-acceptance guard, then archives the artifacts and performs the local no-ff merge with post-merge verification — auto-reverting on failure. Ends with a handoff card whose last line is the point: push is yours, the runner never pushes.

--dry-run prints the full plan (flagging any §11 command the safety gate would refuse) and executes nothing. A nested non-dry-run invocation refuses (recursion sentinel).

gate land PRD-XXX

The merge step only — alias for run --from-phase=merge.

gate check PRD-XXX / gate check --wiring

The readiness lint: every FR needs Targets and a runnable §11 row, DO NOT present, Open Questions empty, no bare placeholders, plus manifest hardCaps (targets-conditional required-evidence rules). --wiring audits wire-or-delete: manifest commands must name real scripts; verify:*-pattern scripts must be wired in the manifest/CI or carry a shrink-only exception.

gate doctor --memory [--json]

Read-only diagnosis of a memory install: config containment, store root and index, record validation, at least one configured entrypoint carrying the index pointer, validator presence and package-script wiring, and Phase 7 reachability. Each check has a stable id you can grep or branch on.

It never edits config, manifests, entrypoints, scripts, or state — on the failing path as well as the passing one. A diagnostic that writes only when it fails is still a writer, and the failing path is when you can least afford a surprise edit.

Mandatory failures exit 1. Two checks only warn: CI reachability, because workflow layouts are user-defined and absence there proves nothing this tool can establish; and unfilled {{TOKEN}} placeholders, a real install defect that breaks no gate today. A warning never changes the exit code.

A symlinked entrypoint is valid as long as it stays inside the repository — containment rejects escapes, not symlinks — and two entrypoints resolving to one real file count as one satisfied entrypoint rather than two.

Bare gate doctor prints usage and exits 1 rather than guessing a mode.

gate memory find [--query=<text>] [--paths=<a,b>] [--tag=<slug>] [--limit=N] [--json]

Deterministic local recall over the record store. Ranks by watched-path overlap, then exact name or tag, then description and name tokens, with the slug as a final tie-break — so the same question returns the same bytes on any machine. Default limit 20, allowed 1–1000.

Deterministic, not relevant. No embedding, no persistent index, no model, no network. A record that matters but shares no watched path, no exact name or tag, and no description token will not be found; find augments the always-loaded _brain/INDEX.md rather than replacing it. Every hit carries the reasons it matched, so you can see which rule fired.

At least one selector is required — a selectorless find would be the whole store in slug order. Disabled memory refuses instead of returning an empty list, because an empty list reads as "nothing relevant" about a store that was never consulted. Superseded and unreadable records never appear: acting on a record the validator would reject is worse than finding nothing.

gate init [--dry-run] [--practices]

Scaffolds the workflow tree (artifact dirs × lifecycle states, state and locks dirs) plus starter workflow.config.json and gates.manifest.json. Additive-only and idempotent: nothing is ever overwritten; re-run any time. Roots at the nearest .git walking up from the current directory, else the current directory itself.

--practices additionally installs the practices pack: the agent bootstrap templates, the artifact templates, and scripts/verify/ — the checks that hold artifacts to what they claim. The never-overwrite guarantee covers it too: every file that already exists is reported as skipped, which is what makes --practices safe to add to a repository that has already been scaffolded.

The pack creates files only. Adding its package.json scripts, wiring CI, and pasting the agent-entry shims are deliberate manual steps — gate init prints them (NEXT_STEPS.md) and performs none of them, because editing an adopter's package.json and CI config is not something a scaffold should do behind their back.

gate new <slug> [--class=X] [--template=path]

Creates the next work item from the shipped PRD template: allocates the next free id (max across ALL lifecycle states + 1 — completed and deferred ids are never reused), substitutes id/slug/dates/status/class into the template, and writes _prds/wip/prd-XXX-<slug>.md. Never overwrites; a concurrent gate new race is detected and retried with the next id. --template points at a forked template (its metadata anchors must survive the fork — a drifted template fails loudly).

gate open <PRD-XXX> [--steal] [--worktree]

Claims the PRD's declared ## Conflict Surface: checks the globs against every active lease with the same overlap engine gate queue uses, then either writes a lease into the locks dir or refuses (exit 1) naming each overlap. Claiming is atomic — no lease is written while any conflict exists. Re-claiming your own PRD refreshes the lease ("already held"). A stale foreign lease still blocks, but --steal may take it over — the takeover prints the victim's PRD, agent, and expiry; a valid foreign lease is never stealable. A PRD with no conflict surface is refused: a claim over nothing protects nothing.

Overlap is decided against the files two surfaces actually share; when a surface covers a directory that does not exist yet (zero tracked files), the check falls back to the patterns. That structural check is sound over the supported glob grammar (**, *, ?, literals): sibling wildcards that can match a common future path — src/api/*.ts against src/api/users.ts, or src/*/handlers/** against src/auth/handlers/** — collide at claim time, not merge time, even on a greenfield tree. The bias is deliberately conservative: an uncertain pair refuses (recoverable by narrowing a surface) rather than risk a silent double-claim. Genuinely disjoint surfaces (src/a/** against src/b/**) stay claimable in parallel, and shared append-only manifests never count as a conflict.

--worktree extends the atomic claim to the checkout: after the lease installs, a feature branch (from branches.featurePattern) and a linked worktree under the configured worktree.dir are provisioned, and the lease is stamped with both. The checkout is cut from the configured base ref, so the PRD and the control files that decide what runs there (workflow.config.json, gates.manifest.json, when present) must match the base ref first — missing OR edited-since-commit both refuse, instead of producing a checkout whose PRD, layout, or gate policy differs from the one just claimed. Provisioning failure (branch or path collision) rolls the lease back — claim and checkout are one outcome. After gate run lands the merge, the runner removes the worktree and deletes the merged branch; a dirty worktree refuses removal and degrades to a handoff-card warning (never --force on user trees). Branch deletion is decided by an explicit merge-base --is-ancestor proof against the configured base — a branch not provably merged, the base itself, or any configured protected branch is never deleted. When a parked primary checkout makes plain -d refuse a proven-merged branch, deletion retries -d from a throwaway detached scratch context at the base tip, so git's own mergedness and checked-out-branch guards re-evaluate at delete time. Locks stay platform-agnostic: external worktree managers keep working, the flag is optional sugar.

--hours=N overrides the lease duration (default 12h); a non-positive or non-finite value is refused (exit 1).

gate renew <PRD-XXX> [--hours=N]

Extends your lease. Renew is the idempotent refresh path — the same code gate open uses to re-claim a PRD you already hold — so the Conflict Surface is re-parsed and re-checked against active leases: a surface edited since the claim is re-validated, not grandfathered, and a conflict discovered now refuses exactly like a fresh claim. --hours sets the new duration. Renew before your lease goes stale, so a rival's --steal never gets the chance.

gate release <PRD-XXX> [--force]

Drops a PRD's lease under the same claim mutex, so a release racing a claim can never unlink a lease the claim just refreshed. Releasing your own lease is clean; releasing one held by a different agent requires --force and prints the victim (PRD, agent, expiry) — the takeover is reported, never silent. No lease for the id is a no-op success ("nothing to release"); a malformed lease for the id fails closed (no unlink, repair named). This retires hand-editing files under _state/locks/.

Layout, id pattern, status vocabulary, and branch policy come from an optional workflow.config.json; gate membership and policy from an optional gates.manifest.json — see the package README for both surfaces.

On this page