GitVibes / CI, Bots & Releases
Part 8

Ship It: CI, Bots, and Releases

"The robots handle the vigilance so you can spend your attention on judgment."

Everything so far happened between you, your agent, and your repository. But open any active project on GitHub and you'll see an entourage you didn't create: green checkmarks appearing on every pull request, PRs opened by accounts named dependabot and release-please, security scans running on a schedule, version numbers bumping themselves. None of it is magic, and none of it is optional knowledge anymore — this machinery is how modern software actually ships, and every piece of it is built from things you already know: branches, commits, PRs, and tags.

One lens makes the whole chapter click: everything here is either a safety net (it catches mistakes before users see them) or a memory (it records what happened and why, for the future maintainer — usually you). CI checks are safety nets. Changelogs and releases are memories. The bots just run both without being asked.

8.1 CI — Where the Green Checkmark Comes From

Every push gets a fresh machine and the full gauntlet — green means the gate opens
Note
The Problem: "It works on my machine" — but your machine has files that aren't committed, packages that aren't declared, and a you that forgot to run the tests. Multiply that by an AI agent pushing ten branches a day, and hoping everyone remembered to check everything stops being a plan.

CI — Continuous Integration — is the fix, and the idea is almost embarrassingly simple: every time anyone pushes, a robot builds the project from scratch and runs every check against it. Not "when someone remembers." Every push, every PR, every time. On GitHub the robot service is called GitHub Actions: each run spins up a runner — a fresh, disposable Linux machine in the cloud — that clones your repo, installs dependencies from the lockfile, and works through the checklist. If everything passes, your PR gets the green checkmark. If anything fails, you get a red X and a log pointing at the failure — minutes after pushing, not weeks later in production.

The checklist itself is just a YAML file committed to your repo, which means it's versioned, reviewed, and branch-protected like everything else. A real, minimal one:

.github/workflows/ci.yml
name: CI
on:
  pull_request:
  push:
    branches: [main]

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci        # install EXACTLY the lockfile versions
      - run: npm run lint  # style + suspicious patterns
      - run: npm test      # the whole suite, every time
      - run: npm run build # prove a production build works

Read it top to bottom: on these triggers, run these steps. That's the entire programming model. The steps are the same commands you (or the hooks you wrote in Automating with Hooks) run locally — the difference is where and always. A pre-commit hook is a seatbelt you buckle on your own machine, and --no-verify unbuckles it. CI runs on a machine nobody can sweet-talk. Hooks are the seatbelt; CI is the law.

Branch protection (the rulesets from Pull Requests) is what wires the checkmark to the merge button: no green, no merge — for you, your teammates, and every agent equally.

The sibling acronym, CD — Continuous Delivery or Deployment — is what happens after green: code that reaches main ships to users automatically. Many projects (including this site) deploy on every merge — a second workflow builds the app and publishes it the moment a PR lands. That immediacy is exactly why the gate in front of main matters: when merging is shipping, "we'll fix it before the release" is not a sentence that exists.

Tip
Why vibe coders should care most: CI is the one reviewer that scales with your agents. You can't personally re-run the test suite for every branch three agents push in parallel — but the runner can, does, and never gets tired. Green checks are what let you supervise outcomes instead of babysitting every command.
Vibe it

"Add a GitHub Actions workflow to my repo that runs lint, tests, and a build on every pull request"

"My tests pass locally but fail in CI — walk me through the usual suspects (lockfile, node version, environment)"

8.2 The Robot Coworkers: Dependabot, CodeQL & Friends

Bots open PRs like everyone else — and face the same green-check gate

Once CI guards the gate, something clever becomes possible: you can let robots propose changes, because no proposal — human, agent, or bot — gets through without passing the same checks. A bot's PR is a completely ordinary PR: a branch, a diff, a conversation, a checkmark. You already know how to review one. Meet the three coworkers you'll see most.

Dependabot — the dependency gardener

Your project stands on dozens of open-source packages, and dependencies age like food, not wine: every one has its own release stream and, occasionally, its own security holes. Dependabot watches all of them and opens PRs on your behalf — branches named dependabot/npm_and_yarn/... with commits like chore(deps): bump lodash from 4.17.20 to 4.17.21. The elegant part: its PR triggers your CI. The robot proposes, your test suite disposes. If the update breaks the build, you find out in the PR — not in production.

CodeQL — the code detective

GitHub's code-scanning engine treats your codebase like a database and runs queries written by security researchers against it — hundreds of known-dangerous shapes, like user input flowing unsanitized into HTML (cross-site scripting) or into file paths. It runs on PRs and on a schedule, so when a new attack pattern is discovered, your old code gets re-checked too. Think of it as a security specialist who re-reads your entire repo every week and only speaks up on a match.

Secret scanning — the leak alarm

Remember the staged .env drama from What NOT to Commit? GitHub runs a last line of defense: it recognizes the formats of API keys and tokens and — with push protection on — refuses the push outright. A blocked push is a gift. Treat any key that reaches a public commit as burned, and rotate it.

Dependabot is configured with — you guessed it — a YAML file in the repo. The one setting worth knowing on day one is grouping, which turns thirty tiny weekly PRs into one digestible one:

.github/dependabot.yml
version: 2
updates:
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: weekly
    groups:
      minor-and-patch:
        update-types: ["minor", "patch"]
        # major bumps stay separate — those need real review

Two quieter pieces complete the safety net. The lockfile (package-lock.json) pins the exact version of every package and every package's packages, so your laptop, CI, and production all install byte-identical dependencies — it's why the lockfile belongs in Git even though you never edit it by hand. And supply-chain pinning: careful repos reference third-party Actions by full commit hash instead of a friendly tag. You know from Tags & Releases that a tag is just a movable label — and if an attacker compromises an Action's repo, they can quietly move v4 to malicious code. A commit hash can't be moved. Same Git concept, now a security boundary.

Here's what a healthy history looks like with the robots at work — one of these commits was written by a human:

git log on a well-tended repo
git log --oneline -n 4
e4f5a6b feat: add csv export
b7c8d9e chore(deps): bump the npm group with 3 updates
a1b2c3d chore(main): release 1.4.2 (#118)
9f8e7d6 fix: handle empty header row
Warning
Bots are agents with one narrow job. Everything Part 6 taught you about AI agents applies: read the diff before you merge, be extra awake for major version bumps (breaking changes ride in on those), and never grant a bot more permissions than its one job needs. The green check tells you the tests still pass — it cannot tell you whether the new major version quietly changed a behavior your tests never covered.

Try It: Review the Robot's PR

Dependabot has pushed a branch. Inspect exactly what it wants to change with git diff, merge it, and clean up the branch — the same moves the "Merge" button does for you on GitHub.
Review the Robot's PR

Loading playground...

Vibe it

"Set up Dependabot for my repo with weekly, grouped minor/patch updates"

"Dependabot opened a major-version bump PR — read the changelog of the dependency and tell me what could break"

8.3 Releases on Autopilot: SemVer, Conventional Commits, release-please

Structured commit messages are the fuel — the changelog and version number write themselves

A green merge says the code is good. A release answers two different questions: what do we call this state, and what changed since the last one? In Tags & Releases you did this by hand — decided a version number, wrote an annotated tag. This lesson is about the grammar behind those version numbers, and the robot that does the paperwork.

Semantic Versioning: the number is a promise

A version like 2.4.1 reads as major.minor.patch, and each position carries a promise to whoever upgrades: a patch bump (2.4.1 → 2.4.2) means "bug fixes only, upgrade blind"; a minor bump (2.4 → 2.5) means "new features, nothing you rely on changed"; a major bump (2 → 3) means "something breaks — read the notes before touching it." That's why Dependabot's major-version PRs deserve your full attention while patch bumps barely need a glance: the versioning scheme is literally telling you how scared to be.

Conventional Commits: the payoff

Since Committing you've been writing feat: and fix: prefixes, and in Automating with Hooks a hook started enforcing them. Here's the payoff: those prefixes map straight onto SemVer. fix: means the next release is at least a patch. feat: promotes it to a minor. A feat!: or a BREAKING CHANGE: footer forces a major. Your commit history stopped being prose and became data — which means a machine can read it.

release-please: the release accountant

release-please (Google's oddly polite release bot) watches main and keeps a running draft of the next release. It reads every conventional commit since the last tag, computes the right version bump, and opens — a pull request. The PR contains exactly two things: an updated CHANGELOG.md grouping your commits into Features and Bug Fixes, and the version bump. As more commits land on main, the bot quietly amends its own PR. When you decide it's release time, you merge the PR like any other — and the bot tags the commit and publishes a GitHub Release. If you've ever wondered what a commit like chore(main): release 1.1.0 (#42) is: that's someone merging the accountant's paperwork.

The changelog it maintains is the memory half of this chapter at its purest — the human-readable answer to "what changed since 1.0.0?", assembled from messages you were already writing:

CHANGELOG.md — written by the robot, from your commits
## 1.1.0 (2026-07-17)

### Features

* add csv export (#31)

### Bug Fixes

* handle empty header row (#33)
Note
A release is not a deploy. If your project deploys on every merge (8.1), users may be running code from ten minutes ago while your latest release is v1.1.0 from last week. Deploying is code reaching users; releasing is giving a state a name, a changelog entry, and a tag you can return to. Small tools may release without deploying anything; a website deploys constantly and releases occasionally, as a bookmark.

Try It: Be release-please for a Day

Two conventional commits have landed since v1.0.0. Do the accountant's job by hand exactly once — read the log, write the changelog, commit the paperwork, cut the tag — and you'll never wonder what the bot does again.
Be release-please for a Day

Loading playground...

Vibe it

"Set up release-please for my repository and explain what its first PR will contain"

"Read my commits since the last tag and tell me the next version number — and why"

Challenge: Review the Robot

Loading challenge...