Skip to content

[BUG] Skill re-invocation dedupe is keyed on the RENDERED content, so changing only the arguments re-appends the entire SKILL.md — composing skills costs N × body #95340

Description

@anodynos

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

Title: Skill re-invocation dedupe is keyed on the RENDERED content, so changing only the arguments re-appends the entire SKILL.md — composing skills costs N × body

Type: design flaw / enhancement (the behaviour matches the docs; the docs describe a design that defeats skill composition)

Environment

  • Claude Code 2.1.276 (CLI), Linux (WSL2)
  • Project skills under .claude/skills/*/SKILL.md, invoked by the model through the Skill tool

What happens

The skills docs (§ Skill content lifecycle) state:

When Claude re-invokes a skill whose rendered content is identical to the copy already in context, Claude Code adds a short note that the skill is already loaded rather than a second copy of the content. When the rendered content differs, because the arguments changed […], Claude Code appends the full content again.

So the dedupe key is the skill body after argument substitution. Any skill that takes an argument — i.e. any skill designed to be called — renders differently on every call with a new argument, and the full body is appended again each time.

Why this is worth fixing

The control shows Claude Code already has the right rendering: instructions once, arguments delivered per call. It only takes that path when the arguments did not change — the one case where re-invoking is least useful. It is a loader that hashes a function together with its call frame, so every distinct call looks like a new function.

The re-invocation header even reads as though a delta was intended ("the arguments or dynamic output below are new"), but what follows is the whole body, not just the new arguments.

Practical cost: an orchestrating skill that calls a worker skill once per item (per file, per ticket, per finding) pays the worker's full body per item. That pushes authors away from small, composable, argument-taking skills toward either monolithic skills, or passing the subject implicitly through conversation state purely to keep the args string constant — ambient state, which is worse engineering and fails silently when mis-resolved.

What Should Happen?

Proposed behaviour

Key the dedupe on the skill's template (pre-substitution body + resolved file identity), not the rendered output:

  • template unchanged, args changed → emit the short note plus the new Arguments: — the exact shape the identical-args path already produces;
  • template unchanged, a dynamic-context command's output changed → emit the note plus only the changed dynamic output;
  • template changed on disk → append the full content (today's behaviour).

If a skill interpolates $ARGUMENTS mid-body, the note can carry the arguments once; the model already holds the body that says where they apply.

Error Messages/Logs

Steps to Reproduce

Repro

Use any reasonably large project skill that accepts arguments — say .claude/skills/process-item/SKILL.md (~6–7K tokens), whose body refers to its arguments (via $ARGUMENTS, or the auto-appended ARGUMENTS: trailer).

  1. Have the model call Skill(skill="process-item", args="item-1") → the full body enters context. Expected.

  2. Have it call Skill(skill="process-item", args="item-2"), then item-3, then item-4.

  3. Each of those calls is answered with

    (Re-invocation of /process-item — the skill instructions were previously loaded; the arguments or dynamic output below are new.)
    

    followed by the complete SKILL.md body again. Four calls ≈ 20K+ tokens of byte-identical instructions; only the one argument token differs between them.

Control — re-invoke a skill with byte-identical args. The entire response is one line:

Skill /process-item is already loaded above; instructions unchanged. Arguments: item-1

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

No response

Claude Code Version

2.1.276

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

Not the same as

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions