[FEATURE] Recursive skill discovery - scan subdirectories in ~/.claude/skills/

Open 💬 37 comments Opened Jan 14, 2026 by simfor99
💡 Likely answer: A maintainer (wolffiex, collaborator) responded on this thread — see the highlighted reply below.

Summary

Currently, Claude Code only scans the top-level of ~/.claude/skills/ for skill directories containing SKILL.md files. Skills organized in subdirectories (e.g., ~/.claude/skills/spec-system/spec-creator/) are not discovered automatically.

Problem

When organizing related skills into logical groupings (suites), users must manually create symlinks at the top level for each nested skill:

~/.claude/skills/
├── spec-system/                    ← Container directory
│   ├── spec-creator/SKILL.md       ← Not discovered!
│   ├── spec-executor/SKILL.md      ← Not discovered!
│   └── spec-archiver/SKILL.md      ← Not discovered!
├── spec-creator → spec-system/spec-creator    ← Manual symlink required
├── spec-executor → spec-system/spec-executor  ← Manual symlink required
└── spec-archiver → spec-system/spec-archiver  ← Manual symlink required

Without symlinks, calling Skill("spec-creator") fails with "Unknown skill".

Proposed Solution

Recursively scan ~/.claude/skills/ (and .claude/skills/) for directories containing SKILL.md files, regardless of nesting depth.

Option A: Full Recursive Scan

Scan all subdirectories up to a reasonable depth (e.g., 3 levels).

Option B: Configurable Depth

Add a setting like skills.scanDepth: 2 to control how deep to scan.

Option C: Explicit Suite Marker

Only recurse into directories containing a marker file (e.g., SKILL_SUITE.md or .skill-suite).

Benefits

  1. Better organization - Group related skills (spec-system, gsd-toolkit, etc.)
  2. No manual symlink maintenance - Skills just work when placed in subdirectories
  3. Cleaner top-level - Reduce clutter in ~/.claude/skills/
  4. Suite versioning - Version control entire skill suites as units

Current Workaround

Users must:

  1. Create symlinks manually: ln -s spec-system/spec-creator spec-creator
  2. Maintain a validation script to check for missing symlinks
  3. Remember to create symlinks when adding new nested skills

Environment

  • Claude Code version: Latest (Jan 2026)
  • Platform: All (Linux, macOS, Windows)
  • Skills location: ~/.claude/skills/

Related

This is separate from the "nested skills" issues about skills calling other skills (#17351, #17339) - this is purely about directory structure and discovery.

View original on GitHub ↗

37 Comments

eins78 · 6 months ago

+1 for this feature. We have a specific use case that makes subdirectory support particularly valuable: Team-wide shared config via symlinks

We maintain a company config repo with shared skills, commands, and rules. Each developer symlinks it into their ~/.claude/:

ln -sfn /path/to/config-repo/skills ~/.claude/skills/acme

Inconsistency with commands: This pattern works perfectly for commands—~/.claude/commands/acme/init-agent.md becomes /acme:init-agent. But skills in ~/.claude/skills/acme/my-skill/SKILL.md aren't discovered.

Our workaround: We now iterate and create individual symlinks with a prefix:

for skill_dir in "$repo/skills"/*/; do
ln -sfn "$skill_dir" ~/.claude/skills/acme-"$(basename "$skill_dir")"
done

Recursive discovery (Option A) would let us use a single symlink like we do for commands.

wolffiex collaborator · 6 months ago

Fix is coming in 2.1.10 today

andrewreedy · 5 months ago

@wolffiex it doesn't look like this is working still. https://github.com/anthropics/claude-code/issues/10238#issuecomment-3754882855 -- These issues could likely be merged

yordis · 5 months ago

I just checked, I can confirm it does not work

RonanCodes · 5 months ago

Workaround for skill collections:

Until recursive discovery is implemented, here's a script to symlink all skills from a cloned repo:

#!/bin/bash
# sync-skills.sh - Symlink all skills from a collection
REPO_DIR="$1"
TARGET="${2:-$HOME/.claude/skills}"

for skill in "$REPO_DIR"/*/; do
  if [ -f "$skill/SKILL.md" ]; then
    ln -sf "$skill" "$TARGET/"
    echo "✓ $(basename $skill)"
  fi
done

Usage: ./sync-skills.sh ~/my-skills-repo

This lets you git pull to update and re-run the script for new skills. Not ideal, but works.

+1 for native recursive discovery!

RealmX1 · 5 months ago

would be even better if we can have dynamic loading of skills upon start working on subdirectories.

ThePlenkov · 4 months ago

Strange , version 2.1.6 changelog already declares that it should be enabled - but even i 2.1.45 i still see no efffect

ivanjuras · 4 months ago

Still not working. This is so bad.

wolffiex collaborator · 4 months ago

The nested skills feature is intended for subdirectories in e.g. a monorepo where you have like ./.claude/skills and ./sub-module/.claude/skills

directories inside a skill directory are not and have not been supported. what's the use case?

ThePlenkov · 4 months ago

@wolffiex think of global skills, not even project skills, you want to asemble it from different sources. So let's say we create ~/.agents directory ( codex, opencode, cascade already support it ) Now we want to add , personal, work skills . Or even like this we have own personal skills - but for sake of readability we want to structure them properly , like ( tools, integrations, cognitive skills ) and so on. In both cases it's a folder with skills with subfolders..

yordis · 4 months ago

@wolffiex you can see more in details at https://github.com/agentskills/agentskills/issues/59

Based on Boris response, you supposed to support it it is just a bug.

jameskoch · 4 months ago
The nested skills feature is intended for subdirectories in e.g. a monorepo where you have like ./.claude/skills and ./sub-module/.claude/skills

I have this exact layout. I'm running v2.1.63 and checking skills using /skills. Interestingly the skills in subdirectories are not eagerly loaded, but do become visible after some progressive directory exploration. If I ask claude to read a random non-skill file in subdir then it discovers and loads the skills.

I tried setting CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 as a means to force more eager loading, but it didn't alter behavior.

/tmp/proj $ find .
.
./.claude
./.claude/skills
./.claude/skills/foo
./.claude/skills/foo/SKILL.md
./subdir
./subdir/.claude
./subdir/.claude/skills
./subdir/.claude/skills/bar
./subdir/.claude/skills/bar/SKILL.md
wolffiex collaborator · 4 months ago

@jameskoch this is the intended behavior. it's to save context in environments where different modules in the same repo may be used independently. this is also how CLAUDE.md files work

wolffiex collaborator · 4 months ago

Ok, thanks for the clarification. @ThePlenkov and @yordis I understand this feature request. It's not what I meant by "nested skills" but it's totally valid. Is this part of the emerging skills spec? Do other clients support it?

yordis · 4 months ago
Is this part of the emerging skills spec? Do other clients support it?

@wolffiex It is tricky. The reason I created that issue in the agentskills itself is that the spec is not precise enough, so they are diverging in implementation. So, no?!
Which, personally, I do not care what the ultimate solution is, but ideally, all tools behave the same so we can adjust accordingly.

Claude is broken for me, while Cursor isn't broken. Ideally, I would appreciate being allowed to use subnested scanning since a lot of symlinking, personal stuff, and so on live in that directory without having to deal with any plugin system. The feedback loop and maintenance are too slow; those skills are changing as I go.

ivanjuras · 4 months ago
The nested skills feature is intended for subdirectories in e.g. a monorepo where you have like ./.claude/skills and ./sub-module/.claude/skills directories inside a skill directory are not and have not been supported. what's the use case?

The use case is better organization. Now we have to have a flat directory structure with skill prefixes as categories, which doesn't make sense.

/skills/design/skill1/
...
/skills/dev/skill1/
...

ThePlenkov · 4 months ago

I had to create another skill with own scripts which updates claude skills with flat structure using symlinks =)

ericdriggs · 4 months ago

@wolffiex
To add to @yordis 's point about Cursor - I can confirm it supports subfolder discovery. You can symlink multiple skill repos as subdirectories and they're discovered without flattening.

Re: the plugin system as an alternative path - it doesn't solve this either. Plugins cache copies to ~/.claude/plugins/cache/, which breaks the edit→test→commit loop. There's no plugin link for local
development, so you can't point Claude at a working git directory.

The feedback loop issue @yordis mentioned is real. Skills evolve as you use them. The current options are:

  1. Flat symlinks with manual sync scripts (what @ThePlenkov built)
  2. Plugin packaging with cached copies (breaks git workflow)

Neither supports iterating on skills across multiple source repos cleanly.

teobz · 3 months ago

+1 from me.

I’d also like .claude/skills/ to support recursive discovery so skills can be organised by category instead of forcing everything into a flat first-level structure.

e.g., I’d like to organise related skills like this:

.claude/
└── skills/
    ├── obsidian/
    │   ├── plugin-dev/
    │   │   └── SKILL.md
    │   └── dataview/
    │       └── SKILL.md
    └── etsy/
        ├── listing-copy/
        │   └── SKILL.md
        ├── seo-tags/
        │   └── SKILL.md
        └── product-photography/
            └── SKILL.md

That feels much more natural for larger skill libraries.

A recursive scan that recognises any directory containing SKILL.md under a skills root would make skill organisation much cleaner while keeping existing flat layouts compatible 🤷

yordis · 3 months ago

Current behavior

The skill directory scanner does a single readdir() and checks each immediate child for a SKILL.md. No recursion.

.claude/skills/
  deploy/SKILL.md              ✅ discovered
  lint/elixir/SKILL.md         ❌ never reached
  lint/typescript/SKILL.md     ❌ never reached

How the loader works

5 skill sources, loaded in priority order:

  1. Managed/MDM/Library/Application Support/ClaudeCode/skills/ (macOS)
  2. User~/.claude/skills/
  3. Project.claude/skills/ walked upward from cwd to filesystem root
  4. Additional dirs--add-dir arguments, each gets .claude/skills/ scanned
  5. Legacy commands — deprecated commands/ directories from plugins

All 5 feed through the same directory scanner function:

scanSkillDir(dir, source):
  readdir(dir)
  for each entry:
    skip if not directory and not symlink
    try to read entry/SKILL.md
    if found:
      parse YAML frontmatter (regex: /^---\s*\n([\s\S]*?)---\s*\n?/)
      extract fields (description, allowed-tools, model, paths, hooks, etc.)
      build skill descriptor
    if not found:
      skip (no recursion)

The skill name is set to entry.name (the immediate directory name). After collection, skills are deduplicated by SHA-256 of file content, then split into unconditional (immediately active) and conditional (activated when matching files are touched, via the paths: frontmatter field).

What needs to change

One function — the directory scanner. Same signature (dir: string, source: string) → Promise<{ skill, filePath }[]>.

Make it recursive, but stop descending into a directory once a SKILL.md is found thereSKILL.md acts as a leaf marker (same pattern as .git or package.json):

walk(dir):
  if dir/SKILL.md exists → parse it, return (don't recurse further)
  else → readdir(dir), walk each child directory

The skill name changes from entry.name to path.relative(root, dir) with path separators replaced by : — so lint/elixir/SKILL.md becomes lint:elixir. This is already the convention for namespaced skills (plugins use it), so flat layouts produce the same single-segment names as today.

The dynamic rediscovery codepath also calls the same scanner, so it benefits automatically.

What this enables

.claude/skills/
  deploy/SKILL.md                        → /deploy
  lint/
    elixir/SKILL.md                      → /lint:elixir
    typescript/SKILL.md                  → /lint:typescript
  event-modeling/
    brainstorming/SKILL.md               → /event-modeling:brainstorming
    plotting/SKILL.md                    → /event-modeling:plotting
  testing/
    SKILL.md                             → /testing (leaf — children ignored)
    fixtures/                            → supporting files, not a skill

Reference implementation

Drop-in replacement for the current scanner — same signature, same return type:

import { readdir, readFile } from "fs/promises";
import { join, relative, sep, basename } from "path";

/**
 * Recursively discover SKILL.md files in a directory tree.
 * Stops descending once a SKILL.md is found (leaf marker pattern).
 *
 * @param rootDir - Skills root (e.g. ~/.claude/skills/)
 * @param source  - Permission source ("userSettings" | "projectSettings" | "policySettings")
 * @returns Array of { skill, filePath }
 */
async function scanSkillsRecursive(
  rootDir: string,
  source: string,
): Promise<{ skill: Skill; filePath: string }[]> {
  const fs = getFs();
  const results: { skill: Skill; filePath: string }[] = [];

  async function walk(dir: string): Promise<void> {
    const skillPath = join(dir, "SKILL.md");

    // Try to read SKILL.md in this directory
    let content: string;
    try {
      content = await fs.readFile(skillPath, { encoding: "utf-8" });
    } catch {
      // No SKILL.md here — recurse into children
      let entries;
      try {
        entries = await fs.readdir(dir);
      } catch (err) {
        if (!isEnoent(err)) logError(err);
        return;
      }

      await Promise.all(
        entries.map(async (entry) => {
          try {
            if (entry.isDirectory() || entry.isSymbolicLink()) {
              await walk(join(dir, entry.name));
            }
          } catch (err) {
            logError(err);
          }
        }),
      );
      return;
    }

    // Found SKILL.md — parse and DO NOT recurse further
    try {
      const { frontmatter, content: body } = parseFrontmatter(content, skillPath);

      // "lint/elixir" → "lint:elixir", fallback to basename for root-level
      const name =
        relative(rootDir, dir).split(sep).join(":") || basename(dir);

      const fields = parseFields(frontmatter, body, name);
      const paths = parsePaths(frontmatter);

      results.push({
        skill: createSkill({
          ...fields,
          skillName: name,
          markdownContent: body,
          source,
          baseDir: dir,
          loadedFrom: "skills",
          paths,
        }),
        filePath: skillPath,
      });
    } catch (err) {
      logError(err);
    }
  }

  await walk(rootDir);
  return results;
}

Edge cases to consider

  • Flat layouts — no behavior change, relative() returns just the dir name
  • SKILL.md at skills root itself — name falls back to basename(dir)
  • SKILL.md + subdirs with their own SKILL.md — only the parent is discovered (leaf boundary stops descent)
  • Symlinks — already followed today (isSymbolicLink() check), would work the same in nested dirs
  • Symlink cycles — not handled today either, could be addressed with a visited-set if desired
yordis · 3 months ago

@wolffiex I expend some time trying to dig out as much context as possible from the existing compilation, it sounds something the AI would one-shot very easy, please, help us here 🙏🏻 this is the only frustration I have with claude at the moment

ivanjuras · 3 months ago

@wolffiex Can you please look into this? Please?

mecampbellsoup · 3 months ago

Adding a data point confirming this is still broken on CC 2.1.104 (post the 2.1.10 fix). Verified via a minimal harness:

parent/
├── sub-a/.claude/skills/foo-test/SKILL.md
└── sub-b/.claude/skills/bar-test/SKILL.md

Launching CC at parent/:

  • Eager: /foo-test → "unknown slash command"
  • Lazy (read regular file in sub-a/ first): still not found
  • Lazy (read the SKILL.md itself): still not found
  • Control (launch in sub-a/): ✅ works as expected

Reproduces in both interactive and --print modes. The phrasing in the skills doc ("Automatic discovery from nested directories") is not accurate in practice today — also tracked in #40640.

Genuine question for maintainers: is this lower-priority because the intended path for sharing skills across multiple repos (monorepos, or side-by-side repos opened from a parent dir) is meant to be plugins + enabledPlugins rather than nested .claude/skills/? The other parts of the CC config model seem to support that interpretation:

  • Plugins are globally loadable via settings
  • .mcp.json walks up ancestors (not nested)
  • CLAUDE.md nests on-demand

...which would position subdir .claude/skills/ as a single-project convenience rather than a first-class multi-repo primitive. If that's the design direction, it'd help to:

  1. Update the skills doc — current phrasing implies nested discovery is a supported primary path
  2. Add "share skills across repos" guidance pointing to plugins

If we're misreading the design and this just needs more time on the roadmap, that'd also be useful to know. Our team is building tooling across two repos and trying to pick the right abstraction to invest in.

jsulopzs · 3 months ago

+1 on recursive discovery. Sharing a real-world setup where this would be the missing piece, plus a concrete two-track proposal that's non-breaking and, I think, trivial to implement.

Current workaround: parent skill + opaque workflow files

I maintain a multi-workflow skill (crm:pm) that routes via a table in SKILL.md:

crm/skills/pm/
├── SKILL.md                     # routing table + shared context
└── workflows/
    ├── update.md                # plain markdown, no frontmatter
    ├── register.md
    ├── proposal-workflow.md
    └── daily-planning.md

SKILL.md contains:

| Argument pattern                         | Workflow |
|------------------------------------------|----------|
| `update`, `daily update`                 | @workflows/update.md |
| `plan`, `organize day`, `expand update`  | @workflows/daily-planning.md |
| `proposal`                               | @workflows/proposal-workflow.md |

This works, but the workflow files are invisible to Claude's skill discovery. The only way to reach them is via the parent skill's routing table, which requires the user to phrase the request in a way that matches an entry. Natural-language invocation ("help me plan the day") doesn't trigger them directly.

Proposal — two separable tracks

Track 1: Generalized recursive discovery (primary ask)

Rule: walk any subfolder of a skills/ root until a SKILL.md is found. That SKILL.md is the skill; don't descend further once matched (preserves skill isolation).

Key points:

  • Not tied to a workflows/ convention — the folder name is irrelevant. Any depth, any naming.
  • Backward compatible: existing flat skills (skills/pm/SKILL.md) still work unchanged. Sibling-flat layouts (skills/auto/SKILL.md, skills/cuts/SKILL.md) still work. Nothing breaks.
  • Implementation: add one pattern to the discovery walker. The walker already knows where skills/ roots are; just recurse until hitting SKILL.md.

Example after Track 1 — same directory tree as above but each workflow is now a folder with its own SKILL.md:

crm/skills/pm/
├── SKILL.md                     # parent: shared context + optional routing table
└── workflows/
    ├── update/SKILL.md          # child skill, frontmatter with description
    ├── daily-planning/SKILL.md
    └── proposal-workflow/SKILL.md

Both invocation paths now work:

  1. LLM inference from description — child skill is discoverable via its own description:, so Claude triggers it naturally on "help me plan the day" without the parent being invoked.
  2. Explicit parent routing — parent SKILL.md keeps its table with @workflows/daily-planning/SKILL.md references for when the user wants the CRM-specific preamble (context-loading rules, entity format, shared CLI conventions) loaded first.

Slash-command naming: reflect the path with colons, e.g. /crm:pm:daily-planning. Keeps namespacing unambiguous and matches the current /<plugin>:<skill> convention by extension.

Frontmatter conflicts between parent and child: child wins. Parent is context, child is the active skill being invoked.

Track 2 (bonus, separable): Auto-attach ancestor SKILL.md files on the path

When a nested child skill is invoked, the harness automatically prepends every SKILL.md on the path from the skills/ root down to the child into the system prompt.

Invoking:  skills/pm/workflows/daily-planning/SKILL.md
Attached:  skills/pm/SKILL.md  →  skills/pm/workflows/daily-planning/SKILL.md
                 (parent first)              (child second)

This gives progressive disclosure for free — the shared preamble (auth, conventions, CRM entity format, pm graphql usage) is loaded without needing @ references in each child SKILL.md. DRY by construction.

Why separable from Track 1: Track 1 is a trivial discovery-code change. Track 2 introduces token-cost and ordering questions (below) that could legitimately take longer to design. Shipping Track 1 alone is already hugely valuable — users can opt into Track 2's effect manually via @../SKILL.md references until it lands natively.

Open questions (Track 2)

  • Always-attach vs lazy: should ancestor SKILL.md files be appended to the system prompt on every invocation of the child, or only loaded on first mention? Always-attach is simpler; lazy is more token-efficient but harder to reason about.
  • Cross-plugin path traversal: if a skill lives at skills/pluginA/skills/pluginB/child/SKILL.md (or something exotic), should pluginA's SKILL.md be attached? My intuition: discovery should never cross plugin boundaries; ancestors are only attached within the same plugin.

Please fix the nested-invocation bugs at the same time

If recursive discovery ships (and especially if Track 2 lands), the existing bugs around skill-calls-skill should be addressed in parallel, or hierarchical invocation stays fragile:

  • #30028 — parent skill halts entirely after nested completes
  • #17351 — nested skill doesn't return to parent context
  • #39138 — 3-level nesting not discovered
  • #40640 — "Automatic Discovery from Nested Directories" docs don't match actual behavior

TL;DR

Two non-breaking tracks, ship independently:

  1. Recursive discovery: walk any depth under skills/<plugin>/ until hitting SKILL.md; folder names arbitrary. Slash command reflects path (/crm:pm:daily-planning). Existing skills keep working.
  2. Auto-attach ancestors (separable bonus): when a nested child is invoked, prepend every SKILL.md on the path into the system prompt. Progressive disclosure without manual @ plumbing.

Child wins on frontmatter conflicts. Cross-plugin traversal: probably no.

webern · 3 months ago

I want this feature so that I can have global symlinks to different source control repositories:

~/.claude/skills/personal -> $REPOS/personal-skills

~/.claude/skills/work -> $REPOS/skills-that-shouldnt-leave-the-corp-environment

I don't want to have to create per-skill symlinks and update them when creating or deleting a skill.

ThePlenkov · 3 months ago

It's unbelievable to observe how much behind other agents claude stands today in terms of unified agents dev experience being stuck with such straightforward requests as this one, or chat history lost.. I can only explain this that they are trying possibly to keep staying a trendmaker and focusing on new features no matter what's in backlog.. But community demand should be also respected guys..

schmunk42 · 2 months ago

FWIW, my (old) commands are treated as skills in my case.
/company:time-tracking is actually a command, but was automatically loaded and used as a skill for the prompt create a time tracking entry for yesterday.

It resides in a subdirectory btw.

●  ▐▛███▜▌   Claude Code v2.1.114
  ▝▜█████▛▘  Opus 4.7 (1M context) · Claude Team
    ▘▘ ▝▝    ~/Workspace/project

  ❯ create a time tracking entry for yesterday

  ● Skill(/company:time-tracking)
    ⎿  Successfully loaded skill

  ● Bash(mkdir -p ~/Workspace/project/_debug/tt-2026-04-20/phase-1
        ~/Workspace/project/_debug/tt-2026-04-20/phase-2
        ~/Workspace/project/_debug/tt-2026-04-20/phase-3
        ~/Workspace/project/_debug/tt-2026-04-20/phase-4)
    ⎿  Done

  ● Bash(python3 ~/Workspace/company/ai/scripts/tt-aw-extract.py 2026-04-20
        ~/Workspace/project/_debug/tt-2026-04-20/)
    ⎿  Window bucket aw-watcher-window_hostname: 7442 events
       AFK bucket aw-watcher-afk_hostname: 135 events
       ActivityWatch extraction complete: 7442 window, 135 afk events

  ● Bash(python3 ~/Workspace/company/ai/scripts/tt-claude-extract.py 2026-04-20
        ~/Workspace/project/_debug/tt-2026-04-20/)
    ⎿  Claude sessions extraction complete: 178 entries

  ● email-searcher - open_mailbox (MCP)

  ● basecamp2 - bcx_people_get_current (MCP)

  ● email-searcher - search_by_subject (MCP)(subject: "Re:", startDate: "2026-04-20", endDate: "2026-04-20 23:59:59")

  ● basecamp2 - bcx_people_get_assigned_todos (MCP)(personId: "XXXXXXXX")
eins78 · 2 months ago

I gave a +1 for this feature back in january, but much has change since and I'd argue this should be closed.

Custom Marketplaces and plugins are much better ways to achieve the use cases that would need recursive skill discovery. Since they both can be local only (don't need to distributed via GitHub), I think there is no reason for skill sub-dirs anymore.

webern · 2 months ago
I gave a +1 for this feature back in january, but much has change since and I'd argue this should be closed. Custom Marketplaces and plugins are much better ways to achieve the use cases that would need recursive skill discovery. Since they both can be local only (don't need to distributed via GitHub), I think there is no reason for skill sub-dirs anymore.

I don't think these address my use case (from above):

I want this feature so that I can have global symlinks to different source control repositories: ~/.claude/skills/personal -> $REPOS/personal-skills ~/.claude/skills/work -> $REPOS/skills-that-shouldnt-leave-the-corp-environment I don't want to have to create per-skill symlinks and update them when creating or deleting a skill.

Are you saying "marketplace" would solve this problem?

jsulopzs · 2 months ago

@wolffiex hi Adam, would you mind sharing what the team is internally thinking about this feature, please?

ivanjuras · 2 months ago

@wolffiex Can we please get some update on this? Please.

tleszczynski-cribl · 2 months ago

+1

ZahScr · 2 months ago

+1

steinybot · 2 months ago
+1 for this feature. We have a specific use case that makes subdirectory support particularly valuable: Team-wide shared config via symlinks We maintain a company config repo with shared skills, commands, and rules. Each developer symlinks it into their ~/.claude/: ln -sfn /path/to/config-repo/skills ~/.claude/skills/acme Inconsistency with commands: This pattern works perfectly for commands—~/.claude/commands/acme/init-agent.md becomes /acme:init-agent. But skills in ~/.claude/skills/acme/my-skill/SKILL.md aren't discovered. Our workaround: We now iterate and create individual symlinks with a prefix: for skill_dir in "$repo/skills"/*/; do ln -sfn "$skill_dir" ~/.claude/skills/acme-"$(basename "$skill_dir")" done Recursive discovery (Option A) would let us use a single symlink like we do for commands.

@eins78 you don't need to do that. I mean it works but a better solution IMO is to use Vercel's skills CLI and point it at a GitHub repo with a skills/ directory.

anujkumar-df · 1 month ago

Highly need this feature. We embed skills in the product repos. Don't need extra plumbing just to distribute them.

XedinUnknown · 28 days ago

Would be very useful together with e.g. agentdeps, which puts its skills into .agents/skills/_agentdeps_managed/.

rhigonet · 24 days ago

+1