EXXETA / EXXETA/exxperts

Make web skill discovery recursive, matching the CLI

Open
#49 0 comments 0 reactions 0 assignees View on GitHub
enhancement
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.