Skip to content

fix(skills): resolve customization lookup via CLAUDE_CONFIG_DIR, not hardcoded ~/.claude - #1924

Open
neilinger wants to merge 1 commit into
danielmiessler:mainfrom
neilinger:fix-skill-customization-lookup-config-dir
Open

fix(skills): resolve customization lookup via CLAUDE_CONFIG_DIR, not hardcoded ~/.claude#1924
neilinger wants to merge 1 commit into
danielmiessler:mainfrom
neilinger:fix-skill-customization-lookup-config-dir

Conversation

@neilinger

Copy link
Copy Markdown
Contributor

What

Every affected skill's ## Customization block hard-codes
~/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/<Name>/ as a literal path in
the prose the model reads before running the skill. On any install where
CLAUDE_CONFIG_DIR points somewhere other than ~/.claude, that path
doesn't exist — and the skill's own documented fallback ("if the
directory does not exist, proceed with skill defaults") turns the wrong
path into a silently ignored customization. No error, the user's
config is just quietly dropped.

Why this form

Claude Code does not substitute shell variables into a skill body — only
!`cmd` dynamic-context injections are expanded before the model
sees the text. This PR replaces the static path line with a find-based
injection that resolves at invocation time, falling back to the
documented default ($HOME/.claude) when CLAUDE_CONFIG_DIR is unset —
so a default-config-dir install behaves exactly as it did before this
change.

Two details that matter and were found the hard way:

  • find, not a glob. The harness evaluates these injections in zsh,
    whose default nomatch turns an unmatched glob into a hard expansion-time
    error — and an empty customization directory is the common case, so a
    glob here breaks the skill body on nearly every invocation.
  • Always exits 0. A non-zero exit from the injected command aborts the
    entire skill invocation, so the command ends in ; true.

Scope

35 skills whose ## Customization block used the exact canonical wording
(**Before executing, check for user customizations at:** + a standalone
path line). A 36th skill matching that wording, ContextSearch, has since
been removed from this tree, so it's not part of this diff.

Not included: WorldThreatModel, CMUX, and Webdesign use differently
worded customization blocks (different phrasing / embedded prose rather
than the standalone canonical line), so a safe mechanical fix isn't
possible without hand-editing skill-specific text — left for a follow-up.

One more thing worth your attention

Telos's Workflows/Update.md already uses this same !`cmd`
injection syntax (e.g. lines 81, 105, 108) — so the mechanism is already
an established idiom in this codebase. But that file is reached through
Telos/SKILL.md's "Workflow Routing" table and read on demand rather than
loaded at skill-invocation time the way SKILL.md itself is, so the
injection there doesn't appear to actually be live. Same bug family
(hardcoded-path-adjacent), different manifestation — flagging it here
since I didn't want to scope-creep this PR into fixing it too.

Behavior check

Verified in both bash and zsh, with CLAUDE_CONFIG_DIR unset (falls back
to $HOME/.claude, matches current behavior) and set to a directory that
does/doesn't contain a matching customization (correctly lists the file
or emits nothing) — exits 0 in every case.

…hardcoded ~/.claude

Every affected skill's "Customization" block hard-codes
~/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/<Name>/ as a literal path in
the prose the model reads. On any install where CLAUDE_CONFIG_DIR points
somewhere other than ~/.claude, that path does not exist, and the skill's
own documented fallback ("if the directory does not exist, proceed with
skill defaults") turns the wrong path into a silently ignored
customization — no error, just quietly-dropped user config.

Claude Code does not substitute shell variables into a skill body — only
`!`cmd`` dynamic-context injections are expanded before the model sees the
text. This replaces the static path line with a `find`-based injection
that resolves at invocation time, guarded to fall back to the documented
default ($HOME/.claude) when CLAUDE_CONFIG_DIR is unset, so a default-dir
install behaves exactly as before. `find`, not a glob, because the
harness evaluates injections in zsh, whose default `nomatch` makes an
unmatched glob a hard error at expansion time (the common case is an
empty customization directory). The command always exits 0, since a
non-zero exit here would abort the whole skill invocation.

Scope: the 36 skills whose Customization block used the exact canonical
wording ("**Before executing, check for user customizations at:**" +
standalone path line). ContextSearch was in that set but has since been
removed from this tree, leaving 35 files changed here. Skills with
differently-worded customization blocks (WorldThreatModel, CMUX,
Webdesign) are not touched — the wording differs enough that a safe
mechanical fix isn't possible without rewriting skill-specific prose,
which is out of scope for this change.

Also worth a maintainer's attention, not fixed here: Telos's
`Workflows/Update.md` already uses this same `!`cmd`` injection syntax
(e.g. line 81, 105, 108), but that file is reached through Telos/SKILL.md's
"Workflow Routing" table and read on demand rather than loaded at
skill-invocation time — the injection there does not appear to be live.
Same bug family, different manifestation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant