Skip to content

connect-chrome and open-gstack-browser install with the same frontmatter name, so one silently shadows the other #2201

Closed

Description

@jonahberg

Summary

connect-chrome and open-gstack-browser are installed into ~/.claude/skills/ as two separate skill directories that both declare name: open-gstack-browser in their frontmatter. Claude Code keys skills on that frontmatter name, so the two collide: one is silently discarded, and which one survives follows unsorted readdir order.

On my machine connect-chrome won, so /open-gstack-browser is not a registered command — even though README.md, AGENTS.md, the router SKILL.md, and the sidebar extension's copy-to-clipboard button all tell users to run exactly that.

Why it happens

In the repo, connect-chrome is a symlink to open-gstack-browser (one skill, correct). The collision is created at install time, by two independent paths:

  1. bin/gstack-relink discovers skills with for skill_dir in "$INSTALL_DIR"/*/. The trailing-slash glob matches the connect-chrome symlink, and the loop names the installed entry from the directory basename while symlinking the canonical SKILL.md into it. Result: skills/connect-chrome/SKILL.md -> .../open-gstack-browser/SKILL.md, carrying name: open-gstack-browser.

  2. setup then re-creates the same alias explicitly:

    # Backwards-compat alias: /connect-chrome → /open-gstack-browser
    _OGB_LINK="$INSTALL_SKILLS_DIR/connect-chrome"
    ...
    _link_or_copy "gstack/open-gstack-browser" "$_OGB_LINK"

    which symlinks the alias directory straight at the canonical skill directory — so its SKILL.md is, again, the canonical one.

Note that setup's own link_claude_skill_dirs is not the culprit: it derives the entry name from the frontmatter name:, so it maps both directories onto a single open-gstack-browser target. Only the two paths above mint a second, differently-named directory holding the same frontmatter name.

Reproduction

Against 11de390 (v1.58.5.0), using only the shipped scripts:

T=$(mktemp -d); I="$T/gstack-install"; S="$T/skills"
mkdir -p "$I/bin" "$S"
cp bin/gstack-config bin/gstack-relink bin/gstack-patch-names "$I/bin/"; chmod +x "$I/bin"/*
mkdir -p "$I/open-gstack-browser"
printf -- '---\nname: open-gstack-browser\ndescription: launch\n---\n# ogb\n' > "$I/open-gstack-browser/SKILL.md"
ln -s open-gstack-browser "$I/connect-chrome"          # exactly as the repo ships it
printf -- '---\nname: gstack\ndescription: root\n---\n# root\n' > "$I/SKILL.md"

GSTACK_STATE_DIR="$T" GSTACK_INSTALL_DIR="$I" GSTACK_SKILLS_DIR="$S" "$I/bin/gstack-config" set skill_prefix false
GSTACK_STATE_DIR="$T" GSTACK_INSTALL_DIR="$I" GSTACK_SKILLS_DIR="$S" "$I/bin/gstack-relink"

for d in "$S"/*/; do
  echo "$(basename "$d") -> $(grep -m1 '^name:' "$d/SKILL.md")"
done

Actual:

_gstack-command -> name: gstack
connect-chrome -> name: open-gstack-browser      # <-- collides
open-gstack-browser -> name: open-gstack-browser # <-- collides

Expected: three distinct names.

This also matches a real install (~/.claude/skills/connect-chrome/SKILL.md is a symlink into gstack/connect-chrome/SKILL.md).

Impact

  • /open-gstack-browser is missing on an arbitrary subset of installs, while every doc and the browser extension reference it.
  • Which command exists is non-deterministic across machines, so the failure is hard to reproduce and reads to users as "gstack is broken on my laptop."
  • A user auditing their skills sees two entries for one skill.

Suggested fix

Install the backwards-compat alias as a thin skill with its own name: that delegates to the canonical skill, rather than as a symlink to the canonical skill directory. Then both /connect-chrome and /open-gstack-browser register, on every machine.

I have a PR ready that does this in bin/gstack-relink (making it the single owner of the alias), removes the now-duplicated alias blocks from setup, and adds five regression tests to test/relink.test.ts covering the name-uniqueness invariant, the skill_prefix flip, idempotency, and in-place upgrade of existing symlinked aliases.

Environment

  • gstack 11de390 (v1.58.5.0)
  • Claude Code 2.1.205, native install, macOS 15 (Darwin 25.5.0)
  • bun 1.3.14

Activity

  1. added a commit that references this issue on Jul 14, 2026
    cd5a859
  2. time-attack commented on Jul 15, 2026

    @time-attack
    Contributor

    @16francej — recommend closing this issue as a duplicate of #2199. The collision is valid, but #2199 already owns the packaging and legacy-alias contract for one discoverable browser-opening skill, so splitting it would divide one acceptance surface. Fold #2201’s deterministic same-name reproduction and reporter attribution into #2199.

  3. added a commit that references this issue on Aug 17, 2026
    ae8914a
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