Skip to content

Skills hardcode ~/.claude/skills/gstack/ paths — any install dir not named gstack silently breaks after setup #1882

@rvdlaar

Description

@rvdlaar

Summary

Every skill's SKILL.md hardcodes the absolute string ~/.claude/skills/gstack/... for its own bin/ and asset calls (e.g. the telemetry/config preamble that runs on every skill invocation). setup, however, is parameterised on its own checkout location and wires the skill symlinks correctly for any directory name. The result: if gstack is installed at ~/.claude/skills/<name> where <name> isn't literally gstack, the symlinks resolve but the skills' internal bin/asset references point at a non-existent ~/.claude/skills/gstack/ and fail silently, at skill-invocation time.

This is the gstack-dir-name sibling of #349 ($CLAUDE_CONFIG_DIR, the ~/.claude prefix). Same underlying cause — hardcoded absolute self-paths — different segment. Both ladder up to the "make path resolution dynamic rather than hardcoded" direction from #289.

Root cause (with file:line)

  • setup:17-18 — the install dir is derived, not fixed:

    INSTALL_GSTACK_DIR="$(cd "$(dirname "$0")" && pwd)"
    SOURCE_GSTACK_DIR="$(cd "$(dirname "$0")" && pwd -P)"

    So setup is designed to run from wherever the repo lives, and INSTALL_SKILLS_DIR="$(dirname "$INSTALL_GSTACK_DIR")" (setup:19). The per-skill install (setup:535-569) creates a real dir at ~/.claude/skills/<skill>/ with an absolute SKILL.md symlink into the actual checkout — correct for any dir name.

  • But the skill bodies are committed with the literal absolute path. Example — qa/SKILL.md at HEAD contains 52 occurrences of ~/.claude/skills/gstack/ across 51 lines (the preamble alone calls ~/.claude/skills/gstack/bin/gstack-config, .../bin/gstack-telemetry-log, etc.).

  • setup already rewrites these paths when it generates the non-Claude host copies — e.g. setup:~1012-1028 rewrites .claude/skills/gstack.kiro/skills/gstack (and the codex/cursor/factory/gbrain equivalents). The primary Claude install is the one host that never gets its in-file paths reconciled with INSTALL_GSTACK_DIR's actual basename.

Reproduction

# install under any name that isn't "gstack"
git clone https://github.com/garrytan/gstack ~/.claude/skills/gstack-dev
cd ~/.claude/skills/gstack-dev && ./setup

# the skill symlinks are correct, but the in-file paths are not:
grep -c '~/.claude/skills/gstack/' ~/.claude/skills/gstack-dev/qa/SKILL.md   # > 0
ls ~/.claude/skills/gstack/bin/gstack-config 2>&1                            # No such file or directory

Then invoke any skill (e.g. /qa): its preamble shells out to ~/.claude/skills/gstack/bin/gstack-config …, which doesn't exist. No error surfaces to the user at install time — it only fails when a skill runs.

Observed directly while upgrading an install located at ~/.claude/skills/i-gstack: after git reset --hard origin/main && ./setup, every top-level */SKILL.md that references the install path (52 files on that checkout) still pointed at ~/.claude/skills/gstack/, and setup did not reconcile them.

Impact

  • Affects anyone whose global install lives at ~/.claude/skills/<name> where <name> != gstack (setup installs the skill siblings into INSTALL_SKILLS_DIR="$(dirname "$INSTALL_GSTACK_DIR")", so it accepts this layout — it just doesn't reconcile the in-file paths).
  • Silent: nothing fails at install; skills break later, at invocation, in a way that looks like the skill itself is broken.
  • Affects every skill (the shared preamble), not a subset.

Suggested fixes (maintainer's call)

  1. Compatibility symlink (smallest). When basename "$INSTALL_GSTACK_DIR" != gstack, create/refresh $INSTALL_SKILLS_DIR/gstack -> $INSTALL_GSTACK_DIR so the hardcoded references resolve with zero file edits. Caveat: must not let Claude Code discover the repo-shaped dir as duplicate skills — setup:589 already has handling for skipping the repo-shaped gstack dir, so this needs to compose with that.

  2. Runtime-relative resolution (cleanest, aligns with RFC: define a standard host integration contract for gstack #289). Have the preamble resolve its own bin/asset dir relative to the SKILL.md location instead of a hardcoded absolute path (a resolved $GSTACK_DIR), removing the dir-name dependency entirely. Larger change (touches the shared preamble across all skills).

  3. Extend the existing rewrite to the Claude host (symmetric). Apply the same path rewrite setup already does for kiro/codex to the primary install, mapping ~/.claude/skills/gstack/$INSTALL_GSTACK_DIR. Caveat: the Claude install symlinks to source rather than copying, so this would either dirty the working tree or require switching that host to a copy-and-rewrite step.

Workaround (for affected users today)

After each install/upgrade, re-point the hardcoded references in the top-level skill files to the real install dir:

cd ~/.claude/skills/<your-dir>
# macOS/BSD sed shown; on GNU/Linux use `sed -i` (no '').
find . -maxdepth 2 -name SKILL.md -not -path './.*' -print0 \
  | xargs -0 sed -i '' "s|skills/gstack|skills/$(basename "$PWD")|g"

Scope to top-level */SKILL.md only; the generated host copies under .agents/.cursor/.factory/.gbrain/hosts use a gstack- prefix convention and should be left as-is. (This needs re-running after every upgrade, since git reset --hard reverts it — which is the motivation for fix #1 or #2.)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions