Skip to content

fix(architecture): improve's Gotcha asserts ${CLAUDE_PLUGIN_DATA} does not substitute in skill content — plugins-reference says it does #2207

Description

@kyle-sexton

architecture:improve's ## Gotchas surface states a harness fact that is false as written: that
${CLAUDE_PLUGIN_DATA} "does not substitute in skill markdown content (it is a hook/monitor/MCP path
substitution only)". The plugins reference's per-component substitution table puts skill and agent
content
in the "anywhere the placeholder appears" row, with no version qualifier. Nothing breaks at
runtime — the rule the sentence justifies is correct on other grounds and must stay — but the
stated mechanism is wrong on a surface that reads as authoritative to every future author of this
plugin, it is repeated in shipped release history, and it carried no source, date, or recheck trigger,
which is why it survived four releases. architecture is the last surviving carrier of this claim in
the repo: the same sentence was authored into plugin-quality and corrected there in-tree.

Rows

  • A-F1plugins/architecture/skills/improve/SKILL.md:71 — the bullet asserts the token
    "does not substitute in skill markdown content (it is a hook/monitor/MCP path substitution only)";
    plugins-reference says it does substitute in skill and agent content.
  • A-F3plugins/architecture/CHANGELOG.md:112-115 — the same false mechanism is the stated
    reason in the 0.3.6 "Fixed" entry, and :74 records its 0.4.1 promotion to a permanent Gotcha.
    Fix additively (see constraints); do not rewrite the entry.
  • A-F4plugins/architecture/skills/improve/SKILL.md:71 — the claim is written as bare prose
    with no source URL, no verification date and no recheck trigger, so it could not go stale visibly.
    This repo already owns that shape (docs/conventions/upstream-drift/, docs(conventions): upstream-drift re-derivation triggers are practiced in five places with no owner doc #1638) and that convention
    binds on touch, so the corrected sentence should land as a conforming record rather than as more
    unstamped prose.

A-F2 is a constraint, not work (recorded here so the fix is not overshot): the operative rule —
"the durable candidate artifact is a per-project memory-tier file, never ${CLAUDE_PLUGIN_DATA}" —
is correct on three legs that have nothing to do with substitution: the path has no project
dimension, uninstalling from the last remaining scope deletes the directory, and the documented use
is deps/caches/generated code. Delete the mechanism clause; do not reverse the rule. The edit is
surgical: remove "That token does not substitute in skill markdown content" and the parenthetical
"(it is a hook/monitor/MCP path substitution only)", keep the collision clause and the topic-docs
routing that follow it in the same bullet.

Evidence

plugins/architecture/skills/improve/SKILL.md:71 at HEAD:

- **The durable candidate artifact is a per-project memory-tier file, never `${CLAUDE_PLUGIN_DATA}`.** That token does not substitute in skill markdown content (it is a hook/monitor/MCP path substitution only), and even resolved it points at a plugin-global dir that collides candidates across projects. …

plugins/architecture/CHANGELOG.md:112-115 (inside the 0.3.6 entry):

- Deepening lens: the durable candidate artifact's default location no longer uses
  `${CLAUDE_PLUGIN_DATA}` — that token does not substitute in skill markdown content
  (it is a path substitution for hook/monitor commands and MCP/LSP server configs
  only), so consumers following the default literally wrote to an unexpanded

and plugins/architecture/CHANGELOG.md:74 (0.4.1):

  — the `${CLAUDE_PLUGIN_DATA}` artifact-path trap (F1) and the unverified

The corrected mechanism, stated affirmatively: ${CLAUDE_PLUGIN_DATA} does resolve in skill
and agent content. https://code.claude.com/docs/en/plugins-reference, "Environment variables",
fetched 2026-08-11 during verification: "Which fields substitute them inline depends on the
plugin component:" introduces a table whose first row is | Skill and agent content | Anywhere the placeholder appears |, with Hook and monitor commands as a separate row and no version
qualifier.

Proven in-tree replacement wording already existsplugins/plugin-quality/skills/audit/SKILL.md:123-131
states that the placeholder does resolve, cites the page and section with a fetch date, and keeps a
deterministic fallback
for the case where it arrives unexpanded. Copying that shape closes A-F1 and
the architecture instance of A-F4 in one edit and converges two plugins' histories on one
explanation.

A-F4's remedy is adoption, not authorship. docs/conventions/upstream-drift/README.md is the
owner doc for verification stamps and recheck triggers (closed #1638). It states the name "binds on
touch": a surface restating an upstream-owned specific "additionally adopts the required parts" the
next time it changes. architecture is not in its Adopters table. The same doc independently
confirms A-F3's constraint: "History is never rewritten: CHANGELOG.md entries, dated audit
records, and ADR sections keep the wording they shipped with."

Cross-plugin context (do not turn this into a cross-plugin fix). A repo-wide sweep for both
phrasings returns exactly three hits: SKILL.md:71, architecture/CHANGELOG.md:112, and
plugins/plugin-quality/CHANGELOG.md:147 — which is the record of the correction, not the claim.
The sweep matched two phrasings only; a paraphrase ("only hooks can use it", "not available to
skills") would not have been found, so this is a lower bound, not a census.

Relationship to existing issues

Open question a fixer should see

A parsimonious alternative explanation is open and unresolved: that a Read of the line returns
the token literal while skill-loading expands it, and that 0.3.5's token lived in a Read-loaded
actions/deepening.md rather than a SKILL.md body. If true, the historical symptom was real, the
0.3.6 reversal was right, and only the mechanism was wrong. It does not soften A-F1 — the
plugins-reference row is unambiguous — but it bears on how A-F3's corrective entry should be worded,
so do not write the corrective entry as though the 0.3.6 symptom was imaginary. A throwaway plugin
carrying the token in both a SKILL.md body and an actions/*.md file would settle it.

Provenance

Severity: MED · Provenance: AUDITOR_VERIFIED (two independent verifications ten days apart
against the same doc row, plus three session observations from the audit packet)
Origin: handoff-inbox item 20260811-021645-plugin-audit-four-components-and-guard-deadlock-ownership
Ledger: .work/handoff-inbox-batch-4/ledgers/I9-021645-four-components.md § Lane E — architecture / improve
Verified against repo HEAD 685dd381.

Which legs were re-fetched, and which were not. The plugins-reference substitution-table row
(A-F1's load-bearing leg) was re-fetched by the verifier on 2026-08-11. A-F2's other two legs
(uninstall deletes the data directory; "use it for" names deps/caches/generated code) and A-F4's
supporting datum that upstream version-gates substitution changes when they occur
("${CLAUDE_PROJECT_DIR} substitution requires Claude Code v2.1.196 or later", skills page) are
auditor-quoted only and were not independently re-fetched — treat them as unconfirmed until a
fixer re-fetches. A genuine cross-page tension is also live and is the likely reason the error was
made in good faith: the skills page's own substitutions table omits ${CLAUDE_PLUGIN_DATA} and
${CLAUDE_PLUGIN_ROOT} entirely. A corrected sentence should cite plugins-reference specifically
rather than asserting a bare correction.

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

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions