<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: AI CodeOps</title>
    <description>The latest articles on DEV Community by AI CodeOps (@aicodeops_dev).</description>
    <link>https://dev.to/aicodeops_dev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4216096%2F12d249ad-b089-4414-b620-8a1e0d3c1df8.png</url>
      <title>DEV Community: AI CodeOps</title>
      <link>https://dev.to/aicodeops_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aicodeops_dev"/>
    <language>en</language>
    <item>
      <title>AI Coding Agents Beyond GitHub: GitLab, Bitbucket, Gitea and Forgejo</title>
      <dc:creator>AI CodeOps</dc:creator>
      <pubDate>Fri, 30 Oct 2026 02:02:05 +0000</pubDate>
      <link>https://dev.to/aicodeops_dev/ai-coding-agents-beyond-github-gitlab-bitbucket-gitea-and-forgejo-52f6</link>
      <guid>https://dev.to/aicodeops_dev/ai-coding-agents-beyond-github-gitlab-bitbucket-gitea-and-forgejo-52f6</guid>
      <description>&lt;p&gt;&lt;em&gt;Most AI coding agents assume your code lives on GitHub. A lot of it doesn't. Here's what it takes to run gated AI changes on the Git host you already use.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you read the docs of most AI coding agents closely, one line keeps showing up: works with repositories hosted on GitHub. That's a reasonable place to start. GitHub is huge.&lt;/p&gt;

&lt;p&gt;But plenty of teams aren't there. Enterprises run self-managed GitLab. Agencies live in Bitbucket. Privacy-minded teams and a growing slice of open source run Gitea or Forgejo on their own servers. For them, "just use the agent" means moving their code first, which usually means not using the agent.&lt;/p&gt;

&lt;p&gt;We built AI CodeOps to work where the code already is.&lt;/p&gt;

&lt;h2&gt;
  
  
  One workflow, five Git hosts
&lt;/h2&gt;

&lt;p&gt;AI CodeOps connects to &lt;strong&gt;GitHub, GitLab, Bitbucket, Gitea and Forgejo&lt;/strong&gt;. The flow is the same on each:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Connect once.&lt;/strong&gt; Use OAuth for the hosted services, or a personal access token for your own server. For a self-hosted GitLab, Gitea or Forgejo, you enter the server's public https address and paste a token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Describe a change in the browser.&lt;/strong&gt; Agents plan it, write it, review it and run the project's own tests in a sandbox&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get a pull request on your host.&lt;/strong&gt; When the change passes the release gate, AI CodeOps pushes a branch named &lt;code&gt;codeops/run-&amp;lt;id&amp;gt;&lt;/code&gt; and opens a pull request (a merge request on GitLab) into the default branch&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A team that uses more than one host can run all of them from one workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does, and what it doesn't
&lt;/h2&gt;

&lt;p&gt;For teams that own their tooling, the second list matters as much as the first. On Gitea and Forgejo, for example, AI CodeOps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Does&lt;/strong&gt; list the repositories, branches, files and pull requests the connected account can see&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does&lt;/strong&gt; push a branch and open a pull request, with commits authored as "AI CodeOps"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doesn't&lt;/strong&gt; need admin access. An account that can read the repository, push a branch and open pull requests is enough&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doesn't&lt;/strong&gt; install webhooks, post commit statuses or comment on your pull requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never&lt;/strong&gt; pushes to your default branch directly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tokens are encrypted at rest and never written into a repository's Git configuration. To remove access, disconnect in AI CodeOps or revoke the token on your server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gate goes with you
&lt;/h2&gt;

&lt;p&gt;The point isn't only that the agent can reach your host. It's that the same rules apply there. A change opens a pull request only when your tests passed on that exact version, the AI review of the real diff has no open high or critical findings, and a person approved it. If a check errors, the gate fails closed.&lt;/p&gt;

&lt;p&gt;A pull request opened by AI CodeOps can be merged from the console only after the release gate passes again. You can also merge it on your host as usual, and if you want those merges gated too, your CI can ask the gate for a verdict through an API and fail the job on a "no".&lt;/p&gt;

&lt;h2&gt;
  
  
  A note for Codeberg users
&lt;/h2&gt;

&lt;p&gt;Codeberg runs Forgejo, so the connection works with &lt;code&gt;https://codeberg.org&lt;/code&gt; and a personal access token. But read Codeberg's Terms of Use first: they don't allow projects that mostly consist of code written by generative AI tools. That's their call, and worth respecting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it on your host
&lt;/h2&gt;

&lt;p&gt;AI CodeOps runs in the browser, with nothing to install. It's free during the open beta, and &lt;strong&gt;free forever for non-commercial open-source projects&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrations: &lt;a href="https://aicodeops.dev/integrations" rel="noopener noreferrer"&gt;aicodeops.dev/integrations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Open source program: &lt;a href="https://aicodeops.dev/pricing/open-source" rel="noopener noreferrer"&gt;aicodeops.dev/pricing/open-source&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance and edited by the AI CodeOps team.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gitlab</category>
      <category>selfhosted</category>
      <category>ai</category>
      <category>devops</category>
    </item>
    <item>
      <title>Free Forever for Open Source: Why We're Giving AI CodeOps to Maintainers</title>
      <dc:creator>AI CodeOps</dc:creator>
      <pubDate>Fri, 30 Oct 2026 02:01:24 +0000</pubDate>
      <link>https://dev.to/aicodeops_dev/free-forever-for-open-source-why-were-giving-ai-codeops-to-maintainers-3d3f</link>
      <guid>https://dev.to/aicodeops_dev/free-forever-for-open-source-why-were-giving-ai-codeops-to-maintainers-3d3f</guid>
      <description>&lt;p&gt;&lt;em&gt;Maintainers carry a lot of the software world. If AI agents are going to touch their projects, they should do it behind the same quality gates as everyone else, at no cost.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Open-source maintainers are in an odd spot right now. AI tools make it easy for anyone to send a pull request, so the volume of contributions goes up. The time a maintainer has to review them does not.&lt;/p&gt;

&lt;p&gt;The usual answers are to review faster or to say no more often. Neither scales. What does scale is making every change prove itself before a person spends time on it.&lt;/p&gt;

&lt;p&gt;That's the idea behind AI CodeOps, and it's why we're making it &lt;strong&gt;free forever for non-commercial open-source projects&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What maintainers get
&lt;/h2&gt;

&lt;p&gt;The open source plan isn't a trial. Approved projects get, at no cost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Higher limits than the free plan:&lt;/strong&gt; more workspaces, seats and AI models&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;300 sessions a month&lt;/strong&gt; on the platform's models. Past that, you can keep going on your own model provider key, or wait for the monthly reset&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The release-gate badge&lt;/strong&gt; for your README, turned on for you&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A usage meter&lt;/strong&gt; in the console, so you always know where you stand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's the same product, with the same gates. Nothing is held back for paying customers when it comes to what a change must pass before it merges.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the gate does for a project
&lt;/h2&gt;

&lt;p&gt;Every AI change in AI CodeOps waits at a release gate. It becomes a pull request only when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Your own test suite passed&lt;/strong&gt; in a sandbox, on that exact version of the change&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The AI review of the real diff&lt;/strong&gt; has no open high or critical findings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A person approved it.&lt;/strong&gt; The person who started the session can't cast the approving vote while someone else in the workspace can&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any check errors, the gate fails closed. For a maintainer, that means the pull request in your queue has already been tested and reviewed, and someone has looked at it.&lt;/p&gt;

&lt;p&gt;Each change also carries a signed evidence pack: the task, the models used, the findings, the test runs and the approvals. When someone asks how a change got in, there's a record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Git host, your server
&lt;/h2&gt;

&lt;p&gt;A lot of open source doesn't live on GitHub. AI CodeOps works with GitHub, GitLab, Bitbucket, Gitea and Forgejo, including self-hosted GitLab, Gitea and Forgejo servers connected with a personal access token. Branches and pull requests stay on your server.&lt;/p&gt;

&lt;p&gt;One honest note: if your project is on &lt;strong&gt;Codeberg&lt;/strong&gt;, read its Terms of Use first. Codeberg doesn't allow projects that mostly consist of code written by generative AI tools. The connection works, but the rules are Codeberg's to set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who qualifies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;public repository&lt;/strong&gt; under an &lt;strong&gt;OSI-approved license&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;non-commercial&lt;/strong&gt; project: not sold, not the core of a paid product, and not run by a company to make money from it. Community projects, libraries and tools qualify, even with sponsors or donations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approved by application.&lt;/strong&gt; We read every one, usually within a few working days, and email you either way&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to apply
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign up at &lt;a href="https://aicodeops.dev" rel="noopener noreferrer"&gt;aicodeops.dev&lt;/a&gt; with the email you'll use for the project. Approval moves that account's own organization onto the open source plan&lt;/li&gt;
&lt;li&gt;Fill in the short form at &lt;strong&gt;&lt;a href="https://aicodeops.dev/pricing/open-source" rel="noopener noreferrer"&gt;aicodeops.dev/pricing/open-source&lt;/a&gt;&lt;/strong&gt;: email, repository URL, maintainer's GitHub username, license, and a few words about the project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And as with every plan: AI CodeOps doesn't use your code, prompts or outputs to train AI models.&lt;/p&gt;




&lt;p&gt;If you maintain something people depend on, we'd like to help you ship changes you can trust. Apply here: &lt;a href="https://aicodeops.dev/pricing/open-source" rel="noopener noreferrer"&gt;aicodeops.dev/pricing/open-source&lt;/a&gt;. Program updates are posted at &lt;a href="https://github.com/aicodeops-dev/announcements/discussions" rel="noopener noreferrer"&gt;github.com/aicodeops-dev/announcements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance and edited by the AI CodeOps team.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ai</category>
      <category>devops</category>
      <category>github</category>
    </item>
    <item>
      <title>AI CodeOps vs GitHub Copilot's Coding Agent: When Each One Fits</title>
      <dc:creator>AI CodeOps</dc:creator>
      <pubDate>Fri, 30 Oct 2026 01:43:11 +0000</pubDate>
      <link>https://dev.to/aicodeops_dev/ai-codeops-vs-github-copilots-coding-agent-when-each-one-fits-1n2b</link>
      <guid>https://dev.to/aicodeops_dev/ai-codeops-vs-github-copilots-coding-agent-when-each-one-fits-1n2b</guid>
      <description>&lt;p&gt;&lt;em&gt;A fair comparison as of October 2026, including when Copilot is the better choice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;GitHub Copilot's coding agent (GitHub's docs now call it the Copilot cloud agent) and AI CodeOps solve a similar problem. You hand over a task, the work happens in the cloud, and you get back a pull request. The differences are in where they work, how changes are gated, and what you pay.&lt;/p&gt;

&lt;p&gt;This comparison uses GitHub's own documentation for the Copilot facts, as of October 2026. It's about the coding agent, not Copilot code review, which is a separate feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Copilot agent does
&lt;/h2&gt;

&lt;p&gt;According to GitHub's docs, the agent can research a repository, plan changes and implement them in the background, in a temporary cloud environment where it can run tests and linters. You can start it from an issue, a pull request, a chat or the agents panel. It creates a branch, pushes commits and opens a pull request.&lt;/p&gt;

&lt;p&gt;GitHub builds solid safeguards around it. The person who asked for the pull request can't approve it. The agent can't approve or merge, and it can only push to its own branch. By default, workflows don't run until a person has reviewed its code.&lt;/p&gt;

&lt;p&gt;Its documented limits: it works only with repositories hosted on GitHub, it works on one branch and opens one pull request per task, and each session runs for at most 59 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI CodeOps does
&lt;/h2&gt;

&lt;p&gt;AI CodeOps runs AI software-engineering sessions in your browser. Specialised agents (architect, builder, reviewer, tester, security auditor and others) plan the task, write the change, run your tests and review the result. The change then waits at a release gate until your tests pass, the AI review is clear and a person approves it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Copilot coding agent&lt;/th&gt;
&lt;th&gt;AI CodeOps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Git hosts&lt;/td&gt;
&lt;td&gt;Repositories hosted on GitHub&lt;/td&gt;
&lt;td&gt;GitHub, GitLab, Bitbucket, Gitea, Forgejo (incl. self-hosted)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approvals&lt;/td&gt;
&lt;td&gt;Requester can't approve; agent can't approve or merge&lt;/td&gt;
&lt;td&gt;Session starter can't cast the approving vote when another approver exists; policies can require two&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gate&lt;/td&gt;
&lt;td&gt;Your branch protection and required checks&lt;/td&gt;
&lt;td&gt;Built-in gate combining tests, review findings and approvals; fails closed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evidence&lt;/td&gt;
&lt;td&gt;GitHub history&lt;/td&gt;
&lt;td&gt;Signed evidence pack per change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Individual pricing&lt;/td&gt;
&lt;td&gt;Copilot Pro $10/mo, Pro+ $39/mo, Max $100/mo (not in Free)&lt;/td&gt;
&lt;td&gt;Free during the open beta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Org pricing&lt;/td&gt;
&lt;td&gt;Business $19/seat, Enterprise $39/seat; admin must enable the agent&lt;/td&gt;
&lt;td&gt;Enterprise per seat, through sales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where it runs&lt;/td&gt;
&lt;td&gt;GitHub.com, supported IDEs, CLI&lt;/td&gt;
&lt;td&gt;Browser only (no IDE extension or CLI)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When Copilot is the better choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your code is all on GitHub and you already pay for Copilot.&lt;/li&gt;
&lt;li&gt;You want the smallest change to your tooling, with no second product to adopt.&lt;/li&gt;
&lt;li&gt;You like GitHub's default safeguards on agent pull requests.&lt;/li&gt;
&lt;li&gt;Your developers already use Copilot in the editor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When AI CodeOps fits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your code lives on GitLab, Bitbucket, Gitea or Forgejo, or across several hosts.&lt;/li&gt;
&lt;li&gt;You want several agents to review each change before a person sees it.&lt;/li&gt;
&lt;li&gt;You want one gate that covers tests, findings and approvals together, with signed evidence for each change.&lt;/li&gt;
&lt;li&gt;You need spend control: caps per workspace and per workflow, cost per session, model tiers, or your own provider key.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to decide
&lt;/h2&gt;

&lt;p&gt;If your code is on GitHub and Copilot is already in place, try the Copilot agent first, since it costs you the least to adopt. If you need other Git hosts, a gate with signed evidence, or per-workflow spend caps, run AI CodeOps on the same repository and compare.&lt;/p&gt;




&lt;p&gt;Full comparison with sources: &lt;a href="https://aicodeops.dev/compare/aicodeops-vs-copilot-agent" rel="noopener noreferrer"&gt;aicodeops.dev/compare/aicodeops-vs-copilot-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💚 AI CodeOps is &lt;strong&gt;free forever for non-commercial open-source projects&lt;/strong&gt;: &lt;a href="https://aicodeops.dev/pricing/open-source" rel="noopener noreferrer"&gt;apply here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@aicodeops/ai-codeops-vs-github-copilots-coding-agent-when-each-one-fits-3fb7583efcc0" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. Drafted with AI assistance and edited by the AI CodeOps team. Copilot details are from GitHub's documentation as of October 2026 and may change.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>github</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Who Approves the AI's Code?</title>
      <dc:creator>AI CodeOps</dc:creator>
      <pubDate>Thu, 29 Oct 2026 21:49:04 +0000</pubDate>
      <link>https://dev.to/aicodeops_dev/who-approves-the-ais-code-1kd6</link>
      <guid>https://dev.to/aicodeops_dev/who-approves-the-ais-code-1kd6</guid>
      <description>&lt;p&gt;&lt;em&gt;When an AI agent writes the code, who reviews it? The rules that keep "approved" meaning something.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the first post in this series, &lt;a href="https://dev.to/aicodeops_dev/nothing-should-merge-on-an-ais-word-23b8"&gt;Nothing Should Merge on an AI's Word&lt;/a&gt;, one of the gate's checks was "a person approves it." That sounds like the easy part. It's not.&lt;/p&gt;

&lt;p&gt;With human-written code, the author and the reviewer are obviously different people. With AI-written code, the line blurs. Someone writes a prompt, an agent writes the change, and the same someone looks at the diff and clicks approve. Technically a human approved it. In practice, nobody but the requester ever looked.&lt;/p&gt;

&lt;p&gt;That's the problem this post is about: keeping approval a real second opinion when the "author" is an agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompter is the author
&lt;/h2&gt;

&lt;p&gt;The person who starts an AI session is the closest thing that change has to an author. They chose the task, steered the agent, and probably accepted its first plan. They're also the person most likely to approve it quickly, because it does what they asked.&lt;/p&gt;

&lt;p&gt;So the rule should be the same as for human code: &lt;strong&gt;the person who launched the session can't be the one who approves it&lt;/strong&gt;, as long as someone else can.&lt;/p&gt;

&lt;p&gt;In AI CodeOps that's built in. A code-change review needs one approval from someone other than the person who launched the session. That makes it a two-person rule whenever a second approver exists. The launcher can still reject their own change, because stopping something never needs a second opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't lock out the solo developer
&lt;/h2&gt;

&lt;p&gt;A strict two-person rule has an obvious failure: a team of one can never ship anything. Small teams then switch the rule off entirely, and it never comes back on.&lt;/p&gt;

&lt;p&gt;The better rule is conditional. The launcher can't approve &lt;strong&gt;when anyone else in the workspace can&lt;/strong&gt;. A solo workspace can still approve its own work. The moment a second approver joins, the two-person rule applies on its own, with no settings to remember.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five rules that keep approval honest
&lt;/h2&gt;

&lt;p&gt;Separation of duties is the headline, but a few smaller rules matter just as much.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Editing after approval resets it.&lt;/strong&gt; If the change is edited after someone approved it, the approval goes back to pending. Otherwise "approve now, fix it up later" turns an approval into a blank check. This is the same idea as the tested-version rule from the first post: approval applies to a version, not to a pull request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. One reject ends it.&lt;/strong&gt; A single rejection closes the request. Another person's approval doesn't reopen it. If one reviewer saw a real problem, three approvals from people who didn't shouldn't outvote them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. A reject needs a reason.&lt;/strong&gt; Approvals take an optional note. Rejections require a reason. A bare "no" teaches the requester nothing and tends to get worked around.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. People are counted, not clicks.&lt;/strong&gt; Votes are counted per distinct person, and voting again replaces your earlier vote. Nobody gets two votes by clicking twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Approvals expire.&lt;/strong&gt; A code-change review expires after 7 days. A week-old approval was given against a codebase that has since moved, so it's asked for again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approval is one check, not the only one
&lt;/h2&gt;

&lt;p&gt;Approval doesn't open the pull request on its own. The pull request opens only if the quality gate also passes: tests ran on this version, no high or critical findings are open, and policy allows it.&lt;/p&gt;

&lt;p&gt;That separation matters. A reviewer shouldn't have to re-run the tests in their head or re-check every file path against policy. The gate handles evidence. The person answers the question only a person can answer: is this the change we actually want?&lt;/p&gt;

&lt;h2&gt;
  
  
  Policies decide when to ask
&lt;/h2&gt;

&lt;p&gt;Not every action needs a human, and asking for everything trains people to click "approve" without reading. Policies let you decide where approval is worth the interruption.&lt;/p&gt;

&lt;p&gt;Each policy rule is &lt;strong&gt;allow&lt;/strong&gt;, &lt;strong&gt;ask&lt;/strong&gt; or &lt;strong&gt;deny&lt;/strong&gt;. When several rules match, the strictest one wins: deny beats ask, and ask beats allow.&lt;/p&gt;

&lt;p&gt;A few patterns that work well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protected paths.&lt;/strong&gt; Rules on file patterns, such as &lt;code&gt;infra/**&lt;/code&gt; or anything under auth and payments, are checked when the pull request opens, against every file the change touches. The agent can still write the change; it just can't ship it without passing the rule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask before starting risky work.&lt;/strong&gt; Dispatching certain workflows or agents can be set to ask, so a person signs off before the session even starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some actions can't wait.&lt;/strong&gt; Running a shell command, calling an MCP tool or deploying can't pause for a person, so those can only be allowed or denied, never "ask." That's a useful constraint: it forces you to decide ahead of time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try rules in log-only mode first.&lt;/strong&gt; A rule set to log only records what it would have done without blocking anything. Run it for a week, check what it would have stopped, and then enforce it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every policy change is saved as a new version with an audit entry, so "who loosened this rule?" always has an answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approvals belong in the record
&lt;/h2&gt;

&lt;p&gt;The last piece connects to the next post in this series. The approval, the list of people who were eligible to approve, and each vote with its time and note all go into the change's signed evidence pack. Months later, "who approved this?" isn't a Slack search. It's a field in a record you can verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The launcher doesn't approve.&lt;/strong&gt; Require someone other than the person who started the session, whenever someone else can.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep solo teams working.&lt;/strong&gt; Make the rule conditional instead of switching it off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approve versions, not pull requests.&lt;/strong&gt; Any edit after approval resets it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Let one "no" win, and make it explain itself.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask only where it matters.&lt;/strong&gt; Use protected paths and ask rules for risky areas, and try new rules in log-only mode first.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An approval is only worth something if the person giving it could have said no, and wasn't the one who asked for the change.&lt;/p&gt;




&lt;p&gt;AI CodeOps is free during the open beta and &lt;strong&gt;free forever for non-commercial open-source projects&lt;/strong&gt;. The full rules are in the &lt;a href="https://aicodeops.dev/docs/approvals-and-policies" rel="noopener noreferrer"&gt;approvals and policies docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance and edited by the AI CodeOps team.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>codereview</category>
      <category>security</category>
    </item>
    <item>
      <title>Your Merge Button Is the Real Quality Gate</title>
      <dc:creator>AI CodeOps</dc:creator>
      <pubDate>Thu, 29 Oct 2026 21:48:49 +0000</pubDate>
      <link>https://dev.to/aicodeops_dev/your-merge-button-is-the-real-quality-gate-11l3</link>
      <guid>https://dev.to/aicodeops_dev/your-merge-button-is-the-real-quality-gate-11l3</guid>
      <description>&lt;p&gt;&lt;em&gt;A release gate only works if the merge button has to ask it. Here's how to wire one into CI so it fails closed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the last post, &lt;a href="https://dev.to/aicodeops_dev/nothing-should-merge-on-an-ais-word-23b8"&gt;Nothing Should Merge on an AI's Word&lt;/a&gt;, I argued that AI-written code needs a gate between "the agent finished" and "this is a pull request," and that the gate should check evidence: a review that ran, tests that passed on this exact version, and a person who said yes.&lt;/p&gt;

&lt;p&gt;There's a hole in that picture. A gate inside one tool only covers changes made through that tool. Pull requests still get opened by hand, branches still get pushed, and the merge button on GitHub or GitLab doesn't know your AI platform exists. If the gate can be skipped by clicking somewhere else, it's not a gate.&lt;/p&gt;

&lt;p&gt;So the real question is: &lt;strong&gt;how do you make the merge itself ask for a verdict?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Put the check where the merge happens
&lt;/h2&gt;

&lt;p&gt;The answer is boring, which is a good sign: a CI job that asks the gate for a verdict on this pull request, and fails when the answer is no. Then you make that job a &lt;strong&gt;required status check&lt;/strong&gt; in branch protection.&lt;/p&gt;

&lt;p&gt;That second step is the one teams forget. A CI job that isn't required is a dashboard. It only becomes a gate when the merge button is greyed out until it passes.&lt;/p&gt;

&lt;p&gt;In AI CodeOps, the question goes to one endpoint, &lt;code&gt;POST /api/release/check&lt;/code&gt;, with a workspace API key. You send a pull request URL (or a commit SHA, at least 7 characters) and get back a verdict that covers every AI session that touched that change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allowed&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;summary&lt;/code&gt; and &lt;code&gt;reasons&lt;/code&gt;: plain-English explanations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blockingFindings&lt;/code&gt;, &lt;code&gt;testFailures&lt;/code&gt;, &lt;code&gt;coverageShortfall&lt;/code&gt;, &lt;code&gt;licenseViolations&lt;/code&gt;: the detail behind a deny&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;runsConsidered&lt;/code&gt;: which sessions the verdict was based on&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The trap: "200 OK" doesn't mean "allowed"
&lt;/h2&gt;

&lt;p&gt;Here's the detail that makes or breaks a CI gate. The endpoint returns &lt;strong&gt;HTTP 200 for both outcomes&lt;/strong&gt;. A denied change is a successful API call with &lt;code&gt;"allowed": false&lt;/code&gt; in the body.&lt;/p&gt;

&lt;p&gt;That means the most common way to write this check is wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Looks fine. Lets everything through.&lt;/span&gt;
curl &lt;span class="nt"&gt;-sf&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CONSOLE&lt;/span&gt;&lt;span class="s2"&gt;/api/release/check"&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;curl -f&lt;/code&gt; only fails on HTTP errors. A deny comes back as 200, so the step goes green and the change merges. That's a gate that fails open, which is the one thing a gate must never do.&lt;/p&gt;

&lt;p&gt;The fix is to read the body and treat anything other than an explicit &lt;code&gt;true&lt;/code&gt; as a no:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'.allowed == true'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;jq -e&lt;/code&gt; exits non-zero when the result is &lt;code&gt;false&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;, so a deny fails the job, and so does a missing or malformed field.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fail-closed GitHub Actions job
&lt;/h2&gt;

&lt;p&gt;Putting it together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ai-release-gate&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release-gate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ask the release gate for a verdict&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;WORKSPACE_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AICODEOPS_API_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;PR_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.pull_request.html_url }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;set -euo pipefail&lt;/span&gt;

          &lt;span class="s"&gt;body=$(jq -n --arg pr "$PR_URL" '{&lt;/span&gt;
            &lt;span class="s"&gt;pullRequestURL: $pr,&lt;/span&gt;
            &lt;span class="s"&gt;blockingSeverity: "medium",&lt;/span&gt;
            &lt;span class="s"&gt;minCoveragePct: 80,&lt;/span&gt;
            &lt;span class="s"&gt;blockOnInFlight: true&lt;/span&gt;
          &lt;span class="s"&gt;}')&lt;/span&gt;

          &lt;span class="s"&gt;resp=$(curl -sSf --retry 3 --retry-all-errors \&lt;/span&gt;
            &lt;span class="s"&gt;-X POST "https://console.aicodeops.dev/api/release/check" \&lt;/span&gt;
            &lt;span class="s"&gt;-H "Authorization: Bearer $WORKSPACE_API_KEY" \&lt;/span&gt;
            &lt;span class="s"&gt;-H "Content-Type: application/json" \&lt;/span&gt;
            &lt;span class="s"&gt;-d "$body")&lt;/span&gt;

          &lt;span class="s"&gt;echo "$resp" | jq -r '.summary'&lt;/span&gt;
          &lt;span class="s"&gt;echo "$resp" | jq '.reasons'&lt;/span&gt;

          &lt;span class="s"&gt;# Anything other than an explicit "true" fails the job.&lt;/span&gt;
          &lt;span class="s"&gt;echo "$resp" | jq -e '.allowed == true' &amp;gt; /dev/null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every way this can go wrong ends in a red check:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gate says no&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;allowed&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;jq -e&lt;/code&gt; fails the job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gate couldn't evaluate&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;allowed: false&lt;/code&gt;, summary "Evaluation failed."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No AI session touched this change&lt;/td&gt;
&lt;td&gt;Denied: there's nothing to judge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bad or missing API key (401/403)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;curl -f&lt;/code&gt; fails the job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invalid request (400)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;curl -f&lt;/code&gt; fails the job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limited (429, 60 checks/min per workspace)&lt;/td&gt;
&lt;td&gt;curl retries, then fails if it still can't get through&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network down, API unreachable&lt;/td&gt;
&lt;td&gt;curl retries, then fails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response isn't valid JSON&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;jq&lt;/code&gt; errors, &lt;code&gt;set -e&lt;/code&gt; fails the job&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nothing on that list ends in a green check. That's the property you want.&lt;/p&gt;

&lt;p&gt;Two practical notes. The key only needs the &lt;code&gt;workspace:read&lt;/code&gt; permission, so don't hand CI a more powerful one. And use the same host you open the console on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tune the bar per pipeline
&lt;/h2&gt;

&lt;p&gt;The defaults block on open high and critical findings and on failing tests. CI is where you can be stricter, because different branches deserve different bars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;blockingSeverity: "medium"&lt;/code&gt;&lt;/strong&gt; blocks on medium findings too. Reasonable for anything that touches auth, payments, or infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;minCoveragePct&lt;/code&gt;&lt;/strong&gt; sets a coverage floor for the latest run that reported coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;requiredWorkflows&lt;/code&gt;&lt;/strong&gt; lists workflows that must have completed on this change, such as a security audit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;disallowedLicenses&lt;/code&gt;&lt;/strong&gt; checks the project's SBOM for licenses you can't ship.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;requireDeployedTo: "staging"&lt;/code&gt;&lt;/strong&gt; denies until the change has been deployed to staging. Useful on the job that promotes to production, not on every pull request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;blockOnInFlight: true&lt;/code&gt;&lt;/strong&gt; denies while a session for the change is still running, so nobody merges halfway through a fix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gate looks back 14 days by default (&lt;code&gt;lookbackMs&lt;/code&gt; changes that). An old session isn't silently reused forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then keep the receipt
&lt;/h2&gt;

&lt;p&gt;The gate decides whether a change ships. The evidence pack is how you prove later why it did.&lt;/p&gt;

&lt;p&gt;Every change gets a signed pack: the task and the models used, each run with its tokens and cost, review findings and how they were triaged, test results and coverage, policy decisions, who was eligible to approve and how each person voted, and the pull request and deployment it ended up in. The code itself isn't included. Instead the pack carries a SHA-256 hash of the diff, so you can match it against the pull request.&lt;/p&gt;

&lt;p&gt;The part I like is that you don't have to trust the platform to check it. Packs are signed with Ed25519 over canonical JSON, and the public keys are published at &lt;code&gt;/api/evidence?action=keys&lt;/code&gt;. You can verify a pack in the browser at &lt;a href="https://aicodeops.dev/evidence/verify" rel="noopener noreferrer"&gt;aicodeops.dev/evidence/verify&lt;/a&gt; without an account, or offline with Node's built-in &lt;code&gt;crypto&lt;/code&gt; module. Keep a copy of the keys file next to your audit records, and verification doesn't depend on the vendor still being reachable in three years.&lt;/p&gt;

&lt;p&gt;Retired keys stop signing new packs but are never deleted, so old packs keep verifying.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;p&gt;If you're adding AI agents to a repository this quarter, here's the short version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gate the merge, not just the agent.&lt;/strong&gt; Run the verdict check in CI and make it a required status check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the verdict, not the status code.&lt;/strong&gt; &lt;code&gt;allowed == true&lt;/code&gt; or the job fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make every error a no.&lt;/strong&gt; Bad key, timeout, rate limit, unreadable response: all red.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raise the bar where it matters.&lt;/strong&gt; Stricter severity and coverage on sensitive paths, a staging requirement before production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep evidence you can verify yourself.&lt;/strong&gt; A signed record beats a chat log.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AI agents can write a lot of code. The merge button is where you decide how much of it you trust.&lt;/p&gt;




&lt;p&gt;AI CodeOps is free during the open beta and &lt;strong&gt;free forever for non-commercial open-source projects&lt;/strong&gt;. The full field list is in the &lt;a href="https://aicodeops.dev/docs/api" rel="noopener noreferrer"&gt;API docs&lt;/a&gt;, and the gate itself is described at &lt;a href="https://aicodeops.dev/product/quality-gates" rel="noopener noreferrer"&gt;aicodeops.dev/product/quality-gates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance and edited by the AI CodeOps team.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>cicd</category>
      <category>security</category>
    </item>
    <item>
      <title>An Audit Trail You Don't Have to Take on Trust</title>
      <dc:creator>AI CodeOps</dc:creator>
      <pubDate>Thu, 29 Oct 2026 21:48:00 +0000</pubDate>
      <link>https://dev.to/aicodeops_dev/an-audit-trail-you-dont-have-to-take-on-trust-44cn</link>
      <guid>https://dev.to/aicodeops_dev/an-audit-trail-you-dont-have-to-take-on-trust-44cn</guid>
      <description>&lt;p&gt;&lt;em&gt;"The AI wrote it" isn't an answer. A signed record of how each change shipped is, as long as you can check it without trusting the vendor.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the last post in a short series. The first, &lt;a href="https://dev.to/aicodeops_dev/nothing-should-merge-on-an-ais-word-23b8"&gt;Nothing Should Merge on an AI's Word&lt;/a&gt;, argued for a gate between "the agent finished" and "this is a pull request." The second and third covered &lt;a href="https://dev.to/aicodeops_dev/your-merge-button-is-the-real-quality-gate-11l3"&gt;wiring that gate into CI&lt;/a&gt; and &lt;a href="https://dev.to/aicodeops_dev/who-approves-the-ais-code-1kd6"&gt;keeping approvals honest&lt;/a&gt;. This one covers what's left after a change ships: the record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six months later
&lt;/h2&gt;

&lt;p&gt;A bug reaches production. Someone runs &lt;code&gt;git blame&lt;/code&gt; and finds the commit. It came from an AI session in the spring.&lt;/p&gt;

&lt;p&gt;Now the questions start. What was the agent asked to do? Which model wrote it? Did the review flag anything, and if so, who decided it was fine? Did the tests actually run on this version? Who approved it?&lt;/p&gt;

&lt;p&gt;For human-written code you'd ask the author. For AI-written code there's no author to ask, and the chat history is probably gone. If the answers aren't written down somewhere durable, they're lost.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a useful record contains
&lt;/h2&gt;

&lt;p&gt;A good record answers those questions without needing anyone's memory. In AI CodeOps, every change gets an &lt;strong&gt;evidence pack&lt;/strong&gt; that covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The task:&lt;/strong&gt; the prompt, the model and provider, and the context files the agent was given.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The runs:&lt;/strong&gt; each session and follow-up run, with status, timings, tokens, cost, and which provider and model handled each agent step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The result:&lt;/strong&gt; the summary, the changed files, and a SHA-256 hash of the diff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approvals:&lt;/strong&gt; who was eligible to approve, and each vote with its time and note.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy decisions:&lt;/strong&gt; every allow, deny or ask made during the change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Findings and tests:&lt;/strong&gt; review findings and how each was triaged, plus test results and coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivery:&lt;/strong&gt; the pull request, the deployment, and any linked incident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The audit trail:&lt;/strong&gt; the related audit log entries, and the email address behind each account ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice what's missing: the code itself. The pack carries a hash of the diff, not the diff. You match the hash against the pull request, which keeps source code out of an artifact you might hand to an auditor.&lt;/p&gt;

&lt;h2&gt;
  
  
  A record you can edit isn't evidence
&lt;/h2&gt;

&lt;p&gt;A log stored in a database the vendor controls proves very little. Anyone with write access, including the vendor, could change it after the fact. For a record to count as evidence, you need to be able to tell whether it was altered.&lt;/p&gt;

&lt;p&gt;That's what the signature is for. Each pack is signed with &lt;strong&gt;Ed25519&lt;/strong&gt; over a canonical form of its contents: the JSON payload with object keys sorted at every level and no whitespace. Canonical form matters because the same data can be serialised many ways. Without it, re-saving a file in an editor could break a valid signature.&lt;/p&gt;

&lt;p&gt;If anyone changes a single field, whether it's a vote, a finding's triage status or a model name, the signature no longer matches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't trust the verifier either
&lt;/h2&gt;

&lt;p&gt;A signature is only useful if the check doesn't depend on the party that signed it. "Our server says the pack is valid" proves nothing if the server is the thing in question.&lt;/p&gt;

&lt;p&gt;So there are two ways to verify a pack, and the second needs no trust in the platform at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the browser.&lt;/strong&gt; Open &lt;a href="https://aicodeops.dev/evidence/verify" rel="noopener noreferrer"&gt;aicodeops.dev/evidence/verify&lt;/a&gt; and pick the file. No account is needed. It tells you whether the signature matches and which key signed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offline, on your own machine.&lt;/strong&gt; First fetch the public keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; keys.json &lt;span class="s2"&gt;"https://console.aicodeops.dev/api/evidence?action=keys"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run a short Node.js script. It uses only Node's built-in &lt;code&gt;crypto&lt;/code&gt; module and needs Node 20 or later. The script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads the pack and &lt;code&gt;keys.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finds the public key whose &lt;code&gt;kid&lt;/code&gt; matches the pack's &lt;code&gt;signature.kid&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Rebuilds the canonical JSON of the pack's &lt;code&gt;payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Checks the Ed25519 signature against it.&lt;/li&gt;
&lt;li&gt;Prints &lt;code&gt;VERIFIED&lt;/code&gt;, or &lt;code&gt;NOT VERIFIED: the pack was altered&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full script is in the &lt;a href="https://aicodeops.dev/docs/evidence-packs" rel="noopener noreferrer"&gt;evidence pack docs&lt;/a&gt;, under "Verify a pack offline." It's short enough to read in a minute, which is the point: you should be able to see exactly what it checks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node verify-evidence.mjs evidence-chg_....json keys.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Keep the keys with the records
&lt;/h2&gt;

&lt;p&gt;One step people skip: &lt;strong&gt;save a copy of &lt;code&gt;keys.json&lt;/code&gt; next to your audit records.&lt;/strong&gt; If you only ever fetch keys live, verification depends on the platform still being online, and still serving the same keys, years from now.&lt;/p&gt;

&lt;p&gt;Keys are never deleted. A retired key stops signing new packs, but every pack it already signed keeps verifying. Still, an auditor shouldn't have to take that on faith. A local copy of the keys file turns "the vendor says so" into "the maths says so."&lt;/p&gt;

&lt;h2&gt;
  
  
  Who can download a pack
&lt;/h2&gt;

&lt;p&gt;Evidence packs include people's email addresses and the full history of a change, so access is limited. Only owners, admins and security admins can download them, from &lt;strong&gt;Changes&lt;/strong&gt;, then the change, then &lt;strong&gt;Download evidence pack&lt;/strong&gt;. Each download is itself recorded in the audit log.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Record the decisions, not just the code.&lt;/strong&gt; Task, models, findings, triage, tests, approvals, policy decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sign the record.&lt;/strong&gt; An unsigned log is a claim, not evidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use canonical form.&lt;/strong&gt; So the same data always produces the same signature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify without the vendor.&lt;/strong&gt; Public keys plus a script you can read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the keys.&lt;/strong&gt; Store &lt;code&gt;keys.json&lt;/code&gt; with your audit records.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Across the series, the idea has been the same: AI agents can do the work, but trust comes from evidence. Tests that ran on this version, a review that read the real diff, a second person who said yes, and a record of all of it that anyone can check.&lt;/p&gt;




&lt;p&gt;AI CodeOps is free during the open beta and &lt;strong&gt;free forever for non-commercial open-source projects&lt;/strong&gt;. Learn how evidence packs work in the &lt;a href="https://aicodeops.dev/docs/evidence-packs" rel="noopener noreferrer"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance and edited by the AI CodeOps team.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>security</category>
      <category>compliance</category>
    </item>
    <item>
      <title>Nothing Should Merge on an AI's Word</title>
      <dc:creator>AI CodeOps</dc:creator>
      <pubDate>Thu, 29 Oct 2026 21:35:36 +0000</pubDate>
      <link>https://dev.to/aicodeops_dev/nothing-should-merge-on-an-ais-word-23b8</link>
      <guid>https://dev.to/aicodeops_dev/nothing-should-merge-on-an-ais-word-23b8</guid>
      <description>&lt;p&gt;&lt;em&gt;Why AI-written code needs quality gates that fail closed, and what a good one checks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI coding agents are fast now. They can read a repository, plan a change, write it, and open a pull request in minutes. That speed is real, but it creates a quiet problem: the volume of changes grows faster than a team's ability to check them.&lt;/p&gt;

&lt;p&gt;When an agent says "done," teams tend to take one of two shortcuts. Either they trust the agent's summary of its own work, or they skim a diff that is too large to read carefully. Both mean the bar for AI-written code ends up lower than the bar for human-written code. It should be the same, or higher.&lt;/p&gt;

&lt;p&gt;The fix isn't to slow agents down. It's to put a gate between "the agent finished" and "this is a pull request," and to make that gate check evidence, not opinions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a quality gate should check
&lt;/h2&gt;

&lt;p&gt;At AI CodeOps, every AI change waits at a release gate. It opens a pull request only when all of these hold:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The review actually ran.&lt;/strong&gt; A review step reads the real diff and records structured findings. If the review couldn't finish, the change is held. A missing review never counts as a pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No serious findings are open.&lt;/strong&gt; A high or critical finding that is still open, acknowledged or in progress blocks the change. To clear it, you fix it or triage it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your tests don't fail.&lt;/strong&gt; The project's own test suite runs against the change in a sandbox. The agent may plan tests, but only a real test run counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The tested version is current.&lt;/strong&gt; If someone edits the change after the tests ran, the old result no longer counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A person approves it.&lt;/strong&gt; The person who started the session can't cast the approving vote while someone else in the workspace can. Editing the code after approval resets it to pending.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace policy allows it.&lt;/strong&gt; The repository and every changed file are checked against your policies before the pull request opens.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Fail closed, not open
&lt;/h2&gt;

&lt;p&gt;The most important property of a gate is what it does when something goes wrong. If a check errors, the safe answer is "no." A gate that lets changes through when the reviewer times out or the test runner crashes isn't a gate. It's a suggestion.&lt;/p&gt;

&lt;p&gt;The same goes for missing evidence. If the gate can't find a session for a change, it has nothing to judge, so it denies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gating merges outside the platform
&lt;/h2&gt;

&lt;p&gt;A gate inside one tool only covers changes made through that tool. Someone can still merge directly on GitHub or GitLab. To cover that path, your CI can ask the gate for a verdict through an API, with a pull request URL or commit SHA, and fail the job when the answer is no. You can also make CI stricter per pipeline: block on medium findings, set a coverage floor, or require a change to be deployed to staging first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep a record of how each change shipped
&lt;/h2&gt;

&lt;p&gt;When something breaks in production, "the AI wrote it" isn't an answer. Each change should leave a trail: the task, the models used, the findings, the test runs, who approved it and how each person voted. In AI CodeOps that trail is a signed evidence pack that anyone can verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bar should not move
&lt;/h2&gt;

&lt;p&gt;AI agents are a real productivity gain. The way to keep that gain is to hold their work to the same standard as everyone else's: tests that ran on this exact version, a review that read the real diff, and a person who said yes.&lt;/p&gt;




&lt;p&gt;AI CodeOps is free during the open beta and &lt;strong&gt;free forever for non-commercial open-source projects&lt;/strong&gt;. Learn how the gate works at &lt;a href="https://aicodeops.dev/product/quality-gates" rel="noopener noreferrer"&gt;aicodeops.dev/product/quality-gates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@aicodeops/nothing-should-merge-on-an-ais-word-ffed3cf5c949" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. Drafted with AI assistance and edited by the AI CodeOps team.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>codereview</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
