Back to News & Insights
Artificial Intelligence October 7, 2026 · 9 min read

Progressive Disclosure: Why Isn't Claude Code Following My Instructions?

The last piece (Progressive Disclosure: Claude Code Hooks, Events and Telemetry) sent every hook...

Progressive Disclosure: Why Isn't Claude Code Following My Instructions?

The last piece (Progressive Disclosure: Claude Code Hooks, Events and Telemetry) sent every hook event through one bus and wrote it all down. It ended on what that log can't tell you: whether a rule that loaded "was worded well enough to steer anything".

So I loaded one spec, worded two ways, into the same 16-turn Claude Code session, three times each, and read what came out at the end. Here's the last migration doc from each, written with roughly 120K to 140K tokens of work piled on top of the spec:

Both specs asked for the release. The bus log shows each one delivered once, on the first prompt, and nothing took it out of the context after that. The named spec put Release: 4.2.0 on every migration doc. The vague one put TBD there every time.

The demo is a small Node payments service with two legacy knex migrations. Neither has a down step, and neither doc says which release it went out in, so whatever the agent does about either comes from the spec.

The spec lives in specs/migrations.md, and the bus from last time delivers it. One step is new: a prompt that starts with #migration gets the spec printed into its context, and the log records the delivery. Whatever a UserPromptSubmit hook prints goes in front of the model before it starts (hooks).

The two versions ask for the same two things: a way back from every migration, and the release named in its doc.

Each session is 16 prompts, run headless with claude -p on Claude Code 2.1.285 and claude-opus-5-5 at its default medium effort. The first prompt starts the migration work and asks for one migration, turn 8 asks for a second and turn 16 for a third. In between, the agent does the rest of a working day: it groups the failures in an import log, finds and fixes bugs in a legacy importer, renames a column across the repository, the API serializer and five billing modules, writes tests, and runs the suite after each change. I ran three sessions per version.

| | Turn 1 | Turn 8 | Turn 16 | |---|---|---|---| | Named spec | Release: 4.2.0 in 3 of 3 | Release: 4.2.0 in 3 of 3 | Release: 4.2.0 in 3 of 3 | | Vague spec | TBD in 3 of 3 | TBD in 3 of 3 | TBD in 3 of 3 |

The vague runs wrote Release: TBD, or Release: TBD (next release after 4.2.0). That's a fair reading of "mention which release a change goes out in": the change hasn't shipped yet, so its release is the next one, whatever that turns out to be. What I wanted on that line was the version in package.json, and only the named spec said so.

Every migration in both sets got a down step. Claude writes one for a knex migration whether you ask or not, so that half of the spec costs nothing to follow in either wording. The release line asks for something Claude wouldn't do on its own, and that's where the wording decided the result.

Then I ran the same six sessions at --effort low. The named spec still put Release: 4.2.0 on the first line of all nine migration docs. The vague one dropped the release altogether: none of its nine docs has a release line, not even TBD.

Three sessions per version is a demonstration, and four shorter 8-turn sessions per version came out the same way. The measured effect comes from earlier controlled experiments, where specificity produced a 10.9x odds ratio in compliance (The State of AI Instruction Quality).

Claude Code's docs put it plainly: Claude treats CLAUDE.md "as context, not enforced configuration, so how you write instructions affects how reliably Claude follows them", and there's "no guarantee of strict compliance, especially for vague or conflicting instructions" (How Claude remembers your project). A spec your bus delivers is context too.

The vague spec asks for the release "ideally" and never says where the release comes from. So the model read it as the release still to come. One of the shorter runs wrote Release: TBD (current package version is 4.2.0): it had the version in front of it and still wrote TBD. From the chair that looks exactly like Claude ignoring the spec. It was doing what the spec said, and the part I meant was never in the words.

It's also the common case. In our analysis of 28,721 repositories, 89.9% of agent configurations contain at least one instruction that doesn't name what it means (same article).

I went in expecting the other failure as well: a spec that holds early and fades as the turns pile up. By turn 16 the context held the import log, the importer, the billing modules and a dozen test runs, and neither spec had moved. Whatever a version did on turn 1, it still did on turn 16.

Long enough sessions do get there. In the decay piece (See how AI instructions decay, then write ones that hold), Never write directly to the database was still sitting in the prompt when the agent, a long session later, wrote directly to the database. The model leans on what it read most recently. It's the same recency tendency that, inside one file, swings how often a rule is obeyed by about 90 points when you move it from the top to the bottom (Opus 5: Cost of Instruction Conflicts).

Here's the picture I use for it. Each hill is an instruction and its height is how well it's written. The water is everything the session piles on. Drag the load up and watch which hills go under first.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation