CI Gates for Multiple Coding Agents: Validate the Combined Change
Design CI gates for multiple coding agents with worker checks, contract-boundary tests, integrated-candidate proof, generated-output verification, recovery tests, and evidence artifacts.
CI Gates for Multiple Coding Agents: Validate the Combined Change
A repository can have five green coding-agent branches and one broken product.
Each agent may have tested its own patch correctly. The API branch passed against schema version A. The client branch passed against generated types from version B. The migration branch passed on an empty database. The UI branch used a fixture that bypassed the API entirely.
Every local result is real. The combined conclusion is false.
CI for multiple coding agents must prove the integrated candidate, not merely collect green worker runs. The pipeline needs separate gates for worker claims, changed contracts, producer-consumer boundaries, the combined outcome, and release-specific risks.
This guide starts after work has been decomposed into bounded tasks and before the final claim-first code review. It complements dependency-aware integration by turning its validation boundaries into repeatable automation.
If your repository does not yet have standard task packets, validation contracts, and evidence handoffs, repository-harness provides a starting structure.
The pipeline protects claims, not branches
A branch is a transport mechanism. It is not the unit of correctness.
The useful unit is a claim:
C1: API accepts JPEG and PNG avatars up to 2 MB.
C2: generated clients represent every accepted API error.
C3: web and CLI surface those errors consistently.
C4: the migration preserves existing avatar references.
C5: all four claims hold on candidate 8c21f4e.
CI should answer four different questions:
| Gate | Question | Runs against | Failure owner |
|---|---|---|---|
| Worker gate | Does this bounded implementation support its claim? | worker checkpoint | worker |
| Contract gate | Is the changed source of truth valid and accepted by consumers? | producer plus representative consumers | contract owner |
| Candidate gate | Do accepted checkpoints work together? | exact integration candidate | integrator plus owning worker |
| Release gate | Is the artifact safe to publish, migrate, or deploy? | immutable release candidate | release owner |
Collapsing these into one command creates ambiguous failures. Running only worker gates misses integration faults. Running only a full suite after everything merges makes failures slow to localize.
The reliable pipeline preserves both: fast claim-local feedback and explicit combined proof.
A layered multi-agent CI architecture
The ordering is intentional. A cheap worker failure should stop before integration. A producer-consumer mismatch should stop before the full repository suite. Release writers should never run against a candidate that failed combined proof.
1. Freeze one exact candidate
Do not let CI prove one commit while review examines another.
Record:
base_commit=4ab91ce
candidate_commit=8c21f4e
task_graph=docs/tasks/avatar-upload/graph.md
integration_record=docs/tasks/avatar-upload/integration.md
toolchain_lock=toolchain.lock
Every candidate-level artifact should include the candidate SHA. Every rerun should say whether it uses the same source, same toolchain, and same relevant environment.
A branch name such as integration/avatar-upload is not enough. It can move after the checks start.
If the candidate changes:
- classify which claims the new commit can affect;
- invalidate the affected evidence;
- rerun the required gates;
- preserve the old result as historical evidence, not current proof.
This is especially important when an agent responds to review feedback while other checks are still running.
2. Classify the change before selecting checks
The repository should map changed surfaces to required gates.
| Change class | Focused worker checks | Boundary checks | Candidate or release checks |
|---|---|---|---|
| Public API or schema | schema validation, contract tests | old/new consumer compatibility, generated clients | representative end-to-end request |
| Database migration | migration unit tests | reader/writer compatibility | old-state upgrade, rollback or forward-repair proof |
| Authentication | policy and unit tests | client/server authorization matrix | negative-path integration and audit evidence |
| Generated output | source validation | pinned regeneration and compile | second generation leaves tree clean |
| CLI behavior | parser and command tests | script and API contract compatibility | packaged-binary smoke |
| UI flow | component tests | API/error mapping | browser smoke on integrated backend |
| Recovery journal | state-machine tests | persisted-state compatibility | fault injection and idempotent resume |
| Documentation or instructions | link and syntax checks | command existence and path checks | clean-session discovery probe |
Do not route solely by file extension. A one-line schema edit may require more proof than a 500-line internal refactor.
The classification should come from accepted behavior and ownership:
change_classes:
- public-api
- generated-client
- browser-flow
required_claims:
- C1
- C2
- C3
Agents can propose the classification. The repository policy decides the gates.
3. Run worker gates against bounded claims
Worker CI should be fast enough to run before a handoff.
A useful worker result contains:
## Worker evidence
- Claim: C2 — generated clients match the accepted avatar schema
- Base: `4ab91ce`
- Checkpoint: `agent/avatar-clients@7d52a10`
- Input contract: `openapi/avatar.yaml@19c88d4`
- Commands:
- `scripts/validate-openapi`
- `scripts/generate-clients`
- `scripts/check-generated-clean`
- `npm test -- avatar-client`
- Result: PASS
- Omitted: package publish smoke
- Residual risk: publish metadata is deferred to the release gate
Worker gates should prove the narrow claim without pretending to prove the whole product.
Good worker gates are:
- deterministic where possible;
- tied to a stable checkpoint;
- explicit about source inputs;
- small enough to rerun during integration;
- honest about omitted environments and tests.
A worker should not report “all tests pass” when it ran one package suite. Name the command and the scope.
4. Test producer-consumer boundaries
Most multi-agent failures live between green branches.
Identify every dependency edge:
OpenAPI schema -> generated TypeScript client -> web uploader
OpenAPI schema -> generated Go client -> CLI command
migration -> repository reader -> API response
feature flag -> backend behavior -> frontend visibility
For each edge, define a boundary gate before integration begins.
| Edge | Boundary gate |
|---|---|
| Schema → client | regenerate from exact schema; compile consumer |
| API → UI | contract fixture plus real integrated smoke |
| Migration → reader | load pre-change state, migrate, read with new code |
| Event producer → consumer | schema compatibility plus replay fixture |
| CLI → service | packaged CLI against candidate service |
| Config → runtime | parse accepted config and verify observable behavior |
The strongest boundary check uses the producer artifact and consumer code that will actually ship together.
Fixtures are useful but can become parallel sources of truth. If a fixture can disagree with the authoritative schema without failing, the boundary gate is incomplete.
5. Regenerate derived output from canonical sources
Generated files attract conflicts because several agents can touch nearby source and output paths.
The gate should enforce this sequence:
- validate the authoritative schema, template, or specification;
- pin the generator version;
- remove or reset generated output according to repository policy;
- regenerate from the accepted source;
- compile or test representative consumers;
- run generation again;
- require the second run to produce no diff.
The second generation is critical. It proves the process is stable and the committed output is reproducible.
Do not pass a generated-output gate because the checked-in diff “looks plausible.” Do not resolve generated conflicts by hand and then bless the result with a compile-only check.
The source owns the behavior. The generator owns the derived text.
6. Build and test one integrated candidate
After worker and boundary gates pass, create one candidate in dependency order.
The candidate gate should cover:
- required build and static analysis;
- changed contract tests;
- producer-consumer checks;
- representative repository-wide tests;
- generated-output cleanliness;
- user-visible smoke behavior;
- repository cleanliness after all checks;
- explicit omissions and residual risks.
A candidate matrix might look like this:
candidate_gates:
identity:
- verify-base-and-candidate
contracts:
- validate-openapi
- test-client-compatibility
build:
- build-server
- build-web
- build-cli
behavior:
- smoke-avatar-api
- smoke-avatar-web
- smoke-avatar-cli
reproducibility:
- regenerate-clean
- verify-clean-tree
The matrix should reflect the requested outcome, not a generic collection of available scripts.
If web and CLI are both named in acceptance criteria, proving only the API is not sufficient. If the task changes error behavior, a happy-path smoke is not sufficient.
7. Treat migrations and recovery as state transitions
A green fresh-install test says little about upgrade safety.
For a migration, preserve representative old states:
empty database
small normal database
legacy nullable field
partially applied earlier migration
large or boundary-value record
Then prove the accepted transition:
old state -> new migration -> new reader/writer -> observable outcome
If rollback is promised, test rollback. If the policy is forward-only repair, test the repair path instead of implying reversibility.
Recovery workflows need stronger proof. Inject failure around mutation boundaries:
before mutation
mutation succeeded, journal not advanced
journal advanced, next mutation not started
process exits during cleanup
Reload persisted state and invoke recovery again. The next run must infer what already happened and continue safely.
A retry that works only in the same process is not crash recovery.
8. Separate required, advisory, and release-only checks
Not every check has the same authority.
| Check type | Merge effect | Example |
|---|---|---|
| Required | blocks candidate acceptance | contract compatibility, core tests, clean generation |
| Advisory | reports risk but does not block | broad performance sample with noisy infrastructure |
| Release-only | blocks publishing or deployment | package smoke, signing, migration rehearsal |
| Scheduled | detects drift outside one change | nightly dependency matrix, instruction-link audit |
Name checks by what they prove:
contract/openapi-compatibility
boundary/avatar-web-api
candidate/avatar-outcome
reproducibility/generated-clean
release/package-smoke
Names such as test-1 and ci hide authority. A reviewer should know which accepted claim a required status protects.
If an advisory check repeatedly catches real defects, promote it or repair its reliability. If a required check is routinely ignored, it is not a real gate.
9. Preserve machine-readable evidence
Logs are useful but insufficient as the only record. They are noisy, expire, and rarely explain omissions.
Produce a small evidence manifest:
{
"base": "4ab91ce",
"candidate": "8c21f4e",
"task": "avatar-upload",
"claims": ["C1", "C2", "C3", "C4", "C5"],
"toolchain": "toolchain.lock@6d91b2a",
"required_checks": {
"contract/openapi-compatibility": "pass",
"boundary/avatar-web-api": "pass",
"candidate/avatar-outcome": "pass",
"reproducibility/generated-clean": "pass"
},
"omitted": ["windows packaged-cli smoke"],
"residual_risks": ["package metadata is verified at release gate"]
}
Attach or archive:
- structured test reports;
- migration and fault-injection results;
- generated-output diffs when failing;
- screenshots or traces only where they prove an accepted UI behavior;
- package hashes for release candidates;
- the exact evidence manifest.
Evidence should support the coding-agent handoff protocol and the final review packet. It should not require a reviewer to reverse-engineer meaning from thousands of log lines.
10. Route failures back to the owner
The red check should identify the first wrong layer.
| Failure | Return to |
|---|---|
| Worker unit or focused test | owning worker |
| Disputed public behavior | contract owner |
| Schema/client incompatibility | producer and affected consumer owners |
| Hand-edited generated output | canonical source and generator owner |
| Integration-order fault | integrator and task graph |
| Candidate-only seam failure | owning workers plus integrator |
| Migration or recovery failure | state-transition owner |
| Packaging or deployment failure | release owner |
| Repeated missing instruction | repository contract owner |
Do not allow the integrator to patch every red check directly on the candidate. Integration-owned glue can be fixed there. A false worker claim or broken canonical source should return to its owner, get new evidence, and re-enter the candidate.
That preserves attribution and prevents the integration branch from becoming the only place where the system works.
11. Control flakiness instead of normalizing reruns
Multi-agent pipelines create more checks, which can expose existing flakes. The wrong response is to rerun until green.
Use a declared policy:
1. Preserve the first failure evidence.
2. Classify deterministic product failure vs infrastructure failure vs known flake.
3. Permit a bounded rerun only for documented infrastructure or quarantined-flake classes.
4. Record both attempts.
5. Never let a rerun erase the original failure.
6. Give every quarantined check an owner and expiration date.
A required check that passes on the third unexplained attempt does not provide strong proof.
Also inspect shared resources. Concurrent jobs may collide on ports, test databases, object-store buckets, browser profiles, caches, or deployment environments. Runtime isolation matters even when source worktrees are separate.
12. Keep write-capable workflows out of the proof path
Most CI gates should be read-only with respect to external systems.
Publishing packages, applying migrations, writing releases, or deploying production requires a separate release gate and narrower permissions.
Important distinctions:
- cancellation is not serialization;
- a green build does not authorize publishing;
- branch protection does not make a workflow idempotent;
- an agent-generated workflow change should not gain write credentials before review;
- a release job needs a known artifact identity and safe retry behavior.
Use least privilege. Keep untrusted code away from secrets. Require environment approval where policy demands it. Queue or otherwise serialize write-capable release operations when overlapping writers would be unsafe.
The candidate pipeline proves the artifact. The release pipeline governs the external mutation.
13. Example GitHub Actions shape
The repository-specific commands will differ, but the separation should remain visible:
name: candidate-proof
on:
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
classify:
runs-on: ubuntu-latest
outputs:
api: ${{ steps.changes.outputs.api }}
generated: ${{ steps.changes.outputs.generated }}
migration: ${{ steps.changes.outputs.migration }}
steps:
- uses: actions/checkout@v4
- id: changes
run: ./scripts/classify-change
worker-and-static:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/validate-static
- run: ./scripts/test-focused
contract-boundaries:
needs: [classify, worker-and-static]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/test-contract-boundaries
- if: needs.classify.outputs.generated == 'true'
run: ./scripts/check-generated-clean
candidate:
needs: [contract-boundaries]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/test-candidate
- run: ./scripts/smoke-accepted-outcome
- run: ./scripts/write-evidence-manifest
- uses: actions/upload-artifact@v4
with:
name: candidate-evidence-${{ github.sha }}
path: artifacts/evidence/
The release workflow is intentionally absent. It should consume a proven immutable artifact through a separate permission boundary rather than inheriting write access in every pull-request run.
Do not copy this file without adapting the change classifier, accepted outcomes, and security model. The architecture matters more than the vendor syntax.
14. Adopt the gates incrementally
A small repository does not need a sophisticated matrix on day one.
Stage 1: Name the evidence
Require every worker to report an exact checkpoint, command, result, omission, and risk.
Stage 2: Add one boundary gate
Choose the seam that has caused the most integration failures: schema/client, migration/reader, API/UI, or generator/output.
Stage 3: Pin the candidate
Run combined proof against one candidate SHA and preserve the evidence manifest.
Stage 4: Add generated and clean-tree checks
Make derived output reproducible and detect tests that mutate the repository.
Stage 5: Add state-transition proof
Cover migration, rollback, recovery, and failure injection where the product needs them.
Stage 6: Separate release authority
Move package, migration, and deployment writes behind their own permissions and gates.
Add complexity only when it controls a real risk. The smallest useful pipeline is one that can explain which claim failed, who owns the repair, and whether the integrated outcome is proven.
Multi-agent CI checklist
# Multi-agent candidate proof
## Identity
- [ ] exact base and candidate commits recorded
- [ ] task graph and integration record linked
- [ ] toolchain and relevant environment identified
## Worker proof
- [ ] each claim maps to one owner and checkpoint
- [ ] focused commands and results are preserved
- [ ] omissions and residual risks are explicit
## Boundaries
- [ ] changed contracts have authoritative sources
- [ ] producers integrate before consumers
- [ ] representative producer-consumer checks pass
- [ ] generated output is recreated and stable
## Candidate
- [ ] required build and static checks pass
- [ ] representative repository tests pass
- [ ] accepted user-visible outcome is reproduced
- [ ] migration or recovery proof runs when relevant
- [ ] final tree is clean
## Evidence
- [ ] machine-readable manifest names candidate and claims
- [ ] failed first attempts are preserved
- [ ] advisory and release-only checks are labeled
- [ ] artifacts have retention appropriate to review and release
## Authority
- [ ] failed claims return to the owning source
- [ ] external write workflows use separate permissions
- [ ] release jobs consume an immutable proven artifact
Make CI part of the repository contract
Keep the root instruction short and link to executable controllers:
## Validation for concurrent coding-agent work
- Every worker returns a stable checkpoint and claim-scoped evidence.
- Changed contracts require producer-consumer boundary checks.
- Worker-green is not candidate-green; one exact integrated commit must pass combined proof.
- Generated output is recreated from canonical sources and must be reproducible.
- Migration, recovery, packaging, and deployment risks use explicit gates.
- Failed claims return to their owning source before the candidate is rebuilt.
- External write workflows are separate from pull-request proof and use least privilege.
The detailed matrix belongs in version-controlled scripts and documentation. The root AGENTS.md should route agents to those sources instead of duplicating every command.
When the same CI failure repeats, repair the controller:
- unclear change classification becomes a path-to-gate map;
- missing contract proof becomes a boundary test;
- unstable generation becomes a pinned toolchain;
- silent omission becomes an evidence-manifest field;
- unsafe retry becomes an idempotency or serialization rule;
- wrong agent behavior becomes a task or repository-instruction correction.
That is harness engineering: every failure improves the environment that governs the next run.
Prove the combined change
Multiple coding agents can accelerate implementation without weakening confidence, but only when the pipeline preserves the distinction between local claims and combined truth.
Run focused worker checks. Test changed contracts across their consumer boundaries. Regenerate derived output. Freeze one candidate. Reproduce the accepted outcome. Preserve machine-readable evidence. Route failures back to the owner. Keep release writes behind a separate authority boundary.
Then review and ship the candidate whose claims survive together.
Use repository-harness on GitHub to establish the repository-visible tasks, validation contracts, handoffs, checkpoints, and evidence structure that make these CI gates repeatable.
Related pages
- Task Decomposition for Multiple Coding Agents
- How to Integrate Changes from Multiple Coding Agents Safely
- How to Review Code from Multiple Coding Agents
- How to Resolve Merge Conflicts Between Coding Agents
- Coding-Agent Handoff Template
- Git Worktrees for Multiple Coding Agents
- How to Manage Multiple Coding Agents in One Repository
- Repository Harness Patterns
- Coding-Agent Failure Modes
- How to Audit a Repository for Agent-Readiness
- AGENTS.md Template
- repository-harness on GitHub
FAQ
How should CI work when multiple coding agents change one repository?
Use layered gates. Each worker runs focused checks for its own claim, producer-consumer boundaries get compatibility tests, and one exact integrated candidate runs repository-wide and user-visible outcome checks. Preserve the candidate commit, commands, results, omissions, and artifacts so review can reproduce the proof.
Are passing tests on every coding-agent branch enough?
No. Separate branches may pass against different assumptions, contract versions, generated files, or base commits. CI must also test the branches together in dependency order and prove the combined behavior on one immutable candidate.
Which checks should block a multi-agent merge?
Block on checks that protect accepted behavior: changed-contract tests, producer-consumer compatibility, generated-output cleanliness, required build and static checks, migration or recovery proof when relevant, representative end-to-end behavior, and a clean reproducible candidate. Advisory checks should be labeled separately.
How do I keep multi-agent CI fast?
Classify the change, run focused worker checks early, cache only inputs with explicit keys, parallelize independent read-only checks, and reserve full candidate and release gates for the integrated commit. Speed should come from better routing, not from silently dropping coverage.
How should CI validate generated files from coding agents?
Validate the authoritative schema or template, pin the generator, regenerate from the accepted source, and require a second generation run to leave the tree clean. Never treat a hand-edited generated diff as sufficient proof.
Should failed CI be repaired directly on the integration branch?
Only integration-owned glue belongs there. A failed worker claim, source contract, generator input, migration, or subsystem behavior should return to its owning branch or canonical source, then the candidate should be rebuilt. This prevents the integration branch from becoming an unowned patch pile.
What evidence should a coding-agent CI run preserve?
Preserve the base and candidate commits, task and claim identifiers, changed-contract map, exact commands, toolchain identity, machine-readable results, logs for failures, generated-output status, omitted checks, residual risks, and links to durable artifacts. Evidence should explain what passed and what remains unproven.