Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
833 changes: 833 additions & 0 deletions .claude/plans/recommended-skill-catalog.md

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -51,6 +51,20 @@ jobs:
- run: bun install --frozen-lockfile --ignore-scripts
- run: bun run lint

catalog-manifest:
name: Catalog Manifest
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
with:
bun-version-file: package.json
- run: bun install --frozen-lockfile --ignore-scripts
- run: bun run catalog:validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

test:
name: Test
runs-on: ubuntu-latest
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,13 @@

**Migration**: Re-run `allagents mcp update` or `allagents update` after upgrading so synced client configs are regenerated with `mcp proxy`.

### Added

- **Recommended skill catalog**: Added `allagents skill search <query> --catalog recommended`, a hard discovery boundary over curated repository, subtree, marketplace-backed, search-only, and external-lifecycle sources. The catalog includes gstack, Paperclip companies, Matt Pocock skills, Composio awesome skills, distinct Hermes core and optional roots, Anthropic skills and knowledge-work plugins, Addy Osmani skills, obra superpowers, and context-engineering skills.
- Catalog results expose classification, install policy, warnings, source metadata, exact install source and selector, and separate discovery provenance. **Recommended** is a discovery label, not a security, trust, quality, or license guarantee.
- Interactive `skill search` and full-screen TUI discovery now fetch Recommended and global GitHub results concurrently, render Recommended first and All GitHub second, and let Recommended win exact repository/skill-path duplicates. Partial failures are labeled while surviving results remain usable. JSON, redirected no-catalog output, owner-scoped search, and explicit strict catalog search keep their previous boundaries. Exact catalog install descriptors survive selection in both interactive surfaces. Optional sources require confirmation, while search-only and external-installer sources remain non-installable.
- Added authenticated, read-only catalog health validation in CI for repository/ref/root drift, skill presence, local authoritative marketplace paths, and source identity. The check never mutates, vendors, or automatically updates catalog entries.

## [1.0.0] - 2026-03-13

### Breaking Changes
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -95,6 +95,7 @@ clients:
| `allagents plugin uninstall <spec>` | Remove a plugin |
| `allagents plugin list` | List available plugins |
| `allagents skill add <name>` | Add a skill from a repo (plural `skills` alias supported) |
| `allagents skill search <query> [--catalog recommended]` | Interactive discovery shows Recommended then global GitHub; `--catalog` is strict catalog-only search |
| `allagents skill list` | List skills and status |
| `allagents mcp add <name> <commandOrUrl>` | Add an MCP server and sync to clients |
| `allagents mcp proxy <serverUrl>` | Bridge a remote HTTP MCP server to local stdio |
Expand All@@ -104,6 +105,30 @@ clients:

See the [full CLI reference](https://allagents.dev/docs/reference/cli/) for all options.

## Recommended Skill Catalog

In an interactive terminal, `allagents skill search <query>` automatically
shows two ordered sections: **Recommended** first, then **All GitHub**. The
Recommended section is fetched through the built-in catalog boundary rather
than inferred from globally ranked results. Identical repository and skill-path
hits are removed from All GitHub so the Recommended result wins.

Scripts, redirected output, and `--json` keep the existing global GitHub
no-option response. Use `--catalog recommended` when discovery must be strictly
limited to the built-in, versioned catalog:

```bash
allagents skill search testing --catalog recommended
```

Strict catalog failures and empty results never fall back to global search. In
combined interactive discovery, the two searches run concurrently; if one is
unavailable, its section is visibly marked and the surviving section remains
usable. **Recommended** is a discovery label, not a security, trust, quality,
or license guarantee. Review each result's source, classification, policy,
warnings, and upstream content. Installable selections retain the exact
repository, ref, catalog root, selected skill subset, and provenance.

## Supported Clients

**23 AI coding assistants** across two tiers:
Expand Down
32 changes: 32 additions & 0 deletions docs/src/content/docs/docs/guides/marketplaces.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,38 @@ allagents plugin marketplace add owner/repo --branch feat/v2 --name repo-v2

The bare repo name (e.g., `repo`) is reserved for the default branch. Updates automatically pull the correct branch.

## Recommended Catalog vs. Marketplaces

The built-in Recommended skill catalog is a static discovery index, not a
`MarketplaceRegistry` entry. Interactive searches with no explicit owner or
catalog show Recommended first and deduplicated All GitHub results second. Use
the explicit flag for a strict catalog-only search suitable for scripts:

```bash
allagents skill search <query> --catalog recommended
```

The catalog includes heterogeneous source types: direct repositories,
subtrees, valid marketplace-backed distributions, search-only repositories,
and projects with an external installation lifecycle. Catalog inclusion does
not make a source a marketplace or imply that it is one-click installable.
Search-only sources cannot be selected. External-lifecycle sources show
upstream guidance; AllAgents never executes their installer.

For a marketplace-backed catalog result, AllAgents validates the authoritative
upstream manifest and registers it only when the user selects an installable
skill. Project selection writes to the project-scoped registry; it does not
mutate the user's global marketplace registry. The catalog's exact repository,
default-branch ref, root, source identity, and selected skill paths are retained
for sync. Sources with broken or ambiguous manifests are represented honestly
as search-only rather than repaired with a generated manifest.

**Recommended** means curated for discovery only. It is not a security audit,
trust endorsement, quality guarantee, or license assertion. Review upstream
code and the per-result classification, policy, warnings, author, homepage, and
license metadata before installation. Catalog health validation detects source
drift; it does not vendor, rewrite, or automatically update upstream content.

## Creating a Marketplace

```
Expand Down
68 changes: 68 additions & 0 deletions docs/src/content/docs/docs/reference/cli.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,7 @@ allagents skill list [--scope <scope>]
allagents skill remove <skill> [--plugin <plugin>] [--scope <scope>]
allagents skill add <skill> [--from <source>] [--plugin <plugin>] [--scope <scope>]
allagents skill update [skill...] [--scope <scope>] [--yes]
allagents skill search <query> [--catalog recommended] [--owner <owner>] [--page <n>] [--limit <n>]
```

### plugin list
Expand DownExpand Up@@ -258,6 +259,73 @@ allagents skill add brainstorming --plugin superpowers

After enabling, the skill is removed from `disabledSkills` and sync is run to restore it.

### skill search

Search public `SKILL.md` files. In an interactive terminal with no explicit
`--catalog` or `--owner`, results appear in two ordered sections:

1. **Recommended** — an independent catalog-bounded search, including catalog
classification, policy, warnings, metadata, and exact install descriptors.
2. **All GitHub** — ordinary global results, excluding identical repository and
skill-path identities already shown in Recommended.

This separate catalog query prevents Recommended matches from being displaced
by global ranking or pagination. Both searches run concurrently after the user
submits a term. If one side fails, its section is marked unavailable and the
surviving results remain selectable rather than being presented as complete.

Scripts, redirected output, and `--json` retain the existing global GitHub
no-option contract:

```bash
allagents skill search terraform
allagents --json skill search terraform
allagents skill search terraform --owner hashicorp
```

Use the built-in Recommended catalog explicitly when discovery must stay within
its exact repository and subtree boundaries:

```bash
allagents skill search testing --catalog recommended
allagents --json skill search testing --catalog recommended
```

| Flag | Description |
|------|-------------|
| `--catalog recommended` | Search only the versioned built-in catalog. Unknown names are rejected. |
| `--owner <owner>` | Limit global search to one GitHub owner; no Recommended results from other owners are injected. Mutually exclusive with `--catalog`. |
| `--page <n>` | 1-indexed result page (default: `1`). |
| `--limit <n>` | Results per page, from 1 to 100 (default: `15`). In combined interactive mode, each section is fetched independently at this limit. |

Unknown catalogs and the `--catalog`/`--owner` conflict exit with status 2.
Explicit catalog mode is a hard boundary: empty results, source-health failures,
GitHub query failures, and manifest failures never fall back to global results.
Repository constraints are applied to every catalog query and results are also
filtered against catalog roots before ranking and pagination.

**Recommended** is a discovery label. It is not a security review, trust or
quality guarantee, or license assertion. Results expose their classification
(`recommended`, `optional`, or `external-lifecycle`), source kind, install
policy, author and homepage metadata, SPDX value when known, and warnings.
Optional sources require explicit confirmation. `search-only` results remain
visible but cannot be installed; `external-installer` results point to the
upstream lifecycle and AllAgents does not run it.

In either interactive surface, select installable results and choose project or
user scope. Catalog selections use the exact catalog install source and
qualified selector. Marketplace-backed selections are checked against their
authoritative manifest; direct repositories and subtrees use the exact catalog
repository, default-branch ref, and root. Hermes core (`skills`) and Hermes
optional (`optional-skills`) remain separate through installation and sync.

Discovery provenance (the GitHub result path, blob SHA, repository-head SHA,
approved boundary, and catalog version) explains how a result was found.
Install provenance (repository, ref, root, source ID, and plugin spec) is
persisted in `.allagents/sync-state.json`; the selected paths and full catalog
descriptor remain in `workspace.yaml` and control later syncs. These are
deliberately distinct: a search blob SHA is evidence, not an install/update pin.

### skill update

Check installed remote skills for upstream changes, update surviving skills, and safely reconcile skills that were deleted upstream.
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,8 @@
"test:e2e": "bun test tests/e2e",
"smoke:mcp-oauth": "bun run scripts/smoke-mcp-oauth.ts",
"dev:mcp-server": "bun run scripts/dev-mcp-server.ts",
"catalog:validate": "bun run scripts/validate-skill-catalog.ts --ci",
"catalog:health": "bun run scripts/validate-skill-catalog.ts --report",
"typecheck": "tsc --noEmit",
"lint": "biome lint src",
"lint:fix": "biome lint --write src",
Expand Down
113 changes: 113 additions & 0 deletions scripts/validate-skill-catalog.ts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
import { execFile } from 'node:child_process';
import {
type CatalogHealthDependencies,
type CatalogTreeEntry,
checkSkillCatalogHealth,
validateSkillCatalog,
} from '../src/core/skill-catalog-health.js';
import { RECOMMENDED_SKILL_CATALOG } from '../src/core/skill-catalog.js';

const GITHUB_REQUEST_TIMEOUT_MS = 30_000;
const mode = process.argv[2];
if (mode !== '--ci' && mode !== '--report') {
console.error('Usage: bun run scripts/validate-skill-catalog.ts --ci|--report');
process.exit(2);
}

const token =
process.env.GITHUB_TOKEN ||
(await new Promise<string | undefined>((resolve) => {
execFile('gh', ['auth', 'token'], { timeout: 3000 }, (error, stdout) => {
resolve(error ? undefined : stdout.trim() || undefined);
});
}));
const headers: Record<string, string> = {
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': 'allagents-catalog-health',
};
if (token) headers.Authorization = `Bearer ${token}`;

async function githubGet<T>(path: string): Promise<T> {
const response = await fetch(`https://api.github.com${path}`, {
method: 'GET',
headers,
signal: AbortSignal.timeout(GITHUB_REQUEST_TIMEOUT_MS),
});
if (!response.ok) {
throw new Error(`GitHub GET ${path} failed: ${response.status}`);
}
return (await response.json()) as T;
}

const dependencies: CatalogHealthDependencies = {
async getRepository(repo) {
const repository = await githubGet<{
full_name: string;
default_branch: string;
}>(`/repos/${repo}`);
const branch = await githubGet<{ commit: { sha: string } }>(
`/repos/${repo}/branches/${encodeURIComponent(repository.default_branch)}`,
);
return {
fullName: repository.full_name,
defaultBranch: repository.default_branch,
headSha: branch.commit.sha,
};
},
async getTree(repo, ref) {
const result = await githubGet<{
truncated: boolean;
tree: Array<{ path: string; type: string; mode: string }>;
}>(`/repos/${repo}/git/trees/${encodeURIComponent(ref)}?recursive=1`);
if (result.truncated) {
throw new Error(`GitHub tree response was truncated for ${repo}@${ref}`);
}
return result.tree
.filter(
(entry): entry is { path: string; type: 'blob' | 'tree'; mode: string } =>
entry.type === 'blob' || entry.type === 'tree',
)
.map(
(entry): CatalogTreeEntry => ({
path: entry.path,
type: entry.type,
mode: entry.mode,
}),
);
},
async getTextFile(repo, ref, path) {
const result = await githubGet<{
type: string;
encoding?: string;
content?: string;
}>(
`/repos/${repo}/contents/${path.split('/').map(encodeURIComponent).join('/')}?ref=${encodeURIComponent(ref)}`,
);
if (
result.type !== 'file' ||
result.encoding !== 'base64' ||
typeof result.content !== 'string'
) {
return null;
}
return Buffer.from(result.content.replace(/\n/g, ''), 'base64').toString(
'utf8',
);
},
};

const validationIssues = validateSkillCatalog(RECOMMENDED_SKILL_CATALOG);
if (validationIssues.length > 0) {
console.error(JSON.stringify({ validationIssues }, null, 2));
process.exit(1);
}

const report = await checkSkillCatalogHealth(
RECOMMENDED_SKILL_CATALOG,
dependencies,
);
console.log(JSON.stringify(report, null, 2));
if (report.sources.some((source) => source.status !== 'healthy')) {
process.exit(1);
}
Loading