Make web skill discovery recursive, matching the CLI
- Dominant language
- TypeScript
- Stars
- 354
- Forks
- 40
- PR merge metrics
- No merged PRs in 30d
Description
## Problem
The CLI and the web app use different rules to discover skills.
The CLI scans skill directories recursively and follows directory symlinks. The web skill library checks only this path:
```text
//SKILL.md
```
This difference prevents the web app and rooms from finding skills inside a repository-level symlink.
## Example
```text
~/.agents/skills/agent-skills -> ~/Projekte/agent-skills
~/Projekte/agent-skills/skills//SKILL.md
```
With this structure:
- The CLI finds 72 skills.
- The web API finds 24 direct skills.
- The web app misses 48 skills below the `agent-skills` symlink.
A symlink that points directly to one skill works. A symlink that points to a repository or collection does not work.
## Expected behavior
The CLI, web skill library, and rooms should use the same recursive discovery rules. This behavior also matches Pi, Claude Code, and Codex.
## Current implementation
The CLI loader recursively calls `loadSkillsFromDirInternal()` and resolves symlinks with `realPath()`:
```text
runtime/packages/agent/src/harness/skills.ts
```
The web library reads only direct children and checks `path.join(dir, entry.name, "SKILL.md")`:
```text
apps/web-server/src/index.ts
```
The current symlink test covers only a direct symlink to one skill. It does not cover a symlink to a directory that contains several skills:
```text
apps/web-server/scripts/skills-shared-dir-smoke.ts
```
I reproduced the API result locally with v0.8.0. The same non-recursive web discovery code is present in v0.10.1 (`2963a17d9d4b58581d94a8b954511a5c04bb870a`).
## Suggested change
Use the recursive runtime discovery rules for the web skill library and room skill resolution.
Please keep these existing rules:
- Skip dot directories and `node_modules`.
- Honor ignore files.
- Keep the current source precedence.
- Prevent loops when symlinks point back to a parent directory.
- Use the same resolved manifest path for listing, enabling, and fingerprint checks.
## Acceptance criteria
- The web library finds skills in nested directories.
- The web library follows a symlink to a repository or skill collection.
- Direct skill symlinks continue to work.
- The CLI and web app list the same skills for the same configured roots.
- A symlink loop does not hang the scan.
Contributor guide
Research direction
Compare the recursive loader in runtime/packages/agent/src/harness/skills.ts with web discovery in apps/web-server/src/index.ts, then inspect apps/web-server/scripts/skills-shared-dir-smoke.ts. Run the existing smoke coverage first and trace how manifests are used for listing, enabling, and fingerprints. Done means nested and repository symlink skills match CLI results, direct symlinks still work, and symlink loops terminate.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100