Skip to content

gstack-investigate: PreToolUse hook path breaks on standalone marketplace installs (/../freeze/bin/check-freeze.sh not found) #1647

Closed

Description

@ElliotDrel

Summary

When gstack-investigate is invoked, it registers a PreToolUse:Edit and PreToolUse:Write hook with this command:

bash ${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh

This path assumes both gstack-investigate and gstack-freeze are installed under a shared parent directory (monorepo-style, e.g. ~/.claude/skills/gstack/investigate/ and ~/.claude/skills/gstack/freeze/). But when installed as standalone marketplace skills, they land at:

  • ~/.claude/skills/gstack-investigate/
  • ~/.claude/skills/gstack-freeze/

So ${CLAUDE_SKILL_DIR}/../freeze/ resolves to ~/.claude/skills/freeze/ — which doesn't exist.

Error Observed

PreToolUse:Edit hook error
Failed with non-blocking status code: bash: /../freeze/bin/check-freeze.sh: No such file or directory

This fires on every Edit and Write operation for the duration of the session.

Impact

  • ~150–800ms wasted per Edit/Write operation (bash tries to exec a nonexistent path)
  • Noisy error shown in the UI on every file edit
  • The scope lock feature silently fails — gstack-investigate's "debug scope boundary" never actually enforces anything on standalone installs

Root Cause Detail

The YAML frontmatter hook is registered unconditionally at skill invocation time:

hooks:
  PreToolUse:
    - matcher: "Edit"
      hooks:
        - type: command
          command: "bash ${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh"
          statusMessage: "Checking debug scope boundary..."

The skill DOES have a safety check in the Scope Lock workflow section (line ~791):

[ -x "${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh" ] && echo "FREEZE_AVAILABLE" || echo "FREEZE_UNAVAILABLE"

When FREEZE_UNAVAILABLE, it skips writing the freeze-dir state. But the YAML-level hooks are already registered and fire on every Edit regardless.

Reproduction

  1. Install gstack-investigate and gstack-freeze as standalone marketplace skills (not from a bundled gstack install)
  2. Invoke gstack-investigate in a session
  3. Attempt any Edit or Write operation
  4. Observe the /../freeze/bin/check-freeze.sh: No such file or directory error on every edit

Suggested Fixes

Option A — Correct the relative path for standalone installs:

bash ${CLAUDE_SKILL_DIR}/../gstack-freeze/bin/check-freeze.sh

Option B — Guard the hook command so it's a no-op when the script is missing:

bash -c '[ -x "${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh" ] && bash "${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh" || exit 0'

Option C — Gate hook registration on freeze availability (may not be possible in the current YAML hook format).

Environment

  • Platform: Windows 11 / Claude Code
  • gstack-investigate: standalone marketplace install at ~/.claude/skills/gstack-investigate/
  • gstack-freeze: standalone marketplace install at ~/.claude/skills/gstack-freeze/
  • Discovered via session transcript bfeeec6a-fd3e-4eb2-916b-5ec313989fe8 (RunPulse project)

Activity

  1. ElliotDrel commented on May 22, 2026

    @ElliotDrel
    ContributorAuthor

    Additional Findings (from local fix)

    Second broken site: scope lock check

    The same bad path appears in the Scope Lock workflow section (not just the YAML hooks):

    [ -x "${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh" ] && echo "FREEZE_AVAILABLE" || echo "FREEZE_UNAVAILABLE"

    On standalone installs this always returns FREEZE_UNAVAILABLE, so the debug scope boundary silently never enforces anything — no error is shown, it just quietly skips writing freeze-dir.txt. The hook fires (and fails noisily), but the state file that controls what the hook actually blocks never gets written. The net result: scope lock is fully non-functional on standalone installs.

    Two files need fixing, not one

    There are two separate SKILL.md files for gstack-investigate:

    • ~/.claude/skills/gstack-investigate/SKILL.md (standalone marketplace install)
    • ~/.claude/skills/gstack/investigate/SKILL.md (bundled install)

    Plus the template:

    • ~/.claude/skills/gstack/investigate/SKILL.md.tmpl

    All three have both broken spots.

    Exact fix applied locally

    Hook command (try bundled path first, fall back to standalone, exit cleanly if neither exists):

    command: "bash -c 'S=\"${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh\"; [ ! -x \"$S\" ] && S=\"${CLAUDE_SKILL_DIR}/../gstack-freeze/bin/check-freeze.sh\"; [ -x \"$S\" ] && bash \"$S\" || exit 0'"

    Scope lock check (handles both install conventions):

    { [ -x "${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh" ] || [ -x "${CLAUDE_SKILL_DIR}/../gstack-freeze/bin/check-freeze.sh" ]; } && echo "FREEZE_AVAILABLE" || echo "FREEZE_UNAVAILABLE"
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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions