Can Opus 5.5 Make Use of Progressive Disclosure? Path-Scoped Rules vs. Skills: Which One Reaches the Agent

  • #ai
  • #adr
  • #context-engineering

In the previous piece, I showed experimentally that putting one sentence (“check past decisions before you design”) into a standing rule stops the agent from quietly reopening proposals that were already rejected. At the end of that piece I also mentioned the option of writing the same sentence into a skill. A skill is loaded only when it’s needed, so it saves context compared with a rule that is always loaded. But I also wrote that I had “not measured” how reliably a skill gets followed.

Progressive disclosure is the design of not loading all the context up front, but loading it in stages at the point it becomes necessary. Claude Code has two mechanisms for this. One is a rule with paths: specified (loaded when a matching file is opened); the other is a skill (its body is loaded when the agent invokes it). Both assume the model will load the right thing at the right time.

In the two months since the last experiment, the model moved from Claude Opus 4.8 to 5.5. I’ve also been working more often in auto mode, which hands permission checks to a classifier. So I re-ran the previous experiment in the current environment to see whether Opus 5.5 can make use of progressive disclosure. That’s 105 trials in all, against the same repository as before.

Summary

  1. Path-scoped rules barely fire with Opus 5.5. The only trigger that loads such a rule is the Read tool. Opus 5.5 reads 95% of files through Bash (cat, sed), and that doesn’t change even outside auto mode.
  2. A check step written into a skill does reach Opus 5.5. When asked to design something, Opus 5.5 invoked the design-doc skill almost every time (61 out of 63), and reached the rejected ADR 6/6. In July, Opus 4.8 invoked that skill for the same request only 2 times out of 9.
  3. Standing rules and skills behave differently once they find a conflict. A standing rule stops and asks for confirmation; a skill records the conflict in the document and then writes the design through to the end. With both in place, the standing rule’s behavior wins.

The previous experiment, and what changed in two months

The previous experiment asked an agent, once more, for a proposal that had been rejected in the past, and checked whether it noticed the record of the rejection (the ADR). The material was the repository of karasu, an architecture-diagram tool I develop. For example, a request like “drop the braces in .krs notation and switch to a YAML-style indentation syntax” is something karasu already considered and set aside. If the agent notices that rejection record and asks for confirmation, that’s the good behavior; if it starts writing a migration design without noticing, it has quietly reopened a settled discussion.

This time I repeated the experiment as-is in the current environment. What changed over two months was not only the model and the permission mode.

  • Model: from Claude Opus 4.8 to Claude Opus 5.5
  • Permission mode: from bypassPermissions, which skips confirmation, to auto mode, which delegates it to a classifier
  • Repository: ADRs grew from 263 to 391, and their IDs switched from dates to Issue numbers
  • Skill: right after the previous experiment, I wrote the check step into the design-doc skill

I only noticed the last item after the experiment had started. In karasu’s development I use the design-doc skill from hane, a skill collection I develop separately. The day after writing the previous piece, I had added “grep docs/adr/ before designing, specifically looking for rejected decisions” to this skill as a mandatory step. In other words, the prescription from the experiment had gone into a skill used in real work.

Left as is, the check step would take effect through the skill even in the no-rule conditions, and nothing could be compared with July. So I pinned hane’s version and made the July version and the current version switchable as conditions. As a result, this re-run was designed to measure three questions at once1.

  • Do July’s conclusions hold when the model and permission mode change?
  • Do standing rules and skills each reach Opus 5.5?
  • When a difference shows up, is it due to the model, the permission mode, or the repository?

Why don’t path-scoped rules fire?

Let me deal with path-scoped rules first. A report says that paths in .claude/rules doesn’t work in auto mode (in Japanese). According to that post, a path-scoped rule is designed to be loaded when the Read tool runs. Meanwhile, the auto mode system prompt instructs the agent to “do work through Bash wherever Bash can do the job.” As a result, reading a file with cat bypasses the rule, or so the explanation goes.

I checked this with a small controlled experiment. I placed one rule scoped to notes/**, whose content says “if this rule is loaded, write a passphrase at the end of your final answer.” Then I had the agent read a file with Read and with Bash cat, three times each, in both auto mode and bypassPermissions.

Read Bash cat
auto mode 3/3 0/3
bypassPermissions 3/3 0/3

What decided whether the rule fired was not the permission mode but the way the file was read. Read it with Read and the rule fires even in auto mode; read it with Bash and it doesn’t fire even in bypassPermissions.

So which way does the model actually read files in real tasks? Across all trials of the re-run, I counted the share of file reads that went through Bash.

Configuration Share read via Bash
Opus 4.8, bypassPermissions (July) 33%
Opus 4.8, bypassPermissions (this time) 18%
Opus 5.5, bypassPermissions 95%
Opus 5.5, auto mode 94%

Opus 5.5 reads nearly all files through Bash, auto mode or not. The report names the auto mode system prompt as the cause, but at least in this environment, taking auto mode away barely changed how Opus 5.5 reads. Progressive disclosure through path-scoped rules was almost not working with Opus 5.5. karasu’s ADR-authoring rule is also scoped to docs/adr/, so even when the agent read ADRs, that rule was most likely not loaded.

Nor was Opus 5.5 making up for the path-scoped rules that didn’t load. Out of 81 trials in auto mode, 46 wrote a design document into docs/design. A path-scoped rule defining how to write design documents applies to that location, but in only 14 of those 46 did the agent open and read the rule itself (Opus 4.8: 7 out of 12).

Why does it still reach the rejected ADR when reading through Bash?

That leaves a question. If Opus 5.5 reads files through Bash, it must be reading ADRs through Bash as well. Then why did many of the trials shown below still reach the rejected ADR?

Because path-scoped rules and ADRs are read by different mechanisms. A path-scoped rule is something Claude Code injects into the context by watching the agent’s operations. The trigger for injecting it is limited to the Read tool, so when the reading method changes, it doesn’t get injected. An ADR, on the other hand, is data the agent finds and opens on its own. Whether it’s opened with cat or with Read, the text the agent receives is the same.

So how does the agent find ADRs? For the 55 trials that reached the rejected ADR, I looked at the operation where its filename first appeared. In 50 of them it was the result of a Bash grep over the text of docs/adr; the other 5 came from reading the index. A typical search looks like this.

grep -ril -E "indent|インデント|brace|ブレース|YAML" docs/adr

The words from the request are lined up in a single search together with their Japanese and English variants (インデント and ブレース are Japanese for “indent” and “brace”). The Read tool opens one file at a time, but grep can scan the text of all 391 at once.

This kind of search hit a median of 30 ADRs for the YAML request and about 15 for the session-name request. The agent could pick the rejected ADR out of those because the filenames express both the content and the conclusion. As with 7-yaml-style-syntax-cancelled.md or 45-bun-not-adopted.md, the filename tells you what the decision was about and that it wasn’t adopted. The search hits because the ADR’s background is written in the same words as the request. The YAML syntax ADR opens (in Japanese) with “prompted by the problem that, in deep nesting (4 to 5 levels), the closing braces of the brace syntax pile up and become hard to read,” recording almost the same complaint as this request. In the previous piece I wrote that the text explaining why something was rejected becomes a hook for search. Bash grep uses that hook directly.

Conversely, in the trials that didn’t reach it, the rejected ADR’s filename never appeared in any output. There was no trial in which it showed up in the search results and simply wasn’t opened. One cause is truncated search results. One of the Bun trials that missed it searched the ADRs with broad terms like pnpm|vitest|bun|runtime and cut the result to the first 60 lines with | head -60. That search hits 160 ADRs, and the rejected ADR is 112th in the list. The more ADRs there are, the more a broad search hits, and combined with the habit of truncating output, the target ADR falls through. The other cause is not searching docs/adr at all. Most of the session-name trials that missed it went off to investigate the skill collection or Claude Code itself.

In short, what reading through Bash loses is the automatic injection of rules, not the search for ADRs. As long as there’s a trigger to go looking (the check step in a skill or rule), Bash grep can scan many ADRs at once. The effect of the skill shown in the next section is also the result of that search being started by the skill’s instructions.

Does a check step written into a skill reach the agent?

Next, the main question: skills. I asked for a rejected proposal (a feature that renames the agent’s session to the feature name) and split the conditions four ways by where the check step lives. The model is Opus 5.5 throughout, in auto mode.

Old skill (no check step) New skill (with check step)
No standing rule 1/6 6/6
With standing rule 3/3 3/3

The numbers are the share of trials that actually opened the rejected ADR. Just writing the check step into the skill reached it 6/6 even without a standing rule. With a standing rule, it was 3/3 regardless of the skill’s version.

The reason it got through via the skill is simple: Opus 5.5 invoked the design-doc skill almost every time. Every request in this experiment took the form “please put this together as a design doc.” In the conditions without a check step, Opus 5.5 invoked the skill for this kind of request 61 times out of 63. For the session-name request alone, Opus 4.8 invoked it only 2 times out of 9 in July, and 3 out of 6 against the current repository. No matter how correct a skill’s body is, it isn’t loaded unless it’s invoked. That is why writing it into a skill was uncertain in the Opus 4.8 days, and with Opus 5.5 that precondition is now met.

Behavior after reaching it, however, differed between the standing rule and the skill.

After finding the conflict Design document Time and cost
Standing rule Stops and asks for confirmation Not written (0/3) About 30 seconds, $0.28
New skill Writes the conflict into the document and keeps designing Written (6/6) About 4.5 minutes, $1.28

The standing rule says “if the proposal would overturn a past decision, don’t proceed silently; get confirmation,” so the agent stops as soon as it notices the conflict. The skill’s step says “if you find a conflicting past decision, state it in the document’s background and constraints,” so the agent writes the conflict in and then writes the design through to the end. Both are the result of following the written steps as written. With both in place, the behavior was the standing rule’s (stop early).

I also measured the cost imposed on a request without a conflict (adding an FAQ page to the docs). Last time, with Opus 4.8, adding a standing rule doubled the cost. With Opus 5.5 it was $0.96 with no check step, $1.01 with a standing rule, and $1.04 with the new skill: almost no difference. Opus 5.5 searches docs/adr/ a few times even without a check step, so the extra cost from the step seems to have shrunk. No trial stopped when there was no conflict, in any condition.

What changed when the model changed?

From here on, these are the changes in the bare state, with no check step. The biggest change compared with July was that the behavior of quietly pushing ahead with a rejected proposal disappeared.

Here are the results of the session-name request with no check step (A: showed the conflict and asked for confirmation; B: pushed the design ahead without touching past decisions).

Configuration B (pushed ahead quietly) Opened the rejected ADR
Opus 4.8, July’s repository 7/9 1/9
Opus 4.8, current repository 3/6 3/6
Opus 5.5, bypassPermissions 0/6 5/6
Opus 5.5, auto mode 0/6 1/6

Comparing Opus 4.8 and 5.5 on the same repository and the same permission mode, B drops from 3/6 to 0/6. Even in the condition where the ADRs were deleted entirely, Opus 5.5 pushed ahead quietly only 1 time out of 12; the rest raised reasons on their own and took a cautious stance.

That doesn’t mean the ability to recall the rejected ADR went up, though. For the requests targeting the rejections of the YAML syntax and the toolchain (a move to Bun), Opus 4.8 opened the rejected ADR in all 6 trials in July. This time Opus 5.5 (auto mode) did so in 3 out of 6. With ADRs up to 391, broad searches hit more, and the output truncation described earlier makes the target ADR easier to drop. Opus 5.5 was cautious not because it found the ADR, but because it judged from other clues.

One of those clues was on the skill collection’s side. On the session-name request, Opus 5.5 read hane’s changelog and found a record saying “a step to change the session name was added once, but it couldn’t be executed from the model, so it was removed.” The history of the rejection in karasu had also been left in the skill collection’s changelog. It went on to investigate Claude Code itself and found that the current version has a way to change the session name from a hook. The reason for the rejection written in the ADR (there’s no public API to rename a session) had stopped being true within those two months.

The difference between auto mode and bypassPermissions showed up only in the share that opened the rejected ADR on this request (1/6 versus 5/6). Neither had any trial that pushed ahead quietly, and there was no difference on the other requests. With six trials each, this stays within the range of chance, and I can’t claim that auto mode lowers recall. Also, across the 81 trials in auto mode, the permission check never once blocked an operation.

Limits

This is again a single personal repository, at the small scale of 3 to 6 trials per condition. Read it as a check on the direction of differences between conditions, not on effect sizes.

Some factors were not fully controlled. As described above, the reason for rejecting the session-name request had gone stale, so it was no longer a “closed decision” in the same sense as in July. The behavior categories were assigned by a separate model using the same criteria as in July, but “surfacing the conflict” under those criteria also counts references to records other than the target ADR, so whether the target ADR was recalled was judged from the tool execution logs. I pinned the skill collection’s version, but not the other plugins. Whether a path-scoped rule fired couldn’t be observed from the stream output, so I checked it with the small controlled experiment instead.

Takeaways

Opus 5.5 made use of skills among the progressive disclosure mechanisms, but not of path-scoped rules. The difference came not from comprehension but from how files are read. A skill is invoked by the model itself, so as long as the decision to invoke it is reliable, it gets through. A path-scoped rule is tied only to one specific way of reading, the Read tool, so when the model chooses another way, it doesn’t get through.

The other thing that became visible is that the role of records changes as models get smarter. Opus 5.5 became cautious from other clues even when it couldn’t recall the ADR. Still, the settlement that “this proposal was already considered and set aside” can’t be known without reading the ADR. The check step is still needed to get that settlement read. How to deliver the check step (how to design the mechanisms that hand context to the agent) is something I plan to take up in a separate piece, together with further experiments.

The conditions of the experiment, the result tables for every cell, and the pitfalls found in the re-run are collected in the notes companion.

Footnotes

  1. To separate the factors, I added control groups that run both Opus 4.8 and Opus 5.5 with bypassPermissions against the current repository. The difference from July can then be decomposed in order: the change in the repository, the difference between models, and the difference between permission modes. The list of conditions is in the notes companion. ↩