Guards
Guards are validation bundles. Unlike normal pipelines, a guard is designed to run every configured step and report a combined health result.
What A Guard Is
A guard groups existing tasks (or pipelines) under one quality gate name.
guards:
ci:
steps: [lint, test, arch-check]qp guard ciUse guards for stable, policy-level checks you want humans and CI to share.
Guards vs Pipelines
| Feature | Guard | Pipeline task (steps) |
|---|---|---|
| Purpose | Validation bundle/reporting | Orchestration workflow |
| Runs all configured checks | Yes (best effort) | Not by default (stops on first failure unless continue_on_error) |
| Default command | qp guard |
qp <task> |
| Typical use | CI gate, pre-merge verification | Build/test/release flows |
Defining Reusable Guard Inputs
tasks:
lint:
desc: Lint codebase
cmd: golangci-lint run
test:
desc: Run unit tests
cmd: go test ./...
check:
desc: Shared local quality pipeline
steps: [lint, test]
arch-check:
desc: Enforce architecture boundaries
cmd: qp arch-check --json
guards:
local:
steps: [check]
ci:
steps: [check, arch-check]check is reusable as both a task entry point and a guard step.
Running Guards
# run default guard selection
qp guard
# run one named guard
qp guard ci
# machine-readable output
qp guard ci --json
# quiet and verbose modes
qp guard ci --quiet
qp guard ci --verboseIf you need to include risky tasks inside a guard, use:
qp guard ci --allow-unsafeExample Guard Output
$ qp guard ci
guard: ci
lint pass (1.2s)
test pass (6.4s)
arch-check fail (0.3s)
summary: 2 passed, 1 failed
With --json, you get structured per-step status, durations, and parsed errors where available.
Guard State Cache
qp stores the last guard run summary in .qp/last-guard.json.
This is useful for:
- editor/status integrations
- quick local scripts that check the last known guard state
- handoff tooling that wants recent validation context
CI Pattern
tasks:
ci:
desc: CI entrypoint
cmd: qp guard ci --json
safety: idempotentqp ciOne named task (ci) keeps CI command wiring simple while still using guard semantics under the hood.
Next Step
For expression-driven orchestration, continue to DAGs and Run Expressions.