<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Josip Ravas</title><description>Essays on infrastructure, CI/CD, and supply-chain security for agentic development.</description><link>https://jravas.dev/</link><item><title>Your AI coding rules are an unsigned dependency</title><link>https://jravas.dev/writing/ai-rules-unsigned-dependency/</link><guid isPermaLink="true">https://jravas.dev/writing/ai-rules-unsigned-dependency/</guid><description>Every team using coding agents now ships a set of rule files that steer them. Those files have no version, no checksum, and no owner. Here is what that costs, and what it would take to fix.</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every team I know running Cursor, Claude Code or Copilot has some version
of the same set of files. &lt;code&gt;AGENTS.md&lt;/code&gt; at the root. A &lt;code&gt;.cursor/rules/&lt;/code&gt;
directory. &lt;code&gt;CLAUDE.md&lt;/code&gt;. Maybe &lt;code&gt;.github/instructions/&lt;/code&gt; if they are on
Copilot. Different names, same job: tell the agent how we work here.&lt;/p&gt;
&lt;p&gt;We have about ten repos at a 35 person shop, and all of them have these
files.&lt;/p&gt;
&lt;p&gt;Now go look at how those files got there. For us, for a long time: one
person wrote a good one, somebody else copied it into their repo, and
then both copies drifted. That was the entire distribution mechanism.
Copy paste, a gist, or a Slack message that said &quot;use this one&quot;.&lt;/p&gt;
&lt;p&gt;These files change the behaviour of a program that writes code, reads
your filesystem and runs shell commands. They are also the only input to
that process with no version, no checksum and no owner.&lt;/p&gt;
&lt;h2&gt;What they are missing&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;npm package&lt;/th&gt;
&lt;th&gt;rules file&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Version&lt;/td&gt;
&lt;td&gt;semver&lt;/td&gt;
&lt;td&gt;git history, if you are lucky&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Locking&lt;/td&gt;
&lt;td&gt;lockfile&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integrity&lt;/td&gt;
&lt;td&gt;hash in the lockfile&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provenance&lt;/td&gt;
&lt;td&gt;registry, signatures&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;dependencies vs devDependencies&lt;/td&gt;
&lt;td&gt;everyone gets everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm i pkg@1.2.3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We spent fifteen years getting those properties for JavaScript
dependencies. Lockfiles, integrity hashes, provenance, &lt;code&gt;npm audit&lt;/code&gt;. Then
we introduced a new input that steers the thing writing the code, and
shipped it as a markdown file somebody pasted in.&lt;/p&gt;
&lt;h2&gt;How it actually breaks&lt;/h2&gt;
&lt;p&gt;None of this is hypothetical. Here is what we hit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Drift.&lt;/strong&gt; Two repos have copies of the same rules. Six months later
they are not the same file, and nobody knows which one is current. The
agent behaves differently in each repo. It reads like model
nondeterminism. It is not. It is a diff nobody looked at.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version mismatch.&lt;/strong&gt; This is the one I care about most and see
discussed least. We migrated a project from Payload 2 to Payload 3, and
our rules still had Payload 2 patterns in them. A stale rule does not
make the agent uninformed. It makes it confidently wrong. It generates
code against an API that no longer exists, in exactly the same tone it
uses when it is right. A human reading old documentation sees the
version at the top of the page. The agent has no version to see.&lt;/p&gt;
&lt;p&gt;The general shape: a rule is only correct for a range of framework
versions, and nothing anywhere expresses that range.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Onboarding.&lt;/strong&gt; New developer clones a repo and gets whatever rules
existed the last time somebody copied them by hand. Which might have
been March.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No bisect.&lt;/strong&gt; Agent output gets worse over a month. Did the model
change? Did somebody edit a rule? Did a rule get pasted in from another
repo? You cannot answer any of that, because there is no version to
compare against and no changelog to read.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Roles.&lt;/strong&gt; Every engineer gets every rule. Our backend people receive
frontend accessibility rules they will never use. That is not a security
problem, it is a context budget problem, and it makes the rules that do
matter harder to weight.&lt;/p&gt;
&lt;h2&gt;The part I find uncomfortable&lt;/h2&gt;
&lt;p&gt;A rules file is not documentation. It is configuration that steers a
process with filesystem access and a shell.&lt;/p&gt;
&lt;p&gt;That puts it closer to a build script than a README, and we treat it
like a README.&lt;/p&gt;
&lt;p&gt;People pull rules from public collections. awesome-cursorrules,
cursor.directory, gists, blog posts. The instinct is good, sharing what
works is how any of this improves. But look at the mechanism: curl a
file written by a stranger into a directory that instructs your agent.&lt;/p&gt;
&lt;p&gt;I am not claiming there has been an incident. I do not know of one. What
I know is that if a rule in a repo you copied from were edited tomorrow
to say something quietly wrong, or quietly hostile, nothing in your
pipeline would flag it. There is no hash to compare. There is no version
you pinned. Most teams would not notice for months, because nobody
reviews a markdown file the way they review a dependency bump.&lt;/p&gt;
&lt;p&gt;That gap is not exotic. It is the gap npm had before lockfiles, and we
know how that one went.&lt;/p&gt;
&lt;h2&gt;What it would take&lt;/h2&gt;
&lt;p&gt;None of this is novel. It is what we already do for every other
dependency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Versions and a lockfile.&lt;/strong&gt; Rules get semver. You depend on a range,
the resolution gets locked, installs are reproducible. The file format
does not matter. The property does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integrity.&lt;/strong&gt; A hash in the lockfile, verified on every install. If the
content changed, the install fails.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Provenance.&lt;/strong&gt; The registry signs its metadata. The client pins the
registry host, so a compromised metadata response cannot redirect the
download somewhere else. This is the boring part, and it is the part
that actually matters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scope.&lt;/strong&gt; A backend engineer does not receive frontend rules. A rule
written for Payload 2 does not reach a Payload 3 repo. Detect the stack
from &lt;code&gt;node_modules&lt;/code&gt;, fall back to the lockfile, fall back to
&lt;code&gt;package.json&lt;/code&gt;, route accordingly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An upgrade path.&lt;/strong&gt; An &lt;code&gt;update&lt;/code&gt; command, a changelog, and the ability
to go back to the version from before things got worse.&lt;/p&gt;
&lt;h2&gt;About AGENTS.md&lt;/h2&gt;
&lt;p&gt;The obvious objection is that this is already being solved. Cursor,
Claude, Copilot and Codex are converging on &lt;code&gt;AGENTS.md&lt;/code&gt;. One file, every
tool reads it.&lt;/p&gt;
&lt;p&gt;Good. That solves the format. It does not solve distribution.&lt;/p&gt;
&lt;p&gt;A shared file still has no version, no signature, no scoping and no
rollback. Everyone agreeing to read the same filename tells you nothing
about which copy of that file you have, where it came from, or whether
it is correct for the framework version in this repo.&lt;/p&gt;
&lt;p&gt;Format was the easier problem. It got solved first because it was the
one that hurt immediately.&lt;/p&gt;
&lt;h2&gt;What we built&lt;/h2&gt;
&lt;p&gt;We wrote &lt;a href=&quot;https://github.com/prototypdigital/bluetemberg&quot;&gt;Bluetemberg&lt;/a&gt;
because we needed this internally. Rule packs published to npm, resolved
through a lockfile, verified with SHA-512 and ECDSA registry signatures,
routed by role and by detected stack version, emitted to whichever agent
format a given repo uses. It is early, and it is one answer rather than
the answer.&lt;/p&gt;
&lt;p&gt;The requirements above matter more than the tool. If you solve them a
different way, I would like to read about it.&lt;/p&gt;
</content:encoded></item></channel></rss>