Skip to content

fix(setup): resolve hardcoded ~/.claude/skills/gstack paths for installs not named "gstack" (#1882)#2223

Open
time-attack wants to merge 1 commit into
garrytan:mainfrom
time-attack:fix/issue-1882-install-dir-name-compat-alias
Open

fix(setup): resolve hardcoded ~/.claude/skills/gstack paths for installs not named "gstack" (#1882)#2223
time-attack wants to merge 1 commit into
garrytan:mainfrom
time-attack:fix/issue-1882-install-dir-name-compat-alias

Conversation

@time-attack

@time-attack time-attack commented Jul 10, 2026

Copy link
Copy Markdown

Fixes #1882.

The issue, in plain terms

When you install gstack, setup puts each skill (/qa, /ship, ...) into ~/.claude/skills/ and points it back at your gstack checkout. That part works no matter what you name the folder you cloned into.

The problem: the text inside every skill hardcodes one exact path — ~/.claude/skills/gstack/bin/.... Every skill, on every run, quietly calls things like ~/.claude/skills/gstack/bin/gstack-config in its opening steps (reading your config, logging telemetry, checking for updates).

So if you cloned gstack into a folder that isn't literally named gstack (say ~/.claude/skills/gstack-dev or ~/.claude/skills/i-gstack), those calls point at a folder that doesn't exist. And because each call ends in 2>/dev/null || echo default, the failure is swallowed — nothing errors out. Every config setting silently falls back to its default, telemetry silently does nothing, the update check silently skips.

The nasty part: install looks completely fine. Nothing warns you. The skills only misbehave later, when you actually run one, and it looks like the skill itself is broken rather than the folder name.

Who hits this: anyone whose install folder isn't named exactly gstack. setup accepts that layout (it installs the skills as siblings of whatever folder you cloned into) — it just never reconciled the hardcoded path inside the skill files. This is the folder-name sibling of #349 (which is about the ~/.claude prefix), and both point toward the dynamic-path-resolution direction from #289.

Proof (before → after)

Reproduced in a throwaway $HOME with the checkout copied to ~/.claude/skills/i-gstack (a name that isn't gstack) and ./setup --host claude, then running the exact commands a skill's opening steps run:

What a skill runs on startup Before this fix After this fix
~/.claude/skills/gstack/bin/gstack-config get proactive exit 127 (No such file) exit 0true
~/.claude/skills/gstack/bin/gstack-telemetry-log exit 127 exit 0
~/.claude/skills/gstack/bin/gstack-update-check exit 127 exit 0
~/.claude/skills/gstack didn't exist -> i-gstack

The fix (issue's option #1 — a compatibility symlink)

After setup links the Claude skills, if your install folder isn't named gstack it now plants one extra symlink: ~/.claude/skills/gstack -> <your install folder>. That makes every hardcoded ~/.claude/skills/gstack/... path resolve, with zero edits to any skill file.

Safe by design (link_gstack_compat_alias in setup):

  • No-op when your install is already named gstack (paths resolve natively).
  • Never clobbers a real gstack directory that's already there — that could be a separate install, and its own bin/ already works.
  • Idempotent — refreshes a stale alias instead of duplicating.
  • Routes through the existing _link_or_copy helper, so Windows-without-Developer-Mode falls back to a directory copy and the raw-ln invariant test stays green.

Claude Code already skips the repo-shaped gstack directory when it builds the slash-command list (see link_claude_root_skill_alias), so this alias is purely a path-resolution target, not a duplicate skill — which resolves the caveat the issue flagged.

Why not the other options: #2 (make the preamble resolve its own path at runtime) touches every generated skill and can't reliably self-locate in bash; #3 (rewrite the in-file paths for the Claude host) dirties the working tree, since that host symlinks to source instead of copying.

Tests

New: test/setup-gstack-compat-alias.test.ts — static wiring checks plus a behavioral matrix: non-gstack install plants the alias, gstack install is a no-op, a real pre-existing dir is not clobbered, a stale symlink is refreshed.

  • bun test test/setup-gstack-compat-alias.test.ts — pass
  • bun test test/setup-*.test.ts — 74 pass (includes the Windows raw-ln invariant)

Note for maintainers

Raw bug fix only — no VERSION/CHANGELOG bump. Leave versioning to a /ship pass.

🤖 Generated with Claude Code

…stack"

Every generated SKILL.md preamble hard-references the absolute self-path
~/.claude/skills/gstack/bin/... (config, telemetry, update-check, and all
other bin/asset calls). When gstack is installed at ~/.claude/skills/<name>
with <name> != gstack, setup's per-skill symlinks resolve correctly but those
in-file references point at a non-existent ~/.claude/skills/gstack/ and fail
SILENTLY at skill-invocation time (the preamble swallows the 127 via
`|| echo default`), so every config read falls back to defaults and telemetry
no-ops. Nothing surfaces at install; skills break later in a way that looks
like the skill itself is broken.

Fix: after linking the Claude host skills, plant a sibling compatibility alias
<skills_dir>/gstack -> <install_dir> whenever the install dir basename isn't
"gstack". Zero file edits; the hardcoded paths resolve through the alias.
Claude Code already skips the repo-shaped gstack directory when building the
slash-command list, so the alias is a path-resolution target only, not a
duplicate skill. It no-ops when the install is already named gstack and never
clobbers a real (non-symlink) gstack directory already present.

Adds test/setup-gstack-compat-alias.test.ts covering the static wiring and the
behavioral matrix (non-gstack install plants the alias, gstack install is a
no-op, real dir not clobbered, stale symlink refreshed).

Fixes garrytan#1882.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Jul 10, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@time-attack

Copy link
Copy Markdown
Author

Closing — opened without the author's sign-off. Will re-submit only after review and explicit approval.

@time-attack time-attack reopened this Jul 10, 2026
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.

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

1 participant