Guide
Gating a deploy from CI
Run the suite on every pull request and fail the build when a case that must never break, breaks.
A suite nobody runs is documentation. The point of wiring it into CI is that a regression stops a deploy instead of being discovered by a customer three weeks later.
What you need
- An agent reachable from your CI runner. A staging deployment is the usual answer.
- A workspace API key, from API keys in the app. It is shown once.
- At least one regression case, so the gate has something to gate on.
Not production
A run executes real tool calls. An agent marked Production is refused by the API with a 409, deliberately, because a pipeline pointed at production would issue real refunds on every pull request.
The workflow
- name: Run the regression suite
env:
ACTIONPROOF_API_KEY: ${{ secrets.ACTIONPROOF_API_KEY }}
run: |
curl -fsSL https://actionproof.ai/ci/actionproof.mjs -o actionproof.mjs
node actionproof.mjs run \
--agent my-support-agent \
--suite regression \
--version "${GITHUB_SHA::7}" \
--waitThe runner exits 0 on pass or warn and 1 when the gate is blocked, so the build fails on its own. Nothing in your pipeline has to parse JSON.
The gate is decided by us, on purpose
The status response carries an explicit gate field rather than leaving CI to work it out from counts. If every customer derives the verdict themselves, every customer derives it slightly differently, and eventually a blocking regression ships because of an off-by-one in a shell script.
| Gate | Meaning | Exit code |
|---|---|---|
pass | Nothing failed. | 0 |
warn | Something failed, but no case marked blocking. | 0 |
blocked | A blocking regression case failed, or the run was stopped by a guard. | 1 |
pending | The run has not finished. | , |
Which suite to run
Use --suite regression on pull requests. Those are the cases someone decided must never break again, they are scripted, and scripted conversations are byte-identical between runs, so a failure is the agent changing rather than the weather.
Run the full suite on a schedule instead, with generated customers. That is where the next unknown failure is, and a surprise at 3am is better than a broken build at 6pm.
Calling the API directly
If you would rather not use the runner, it is two endpoints.
# start
curl -X POST https://actionproof.ai/api/v1/runs \
-H "Authorization: Bearer $ACTIONPROOF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent":"my-support-agent","suite":"regression","version":"abc1234"}'
# poll
curl https://actionproof.ai/api/v1/runs/<ref> \
-H "Authorization: Bearer $ACTIONPROOF_API_KEY"Or skip polling entirely: add a webhook under Integrations and we will POST the result, signed, when the run finishes.
Keeping the gate trusted
- Block on few things. A gate that blocks on everything gets switched off within a fortnight, and then nothing is gated.
- Never block on `not_verified`. By definition it is not evidence of a defect. Gating on it teaches people the gate is noise.
- Label the version. A failures list that cannot say which build produced it is an argument waiting to happen.
- Watch the runtime. A suite that takes longer than the deploy it guards will be skipped under pressure.
Next guide
Choosing what to test firstTwenty scenarios that matter beat two hundred that do not. How to pick them.