Promotion pipeline
Every scheduled run ends in an explicit promotion decision. Nothing an agent does reaches a branch without passing this pipeline.
The sequence
Section titled “The sequence”agent finishes │ ├─ validations run (lint · test · typecheck, whichever are configured) │ └─ failing or missing commands shape the decision below │ ├─ risk assessment (task risk class × policy.yaml riskClasses) │ ├─ review (optional, deterministic): scope drift + secret detection │ └─ decision ──► auto-merge · pull-request · manual-reviewArtifacts are recorded under .openloop/promotions/; each decision also lands in the event log (promotion-auto-merge-queued, promotion-review-queued, promotion-blocked, promotion-ci-failed).
The decision rules
Section titled “The decision rules”The default policy (policy.yaml) encodes three rules:
| Risk | Validations | Decision |
|---|---|---|
low-risk |
all configured commands pass | auto-merge |
medium-risk |
, | pull request |
high-risk |
, | pull request (and human approval before running) |
Plus the hard preconditions for auto-merge; it is refused when:
- No validation commands are configured for the project. An unvalidated repo never merges autonomously.
- The deterministic review produced blocking findings (scope drift, secrets); the decision is downgraded to manual review.
- A lifecycle hook responded with
{"requireManualReview": true}(see hooks). - Policy denies the touched paths; see policy & risk.
Auto-merge applies the change on an openloop/… branch and merges it. Pull requests are created with gh pr create by default (override with runtime.prCommand).
Review
Section titled “Review”With review.enabled: true in project.json, a deterministic post-implementation review runs before the decision:
- Scope drift: compares the actual diff against the task’s allowed scope and the policy globs.
- Secret detection: scans the diff for leaked credentials.
Blocking findings downgrade auto-merge to manual review and are recorded with the artifact.
Verifier
Section titled “Verifier”With verification.enabled: true (the default), an independent verifier pass double-checks the implementation against the task’s acceptance criteria. Verdicts are written to .openloop/verifications/.
Working the queue
Section titled “Working the queue”openloop promotion list -p api # all artifactsopenloop promotion list -p api --status pendingopenloop promotion show -p api --task add-rate-limit-headersopenloop promotion history -p api --task add-rate-limit-headers
# resolve pending items yourselfopenloop promotion apply -p api --task add-rate-limit-headers --dry-runopenloop promotion apply -p api --task add-rate-limit-headers --note "LGTM"openloop promotion reject -p api --task add-rate-limit-headers --note "wrong layer"
# refresh live PR state (checks, merge status) via ghopenloop promotion refresh -p api --task add-rate-limit-headerspromotion refresh shells out to gh pr view, so it needs an authenticated GitHub CLI and is not polled automatically by the daemon.
Backpressure
Section titled “Backpressure”A project with runtime.maxPendingReviewsPerProject (default 3) or more pending promotions is skipped by the scheduler until its review queue drains, autonomy pauses where human judgment is expected.