UPDATED IN SEPTEMBER 2026

Pipeline definitions in the repo, reviewed like code

Pipeline definitions live in the repository next to the application they build, and changes to them go through the same review, the same checks and the same history as any other change.

L2 · DELEGATEDWhat this level takes
MUSTNot met, not at this level
  • Pipeline definitions are versioned in the repository and changed through code review
  • Dedicated CI runners are allocated per team (no shared queue across all teams)
  • CI completes in under 10 minutes (median)
SHOULDExpected in practice, not required
  • CI duration is tracked as a metric and reviewed monthly
  • Cache hit rate exceeds 70%
EVIDENCEHow you would check
  • CI run duration dashboard showing median under 10 minutes
  • Cache configuration in CI pipeline (e.g., actions/cache, Gradle build cache)
  • Runner allocation configuration showing per-team resources

What It Is

Pipeline definitions live in the repository next to the application they build, and changes to them go through the same review, the same checks and the same history as any other change. The alternative - pipelines configured by clicking through a CI vendor's web UI, with build steps typed into text boxes that nobody can diff - is what most teams start with and what most teams outgrow the first time a pipeline breaks and nobody can say what changed.

This is orchestration, not optimisation. The pipeline definition says what runs, in what order, on which trigger, with which credentials, and what constitutes a pass. How fast those steps run - caching, incrementality, the dependency graph, whether a rebuild can be skipped entirely - belongs to the Build System, and this guide deliberately leaves it there. A pipeline that shells out to a well-behaved build tool is doing the right thing; a pipeline that has grown its own bespoke caching layer in YAML usually means the build system underneath is not carrying its weight.

The mechanism is unremarkable and that is the point. A file (.github/workflows/*.yml, .gitlab-ci.yml, Jenkinsfile, .buildkite/pipeline.yml) is committed alongside the code. A change to it arrives as a pull request. Reviewers see the diff. The change ships when the change that motivated it ships, on the same branch, and rolls back with it. Every pipeline your organisation runs can be found by grepping, because it is text in a repository rather than state in a vendor's database.

For teams running agents this stops being hygiene and becomes a hard prerequisite. An agent can read a pipeline definition, reason about why a job failed, and propose a fix as part of the same change - none of which it can do against a web form. Agents also multiply the number of pipeline edits: when a change needs a new job, the agent proposing the change should be able to propose the job too, and a human should be able to review both in one place. Pipelines that live outside version control become the one part of the system agents cannot touch, which is exactly the part that then rots.

Why It Matters

  • A pipeline change becomes reviewable - a diff on a workflow file gets the same scrutiny as a diff on production code; a change made in a web console gets none, and is usually discovered only when it breaks
  • Pipeline and application move together - a change that needs a new build step ships the step and the code on the same branch, so no branch is ever ahead of the pipeline that verifies it
  • Failures become archaeologically tractable - "when did this job start running with those flags" is a git log question rather than an appeal to whoever has admin access
  • Rollback is the same gesture as any other rollback - reverting a bad pipeline change is a revert, not a reconstruction from memory of what the settings used to be
  • Agents can participate - an agent can read, diff and propose pipeline changes only if the pipeline is a file; UI-configured pipelines are permanently outside the loop

Getting Started

  1. Inventory what is currently defined outside the repo - Walk your CI provider's UI and list every pipeline, every environment variable, every scheduled trigger and every manually configured job. Most teams are surprised by how much of their delivery process exists only as console state. This list is the migration backlog.
  2. Export one pipeline to a file and make it authoritative - Pick a non-critical service. Write its pipeline definition in the repository, run it in parallel with the UI-configured one until the results match, then delete the UI configuration. Deleting the old one matters: two definitions with one authority is worse than either alone.
  3. Move secrets out of the definition but keep their declaration in it - The file should name every secret the pipeline needs and where it comes from (the provider's secret store, an OIDC exchange, a vault path). The value stays out of the repository; the dependency on it does not. A reviewer must be able to see from the diff that a job just gained access to a production credential.
  4. Put the pipeline files under CODEOWNERS - Workflow files are the most privileged code in the repository: they run with credentials, on triggers other people control. Require review from the platform or CI owners on any change to .github/workflows/, .gitlab-ci.yml or equivalent, the same way you would for auth code.
  5. Lint pipeline definitions in the pipeline - Add a job that validates the workflow files themselves - actionlint for GitHub Actions, gitlab-ci-lint for GitLab, Jenkinsfile declarative validation. Broken YAML and misspelled action names should fail on the pull request, not on main at midnight.
  6. Factor the repeated parts into shared, versioned definitions - Once several repositories have pipeline files, the same twenty lines will appear in all of them. Extract reusable workflows or templates into a dedicated repository, reference them by tag, and change them in one place. Resist inlining "just this once" - that is how twenty copies drift.
TIP

The test of whether your pipeline really lives in the repository is to check out a six-month-old commit and ask whether you can tell exactly how it was built and verified. If the answer depends on what the console happened to be configured to do that week, the pipeline is not in the repo yet.

Common Pitfalls

Committing the file while keeping the UI as the real control. Teams frequently add a workflow file and then continue to make urgent changes through the console because it is faster. Now there are two sources of truth and the file is the less accurate one. Pick the file, remove console edit permissions for everyone who does not need them, and accept that urgent pipeline changes now take a pull request.

Treating workflow files as configuration rather than as privileged code. A workflow file can exfiltrate every secret in the repository. Pull requests from forks that modify workflows, unpinned third-party actions referenced by mutable tag, and pull_request_target triggers are all live attack surface. Pin actions to a commit SHA, restrict which triggers run with secrets available, and review pipeline diffs with the seriousness the blast radius deserves.

Growing a caching implementation inside the pipeline definition. When builds are slow, the tempting fix is to add cache save and restore steps to the workflow, hand-rolling keys and hoping they invalidate correctly. This puts build correctness in the hands of YAML. Caching and incrementality belong to the Build System - a build tool that understands its own dependency graph will cache correctly, and the pipeline should simply invoke it.

Copying the same definition into thirty repositories. Pipeline-as-code makes duplication easy and therefore common. Six months later the thirty copies differ in ways nobody chose, and a security fix has to be applied thirty times. Move shared logic into reusable workflows early, before the copies have diverged enough that consolidation becomes its own project.

Leaving the definition unreadable to the people who need to change it. A 900-line workflow file with nested conditionals and generated matrix expansions is version-controlled but not reviewable. If a reviewer cannot tell from the diff what will now run, the file is in the repository without being under review. Keep jobs short, push logic into scripts that can be tested locally, and let the YAML describe orchestration rather than implement it.

How Different Roles See It

BobHEAD OF ENGINEERING

Bob's team had a production incident last month where a deploy job silently stopped running its smoke tests. Nobody could establish when that changed or who changed it, because the pipeline is configured in the CI provider's web console and the console does not keep meaningful history. The post-incident review produced an action item Bob has not yet funded.

Bob should treat this as a governance problem rather than a tooling preference, because that is how it will be received by anyone asking why the incident happened. The ask is small: one engineer, roughly a sprint, to move the deploy pipelines for the top three services into their repositories and put them behind CODEOWNERS review. The outcome Bob can report is concrete - every future change to how software reaches production arrives as a reviewed diff with an author and a date. Bob should also close off the old path explicitly, revoking console edit rights once the files are authoritative, because a migration that leaves the back door open will quietly reverse itself within a quarter.

SarahPRODUCTIVITY LEAD

Sarah keeps hearing that CI is unpredictable, but the complaints do not resolve into anything she can act on: a job that passed yesterday fails today, a step that used to run does not, a build behaves differently on one repository than on its neighbour. She suspects the variability is not in the code.

Sarah should measure how much of the delivery process is invisible to version control. For each active repository she can record whether the pipeline is defined in a committed file, partly committed, or entirely console-configured - a half-day of clicking, and the resulting table is the argument. Repositories with committed pipelines will show a clean correspondence between pipeline changes and commits; the others will show unexplained behaviour changes. That contrast is what turns "CI feels flaky" into a specific, fundable piece of work. Sarah should also start tracking pipeline changes as a review category in their own right, so the team can see that these edits are happening at all - in most organisations moving to pipeline-as-code reveals a change rate nobody had realised was going unreviewed.

VictorSTAFF ENGINEER - AI CHAMPION

Victor has been letting agents propose changes across several services and has run into a consistent wall: an agent can write the code and the tests, but when the change needs a new CI job it stops, because the pipeline is not something it can see or edit. Victor ends up hand-translating the agent's suggestion into the console himself.

Victor should make pipeline definitions part of the agent's working surface. That means committing the workflow files, then making sure the repository's agent instructions describe where they live, what the shared reusable workflows are, and which changes require a platform review. He should also add the pipeline linter to the pull request checks, because an agent proposing workflow edits will get the syntax wrong occasionally and the fast, mechanical feedback is what lets it self-correct without a human round trip. Victor should keep one guardrail deliberately human: changes that grant a job new credentials or add a new trigger stay under CODEOWNERS review regardless of who authored them. The goal is agents proposing pipeline changes freely and a human approving the privileged subset, not agents locked out of a third of the codebase.

How This Guide Changed

What each edition changed in this guide, newest first.

  1. V1.6September 2026LATEST

    The L2 rung of CI/CD Pipeline now asks whether pipeline definitions live in the repository and are reviewed like application code, rather than whether dependency and layer caching is switched on. Caching, incrementality and the dependency graph moved wholesale to Build System, which is where a reader should now go for them: this area orchestrates verification runs, and how fast a step executes is a different capability. Until the line was drawn, a team could score the same caching work twice, once here and once under Build System.

  2. V1.0March 2026

    One of the first edition's foundation items, and deliberately the least exotic thing in the delivery perspective. It made the case that dependency and layer caching is the highest-return change available in CI, and that it turns from an optimisation into a prerequisite the moment agents multiply push volume tenfold against the same runners.

Where does your team actually sit on this?

This guide describes one level of one area. Run the assessment to place your team across all 16 areas, see which gates you have passed, and get a report you can take to your stakeholders.

Start the assessment