Skip to content

Project slash commands are invisible when .claude/commands/*.md are symlinks #2602

Description

@Johannes-Berggren

Summary

bb's slash-command typeahead shows no project commands when .claude/commands/*.md are symlinks. The host-daemon command scanner skips every symlinked directory entry, so a repo that symlinks its commands into a shared location gets an empty "project commands" section, while Claude Code's own CLI loads them fine.

Where

host-daemon src/command-discovery.ts, walkMarkdownTree:

for (const entry of entries) {
  if (entry.isSymbolicLink()) {
    continue;
  }
  ...
}

Symlinks are followed only for user-origin skill roots:

function canFollowSkillSymlink(root: CommandScanRoot): boolean {
  return root.origin === "user" && root.source === "skill";
}

walkMarkdownTree backs the command shape (resolveCommandScanRoots -> <cwd>/.claude/commands, origin: "project"), so a project command that is a symlink is never discovered, in any shape.

Reproduce

  1. In a project, mkdir -p .agents/skills/foo && printf -- '---\ndescription: demo\n---\nhi\n' > .agents/skills/foo/SKILL.md
  2. ln -s ../../.agents/skills/foo/SKILL.md .claude/commands/foo.md
  3. Open the slash-command menu in bb (or GET /api/v1/projects/<id>/commands?provider=claude-code&environmentId=<env>).

Expected: foo listed under project commands.
Actual: absent. Replacing the symlink with a regular file makes it appear immediately, which isolates the cause to the symlink check rather than the path, the environment, or caching.

Impact

Sharing one instruction file between Claude Code and Codex via symlinks is a common monorepo layout (.claude/commands/x.md -> .agents/skills/x/SKILL.md keeps the two harnesses from drifting). In our repo all 14 project commands are invisible in bb for this reason; the only visible non-builtin command is a regular file in ~/.claude/commands/.

Suggested fix

For the command shape, resolve symlinked entries with fs.stat and accept them when the target is a regular file inside the root's boundary. The cycle and root-escape concerns that motivate the blanket skip apply to recursive directory traversal; a symlinked leaf .md can be followed safely with a boundary check. Alternatively, extend canFollowSkillSymlink to project roots for file (non-directory) entries.

Version

bb 0.39.0, macOS (darwin 25.6.0), provider claude-code.

Activity

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

    provider-claude-codeBuilt-in plugin: provider-claude-codeprovidersCross-provider bridges, models, loginworkspacesWorktrees, environments, git, shells

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions