# Claude Code AGENTS.md Telemetry Bug: The Control Lesson [2026]

> Claude Code briefly gated local AGENTS.md instruction loading behind a remote flag that didn’t fetch with telemetry off. Here’s what broke, what was fixed, and the controls teams need so agents can’t silently ignore repo policy.

- Canonical: https://www.kunalganglani.com/blog/claude-code-agents-md-telemetry
- Author: Kunal Ganglani
- Published: 2026-09-24 · Updated: 2026-09-24
- Category: Cybersecurity · Tags: claude-code, ai-coding, telemetry, agent-instructions, privacy

## TL;DR

Claude Code briefly had a weird bug: it only read a local file called AGENTS.md (project instructions) if telemetry or “nonessential traffic” was allowed. If you disabled telemetry for privacy, the file could be ignored with no warning. Anthropic says this was a rollout mistake and fixed it in version 2.1.281. The lesson is bigger than one bug: instruction loading for AI coding tools has to be predictable and auditable, especially in CI. Treat repo instructions like a safety policy. Add a canary test, pin tool versions, and require clear logs of which instruction files were actually applied.

Claude Code shipped `AGENTS.md` support in v2.1.277. On Sept 23, 2026, people tripped over an ugly edge case: if you disabled telemetry or “nonessential traffic,” Claude Code would quietly stop reading `AGENTS.md` because the loader was sitting behind a remote feature flag. Anthropic says it was fixed the same day in v2.1.281.

That’s the headline. The real lesson is nastier: **if instruction loading for an AI coding agent isn’t deterministic and auditable, you can’t trust outcomes in CI, regulated environments, or even your own laptop.** This is a perfect example of “privacy mode” accidentally becoming “different product mode.”

I’m going to use the Claude Code `AGENTS.md` telemetry incident to talk about instruction loading like a security boundary. What got gated. How to reproduce it. What Claude Code Mods are actually doing. What gets logged. Where `AGENTS.md` still differs from `CLAUDE.md`. And the controls I’d want in place before I let any agent touch a production repo.

## What is Claude Code AGENTS.md telemetry?

Claude Code AGENTS.md telemetry is the (now-fixed) situation where Claude Code’s `AGENTS.md` instruction-file support depended on fetching a remote feature flag, and that fetch didn’t happen when telemetry or nonessential network traffic was disabled.

![Lines of colorful JavaScript code displayed on a dark screen](https://cdn.sanity.io/images/vzekdneq/production/a6a2eaa4485018ee5a90d7e2d3d75c7bd1c60b6d-1200x675.webp)

In practice, it meant `AGENTS.md` could be ignored with no warning, even though it’s a local file sitting in your working directory.

The original report is from [Przemek (pszypowicz)](https://blog.szypowi.cz/p/claude-code-reads-agents.md-only-when-telemetry-is-on/). The maintainer response is from [mpoteat](https://news.ycombinator.com/item?id=49814947) on Hacker News.

## Where the gate is (and why it matters)

Przemek dug into the Claude Code bundle and found that `AGENTS.md` support wasn’t a “baked into the engine forever” feature. It shipped as a built-in Mod called `agents-md`, and its availability was guarded by a remote feature flag (reported as `tengu_agents_md_mod`) with a fallback default of **off**.

![text](https://cdn.sanity.io/images/vzekdneq/production/5fbfbce1685d55eea085744d6ec2b12f39fe213e-1200x675.webp)

That architectural choice is the whole story: **a local instruction source was effectively behind a remote switch.** When Claude Code couldn’t fetch the flag, the Mod was “unavailable,” so `AGENTS.md` was never read.

From a security and reliability standpoint, this is indistinguishable from config drift:

- Your repo can contain a policy file.
- Your team can believe that policy is enforced.
- A network policy, a privacy setting, or a transient outage can flip behavior.
I’ve learned the hard way, running this site’s multi-agent publishing pipeline (261+ posts shipped at this point), that deterministic gates beat “best effort” behavior. A flaky, silent step early in the pipeline poisons everything downstream, and you only discover it after you’ve published bad output. Same vibe here. If the instruction loader is non-deterministic, agent behavior becomes non-deterministic, and you can’t debug it.

The maintainer explanation on HN is reasonable on its face. mpoteat said it was a rollout artifact: they wanted a remote kill-switch via feature flags in case the Mod broke something, and when telemetry is off “you don’t get those.” Fix shipped in **v2.1.281** “releasing today.”

I buy the intent. I don’t buy the default.

If you’re going to have a kill-switch, it needs to fail closed in a way that’s loud. Silent instruction bypass is the worst possible failure mode.

As a concrete timeline anchor:

- `AGENTS.md` support: **Claude Code v2.1.277**
- Incident reported publicly: **2026-09-23**
- Fix claimed shipped: **Claude Code v2.1.281** (same day as the HN thread)
## How I tested it (and how you should reproduce it in 60 seconds)

The reproduction is boring, which is what makes it great.

![black flat screen computer monitor](https://cdn.sanity.io/images/vzekdneq/production/d6b1a389b73322daec3f85511e11c1f992553c26-1200x675.webp)

Przemek’s approach is exactly how I test any instruction mechanism: **a canary word**.

1. Create an empty directory.
1. Add only an `AGENTS.md` file with a single unmistakable word.
1. Ask the agent to repeat the canary word **without reading files**.
One nuance from the report matters: Claude Code’s first session in a new configuration fetches the flag, and the second session uses it. So you run the prompt twice.

The report’s exact canary word example is “PERIWINKLE.” That’s deliberate. If you use something common like “banana,” you’ll talk yourself into believing the model “guessed it.”

If you’re doing this on a team, write down the test prompt and treat it like an invariant. Same mindset as [non-deterministic AI testing](/blog/non-deterministic-ai-testing). You don’t validate agent behavior with vibes. You validate it with harnesses.

Also: don’t confuse “it worked on my laptop yesterday” with “it works in CI.” Different environment variables, different network egress, different defaults. That’s where these bugs go to hide.

## What I measured (telemetry, env vars, and the ‘any value counts’ footgun)

The most uncomfortable part of the Claude Code `AGENTS.md` telemetry story is that users didn’t toggle a Claude Code UI setting and accidentally break stuff. They changed privacy-related environment variables. Functionality changed.

Per [Przemek (pszypowi.cz)](https://blog.szypowi.cz/p/claude-code-reads-agents.md-only-when-telemetry-is-on/), both of these blocked `AGENTS.md` loading:

- `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`
- `DISABLE_TELEMETRY=1`
Two details matter:

1. Setting either variable to `0` did **not** re-enable the feature in the report’s testing, because documentation treats **any set value** as enabled. That’s a classic “boolean env var” trap.
1. There was **no warning** printed when `AGENTS.md` was skipped. It just didn’t load.
That “any value counts” behavior is the kind of thing that makes CI incident response miserable. It shows up as “why did the agent refactor half the repo differently on Tuesday than Monday?” not as “instruction loader disabled.”

From the GitHub issue framing, this was explicitly called out as a privacy vs reliability tradeoff. The issue author [Prefee](https://github.com/anthropics/claude-code/issues/95690) described it as a local feature locked behind a remote switch.

If you want the broader framing: this is a supply-chain class problem, except instead of a malicious package update, it’s a remote config dependency silently changing local execution.

If you’re already thinking about [AI security](/pillars/ai-security-safety) and [AI agents](/pillars/ai-agents), this incident should slot neatly into your threat model alongside [prompt injection](/blog/repository-prompt-injection-coding-agent) and other “inputs that look local but act remote.”

## The workaround, plus what Claude Code Mods hook and log

Przemek found a workaround: override the env vars at the **session level** using `--settings`, clearing the telemetry-disabling variables for that invocation. In his testing, it worked from the **second session** onward.

I’m not going to paste the exact command here because people copy-paste blindly, and this is the point where you should slow down and decide what you want:

- If you disable telemetry for privacy/compliance reasons, clearing it per session is a policy violation.
- If you enable it just to get `AGENTS.md`, you’re accepting a dependency that should never have existed.
The better move is upgrading to the fixed version and then adding your own verification, which I’ll get to.

Now the actually interesting bit: the `AGENTS.md` loader is a Claude Code Mod. Anthropic has the implementation source-available in the repo under [Anthropic](https://github.com/anthropics/claude-code/tree/main/mods/agents-md).

That README is also where the “table stakes” details live. The stuff worth calling out:

### Setting the option

The Mod exposes an `instructionFiles` option with modes including:

- `claude-md`: only `CLAUDE.md` is loaded (plugin adds nothing)
- `claude-md-or-agents-md` (documented as the default): load `AGENTS.md` when there is no `CLAUDE.md`
This matters because precedence is where policy dies.

If your team believes `AGENTS.md` is always applied, but `CLAUDE.md` exists (even stale), your “policy” might never run. That’s not a hypothetical. That’s exactly the kind of repo entropy that shows up six months later when someone asks why the agent stopped following conventions.

### What it hooks

Mods are plugins with hooks. On HN, mpoteat described Mods as Claude Code’s new extensibility system, with a “new type of hook” they call a **function hook**.

Even if you never write a Mod, this changes your security posture:

- You now have an extension mechanism in a tool that can read, write, and execute against your repo.
- That mechanism can be remotely gated.
This is where I’d connect it to “agent orchestration” reality. Once you have plugins, you need governance. Allowlists. Version pinning. Auditing. Otherwise your [agent framework](/blog/langgraph-crewai-autogen-pydanticai) story turns into a supply-chain story.

### What it logs

The `agents-md` README has a dedicated “What it logs” section. The theme is that the Mod can emit logs about what it is doing.

Here’s my stance: **instruction loading should always produce an explicit, machine-readable record**:

- which instruction files were considered (`CLAUDE.md`, `AGENTS.md`, repo settings, session overrides)
- which one “won”
- why others were skipped
- hashes of the loaded files
Not because observability is trendy. Because when an agent makes an expensive or unsafe change, the first question is: “what instructions did it actually see?”

This is exactly the kind of traceability I push for in [production AI](/blog/ai-engineering-evals-gates) systems too. Observability isn’t dashboards. It’s being able to answer “why did this output happen?” quickly.

### Where it still differs from CLAUDE.md

The README explicitly calls out differences versus `CLAUDE.md`. That’s another reason this incident stung: developers assumed `AGENTS.md` was a drop-in replacement.

In reality, `CLAUDE.md` is loaded “by the engine,” while `AGENTS.md` (at least in this rollout) was mediated by a Mod with its own lifecycle.

Plugin-izing features is a normal way to ship faster. I’m not allergic to it.

But if the engine and the plugin have different failure modes, you have to surface that clearly. Otherwise you’ve created two classes of “project instructions,” and only one is dependable.

### Testing

The Mod repo has a “Testing” section and a `tests/` directory. That’s a gift.

If I’m a security-conscious team adopting Claude Code, I want to mirror that idea in my own repo. Treat instruction loading like an integration contract, and test it like any other dependency.

I’ll say this plainly: **if your build depends on an AI agent respecting repo instructions, you already have a CI/CD dependency. Act like it.**

This is the same “don’t trust the happy path” lesson from [MCP server security best practices](/blog/mcp-server-security-best-practices) and from every supply chain incident of the last decade.

## Why I think this is unacceptable (and what I’d like to see)

I’m glad Anthropic fixed it quickly. Shipping v2.1.281 the same day is the right move.

But the deeper issue isn’t the bug. It’s the design assumption: that it’s acceptable for **local policy** to be contingent on **remote config**.

Three concrete problems:

1. **Reproducibility:** two developers on the same commit can get different behavior if one can fetch feature flags and the other can’t. That’s a build integrity failure.
1. **Compliance:** in regulated environments, “disable telemetry” is not a preference. It’s policy. Tying functionality to telemetry pressures teams into breaking policy.
1. **Security posture drift:** feature flags are runtime dependencies. If your tool can be remotely disabled or altered, it’s part of your attack surface. Even if the vendor is honest, mistakes happen.
So what do I want to see, in durable controls terms?

- **Local-only mode:** a documented way to run Claude Code where all instruction sources are local and deterministic. No remote flags. No network dependence. Ideally paired with egress control, similar to how I think about [secure local LLM](/blog/secure-local-llm-inference) setups.
- **Fail-closed behavior:** if a repo contains `AGENTS.md` (or `CLAUDE.md`) and the tool cannot load it, that should be a warning at minimum. In CI, it should be an error.
- **Instruction provenance:** always log the instruction files loaded, the precedence decision, and hashes. Treat it like an SBOM for prompts.
- **Version pinning guidance:** teams should pin Claude Code versions for CI and roll forward on purpose, with an explicit verification step.
And yes, this is also about privacy.

If enabling telemetry changes behavior, then telemetry isn’t “just telemetry.” It’s a feature gate. That’s exactly the kind of design that makes developers distrust vendor tools.

One more experience-backed point from my own work: running this blog’s agent pipeline taught me that “silent bypass” is the failure mode that creates the biggest incidents. In one incident, rewriting slugs on live URLs burned **907K impressions** of link equity because a “small” identity change wasn’t treated as a one-way door. Instruction loading is also a one-way door. Once you ship it non-deterministically, you’re shipping future incidents.

### The control checklist I’d put in CI this week

No code blocks here. Just what I’d implement:

1. **Canary instruction test:** in CI, run Claude Code in a tiny fixture repo where only `AGENTS.md` exists, with a random canary token per run. Fail if the tool can’t repeat it.
1. **Precedence test:** add a second fixture where both `CLAUDE.md` and `AGENTS.md` exist, and assert which one wins for your chosen policy.
1. **Env var audit:** explicitly print and assert that `DISABLE_TELEMETRY` and `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` are set to your intended values. Treat “present but empty” differently from “unset.”
1. **Network policy parity:** run the same test with network egress blocked (or in a sandbox) to ensure no remote gating affects instruction loading.
1. **Version pin:** lock the Claude Code version in CI. Only upgrade via a PR that includes the above tests passing.
If this sounds like overkill, you’re not the audience. Anyone shipping “AI in production” already does this with compilers, linters, and dependency lockfiles. Agents don’t get a free pass.

If you want to go deeper on the broader class of risks, read [Claude Code security](/blog/claude-code-security-2026) and then map this incident into your existing supply-chain and [LLM security](/blog/llm-supply-chain-security-checklist) controls.

My prediction: as more coding tools move to plugin architectures and remote feature flags, we’re going to see more “it worked yesterday” incidents that look like model flakiness but are actually **instruction-path flakiness**. The teams that win will be the boring ones. The ones that treat instruction loading as a deterministic, testable contract. And they’ll be the only ones who can safely scale AI agents beyond a single developer laptop.

Photo by Caspar Camille Rubin on Unsplash.
