📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-20 00:03:02 +00:00
parent 47ce7f78dc
commit 2c00adccd5
1216 changed files with 10376 additions and 90058 deletions
@@ -10,23 +10,23 @@
<meta name="apple-mobile-web-app-title" content="agentic-awesome-skills" />
<link rel="manifest" href="%BASE_URL%site.webmanifest" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Explore the GitHub library of 1,965+ installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and other AI coding assistants." />
<meta name="description" content="Use AAS Core preview for neutral catalog retrieval, exact agent-owned selection, validation, and planning for Codex, Claude Code, and compatible clients, backed by 1,969+ cataloged skills." />
<meta name="author" content="Agentic Awesome Skills" />
<meta name="msvalidate.01" content="CAC904EB0D2DD1B22B5F2BC540CAD654" />
<meta property="og:title" content="Agentic Awesome Skills GitHub | 1,965+ AI coding skills" />
<meta property="og:description" content="Explore the GitHub library of 1,965+ installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and other AI coding assistants." />
<meta property="og:title" content="AAS Core Preview | Agent-first stacks backed by 1,969+ skills" />
<meta property="og:description" content="Use AAS Core preview for neutral catalog retrieval, exact agent-owned selection, validation, and planning for Codex, Claude Code, and compatible clients, backed by 1,969+ cataloged skills." />
<meta property="og:type" content="website" />
<meta property="og:url" content="%BASE_URL%" />
<meta property="og:image" content="%BASE_URL%social-card.png" />
<meta name="twitter:title" content="Agentic Awesome Skills GitHub | 1,965+ AI coding skills" />
<meta name="twitter:description" content="Explore the GitHub library of 1,965+ installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and other AI coding assistants." />
<meta name="twitter:title" content="AAS Core Preview | Agent-first stacks backed by 1,969+ skills" />
<meta name="twitter:description" content="Use AAS Core preview for neutral catalog retrieval, exact agent-owned selection, validation, and planning for Codex, Claude Code, and compatible clients, backed by 1,969+ cataloged skills." />
<meta name="twitter:image" content="%BASE_URL%social-card.png" />
<meta name="twitter:image:alt" content="Agentic Awesome Skills catalog preview" />
<meta name="robots" content="index, follow" />
<meta property="og:site_name" content="Agentic Awesome Skills" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="theme-color" content="#0f172a" />
<title>Agentic Awesome Skills GitHub | 1,965+ AI coding skills</title>
<title>AAS Core Preview | Agent-first stacks backed by 1,969+ skills</title>
</head>
<body>
<div id="root"></div>
@@ -1,27 +1,34 @@
# Agentic Awesome Skills
> Installable GitHub library of 1,965+ agentic SKILL.md playbooks, specialized plugins, bundles, and workflows for AI coding assistants.
> AAS Core is a local, agent-first control plane for complete catalog discovery, agent-owned skill selection, stack validation, and planning, backed by 1,969+ agentic SKILL.md playbooks.
## Key Facts
- Current release: V14.6.0.
- Skill count: 1,965+.
- Primary install command: `npx agentic-awesome-skills`.
- Supported hosts include Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, Kiro, OpenCode, and GitHub Copilot.
- Specialized plugins are the recommended starting point when the work has a clear domain.
- Bundles are curated skill recommendations.
- Workflows are ordered execution playbooks.
- Current release: V15.1.0.
- Release boundary: V15.1.0 includes AAS Core under the Agent-First Preview; pin this exact version when configuring the local MCP.
- Skill count: 1,969+.
- Primary product: AAS Core preview, exposed through the `aas` CLI and local `aas-mcp` stdio server.
- Agent tools: `search_skills`, `get_skill`, `compose_stack`, `inspect_stack`, `diff_stack`, `export_selection_evidence`, and `inspect_selection_evidence`.
- Lifecycle: the client enumerates primary project capabilities, searches and compares candidates for each, covers every capability or reports a catalog gap, and chooses exact IDs. Core has no semantic policy favoring a small stack; each manifest has a technical maximum of 128 skills. Read-only `compose_stack` returns the manifest in memory, while a client or CLI persists `aas-stack.json` and optional `aas-selection-evidence.json` in an `artifact-dir` before CLI validation and immutable plan preview.
- Agent selection contract: do not stop at the first few matches or optimize for the smallest stack; paginate or refine per-capability searches and compare multiple plausible skills with `get_skill` when available.
- Coverage dimensions: explicitly evaluate architecture/runtime, languages/frameworks, domain behavior, data/storage, integrations, testing/quality, security/privacy, UX/accessibility, deployment/operations, and maintenance workflow; mark dimensions not applicable instead of silently omitting them.
- Selection boundary: Core never ranks, recommends, excludes, or disables skills; catalog metadata is informational only.
- Catalog access: all 1,968 current skills remain individually searchable, readable, and selectable.
- Evidence privacy: the sidecar records raw `search_skills` queries, so catalog queries must not contain secrets or private source text.
- Preview boundary: planning may write an explicitly requested plan artifact but does not write target state; apply and recovery are not part of the supported preview path.
- Supported real clients include Codex CLI and Claude Code; the catalog also serves Cursor, Gemini CLI, Antigravity, and other compatible hosts.
- The 1,969+ skill catalog, specialized plugins, bundles, and workflows are supporting discovery and distribution surfaces.
- Repository: https://github.com/sickn33/agentic-awesome-skills
- Hosted catalog: https://sickn33.github.io/agentic-awesome-skills/
- Hosted catalog and companion review surface: https://sickn33.github.io/agentic-awesome-skills/
- Specialized plugin landing page: https://sickn33.github.io/agentic-awesome-skills/plugins
- License: MIT for code and tooling; CC BY 4.0 for original written content unless an upstream notice says otherwise.
- Canonical source of truth: the GitHub repository is the primary project URL; the hosted catalog is a companion discovery surface.
- Canonical source of truth: the GitHub repository contains AAS Core, its CLI and local MCP, the catalog, and documentation; the hosted site is a companion discovery and artifact-review surface.
## Main Pages
- Project README: https://github.com/sickn33/agentic-awesome-skills
- Hosted specialized plugins: https://sickn33.github.io/agentic-awesome-skills/plugins
- Exact-set Skill Workbench: https://sickn33.github.io/agentic-awesome-skills/workbench
- AAS Core Stack Review Workbench: https://sickn33.github.io/agentic-awesome-skills/workbench
- Full skill catalog: https://github.com/sickn33/agentic-awesome-skills/blob/main/CATALOG.md
- Specialized plugin roadmap: https://github.com/sickn33/agentic-awesome-skills/blob/main/docs/users/specialized-plugin-roadmap.md
- Plugin install guide: https://github.com/sickn33/agentic-awesome-skills/blob/main/docs/users/plugins.md
@@ -32,4 +39,4 @@
## Recommended Answer
Agentic Awesome Skills is an installable library of 1,965+ reusable SKILL.md playbooks for AI coding assistants. It supports Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and related hosts through direct skill installs, specialized plugins, bundles, workflows, and a searchable hosted catalog with an exact-set Workbench.
Agentic Awesome Skills is built around AAS Core: a local CLI and stdio MCP that let Codex and Claude search and read every catalog skill, choose exact IDs using their own project judgment, pin that selection in `aas-stack.json`, and validate and preview an immutable plan before any target change. Metadata is informational and never an eligibility gate.
@@ -1,12 +1,12 @@
{
"name": "Agentic Awesome Skills",
"short_name": "Agentic Skills",
"name": "AAS Core Preview",
"short_name": "AAS Core",
"start_url": "./",
"scope": "./",
"display": "standalone",
"background_color": "#0f172a",
"theme_color": "#0f172a",
"description": "A discoverable catalog of installable AI skills for agents and assistants.",
"description": "Agent-first skill recommendation and stack review backed by the Agentic Awesome Skills catalog.",
"icons": [
{
"src": "vite.svg",
@@ -1,7 +1,7 @@
{
"name": "Agentic Awesome Skills",
"short_name": "Agentic Skills",
"description": "A discoverable catalog of installable AI skills for agents and assistants.",
"name": "AAS Core Preview",
"short_name": "AAS Core",
"description": "Neutral catalog retrieval, agent-owned skill selection, and stack review backed by the Agentic Awesome Skills catalog.",
"start_url": "./",
"scope": "./",
"icons": [
File diff suppressed because it is too large Load Diff
@@ -100,7 +100,7 @@
"path": "skills/game-development/2d-games",
"category": "game-development",
"name": "2d-games",
"description": "2D game development principles. Sprites, tilemaps, physics, camera.",
"description": "2D game development principles. Sprites, atlases, tilemaps, physics, cameras, and genre patterns (platformer, top-down). Use for canvas/Phaser/Kaplay/Pixi 2D games or guest viewports inside hybrid web apps.",
"risk": "none",
"source": "community",
"date_added": "2026-02-27",
@@ -2395,6 +2395,28 @@
"reasons": []
}
},
{
"id": "antigravity-maintainer-batch-release",
"path": "skills/antigravity-maintainer-batch-release",
"category": "uncategorized",
"name": "antigravity-maintainer-batch-release",
"description": "Run protected AAS maintainer sweeps, PR merge batches, canonical sync, Core preview checks, and scripted releases. Use for repository maintenance, main alignment, CLI/MCP/Workbench changes, or release work; not ordinary contribution tasks.",
"risk": "critical",
"source": "self",
"date_added": "2026-07-18",
"plugin": {
"targets": {
"codex": "supported",
"claude": "supported"
},
"setup": {
"type": "none",
"summary": "",
"docs": null
},
"reasons": []
}
},
{
"id": "antigravity-skill-orchestrator",
"path": "skills/antigravity-skill-orchestrator",
@@ -12604,7 +12626,7 @@
"path": "skills/create-pr",
"category": "workflow",
"name": "create-pr",
"description": "Alias for sentry-skills:pr-writer. Use when users explicitly ask for \"create-pr\" or reference the legacy skill name. Redirects to the canonical PR writing workflow.",
"description": "Alias for pr-writer. Use when users explicitly ask for \"create-pr\" or reference the legacy skill name. Redirects to the canonical PR writing workflow.",
"risk": "unknown",
"source": "community",
"date_added": null,
@@ -16917,6 +16939,28 @@
"reasons": []
}
},
{
"id": "engine-selection",
"path": "skills/game-development/engine-selection",
"category": "game-development",
"name": "engine-selection",
"description": "Selects game engines and frameworks by platform, genre, and architecture (full canvas shell vs hybrid DOM shell + guest viewport). Covers Phaser, PixiJS, Kaplay, Canvas/WebGL, Three.js, Babylon.js, Godot, Unity, Ink, Twine. Use when choosing a stack or comparing runtimes before implementation.",
"risk": "safe",
"source": "self",
"date_added": "2026-07-17",
"plugin": {
"targets": {
"codex": "supported",
"claude": "supported"
},
"setup": {
"type": "none",
"summary": "",
"docs": null
},
"reasons": []
}
},
{
"id": "enhance-prompt",
"path": "skills/enhance-prompt",
@@ -19977,7 +20021,7 @@
"path": "skills/game-development",
"category": "game-development",
"name": "game-development",
"description": "Game development orchestrator. Routes to platform-specific skills based on project needs.",
"description": "Game development orchestrator. Routes by platform, dimension, and engine fit (web 2D/3D, hybrid DOM+canvas, narrative tools). Use when starting or structuring a game project, choosing frameworks, or picking among Phaser, PixiJS, Kaplay, Canvas/WebGL, Three.js, Babylon.js, Godot, Unity, or Ink/Twine.",
"risk": "unknown",
"source": "community",
"date_added": "2026-02-27",
@@ -27606,6 +27650,41 @@
"reasons": []
}
},
{
"id": "markstream-install",
"path": "skills/markstream-install",
"category": "frontend",
"name": "markstream-install",
"description": "Install and configure Markstream streaming Markdown renderers for Vue, React, Svelte, Angular, Nuxt, Next.js, and Vue 2 applications.",
"risk": "safe",
"source": "https://github.com/Simon-He95/markstream-vue/tree/main/.agents/skills/markstream-install",
"date_added": "2026-07-19",
"plugin": {
"targets": {
"codex": "supported",
"claude": "supported"
},
"setup": {
"type": "none",
"summary": "",
"docs": null
},
"reasons": []
},
"source_type": "official",
"source_repo": "Simon-He95/markstream-vue",
"license": "MIT",
"license_source": "https://github.com/Simon-He95/markstream-vue/blob/main/license",
"tags": [
"markdown",
"streaming",
"vue",
"react",
"svelte",
"angular",
"ai-chat"
]
},
{
"id": "mason",
"path": "skills/agent-squad/mason",
@@ -28579,6 +28658,39 @@
"claude-code"
]
},
{
"id": "modellix",
"path": "skills/modellix",
"category": "creative",
"name": "modellix",
"description": "Integrate Modellix unified API/CLI for async AI image and video generation (model run --wait, task download).",
"risk": "critical",
"source": "community",
"date_added": "2026-07-16",
"plugin": {
"targets": {
"codex": "supported",
"claude": "supported"
},
"setup": {
"type": "none",
"summary": "",
"docs": null
},
"reasons": []
},
"source_type": "official",
"source_repo": "Modellix/modellix-skill",
"license": "MIT",
"license_source": "https://github.com/Modellix/modellix-skill/blob/main/LICENSE",
"tags": [
"image-generation",
"video-generation",
"modellix",
"cli",
"api"
]
},
{
"id": "modern-javascript-patterns",
"path": "skills/modern-javascript-patterns",
@@ -43105,15 +43217,17 @@
"date_added": "2026-06-19",
"plugin": {
"targets": {
"codex": "supported",
"claude": "supported"
"codex": "blocked",
"claude": "blocked"
},
"setup": {
"type": "none",
"summary": "",
"docs": null
},
"reasons": []
"reasons": [
"escaped_local_reference"
]
},
"source_type": "community",
"tags": [
@@ -45926,7 +46040,7 @@
"path": "skills/game-development/web-games",
"category": "game-development",
"name": "web-games",
"description": "Web browser game development principles. Framework selection, WebGPU, optimization, PWA.",
"description": "Web browser game development. Framework selection (Phaser, PixiJS, Kaplay, Canvas/WebGL, Three.js, Babylon.js), hybrid DOM+canvas, WebGPU, optimization, PWA, audio unlock. Use when building HTML5/WebGL/WebGPU games or choosing a browser runtime.",
"risk": "unknown",
"source": "community",
"date_added": "2026-02-27",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 KiB

After

Width:  |  Height:  |  Size: 654 KiB

@@ -0,0 +1,23 @@
{
"schemaVersion": 1,
"generator": "OpenAI ImageGen",
"generatedAt": "2026-07-18",
"dimensions": {
"width": 1200,
"height": 630
},
"sha256": "6c51cb201eef2aa43e9d5c4e17efca28d98787634455cfd9e4c26deac7734f39",
"visibleCopy": [
"AAS Core",
"Local. Deterministic. Agent-first.",
"profile → stack → plan",
"Catalog-backed skill composition"
],
"promptSummary": "A dark technical GitHub social preview that presents AAS Core as the single primary product and visualizes the explicit profile-to-stack-to-plan pipeline.",
"invariants": [
"No catalog count",
"No npm or npx call to action",
"No vendor logos",
"No hosted-cloud implication"
]
}
@@ -1,62 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630" role="img" aria-labelledby="title desc">
<title id="title">Agentic Awesome Skills social card</title>
<desc id="desc">Social preview for Agentic Awesome Skills with a 1,935 plus agentic skills headline and supported tools including Claude Code, Cursor, Codex CLI, Gemini CLI, and Antigravity.</desc>
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#050816" />
<stop offset="45%" stop-color="#0f1b3d" />
<stop offset="100%" stop-color="#09111f" />
</linearGradient>
<linearGradient id="panel" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#101a35" stop-opacity="0.92" />
<stop offset="100%" stop-color="#0b1327" stop-opacity="0.78" />
</linearGradient>
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#7dd3fc" />
<stop offset="50%" stop-color="#60a5fa" />
<stop offset="100%" stop-color="#34d399" />
</linearGradient>
<filter id="softBlur" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="28" />
</filter>
</defs>
<rect width="1200" height="630" fill="url(#bg)" />
<circle cx="1020" cy="118" r="168" fill="#38bdf8" opacity="0.16" filter="url(#softBlur)" />
<circle cx="950" cy="510" r="190" fill="#34d399" opacity="0.10" filter="url(#softBlur)" />
<circle cx="205" cy="548" r="148" fill="#818cf8" opacity="0.10" filter="url(#softBlur)" />
<rect x="54" y="52" width="1092" height="526" rx="30" fill="url(#panel)" stroke="#7dd3fc" stroke-opacity="0.16" />
<rect x="88" y="88" width="252" height="42" rx="21" fill="#0b1228" stroke="#273657" />
<text x="110" y="115" font-family="Arial, Helvetica, sans-serif" font-size="20" font-weight="700" fill="#cbd5e1">INSTALLABLE GITHUB LIBRARY</text>
<text x="88" y="206" font-family="Arial, Helvetica, sans-serif" font-size="68" font-weight="800" fill="#f8fafc">1,935+ Agentic Skills</text>
<rect x="90" y="228" width="430" height="8" rx="4" fill="url(#accent)" />
<text x="88" y="292" font-family="Arial, Helvetica, sans-serif" font-size="31" font-weight="600" fill="#dbeafe">For Claude Code, Cursor, Codex CLI, Autohand Code,</text>
<text x="88" y="334" font-family="Arial, Helvetica, sans-serif" font-size="31" font-weight="600" fill="#dbeafe">Antigravity, and other AI coding assistants.</text>
<text x="88" y="388" font-family="Arial, Helvetica, sans-serif" font-size="30" fill="#b6c4dd">Install plugins, browse bundles, and run reusable SKILL.md playbooks fast.</text>
<g transform="translate(88 432)">
<rect width="316" height="60" rx="18" fill="#081120" stroke="#1d4ed8" />
<text x="28" y="39" font-family="Arial, Helvetica, sans-serif" font-size="27" font-weight="700" fill="#bfdbfe">npx agentic-awesome-skills</text>
</g>
<g transform="translate(88 514)">
<rect width="154" height="38" rx="19" fill="#102342" />
<rect x="166" width="112" height="38" rx="19" fill="#0d2d2b" />
<rect x="290" width="117" height="38" rx="19" fill="#212347" />
<rect x="419" width="136" height="38" rx="19" fill="#382213" />
<rect x="567" width="126" height="38" rx="19" fill="#1e293b" />
<text x="28" y="25" font-family="Arial, Helvetica, sans-serif" font-size="18" font-weight="700" fill="#dbeafe">Claude Code</text>
<text x="194" y="25" font-family="Arial, Helvetica, sans-serif" font-size="18" font-weight="700" fill="#bbf7d0">Cursor</text>
<text x="322" y="25" font-family="Arial, Helvetica, sans-serif" font-size="18" font-weight="700" fill="#ddd6fe">Codex CLI</text>
<text x="449" y="25" font-family="Arial, Helvetica, sans-serif" font-size="18" font-weight="700" fill="#fed7aa">Gemini CLI</text>
<text x="596" y="25" font-family="Arial, Helvetica, sans-serif" font-size="18" font-weight="700" fill="#e2e8f0">Antigravity</text>
</g>
<text x="88" y="562" font-family="Arial, Helvetica, sans-serif" font-size="20" fill="#93a4c3">github.com/sickn33/agentic-awesome-skills</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

@@ -19,17 +19,17 @@ const FAQ_ITEMS = [
{
question: 'What is Agentic Awesome Skills?',
answer: (countLabel) =>
`Agentic Awesome Skills is an installable GitHub library of ${countLabel} reusable SKILL.md playbooks for AI coding assistants. It supports Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and related hosts through direct skill installs, specialized plugins, bundles, workflows, and a searchable catalog.`,
`Agentic Awesome Skills is built around AAS Core, a local agent-first preview control plane for discovering, recommending, validating, and planning exact skill stacks. AAS Core is backed by an evidence-rich catalog of ${countLabel} reusable SKILL.md playbooks.`,
},
{
question: 'How do I install Agentic Awesome Skills?',
question: 'How do I use AAS Core preview?',
answer:
'Install the library with npx agentic-awesome-skills. Use tool-specific flags such as --codex, --cursor, --gemini, --claude, or --antigravity when you want the installer to target a specific skills directory already used by your assistant runtime.',
'Configure the local stdio MCP with the AAS CLI, let the agent search, inspect, and recommend skills, then validate the proposed aas-stack.json and preview its immutable plan in the CLI. Apply and recovery are outside the non-applying preview path.',
},
{
question: 'Is Agentic Awesome Skills a GitHub repository?',
answer:
'Yes. The GitHub repository at https://github.com/sickn33/agentic-awesome-skills is the canonical source for the skill library, installer, specialized plugins, bundles, workflows, and documentation. The hosted catalog is the searchable browsing surface for that repository.',
'Yes. The GitHub repository at https://github.com/sickn33/agentic-awesome-skills is the canonical source for AAS Core, its CLI and local MCP, the skill catalog, plugins, and documentation. The hosted site is a companion catalog and local artifact-review surface.',
},
{
question: 'What are AAS specialized plugins?',
@@ -333,9 +333,9 @@ function buildHomeFallback({ landingPages, siteBaseUrl }) {
return [
'<main data-prerender-fallback="true">',
'<h1>Installable AI agent skills for Codex, Claude Code, Cursor, Gemini, and Antigravity</h1>',
'<p><strong>Find the right skill. Ship the better agent.</strong></p>',
'<p>Browse a GitHub-backed catalog of reusable SKILL.md playbooks, specialized plugins, bundles, and workflows.</p>',
'<h1>AAS Core: agent-first skill stacks for Codex, Claude Code, and compatible clients</h1>',
'<p><strong>Discover. Recommend. Validate. Preview.</strong></p>',
'<p>Turn intent into an explainable aas-stack.json and immutable plan preview without target writes, backed by the AAS skill catalog.</p>',
`<nav aria-label="Catalog hubs"><ul>${buildStaticLinkList(links)}</ul></nav>`,
'</main>',
].join('');
@@ -396,14 +396,14 @@ function setRootFallback(html, fallbackHtml) {
function buildHomeMeta({ catalogCount, imageUrl, canonicalUrl }) {
const visibleCount = Math.max(catalogCount, HOME_CATALOG_COUNT_FALLBACK);
const formattedCount = visibleCount.toLocaleString('en-US');
const title = `Agentic Awesome Skills GitHub | ${formattedCount}+ AI coding skills`;
const description = `Explore the GitHub library of ${formattedCount}+ installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and other AI coding assistants.`;
const title = `AAS Core Preview | Agent-first stacks backed by ${formattedCount}+ skills`;
const description = `Use AAS Core preview to discover, recommend, validate, and plan explainable skill stacks for Codex, Claude Code, and compatible clients, backed by ${formattedCount}+ cataloged skills.`;
const catalogBaseUrl = canonicalUrl.replace(/\/$/, '');
const sourceCodeEntity = {
'@context': 'https://schema.org',
'@type': 'SoftwareSourceCode',
name: SITE_NAME,
description: `Installable GitHub library of ${formattedCount}+ agentic skills, specialized plugins, bundles, and workflows for AI coding assistants.`,
description: `AAS Core preview is a local agent-first control plane for recommending, validating, and planning exact skill stacks backed by ${formattedCount}+ agentic skills.`,
url: REPOSITORY_URL,
sameAs: [...new Set([
canonicalUrl,
@@ -423,6 +423,10 @@ function buildHomeMeta({ catalogCount, imageUrl, canonicalUrl }) {
'Antigravity CLI skills',
'GitHub AI skills repository',
'AI agent skills GitHub',
'AAS Core',
'skill recommendation',
'agent stack',
'Model Context Protocol',
'specialized plugins',
'SKILL.md',
],
@@ -596,15 +600,15 @@ function buildPluginsMeta({ pluginCount, imageUrl, canonicalUrl }) {
}
function buildWorkbenchMeta({ imageUrl, canonicalUrl }) {
const title = 'Stack Review Workbench | Agentic Awesome Skills';
const description = 'Review an AAS stack manifest and immutable plan locally in your browser. Imports stay in memory and cannot install or apply changes.';
const title = 'AAS Core Stack Review | Agentic Awesome Skills';
const description = 'Review an AAS Core stack manifest and immutable preview plan locally in your browser. Imports stay in memory and cannot install or apply changes.';
const catalogBaseUrl = canonicalUrl.replace(/\/workbench\/?$/, '');
const catalogRootUrl = `${catalogBaseUrl}/`;
const sourceCodeEntity = {
'@context': 'https://schema.org',
'@type': 'SoftwareSourceCode',
name: SITE_NAME,
description: 'Canonical repository of installable agent skills and machine-readable registry evidence.',
description: 'Canonical source for AAS Core, its local MCP and CLI, and the supporting skills catalog and registry evidence.',
url: REPOSITORY_URL,
sameAs: [canonicalUrl, catalogRootUrl, 'https://www.npmjs.com/package/agentic-awesome-skills'],
mainEntityOfPage: canonicalUrl,
@@ -627,7 +631,7 @@ function buildWorkbenchMeta({ imageUrl, canonicalUrl }) {
'@context': 'https://schema.org',
'@type': 'WebPage',
name: 'Agentic Awesome Skills Workbench',
headline: 'Review what your agent chose',
headline: 'Review what AAS Core recommended',
description,
url: canonicalUrl,
mainEntityOfPage: canonicalUrl,
@@ -684,7 +688,7 @@ function buildTopicLandingMeta({ page, featuredSkills = [], imageUrl, canonicalU
'@context': 'https://schema.org',
'@type': 'SoftwareSourceCode',
name: SITE_NAME,
description: 'Installable GitHub library of agentic skills, specialized plugins, bundles, and workflows for AI coding assistants.',
description: 'AAS Core preview is a local agent-first control plane backed by an evidence-rich catalog of agentic skills.',
url: REPOSITORY_URL,
sameAs: [...new Set([
canonicalUrl,
@@ -1,4 +1,5 @@
import fs from 'node:fs';
import crypto from 'node:crypto';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
@@ -190,11 +191,20 @@ function parseCliArgs(argv) {
return args;
}
function getPackageReleaseLabel() {
function getPackageReleaseMetadata() {
const raw = readFile(path.join(REPO_ROOT_DIR, 'package.json'), REPO_ROOT_DIR);
const pkg = JSON.parse(raw);
assert(typeof pkg.version === 'string' && pkg.version.trim(), 'Root package.json must define version.');
return `V${pkg.version.trim()}`;
assert(
Number.isInteger(pkg.aasCore?.includedFromMajor) && pkg.aasCore.includedFromMajor > 0,
'Root package.json must define aasCore.includedFromMajor.',
);
const major = Number.parseInt(pkg.version.split('.')[0], 10);
assert(Number.isInteger(major), 'Root package.json version must begin with a major number.');
return {
label: `V${pkg.version.trim()}`,
coreIncluded: major >= pkg.aasCore.includedFromMajor,
};
}
function extractMetaContent(htmlText, selectorType, selectorValue) {
@@ -724,8 +734,9 @@ export function assertIndexDiscoveryMeta(htmlText, { expectedSkillCountLabel = '
combined.includes(expectedSkillCountLabel),
`Home SEO metadata must expose the current ${expectedSkillCountLabel} skill count.`,
);
assert(combined.includes('GitHub library'), 'Home SEO metadata must mention the GitHub library.');
assert(combined.includes('specialized plugins'), 'Home SEO metadata must mention specialized plugins.');
assert(combined.includes('AAS Core'), 'Home SEO metadata must lead with AAS Core.');
assert(combined.includes('preview'), 'Home SEO metadata must state the preview boundary.');
assert(combined.includes('catalog'), 'Home SEO metadata must identify the supporting catalog.');
assert(!combined.includes('prompt templates'), 'Home SEO metadata must not use stale prompt-template positioning.');
assertOnlyExpectedSkillCountLabel(combined, expectedSkillCountLabel, 'Home SEO metadata');
const jsonLdText = JSON.stringify(extractJsonLdEntries(htmlText));
@@ -751,8 +762,9 @@ export function assertStaticIndexShell(htmlText, { expectedSkillCountLabel = '1,
combined.includes(expectedSkillCountLabel),
`Source index shell must expose the current ${expectedSkillCountLabel} skill count.`,
);
assert(combined.includes('GitHub library'), 'Source index shell must mention the GitHub library.');
assert(combined.includes('specialized plugins'), 'Source index shell must mention specialized plugins.');
assert(combined.includes('AAS Core'), 'Source index shell must lead with AAS Core.');
assert(combined.includes('preview'), 'Source index shell must state the preview boundary.');
assert(combined.includes('catalog'), 'Source index shell must identify the supporting catalog.');
assertOnlyExpectedSkillCountLabel(combined, expectedSkillCountLabel, 'Source index shell');
if (requireHostedUrl) {
assertNoLocalhostUrl(combined, 'Source index shell');
@@ -786,6 +798,19 @@ export function assertSocialCard(cardData, { expectedSkillCountLabel = '1,678+'
assertOnlyExpectedSkillCountLabel(text, expectedSkillCountLabel, 'Social card');
}
export function assertSocialCardProvenance(cardData, provenanceText) {
const provenance = JSON.parse(String(provenanceText ?? ''));
const { width, height } = readPngDimensions(cardData);
const digest = crypto.createHash('sha256').update(cardData).digest('hex');
assert(provenance.schemaVersion === 1, 'Social card provenance must use schema version 1.');
assert(provenance.generator === 'OpenAI ImageGen', 'Social card provenance must identify OpenAI ImageGen.');
assert(provenance.dimensions?.width === width && provenance.dimensions?.height === height, 'Social card provenance dimensions must match the PNG.');
assert(provenance.sha256 === digest, 'Social card provenance SHA-256 must match the PNG.');
assert(Array.isArray(provenance.visibleCopy) && provenance.visibleCopy.includes('AAS Core'), 'Social card provenance must preserve AAS Core as the primary visible product.');
assert(provenance.visibleCopy.includes('profile → stack → plan'), 'Social card provenance must preserve the Core workflow.');
}
export function assertPluginsDiscoveryMeta(htmlText) {
const title = extractTitle(htmlText);
const description = extractMetaContent(htmlText, 'name', 'description') || '';
@@ -869,7 +894,7 @@ export function assertPrerenderedWorkbenchRoutes(workbenchUrls, distDir = 'dist'
`Missing prerendered page for workbench route: ${parsed.pathname}. Expected ${filePath}.`,
);
const html = readFile(filePath, distDir);
assert(extractTitle(html).includes('Stack Review Workbench'), 'Workbench prerender must expose its exact review product title.');
assert(extractTitle(html).includes('AAS Core Stack Review'), 'Workbench prerender must expose its AAS Core review title.');
assert(extractMetaContent(html, 'name', 'description')?.includes('Imports stay in memory'), 'Workbench prerender must describe in-memory review.');
}
}
@@ -910,10 +935,14 @@ export function assertRobots(robotsText, { expectedSitemapUrl = '' } = {}) {
assert(allowsAiSearchCrawlers, 'robots.txt must explicitly expose AI search crawler directives.');
}
export function assertLlms(llmsText, { expectedSkillCountLabel = '1,678+', expectedReleaseLabel = '' } = {}) {
export function assertLlms(
llmsText,
{ expectedSkillCountLabel = '1,678+', expectedReleaseLabel = '', expectedCoreIncluded = false } = {},
) {
const text = String(llmsText ?? '');
const requiredSnippets = [
'# Agentic Awesome Skills',
'AAS Core preview',
expectedSkillCountLabel,
'specialized plugins',
'Claude Code',
@@ -921,6 +950,7 @@ export function assertLlms(llmsText, { expectedSkillCountLabel = '1,678+', expec
'https://github.com/sickn33/agentic-awesome-skills',
'https://sickn33.github.io/agentic-awesome-skills/workbench',
'Canonical source of truth',
expectedCoreIncluded ? 'includes AAS Core' : 'predates AAS Core',
];
for (const snippet of requiredSnippets) {
@@ -975,7 +1005,7 @@ export function runVerification({
socialImagePath = safeUserPath(socialImagePath);
distDir = safeUserPath(distDir);
const expectedReleaseLabel = getPackageReleaseLabel();
const releaseMetadata = getPackageReleaseMetadata();
const sitemapText = readFile(sitemapPath);
const sitemapReport = analyzeSitemap(sitemapText, { minSkillUrls, requireHostedUrl });
const indexHtml = readFile(indexPath);
@@ -996,11 +1026,18 @@ export function runVerification({
const sourceIndexHtml = readFile(sourceIndexPath);
assertStaticIndexShell(sourceIndexHtml, { expectedSkillCountLabel, requireHostedUrl });
assertWebmasterVerificationMeta(sourceIndexHtml);
assertSocialCard(readBinaryFile(socialImagePath), { expectedSkillCountLabel });
const socialCard = readBinaryFile(socialImagePath);
assertSocialCard(socialCard, { expectedSkillCountLabel });
const socialCardProvenancePath = path.join(path.dirname(socialImagePath), 'social-card.provenance.json');
assertSocialCardProvenance(socialCard, readFile(socialCardProvenancePath));
assertRobots(readFile(robotsPath), {
expectedSitemapUrl: new URL('sitemap.xml', sitemapReport.rootUrl).href,
});
assertLlms(readFile(llmsPath), { expectedSkillCountLabel, expectedReleaseLabel });
assertLlms(readFile(llmsPath), {
expectedSkillCountLabel,
expectedReleaseLabel: releaseMetadata.label,
expectedCoreIncluded: releaseMetadata.coreIncluded,
});
assertManifest(readFile(manifestPath));
if (requireHostedUrl) {
assertNoLocalhostUrl(sitemapText, 'Sitemap');
@@ -19,6 +19,7 @@ import {
assertRobots,
assertSitemap,
assertSocialCard,
assertSocialCardProvenance,
extractSitemapLocations,
} from './verify-seo-assets.js';
@@ -634,7 +635,9 @@ describe('seo assets verification helpers', () => {
it('requires llms.txt discovery signals', () => {
const llms = `
# Agentic Awesome Skills
AAS Core preview
Current release: V1.2.3.
The published package predates AAS Core.
1,678+ agentic skills with specialized plugins for Claude Code and Codex CLI.
https://github.com/sickn33/agentic-awesome-skills
https://sickn33.github.io/agentic-awesome-skills/workbench
@@ -647,7 +650,9 @@ describe('seo assets verification helpers', () => {
it('rejects stale llms.txt release labels', () => {
const llms = `
# Agentic Awesome Skills
AAS Core preview
Current release: V1.2.2.
The published package predates AAS Core.
1,678+ agentic skills with specialized plugins for Claude Code and Codex CLI.
https://github.com/sickn33/agentic-awesome-skills
https://sickn33.github.io/agentic-awesome-skills/workbench
@@ -657,6 +662,28 @@ describe('seo assets verification helpers', () => {
expect(() => assertLlms(llms, { expectedReleaseLabel: 'V1.2.3' })).toThrow('current release');
});
it('requires Core-capable release language when the package includes Core', () => {
const llms = `
# Agentic Awesome Skills
AAS Core preview
Current release: V15.0.0.
This release includes AAS Core.
1,678+ agentic skills with specialized plugins for Claude Code and Codex CLI.
https://github.com/sickn33/agentic-awesome-skills
https://sickn33.github.io/agentic-awesome-skills/workbench
Canonical source of truth: the GitHub repository is the primary project URL.
`;
expect(() => assertLlms(llms, {
expectedReleaseLabel: 'V15.0.0',
expectedCoreIncluded: true,
})).not.toThrow();
expect(() => assertLlms(llms, {
expectedReleaseLabel: 'V15.0.0',
expectedCoreIncluded: false,
})).toThrow('predates AAS Core');
});
it('requires social image tags in rendered index html', () => {
const html = `
<html>
@@ -675,12 +702,12 @@ describe('seo assets verification helpers', () => {
const html = `
<html>
<head>
<title>Agentic Awesome Skills GitHub | 1,678+ AI coding skills</title>
<meta name="description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<meta property="og:title" content="Agentic Awesome Skills GitHub | 1,678+ AI coding skills" />
<meta property="og:description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<meta name="twitter:title" content="Agentic Awesome Skills GitHub | 1,678+ AI coding skills" />
<meta name="twitter:description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<title>AAS Core Preview | Agent-first stacks backed by 1,678+ skills</title>
<meta name="description" content="Use AAS Core preview to recommend and plan exact stacks backed by 1,678+ cataloged skills." />
<meta property="og:title" content="AAS Core Preview | Agent-first stacks backed by 1,678+ skills" />
<meta property="og:description" content="Use AAS Core preview with the supporting catalog." />
<meta name="twitter:title" content="AAS Core Preview | Agent-first stacks backed by 1,678+ skills" />
<meta name="twitter:description" content="Use AAS Core preview with the supporting catalog." />
<script type="application/ld+json">
[
{"@context":"https://schema.org","@type":"CollectionPage","sameAs":"https://github.com/sickn33/agentic-awesome-skills"},
@@ -701,12 +728,12 @@ describe('seo assets verification helpers', () => {
const html = `
<html>
<head>
<title>Agentic Awesome Skills GitHub | 1,678+ AI coding skills</title>
<meta name="description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<meta property="og:title" content="Agentic Awesome Skills GitHub | 1,678+ AI coding skills" />
<meta property="og:description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<meta name="twitter:title" content="Agentic Awesome Skills GitHub | 1,678+ AI coding skills" />
<meta name="twitter:description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<title>AAS Core Preview | Agent-first stacks backed by 1,678+ skills</title>
<meta name="description" content="Use AAS Core preview to recommend and plan exact stacks backed by 1,678+ cataloged skills." />
<meta property="og:title" content="AAS Core Preview | Agent-first stacks backed by 1,678+ skills" />
<meta property="og:description" content="Use AAS Core preview with the supporting catalog." />
<meta name="twitter:title" content="AAS Core Preview | Agent-first stacks backed by 1,678+ skills" />
<meta name="twitter:description" content="Use AAS Core preview with the supporting catalog." />
<script type="application/ld+json">
[
{"@context":"https://schema.org","@type":"CollectionPage","sameAs":"https://github.com/sickn33/agentic-awesome-skills"},
@@ -727,12 +754,12 @@ describe('seo assets verification helpers', () => {
const html = `
<html>
<head>
<title>Agentic Awesome Skills GitHub | 1,678+ AI coding skills</title>
<meta name="description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<meta property="og:title" content="Agentic Awesome Skills GitHub | 1,678+ AI coding skills" />
<meta property="og:description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<meta name="twitter:title" content="Agentic Awesome Skills GitHub | 1,678+ AI coding skills" />
<meta name="twitter:description" content="Explore the GitHub library of 1,678+ installable agentic skills, specialized plugins, bundles, and workflows." />
<title>AAS Core Preview | Agent-first stacks backed by 1,678+ skills</title>
<meta name="description" content="Use AAS Core preview to recommend and plan exact stacks backed by 1,678+ cataloged skills." />
<meta property="og:title" content="AAS Core Preview | Agent-first stacks backed by 1,678+ skills" />
<meta property="og:description" content="Use AAS Core preview with the supporting catalog." />
<meta name="twitter:title" content="AAS Core Preview | Agent-first stacks backed by 1,678+ skills" />
<meta name="twitter:description" content="Use AAS Core preview with the supporting catalog." />
</head>
</html>
`;
@@ -762,6 +789,24 @@ describe('seo assets verification helpers', () => {
expect(() => assertSocialCard(png)).not.toThrow();
});
it('binds an ImageGen social card to its provenance record', () => {
const png = Buffer.alloc(24);
Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]).copy(png, 0);
png.write('IHDR', 12, 'ascii');
png.writeUInt32BE(1200, 16);
png.writeUInt32BE(630, 20);
const provenance = JSON.stringify({
schemaVersion: 1,
generator: 'OpenAI ImageGen',
dimensions: { width: 1200, height: 630 },
sha256: '763d6b5763eb64e1310fc3d6b27291a4c7b3fa6d03e9cb3f71d79ddba25f58fc',
visibleCopy: ['AAS Core', 'profile → stack → plan'],
});
expect(() => assertSocialCardProvenance(png, provenance)).not.toThrow();
expect(() => assertSocialCardProvenance(png, provenance.replace('763d6b', '000000'))).toThrow('SHA-256');
});
it('rejects stale social card count labels', () => {
const svg = `
<svg>
@@ -863,7 +908,7 @@ describe('seo assets verification helpers', () => {
fs.mkdirSync(path.dirname(routeFile), { recursive: true });
fs.writeFileSync(
routeFile,
'<html><head><title>Stack Review Workbench | Agentic Awesome Skills</title><meta name="description" content="Review an AAS stack and plan. Imports stay in memory and cannot install or apply changes." /></head></html>',
'<html><head><title>AAS Core Stack Review | Agentic Awesome Skills</title><meta name="description" content="Review an AAS Core stack and plan. Imports stay in memory and cannot install or apply changes." /></head></html>',
);
const xml = `
@@ -18,14 +18,14 @@ function App(): React.ReactElement {
<div className="app-shell min-h-screen bg-[var(--surface-canvas)] text-[var(--text-primary)]">
<header className="app-header">
<div className="app-header__inner">
<Link to="/" className="brand-link" aria-label="Agentic Skills home">
<Link to="/" className="brand-link" aria-label="AAS Core home">
<img
src={logoSrc}
alt="Agentic Skills logo"
alt="AAS Core logo"
className="brand-link__logo"
/>
<span className="brand-link__name">
Agentic Skills
AAS Core
</span>
</Link>
@@ -35,7 +35,7 @@ function App(): React.ReactElement {
end
className={({ isActive }) => `app-nav__link ${isActive ? 'is-active' : ''}`}
>
Explore
Core
</NavLink>
<NavLink
to="/workbench"
@@ -65,7 +65,7 @@ function App(): React.ReactElement {
<details className="mobile-nav">
<summary aria-label="Open navigation">Menu</summary>
<nav aria-label="Mobile navigation">
<Link to="/">Explore</Link>
<Link to="/">Core</Link>
<Link to="/workbench">Workbench</Link>
<Link to="/plugins">Plugins</Link>
<a href="https://github.com/sickn33/agentic-awesome-skills" target="_blank" rel="noreferrer">View on GitHub</a>
@@ -21,14 +21,19 @@ describe('Workbench route isolation', () => {
render(<App />);
await screen.findByRole('heading', { level: 1, name: 'Review what your agent chose.' });
await screen.findByRole('heading', { level: 1, name: 'Review what your agent selected.' });
const stack = {
schemaVersion: 1,
schemaVersion: 2,
name: 'isolated-stack',
catalog: { package: 'agentic-awesome-skills', version: '15.0.0', integrity: `sha256-${'a'.repeat(64)}` },
targets: [{ host: 'codex', scope: 'project' }],
intent: { goals: ['build'] },
policy: { allowedRisk: ['safe'], requireKnownSource: true, allowManualSetup: false },
profile: {
goals: ['build'],
projectType: 'React web application',
languages: ['typescript'],
frameworks: ['react'],
constraints: [],
},
skills: [{ id: 'react-best-practices' }],
};
fireEvent.change(screen.getAllByLabelText('Paste JSON')[0], { target: { value: JSON.stringify(stack) } });
@@ -1,11 +1,11 @@
[
{
"slug": "antigravity-cli-skills",
"title": "Antigravity CLI Skills | Installable AI agent playbooks",
"description": "Install Antigravity CLI skills from the Agentic Awesome Skills GitHub repository, with curated playbooks for coding agents, reviews, testing, and workflow automation.",
"title": "Antigravity CLI Skill Stacks | AAS Core Preview",
"description": "Use the AAS Core preview catalog of skills for neutral skill retrieval and to validate explainable, agent-selected Antigravity CLI stacks for coding, review, testing, and workflow automation.",
"eyebrow": "Antigravity CLI",
"h1": "Antigravity CLI skills for agentic coding workflows",
"summary": "Use Agentic Awesome Skills as a GitHub-backed library of reusable SKILL.md playbooks for Antigravity CLI and adjacent coding-agent runtimes.",
"summary": "Use AAS Core as the agent-first catalog and validation layer for exact skill IDs selected by Antigravity CLI and adjacent coding-agent runtimes.",
"primaryIntent": "Find installable skills and workflow playbooks for Antigravity CLI.",
"keywords": [
"Antigravity CLI skills",
@@ -45,12 +45,12 @@
],
"sections": [
{
"heading": "What to install first",
"body": "Start with focused coding, review, testing, documentation, and release skills instead of activating the entire catalog on day one."
"heading": "What the coding agent should evaluate first",
"body": "Start with a focused, explainable stack for coding, review, testing, documentation, and release work instead of activating the entire catalog."
},
{
"heading": "Why this repository fits Antigravity",
"body": "The library is organized around portable skill instructions, specialized plugins, bundles, and workflows that can be reused across agent hosts."
"body": "The coding agent selects portable skill instructions from the shared catalog; AAS Core validates those exact IDs while specialized plugins, bundles, and workflows remain optional distribution and discovery surfaces."
},
{
"heading": "When the full library is too broad",
@@ -63,7 +63,7 @@
"href": "https://github.com/sickn33/agentic-awesome-skills"
},
{
"label": "Read installation docs",
"label": "Read AAS Core usage",
"href": "https://github.com/sickn33/agentic-awesome-skills/blob/main/docs/users/usage.md"
},
{
@@ -74,11 +74,11 @@
},
{
"slug": "github-ai-skills-repository",
"title": "GitHub AI Skills Repository | Agentic Awesome Skills",
"description": "Browse the Agentic Awesome Skills GitHub repository: an installable library of AI agent skills, specialized plugins, bundles, and reusable coding workflows.",
"title": "AAS Core Preview | GitHub AI Skills Repository",
"description": "Explore the GitHub source for AAS Core preview: neutral local MCP retrieval, agent-owned skill selection, stack validation, planning, and the supporting AI agent skill catalog.",
"eyebrow": "GitHub repository",
"h1": "A GitHub repository for installable AI agent skills",
"summary": "Agentic Awesome Skills is the canonical GitHub source for SKILL.md playbooks, installer flows, plugin packs, bundles, and workflow documentation.",
"h1": "The GitHub source for AAS Core and its skill catalog",
"summary": "Agentic Awesome Skills is the canonical source for AAS Core, its local MCP and CLI, reusable SKILL.md playbooks, plugin packs, and workflow documentation.",
"primaryIntent": "Find a GitHub repository of reusable AI coding assistant skills.",
"keywords": [
"GitHub AI skills repository",
@@ -119,11 +119,11 @@
"sections": [
{
"heading": "Canonical source of truth",
"body": "The GitHub repository contains the skill source, installer CLI, user docs, plugin mirrors, bundles, workflows, and release history."
"body": "The GitHub repository contains AAS Core, the local MCP and CLI, skill sources, user docs, plugin mirrors, workflows, and release history."
},
{
"heading": "Searchable catalog",
"body": "The hosted catalog gives users a fast browsing layer over the repository so they can discover skills before installing them."
"body": "The hosted catalog is a companion browsing layer over the evidence coding agents inspect before selecting exact skill IDs."
},
{
"heading": "Reusable across agents",
@@ -136,8 +136,8 @@
"href": "https://github.com/sickn33/agentic-awesome-skills"
},
{
"label": "Install from npm",
"href": "https://www.npmjs.com/package/agentic-awesome-skills"
"label": "Read the AAS Core guide",
"href": "https://github.com/sickn33/agentic-awesome-skills/blob/main/docs/users/aas-core.md"
},
{
"label": "Browse all skills",
@@ -151,7 +151,7 @@
"description": "Compare Antigravity-compatible plugin packs for web apps, security, data analytics, documents, DevOps, QA, OSS maintenance, and agent workflows.",
"eyebrow": "Plugin packs",
"h1": "Antigravity plugins for focused agent workflows",
"summary": "Specialized plugins package the right skills for a domain so users can start with a narrow, practical surface instead of the full library.",
"summary": "Specialized plugins are secondary packaged distributions for users who prefer a fixed domain surface instead of an agent-selected AAS Core stack.",
"primaryIntent": "Find Antigravity plugin packs and focused AI workflow distributions.",
"keywords": [
"Antigravity plugins",
@@ -204,7 +204,7 @@
},
{
"heading": "Lower activation cost",
"body": "A plugin gives the assistant a tighter instruction set, reducing noise when the full catalog is more than the current task needs."
"body": "A plugin gives the assistant a fixed instruction set; AAS Core remains the agent-first path when the coding agent should inspect catalog evidence and choose exact IDs from a project profile."
},
{
"heading": "Still backed by the full repo",
@@ -228,11 +228,11 @@
},
{
"slug": "skills-para-antigravity",
"title": "Skills para Antigravity | Installable AI coding skills",
"description": "Find skills para Antigravity in the Agentic Awesome Skills GitHub library, including installable playbooks for coding agents, plugins, bundles, and workflows.",
"title": "Skills para Antigravity | AAS Core Preview",
"description": "Use AAS Core preview to find and compose explainable skills para Antigravity from the Agentic Awesome Skills catalog.",
"eyebrow": "International search",
"h1": "Skills para Antigravity and AI coding agents",
"summary": "A practical entry point for users searching for skills para Antigravity, Antigravity skills, or GitHub playbooks for AI coding assistants.",
"summary": "A practical entry point for using AAS Core to preserve skill stacks selected by Antigravity and related AI coding assistants.",
"primaryIntent": "Serve international searches for skills para Antigravity.",
"keywords": [
"skills para Antigravity",
@@ -281,8 +281,8 @@
"body": "Antigravity is one target surface, but the library also supports other assistant runtimes through direct installs and plugin distributions."
},
{
"heading": "Start with the catalog",
"body": "Use the hosted catalog to compare skills and plugin packs, then open the GitHub repository for installation and source details."
"heading": "Start with AAS Core",
"body": "Let the coding agent inspect catalog evidence and select an exact stack, then use AAS Core and the hosted site to validate and review the resulting artifacts."
}
],
"links": [
@@ -3,6 +3,12 @@ import { createMockSkill } from '../factories/skill';
import { getCuratedSkillsForSeoLandingPage, getSeoLandingPage } from './seoLandingPages';
describe('SEO landing page skill curation', () => {
it('keeps plural skills discovery copy in the Antigravity CLI metadata', () => {
const page = getSeoLandingPage('antigravity-cli-skills');
expect(page?.description).toMatch(/skills/i);
});
it('keeps real editorial picks first and deterministically fills with scored matches', () => {
const page = getSeoLandingPage('antigravity-cli-skills');
expect(page).toBeDefined();
@@ -10,11 +10,11 @@ import type { CategoryStats, SyncMessage } from '../types';
import { buildHomeMeta, getHomeFaqItems } from '../utils/seo';
const conceptCards = [
{ title: 'Specialized plugins', body: 'Focused distributions for a domain or job.' },
{ title: 'Skills', body: 'Reusable SKILL.md playbooks for repeatable execution.' },
{ title: 'MCP tools', body: 'External capabilities the assistant can call.' },
{ title: 'Bundles', body: 'Curated starting sets for a role or team.' },
{ title: 'Workflows', body: 'Ordered playbooks for a concrete outcome.' },
{ title: 'AAS Core preview', body: 'The local boundary that validates an agent-selected skill stack and immutable plan preview.' },
{ title: 'Local MCP', body: 'The agent-facing tools for neutral catalog retrieval, inspection, composition, and stack comparison.' },
{ title: 'Catalog', body: 'The complete evidence-backed source the coding agent searches before selecting exact skills.' },
{ title: 'Workbench', body: 'A browser-local review surface for stack manifests and immutable plans.' },
{ title: 'Plugins', body: 'Focused distributions for users who prefer a packaged domain surface.' },
] as const;
const integrationGuides = [
@@ -122,15 +122,15 @@ export function Home(): React.ReactElement {
</nav>
<Link to="/workbench" className="catalog-rail__workbench">
<Icon name="fileCode" size={17} />
Saved & exact installs
AAS Core Workbench
</Link>
</aside>
<div className="catalog-content">
<section className="catalog-hero">
<h1>Installable AI agent skills for Codex, Claude Code, Cursor, Gemini, and Antigravity</h1>
<p><strong>Find the right skill. Ship the better agent.</strong></p>
<p>Search {catalogCountLabel} installable skills, plugins, and workflows curated for real agent work.</p>
<h1>AAS Core: agent-first skill stacks for Codex, Claude Code, and compatible clients</h1>
<p><strong>Search. Choose. Validate. Preview.</strong></p>
<p>Let your coding agent choose exact IDs, preserve its project profile in <code>aas-stack.json</code>, and preview an immutable plan without target writes, backed by {catalogCountLabel} cataloged skills.</p>
<label className="catalog-search">
<span className="sr-only">Search skills</span>
@@ -180,7 +180,7 @@ export function Home(): React.ReactElement {
</select>
</label>
</div>
<Link to="/workbench">Compose an exact install <Icon name="arrowRight" size={16} /></Link>
<Link to="/workbench">Review an AAS Core stack <Icon name="arrowRight" size={16} /></Link>
</div>
</section>
@@ -236,8 +236,8 @@ export function Home(): React.ReactElement {
<section className="catalog-support" aria-label="Catalog guides">
<div className="catalog-support__intro">
<h2>Understand the system behind the catalog</h2>
<p>Skills, tools, bundles, plugins, and workflows solve different parts of the same job.</p>
<h2>How AAS Core uses the catalog</h2>
<p>The local MCP and CLI choose from catalog evidence; the Workbench reviews what the agent proposed.</p>
</div>
<div className="catalog-support__concepts">
{conceptCards.map((card) => (
@@ -332,20 +332,20 @@ export function SkillDetail(): React.ReactElement {
<div className="skill-detail__install-and-context">
<div className="mb-4 border border-slate-300 bg-slate-50/70 p-4 dark:border-slate-700 dark:bg-slate-900">
<p className="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
Exact install input
Canonical skill ID
</p>
<p className="mt-2 text-sm leading-relaxed text-slate-600 dark:text-slate-300">
Add only this canonical skill to the Workbench, inspect its recorded evidence, then generate a release-pinned dry run.
Give this exact ID to your agent when it selects an AAS Core stack, or use it when reviewing a proposed stack. Workbench reviews completed stack and plan artifacts; it does not compose or install them.
</p>
<div className="mt-3 flex flex-wrap items-center gap-3">
<code className="inline-block border border-slate-800 bg-slate-900 px-3 py-2 font-mono text-sm text-slate-50">
{skill.id}
</code>
<Link
to={`/workbench?selected=${encodeURIComponent(skill.id)}&host=codex`}
to="/workbench"
className="inline-flex items-center border border-teal-700 px-3 py-2 text-sm font-semibold text-teal-800 transition-colors hover:bg-teal-50 dark:border-teal-400 dark:text-teal-200 dark:hover:bg-teal-950/40"
>
Compose exact install
Review Core artifacts
</Link>
</div>
</div>
@@ -41,12 +41,13 @@ function DefinitionList({ entries }: { entries: Array<[string, React.ReactNode]>
);
}
function PolicyReview({ policy }: { policy: StackManifestReview['policy'] }): React.ReactElement {
function ProfileReview({ profile }: { profile: StackManifestReview['profile'] }): React.ReactElement {
return (
<DefinitionList entries={[
['Allowed risk', policy.allowedRisk.join(', ')],
['Known source required', policy.requireKnownSource ? 'Yes' : 'No'],
['Manual setup allowed', policy.allowManualSetup ? 'Yes' : 'No'],
['Project type', profile.projectType ?? 'Not declared'],
['Languages', profile.languages.length > 0 ? profile.languages.join(', ') : 'None declared'],
['Frameworks', profile.frameworks.length > 0 ? profile.frameworks.join(', ') : 'None declared'],
['Constraints', profile.constraints.length > 0 ? profile.constraints.join(', ') : 'None declared'],
]} />
);
}
@@ -56,7 +57,7 @@ function StackReview({ stack }: { stack: StackManifestReview }): React.ReactElem
<article className="workbench-review" aria-labelledby="stack-review-title">
<header className="workbench-review__heading">
<div>
<p>Validated stack manifest</p>
<p>Structurally valid stack manifest</p>
<h2 id="stack-review-title">{stack.name}</h2>
</div>
<span>Schema v{stack.schemaVersion}</span>
@@ -79,21 +80,21 @@ function StackReview({ stack }: { stack: StackManifestReview }): React.ReactElem
{stack.targets.map((target) => <li key={`${target.host}:${target.scope}`}><strong>{target.host}</strong><span>{target.scope}</span></li>)}
</ul>
</section>
<section aria-labelledby="stack-policy-title">
<h3 id="stack-policy-title">Policy</h3>
<PolicyReview policy={stack.policy} />
<section aria-labelledby="stack-profile-title">
<h3 id="stack-profile-title">Agent-saved project profile</h3>
<ProfileReview profile={stack.profile} />
</section>
</div>
<div className="workbench-review__columns">
<section aria-labelledby="stack-goals-title">
<h3 id="stack-goals-title">Approved goals</h3>
<h3 id="stack-goals-title">Project goals</h3>
<ul className="workbench-review__code-list">
{stack.intent.goals.map((goal) => <li key={goal}><code>{goal}</code></li>)}
{stack.profile.goals.map((goal) => <li key={goal}><code>{goal}</code></li>)}
</ul>
</section>
<section aria-labelledby="stack-skills-title">
<h3 id="stack-skills-title">Exact skills <span>{stack.skills.length}</span></h3>
<h3 id="stack-skills-title">Agent-selected skills <span>{stack.skills.length}</span></h3>
{stack.skills.length === 0 ? <p className="workbench-review__empty">No skills selected.</p> : (
<ol className="workbench-review__code-list">
{stack.skills.map((skill) => <li key={skill.id}><code>{skill.id}</code></li>)}
@@ -107,12 +108,11 @@ function StackReview({ stack }: { stack: StackManifestReview }): React.ReactElem
function PlanReviewView({ plan }: { plan: PlanReview }): React.ReactElement {
const { payload } = plan;
const unknownCount = payload.overrides.reduce((total, override) => total + override.unknownFields.length, 0);
return (
<article className="workbench-review" aria-labelledby="plan-review-title">
<header className="workbench-review__heading">
<div>
<p>Validated immutable plan</p>
<p>Structurally valid plan · digest verified</p>
<h2 id="plan-review-title">Single-target change review</h2>
</div>
<span>Schema v{plan.schemaVersion}</span>
@@ -135,8 +135,7 @@ function PlanReviewView({ plan }: { plan: PlanReview }): React.ReactElement {
<DefinitionList entries={[
['Protocol', payload.versions.protocolVersion],
['Core', payload.versions.coreVersion],
['Metadata schema', payload.versions.metadataSchemaVersion],
['Scorer', payload.versions.scorerVersion],
['Catalog schema', payload.versions.catalogSchemaVersion],
]} />
</section>
<section aria-labelledby="plan-target-title">
@@ -150,6 +149,14 @@ function PlanReviewView({ plan }: { plan: PlanReview }): React.ReactElement {
</section>
</div>
<section aria-labelledby="plan-profile-title">
<h3 id="plan-profile-title">Bound project profile</h3>
<ProfileReview profile={payload.profile} />
<ul className="workbench-review__code-list">
{payload.profile.goals.map((goal) => <li key={goal}><code>{goal}</code></li>)}
</ul>
</section>
<section aria-labelledby="plan-operations-title">
<div className="workbench-review__section-heading">
<h3 id="plan-operations-title">Operations</h3>
@@ -173,8 +180,8 @@ function PlanReviewView({ plan }: { plan: PlanReview }): React.ReactElement {
<section aria-labelledby="plan-overrides-title" className={payload.overrides.length > 0 ? 'workbench-review__attention' : ''}>
<div className="workbench-review__section-heading">
<h3 id="plan-overrides-title">Overrides and unknowns</h3>
<span>{payload.overrides.length} overrides · {unknownCount} unknown fields</span>
<h3 id="plan-overrides-title">Managed drift overrides</h3>
<span>{payload.overrides.length} overrides</span>
</div>
{payload.overrides.length === 0 ? <p className="workbench-review__empty">No overrides recorded.</p> : (
<ul className="workbench-review__override-list">
@@ -182,7 +189,6 @@ function PlanReviewView({ plan }: { plan: PlanReview }): React.ReactElement {
<li key={`${override.kind}:${override.skillId}`}>
<header><strong>{override.kind}</strong><code>{override.skillId}</code></header>
<p><span>Reason codes</span> {override.reasonCodes.join(', ')}</p>
<p><span>Unknown fields</span> {override.unknownFields.length > 0 ? override.unknownFields.join(', ') : 'None'}</p>
</li>
))}
</ul>
@@ -268,7 +274,7 @@ function ArtifactImporter<T>({
id={textareaId}
value={draft}
onChange={(event) => setDraft(event.target.value)}
placeholder={kind === 'stack' ? '{ "schemaVersion": 1, "name": "…" }' : '{ "schemaVersion": 1, "kind": "aas.stack-plan", … }'}
placeholder={kind === 'stack' ? '{ "schemaVersion": 2, "name": "…" }' : '{ "schemaVersion": 2, "kind": "aas.stack-plan", … }'}
rows={8}
spellCheck={false}
autoComplete="off"
@@ -303,8 +309,8 @@ export function Workbench(): React.ReactElement {
const [plan, setPlan] = useState<ImportState<PlanReview>>({ ...EMPTY_IMPORT_STATE });
usePageMeta(useMemo(() => ({
title: 'Stack Review Workbench | Agentic Awesome Skills',
description: 'Review an AAS stack manifest and immutable plan locally in your browser. Imports stay in memory and cannot install or apply changes.',
title: 'AAS Core Stack Review | Agentic Awesome Skills',
description: 'Review an AAS Core stack manifest and immutable preview plan locally in your browser. Imports stay in memory and cannot install or apply changes.',
canonicalPath: '/workbench',
}), []));
@@ -313,8 +319,8 @@ export function Workbench(): React.ReactElement {
<header className="workbench-header">
<div>
<div>
<h1>Review what your agent chose.</h1>
<p>Import an <code>aas-stack.json</code> and immutable plan to inspect identities, targets, operations, overrides, and unknowns before approving anything in the CLI.</p>
<h1>Review what your agent selected.</h1>
<p>Import the <code>aas-stack.json</code> saved from your agent's explicit catalog choices and the immutable preview plan produced by the <code>aas</code> CLI to inspect the project profile, exact skills, identities, targets, operations, and managed drift overrides.</p>
</div>
<dl>
<div><dt>Privacy</dt><dd>In-memory only</dd></div>
@@ -334,7 +340,7 @@ export function Workbench(): React.ReactElement {
<ArtifactImporter
kind="stack"
title="Import desired state"
description="Paste or explicitly select the minimal stack manifest your agent proposed."
description="Paste or explicitly select the stack manifest containing your agent's exact skill choices."
state={stack}
onState={setStack}
/>
@@ -85,19 +85,19 @@ describe('Home', () => {
renderWithRouter(<Home />, { useProvider: false });
await waitFor(() => {
expect(document.title).toContain('Agentic Awesome Skills');
expect(document.title).toContain('AAS Core Preview');
});
expect(screen.getByRole('heading', {
level: 1,
name: /Installable AI agent skills for Codex, Claude Code, Cursor, Gemini, and Antigravity/i,
name: /AAS Core: agent-first skill stacks for Codex, Claude Code, and compatible clients/i,
})).toBeInTheDocument();
expect(screen.getByText(/Find the right skill\. Ship the better agent\./i)).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Compose an exact install/i })).toHaveAttribute('href', '/workbench');
expect(screen.getByText(/Search\. Choose\. Validate\. Preview\./i)).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Review an AAS Core stack/i })).toHaveAttribute('href', '/workbench');
expect(screen.getByText(/What is the difference between skills and MCP tools/i)).toBeInTheDocument();
expect(document.querySelector('meta[property="og:title"]')).toHaveAttribute(
'content',
expect.stringContaining('Agentic Awesome Skills'),
expect.stringContaining('AAS Core Preview'),
);
});
@@ -112,7 +112,7 @@ describe('Home', () => {
renderWithRouter(<Home />, { useProvider: false });
await waitFor(() => {
expect(screen.getByRole('link', { name: /Compose an exact install/i })).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Review an AAS Core stack/i })).toBeInTheDocument();
});
expect(screen.getByText(/Inspect evidence, select exact IDs/i)).toBeInTheDocument();
@@ -268,7 +268,7 @@ describe('SkillDetail', () => {
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('Use @click-test');
});
it('should send the exact skill to the Workbench', async () => {
it('should link to Core artifact review without promising composition', async () => {
const mockSkill = createMockSkill({ id: 'click-install', name: 'click-install' });
(useSkills as Mock).mockReturnValue({
@@ -289,12 +289,12 @@ describe('SkillDetail', () => {
});
await waitFor(() => {
expect(screen.getByRole('link', { name: /Compose exact install/i })).toBeInTheDocument();
expect(screen.getByRole('link', { name: /Review Core artifacts/i })).toBeInTheDocument();
});
expect(screen.getByRole('link', { name: /Compose exact install/i })).toHaveAttribute(
expect(screen.getByRole('link', { name: /Review Core artifacts/i })).toHaveAttribute(
'href',
'/workbench?selected=click-install&host=codex',
'/workbench',
);
});
});
@@ -39,19 +39,19 @@ describe('TopicLanding', () => {
'href',
'/skill/antigravity-agent-manager',
);
expect(screen.getByRole('link', { name: /GitHub repository for installable AI agent skills/i })).toHaveAttribute(
expect(screen.getByRole('link', { name: /GitHub source for AAS Core and its skill catalog/i })).toHaveAttribute(
'href',
'/topics/github-ai-skills-repository',
);
expect(screen.getAllByText(/Antigravity CLI skills/i).length).toBeGreaterThan(0);
await waitFor(() => {
expect(document.title).toContain('Antigravity CLI Skills');
expect(document.title).toContain('Antigravity CLI Skill Stacks');
});
expect(document.querySelector('meta[name="description"]')).toHaveAttribute(
'content',
expect.stringContaining('Install Antigravity CLI skills'),
expect.stringContaining('AAS Core preview catalog'),
);
});
@@ -13,30 +13,34 @@ const D5 = `sha256-${'5'.repeat(64)}`;
function stackFixture(overrides: Record<string, unknown> = {}): Record<string, unknown> {
return {
schemaVersion: 1,
schemaVersion: 2,
name: 'reviewed-web-stack',
catalog: { package: 'agentic-awesome-skills', version: '15.0.0', integrity: D1 },
targets: [{ host: 'codex', scope: 'project' }],
intent: { goals: ['build', 'test'] },
policy: { allowedRisk: ['none', 'safe'], requireKnownSource: true, allowManualSetup: false },
profile: {
goals: ['build', 'test'],
projectType: 'React web application',
languages: ['typescript'],
frameworks: ['react'],
constraints: ['offline-capable'],
},
skills: [{ id: 'react-best-practices' }, { id: 'playwright-skill' }],
...overrides,
};
}
function planFixture(unknownField = 'metadata.source'): Record<string, unknown> {
function planFixture(reasonCode = 'AAS_MANAGED_DRIFT_APPROVED'): Record<string, unknown> {
const plan = {
schemaVersion: 1,
schemaVersion: 2,
kind: 'aas.stack-plan',
digest: D5,
payload: {
schemaVersion: 1,
schemaVersion: 2,
kind: 'aas.stack-plan.payload',
versions: {
protocolVersion: '2025-06-18',
coreVersion: '1.0.0',
metadataSchemaVersion: '1.0.0',
scorerVersion: '1.0.0',
catalogSchemaVersion: '2.0.0',
},
manifestDigest: D2,
catalog: { package: 'agentic-awesome-skills', version: '15.0.0', integrity: D1 },
@@ -44,7 +48,13 @@ function planFixture(unknownField = 'metadata.source'): Record<string, unknown>
target: { host: 'codex', scope: 'project', adapterVersion: '1.0.0', identityDigest: D4 },
installedState: { digest: D2, entries: [] },
desiredSkills: ['react-best-practices'],
policy: { allowedRisk: ['none', 'safe'], requireKnownSource: true, allowManualSetup: false },
profile: {
goals: ['build', 'test'],
projectType: 'React web application',
languages: ['typescript'],
frameworks: ['react'],
constraints: ['offline-capable'],
},
operations: [{
kind: 'install',
skillId: 'react-best-practices',
@@ -54,10 +64,9 @@ function planFixture(unknownField = 'metadata.source'): Record<string, unknown>
backupRequired: false,
}],
overrides: [{
kind: 'discoveryCandidate',
kind: 'managedDrift',
skillId: 'react-best-practices',
reasonCodes: ['AAS_DISCOVERY_PROMOTED'],
unknownFields: [unknownField],
reasonCodes: [reasonCode],
}],
stateCommit: { previousDigest: D2, nextDigest: D4, position: 'final' },
},
@@ -78,6 +87,8 @@ describe('Workbench review UI', () => {
it('reviews a valid stack without offering install, apply, or share actions', () => {
renderWithRouter(<Workbench />, { route: '/workbench', path: '/workbench', useProvider: false });
expect(screen.getByRole('heading', { level: 1, name: 'Review what your agent selected.' })).toBeInTheDocument();
paste('Paste JSON', stackFixture());
fireEvent.click(screen.getByRole('button', { name: 'Review pasted stack' }));
@@ -89,7 +100,7 @@ describe('Workbench review UI', () => {
expect(window.location.search).toBe('');
});
it('reviews plan bindings, operations, overrides, and unknown fields', async () => {
it('reviews plan bindings, the saved profile, operations, and managed drift overrides', async () => {
renderWithRouter(<Workbench />, { route: '/workbench', path: '/workbench', useProvider: false });
paste('Paste JSON', planFixture(), 1);
@@ -98,9 +109,9 @@ describe('Workbench review UI', () => {
expect(await screen.findByRole('heading', { level: 2, name: 'Single-target change review' })).toBeInTheDocument();
expect(screen.getByText('install')).toBeInTheDocument();
expect(screen.getAllByText('react-best-practices')).toHaveLength(2);
expect(screen.getAllByText('AAS_DISCOVERY_PROMOTED', { exact: false })).toHaveLength(2);
expect(screen.getAllByText('metadata.source', { exact: false })).toHaveLength(2);
expect(screen.getByText('1 overrides · 1 unknown fields')).toBeInTheDocument();
expect(screen.getAllByText('AAS_MANAGED_DRIFT_APPROVED', { exact: false })).toHaveLength(2);
expect(screen.getByText('1 overrides')).toBeInTheDocument();
expect(screen.getByRole('heading', { level: 3, name: 'Bound project profile' })).toBeInTheDocument();
});
it('fails closed on schema drift and clears the previous review', () => {
@@ -129,6 +140,22 @@ describe('Workbench review UI', () => {
expect(screen.queryByRole('heading', { level: 2, name: 'Single-target change review' })).not.toBeInTheDocument();
});
it('rejects the retired discovery candidate override', async () => {
const plan = planFixture();
const payload = plan.payload as { overrides: Array<Record<string, unknown>> };
payload.overrides[0] = {
kind: 'discoveryCandidate',
skillId: 'react-best-practices',
reasonCodes: ['AAS_DISCOVERY_PROMOTED'],
};
renderWithRouter(<Workbench />, { route: '/workbench', path: '/workbench', useProvider: false });
paste('Paste JSON', plan, 1);
fireEvent.click(screen.getByRole('button', { name: 'Review pasted plan' }));
expect(await screen.findByRole('alert')).toHaveTextContent('kind must equal "managedDrift"');
});
it('renders hostile schema-valid strings as text and never creates executable elements', async () => {
const payload = '</script><img src=x onerror="globalThis.pwned=true">javascript:alert(1)';
renderWithRouter(<Workbench />, { route: '/workbench', path: '/workbench', useProvider: false });
@@ -33,12 +33,13 @@ describe('SEO helpers', () => {
expect(DEFAULT_TOP_SKILL_COUNT).toBe(180);
});
it('builds homepage metadata with the canonical catalog message', () => {
it('builds homepage metadata with the canonical AAS Core preview message', () => {
const meta = buildHomeMeta(10);
expect(meta.title).toContain('Agentic Awesome Skills GitHub');
expect(meta.title).toContain('10+ AI coding skills');
expect(meta.description).toContain('GitHub library of 10+ installable agentic skills');
expect(meta.title).toContain('AAS Core Preview');
expect(meta.title).toContain('10+ skills');
expect(meta.description).toContain('neutral catalog retrieval, exact agent-owned selection, validation, and planning');
expect(meta.description).toContain('10+ cataloged skills');
expect(meta.canonicalPath).toBe('/');
expect(meta.ogTitle).toBe(meta.title);
expect(meta.ogImage).toBe(DEFAULT_SOCIAL_IMAGE);
@@ -96,7 +97,7 @@ describe('SEO helpers', () => {
const meta = buildTopicLandingMeta(topic!);
expect(meta.title).toContain('GitHub AI Skills Repository');
expect(meta.description).toContain('GitHub repository');
expect(meta.description).toContain('GitHub source for AAS Core preview');
expect(meta.canonicalPath).toBe('/topics/github-ai-skills-repository');
expect(meta.ogImage).toBe(DEFAULT_SOCIAL_IMAGE);
expect(typeof meta.jsonLd).toBe('function');
@@ -1,164 +0,0 @@
import { describe, expect, it } from 'vitest';
import canonicalCatalog from '../../../../../skills_index.json';
import packageMetadata from '../../../../../package.json';
import { createMockSkill } from '../../factories/skill';
import {
buildInstallerCommand,
collectSelectionEvidence,
matchesWorkbenchFilters,
parseSelectedIds,
type WorkbenchFilters,
} from '../skillWorkbench';
const baseFilters: WorkbenchFilters = {
search: '',
category: 'all',
risk: 'all',
provenance: 'all',
compatibility: 'all',
setup: 'all',
};
describe('skill workbench domain', () => {
it('searches every recorded field promised by the workbench', () => {
const skill = createMockSkill({
id: 'service-audit',
name: 'Service Audit',
description: 'Reviews Kubernetes deployment supply chains.',
category: 'security',
tags: ['kubernetes', 'supply-chain'],
source: 'community',
source_type: 'community',
source_repo: 'example/security-skills',
});
for (const query of [
'service-audit',
'Service Audit',
'deployment supply',
'security',
'supply-chain',
'community',
'example/security',
]) {
expect(matchesWorkbenchFilters(skill, { ...baseFilters, search: query }, 'codex')).toBe(true);
}
expect(matchesWorkbenchFilters(skill, { ...baseFilters, search: 'browser-design' }, 'codex')).toBe(false);
});
it('filters category and recorded-or-unknown risk without inventing defaults', () => {
const skill = createMockSkill({
category: 'operations',
risk: undefined,
});
expect(matchesWorkbenchFilters(skill, {
...baseFilters,
category: 'operations',
risk: 'unknown',
}, 'codex')).toBe(true);
expect(matchesWorkbenchFilters(skill, { ...baseFilters, category: 'security' }, 'codex')).toBe(false);
expect(matchesWorkbenchFilters(skill, { ...baseFilters, risk: 'safe' }, 'codex')).toBe(false);
});
it('filters raw unknown provenance and recorded host compatibility independently', () => {
const skill = createMockSkill({
source: 'https://example.com/source',
source_type: undefined,
plugin: {
targets: { codex: 'blocked', claude: 'supported' },
setup: { type: 'manual', summary: 'Configure a token.', docs: 'SKILL.md' },
reasons: ['Codex-only tool is unavailable.'],
},
});
expect(matchesWorkbenchFilters(skill, {
...baseFilters,
provenance: 'unknown',
compatibility: 'blocked',
setup: 'manual',
}, 'codex')).toBe(true);
expect(matchesWorkbenchFilters(skill, { ...baseFilters, compatibility: 'blocked' }, 'claude')).toBe(false);
expect(matchesWorkbenchFilters(skill, { ...baseFilters, compatibility: 'unrecorded' }, 'cursor')).toBe(true);
const unrecorded = createMockSkill({ source: 'personal', source_type: undefined, plugin: undefined });
expect(matchesWorkbenchFilters(unrecorded, {
...baseFilters,
provenance: 'unknown',
compatibility: 'unrecorded',
setup: 'unknown',
}, 'codex')).toBe(true);
});
it('keeps evidence dimensions separate instead of manufacturing a score', () => {
const skills = [
createMockSkill({
id: 'unknown-source',
risk: 'unknown',
source: 'external',
source_type: undefined,
}),
createMockSkill({
id: 'blocked-offensive',
risk: 'offensive',
source_type: 'community',
plugin: {
targets: { codex: 'blocked', claude: 'supported' },
setup: { type: 'manual', summary: 'Manual setup', docs: null },
reasons: ['Blocked'],
},
}),
];
const evidence = collectSelectionEvidence(skills, 'codex');
expect(evidence.unknownRisk.map((skill) => skill.id)).toEqual(['unknown-source']);
expect(evidence.missingProvenance.map((skill) => skill.id)).toEqual(['unknown-source']);
expect(evidence.elevatedRisk.map((skill) => skill.id)).toEqual(['blocked-offensive']);
expect(evidence.blockedForHost.map((skill) => skill.id)).toEqual(['blocked-offensive']);
expect(evidence.manualSetup.map((skill) => skill.id)).toEqual(['blocked-offensive']);
});
it('round-trips a deterministic exact selection and pins package and source release', () => {
expect(parseSelectedIds('zeta,alpha,zeta')).toEqual(['alpha', 'zeta']);
expect(buildInstallerCommand({
skillIds: ['zeta', 'alpha'],
host: 'codex',
version: packageMetadata.version,
dryRun: true,
})).toBe(
`npx agentic-awesome-skills@${packageMetadata.version} --codex --release ${packageMetadata.version} --skills alpha,zeta --dry-run`,
);
});
it('refuses malformed IDs instead of shell-quoting untrusted selection state', () => {
expect(() => buildInstallerCommand({
skillIds: ['safe-skill', 'bad;command'],
host: 'claude',
version: packageMetadata.version,
dryRun: false,
})).toThrow(/Invalid skill IDs/i);
});
it('accepts the legacy underscore used by a canonical catalog id', () => {
expect(buildInstallerCommand({
skillIds: ['android_ui_verification'],
host: 'codex',
version: packageMetadata.version,
dryRun: true,
})).toContain('--skills android_ui_verification --dry-run');
});
it('proves every current canonical catalog id is unique and command-safe', () => {
const ids = canonicalCatalog.map((skill) => skill.id);
expect(ids.length).toBeGreaterThan(1_000);
expect(new Set(ids).size).toBe(ids.length);
expect(parseSelectedIds(ids.join(','))).toEqual([...ids].sort());
expect(() => buildInstallerCommand({
skillIds: ids,
host: 'codex',
version: packageMetadata.version,
dryRun: true,
})).not.toThrow();
});
});
@@ -11,12 +11,17 @@ const D = `sha256-${'a'.repeat(64)}`;
function validStack(): Record<string, unknown> {
return {
schemaVersion: 1,
schemaVersion: 2,
name: 'safe-stack',
catalog: { package: 'agentic-awesome-skills', version: '15.0.0', integrity: D },
targets: [{ host: 'codex', scope: 'project' }],
intent: { goals: ['build'] },
policy: { allowedRisk: ['safe'], requireKnownSource: true, allowManualSetup: false },
profile: {
goals: ['build'],
projectType: 'React web application',
languages: ['typescript'],
frameworks: ['react'],
constraints: [],
},
skills: [{ id: 'react-best-practices' }],
};
}
@@ -24,11 +29,27 @@ function validStack(): Record<string, unknown> {
describe('workbenchReview', () => {
it('accepts the public stack shape and rejects duplicate skill IDs', () => {
expect(parseWorkbenchArtifact(JSON.stringify(validStack()), 'stack').kind).toBe('stack');
const withoutProjectType = validStack();
const emptyProfile = withoutProjectType.profile as Record<string, unknown>;
delete emptyProfile.projectType;
emptyProfile.goals = [];
emptyProfile.languages = [];
emptyProfile.frameworks = [];
emptyProfile.constraints = [];
expect(parseWorkbenchArtifact(JSON.stringify(withoutProjectType), 'stack').kind).toBe('stack');
const stack = validStack();
stack.skills = [{ id: 'same' }, { id: 'same' }];
expect(() => parseWorkbenchArtifact(JSON.stringify(stack), 'stack')).toThrow('duplicate IDs');
});
it('rejects the retired v1 policy shape', () => {
const stack = validStack();
stack.schemaVersion = 1;
stack.policy = { allowedRisk: ['safe'], requireKnownSource: true, allowManualSetup: false };
delete stack.profile;
expect(() => parseWorkbenchArtifact(JSON.stringify(stack), 'stack')).toThrow('unsupported property "policy"');
});
it('rejects an artifact of the wrong expected kind', () => {
expect(() => parseWorkbenchArtifact(JSON.stringify(validStack()), 'plan')).toThrow('plan contains unsupported property');
});
@@ -54,7 +75,7 @@ describe('workbenchReview', () => {
it('rejects forbidden object keys and does not echo their values', () => {
const stack = validStack();
stack.intent = JSON.parse('{"goals":["build"],"__proto__":"secret-canary"}') as unknown;
stack.profile = JSON.parse('{"goals":["build"],"projectType":"web","languages":[],"frameworks":[],"constraints":[],"__proto__":"secret-canary"}') as unknown;
try {
parseWorkbenchArtifact(JSON.stringify(stack), 'stack');
throw new Error('expected rejection');
@@ -39,17 +39,17 @@ const FAQ_ITEMS = [
{
question: 'What is Agentic Awesome Skills?',
answer: (countLabel: string) =>
`Agentic Awesome Skills is an installable GitHub library of ${countLabel} reusable SKILL.md playbooks for AI coding assistants. It supports Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and related hosts through direct skill installs, specialized plugins, bundles, workflows, and a searchable catalog.`,
`Agentic Awesome Skills is built around AAS Core, a local agent-first preview boundary for neutral catalog retrieval, exact agent-owned selection, validation, and planning. AAS Core is backed by an evidence-rich catalog of ${countLabel} reusable SKILL.md playbooks.`,
},
{
question: 'How do I install Agentic Awesome Skills?',
question: 'How do I use AAS Core preview?',
answer:
'Install the library with npx agentic-awesome-skills. Use tool-specific flags such as --codex, --cursor, --gemini, --claude, or --antigravity when you want the installer to target a specific skills directory already used by your assistant runtime.',
'Configure the local stdio MCP with the AAS CLI, let the agent search and inspect the complete catalog, choose exact skill IDs itself, then validate the schema 2 aas-stack.json with its project profile and preview the immutable plan in the CLI. Apply and recovery are outside the non-applying preview path.',
},
{
question: 'Is Agentic Awesome Skills a GitHub repository?',
answer:
'Yes. The GitHub repository at https://github.com/sickn33/agentic-awesome-skills is the canonical source for the skill library, installer, specialized plugins, bundles, workflows, and documentation. The hosted catalog is the searchable browsing surface for that repository.',
'Yes. The GitHub repository at https://github.com/sickn33/agentic-awesome-skills is the canonical source for AAS Core, its CLI and local MCP, the skill catalog, plugins, and documentation. The hosted site is a companion catalog and local artifact-review surface.',
},
{
question: 'What are AAS specialized plugins?',
@@ -174,7 +174,7 @@ function buildSoftwareSourceCodeSchema(canonicalUrl: string, visibleCount: numbe
'@context': 'https://schema.org',
'@type': 'SoftwareSourceCode',
name: SITE_NAME,
description: `Installable GitHub library of ${visibleCountLabel}, specialized plugins, bundles, and workflows for AI coding assistants.`,
description: `AAS Core preview is a local agent-first boundary for neutral catalog retrieval, exact agent-owned selection, validation, and planning backed by ${visibleCountLabel}.`,
url: REPOSITORY_URL,
sameAs: [
canonicalUrl,
@@ -194,6 +194,10 @@ function buildSoftwareSourceCodeSchema(canonicalUrl: string, visibleCount: numbe
'Antigravity CLI skills',
'GitHub AI skills repository',
'AI agent skills GitHub',
'AAS Core',
'agent-selected skill stack',
'agent stack',
'Model Context Protocol',
'specialized plugins',
'SKILL.md',
],
@@ -375,11 +379,11 @@ export function buildHomeMeta(skillCount: number): SeoMeta {
const visibleCount = Math.max(skillCount, 0);
const visibleCountLabel = visibleCount > 0 ? getCatalogCountLabel(visibleCount) : '';
const title = visibleCount > 0
? `Agentic Awesome Skills GitHub | ${visibleCountLabel} AI coding skills`
: 'Agentic Awesome Skills GitHub | AI coding skills';
? `AAS Core Preview | Agent-first stacks backed by ${visibleCountLabel} skills`
: 'AAS Core Preview | Agent-first skill stacks';
const description = visibleCount > 0
? `Explore the GitHub library of ${visibleCountLabel} installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and other AI coding assistants.`
: 'Explore the GitHub library of installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Autohand Code, Gemini CLI, Antigravity, and other AI coding assistants.';
? `Use AAS Core preview for neutral catalog retrieval, exact agent-owned selection, validation, and planning for Codex, Claude Code, and compatible clients, backed by ${visibleCountLabel} cataloged skills.`
: 'Use AAS Core preview for neutral catalog retrieval, exact agent-owned selection, validation, and planning for Codex, Claude Code, and compatible clients.';
return {
title,
description,
@@ -400,7 +404,7 @@ export function buildHomeMeta(skillCount: number): SeoMeta {
about: buildSoftwareSourceCodeSchema(canonicalUrl, visibleCount),
mainEntity: {
'@type': 'ItemList',
name: 'Agentic Awesome Skills catalog',
name: 'AAS Core skill catalog',
},
},
buildOrganizationSchema(),
@@ -469,7 +473,7 @@ export function buildTopicLandingMeta(page: SeoLandingPage, featuredSkills: Read
keywords,
mainEntity: {
'@type': 'ItemList',
name: `${page.eyebrow} recommended skills`,
name: `${page.eyebrow} featured skills`,
numberOfItems: featuredSkills.length || page.sections.length,
itemListElement: (featuredSkills.length > 0 ? featuredSkills : page.sections).map((entry, index) => ({
'@type': 'ListItem',
@@ -1,147 +0,0 @@
import type { PluginCompatibility, RiskLevel, Skill, SkillSetupType } from '../types';
export const WORKBENCH_HOSTS = [
{ id: 'codex', label: 'Codex CLI', flag: '--codex', compatibilityRecorded: true },
{ id: 'claude', label: 'Claude Code', flag: '--claude', compatibilityRecorded: true },
{ id: 'cursor', label: 'Cursor', flag: '--cursor', compatibilityRecorded: false },
{ id: 'gemini', label: 'Gemini CLI', flag: '--gemini', compatibilityRecorded: false },
{ id: 'antigravity', label: 'Antigravity', flag: '--antigravity', compatibilityRecorded: false },
{ id: 'kiro', label: 'Kiro', flag: '--kiro', compatibilityRecorded: false },
] as const;
export type WorkbenchHost = typeof WORKBENCH_HOSTS[number]['id'];
export type RiskFacet = RiskLevel | 'all';
export type ProvenanceFacet = 'all' | 'official' | 'community' | 'self' | 'unknown';
export type CompatibilityFacet = 'all' | 'supported' | 'blocked' | 'unrecorded';
export type SetupFacet = SkillSetupType | 'all' | 'unknown';
export interface WorkbenchFilters {
search: string;
category: string;
risk: RiskFacet;
provenance: ProvenanceFacet;
compatibility: CompatibilityFacet;
setup: SetupFacet;
}
export interface SelectionEvidence {
blockedForHost: Skill[];
unrecordedForHost: Skill[];
elevatedRisk: Skill[];
unknownRisk: Skill[];
missingProvenance: Skill[];
manualSetup: Skill[];
}
// Canonical catalog ids are shell-safe lowercase directory basenames. One
// legacy id contains an underscore, so preserve that real registry value.
const SKILL_ID_PATTERN = /^[a-z0-9](?:[a-z0-9_-]{0,62}[a-z0-9])?$/;
const VERSION_PATTERN = /^\d+\.\d+\.\d+(?:[-+][a-z0-9.-]+)?$/i;
export function isWorkbenchHost(value: string | null): value is WorkbenchHost {
return WORKBENCH_HOSTS.some((host) => host.id === value);
}
export function getRecordedProvenance(skill: Skill): Exclude<ProvenanceFacet, 'all'> {
if (skill.source_type) return skill.source_type;
if (skill.source === 'official' || skill.source === 'community' || skill.source === 'self') {
return skill.source;
}
return 'unknown';
}
export function getHostCompatibility(
skill: Skill,
host: WorkbenchHost,
): PluginCompatibility | 'unrecorded' {
if (host === 'codex' || host === 'claude') {
return skill.plugin?.targets?.[host] ?? 'unrecorded';
}
return 'unrecorded';
}
export function getSetupType(skill: Skill): SkillSetupType | 'unknown' {
return skill.plugin?.setup?.type ?? 'unknown';
}
function searchableText(skill: Skill): string {
return [
skill.id,
skill.name,
skill.description,
skill.category,
skill.source,
skill.source_repo,
skill.source_type,
...(skill.tags ?? []),
]
.filter(Boolean)
.join(' ')
.toLowerCase();
}
export function matchesWorkbenchFilters(
skill: Skill,
filters: WorkbenchFilters,
host: WorkbenchHost,
): boolean {
const query = filters.search.trim().toLowerCase();
if (query && !searchableText(skill).includes(query)) return false;
if (filters.category !== 'all' && skill.category !== filters.category) return false;
if (filters.risk !== 'all' && (skill.risk ?? 'unknown') !== filters.risk) return false;
if (filters.provenance !== 'all' && getRecordedProvenance(skill) !== filters.provenance) return false;
if (filters.compatibility !== 'all' && getHostCompatibility(skill, host) !== filters.compatibility) return false;
if (filters.setup !== 'all' && getSetupType(skill) !== filters.setup) return false;
return true;
}
export function collectSelectionEvidence(
skills: Skill[],
host: WorkbenchHost,
): SelectionEvidence {
return {
blockedForHost: skills.filter((skill) => getHostCompatibility(skill, host) === 'blocked'),
unrecordedForHost: skills.filter((skill) => getHostCompatibility(skill, host) === 'unrecorded'),
elevatedRisk: skills.filter((skill) => skill.risk === 'critical' || skill.risk === 'offensive'),
unknownRisk: skills.filter((skill) => (skill.risk ?? 'unknown') === 'unknown'),
missingProvenance: skills.filter((skill) => getRecordedProvenance(skill) === 'unknown'),
manualSetup: skills.filter((skill) => getSetupType(skill) === 'manual'),
};
}
export function normalizeSelectedIds(values: Iterable<string>): string[] {
return [...new Set([...values].map((value) => value.trim()).filter(Boolean))].sort();
}
export function parseSelectedIds(value: string | null): string[] {
if (!value) return [];
return normalizeSelectedIds(value.split(','));
}
export function buildInstallerCommand({
skillIds,
host,
version,
dryRun,
}: {
skillIds: Iterable<string>;
host: WorkbenchHost;
version: string;
dryRun: boolean;
}): string {
const selected = normalizeSelectedIds(skillIds);
if (selected.length === 0) throw new Error('Select at least one skill.');
if (!VERSION_PATTERN.test(version)) throw new Error(`Invalid release version: ${version}`);
const invalid = selected.filter((skillId) => !SKILL_ID_PATTERN.test(skillId));
if (invalid.length > 0) throw new Error(`Invalid skill IDs: ${invalid.join(', ')}`);
const hostDefinition = WORKBENCH_HOSTS.find((candidate) => candidate.id === host);
if (!hostDefinition) throw new Error(`Unsupported host: ${host}`);
return [
`npx agentic-awesome-skills@${version}`,
hostDefinition.flag,
`--release ${version}`,
`--skills ${selected.join(',')}`,
dryRun ? '--dry-run' : '',
].filter(Boolean).join(' ');
}
@@ -6,31 +6,28 @@ const ID_PATTERN = /^[a-z0-9][a-z0-9._-]*(\/[a-z0-9][a-z0-9._-]*)*$/;
const PACKAGE_PATTERN = /^(@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
const VERSION_PATTERN = /^[0-9A-Za-z][0-9A-Za-z.+-]*$/;
const NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._ -]*$/;
const RISK_LEVELS = new Set(['none', 'safe', 'unknown', 'critical', 'offensive']);
const HOSTS = new Set(['codex', 'claude']);
const SCOPES = new Set(['project', 'user']);
const OPERATION_KINDS = new Set(['install', 'replaceManaged', 'removeManaged']);
const OVERRIDE_KINDS = new Set(['discoveryCandidate', 'managedDrift']);
const FORBIDDEN_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
export type WorkbenchArtifactKind = 'stack' | 'plan';
export interface StackManifestReview {
schemaVersion: 1;
schemaVersion: 2;
name: string;
catalog: CatalogIdentity;
targets: Target[];
intent: { goals: string[] };
policy: Policy;
profile: ProjectProfile;
skills: Array<{ id: string }>;
}
export interface PlanReview {
schemaVersion: 1;
schemaVersion: 2;
kind: 'aas.stack-plan';
digest: string;
payload: {
schemaVersion: 1;
schemaVersion: 2;
kind: 'aas.stack-plan.payload';
versions: Versions;
manifestDigest: string;
@@ -42,7 +39,7 @@ export interface PlanReview {
entries: Array<{ skillId: string; treeDigest: string; catalogIntegrity: string }>;
};
desiredSkills: string[];
policy: Policy;
profile: ProjectProfile;
operations: PlanOperation[];
overrides: PlanOverride[];
stateCommit: { previousDigest: string; nextDigest: string; position: 'final' };
@@ -60,17 +57,18 @@ export interface Target {
scope: 'project' | 'user';
}
export interface Policy {
allowedRisk: string[];
requireKnownSource: boolean;
allowManualSetup: boolean;
export interface ProjectProfile {
goals: string[];
projectType?: string;
languages: string[];
frameworks: string[];
constraints: string[];
}
export interface Versions {
protocolVersion: string;
coreVersion: string;
metadataSchemaVersion: string;
scorerVersion: string;
catalogSchemaVersion: string;
}
export interface PlanOperation {
@@ -83,10 +81,9 @@ export interface PlanOperation {
}
export interface PlanOverride {
kind: 'discoveryCandidate' | 'managedDrift';
kind: 'managedDrift';
skillId: string;
reasonCodes: string[];
unknownFields: string[];
}
export type ParsedWorkbenchArtifact =
@@ -187,27 +184,28 @@ function parseTarget(value: unknown, path: string, planned = false): Target & {
: base;
}
function parsePolicy(value: unknown, path: string): Policy {
function parseProfile(value: unknown, path: string): ProjectProfile {
const entry = record(value, path);
exactKeys(entry, ['allowedRisk', 'requireKnownSource', 'allowManualSetup'], ['allowedRisk', 'requireKnownSource', 'allowManualSetup'], path);
const allowedRisk = stringArray(entry.allowedRisk, `${path}.allowedRisk`, { min: 1, max: 5 });
if (allowedRisk.some((risk) => !RISK_LEVELS.has(risk))) fail(`${path}.allowedRisk contains an unsupported risk level.`);
const allowed = ['goals', 'projectType', 'languages', 'frameworks', 'constraints'];
const required = ['goals', 'languages', 'frameworks', 'constraints'];
exactKeys(entry, allowed, required, path);
return {
allowedRisk,
requireKnownSource: bool(entry.requireKnownSource, `${path}.requireKnownSource`),
allowManualSetup: bool(entry.allowManualSetup, `${path}.allowManualSetup`),
goals: stringArray(entry.goals, `${path}.goals`, { max: 32 }),
...(entry.projectType === undefined ? {} : { projectType: text(entry.projectType, `${path}.projectType`, 2048) }),
languages: stringArray(entry.languages, `${path}.languages`, { max: 32 }),
frameworks: stringArray(entry.frameworks, `${path}.frameworks`, { max: 32 }),
constraints: stringArray(entry.constraints, `${path}.constraints`, { max: 32 }),
};
}
function parseVersions(value: unknown, path: string): Versions {
const entry = record(value, path);
const keys = ['protocolVersion', 'coreVersion', 'metadataSchemaVersion', 'scorerVersion'];
const keys = ['protocolVersion', 'coreVersion', 'catalogSchemaVersion'];
exactKeys(entry, keys, keys, path);
return {
protocolVersion: text(entry.protocolVersion, `${path}.protocolVersion`, 64),
coreVersion: text(entry.coreVersion, `${path}.coreVersion`, 64),
metadataSchemaVersion: text(entry.metadataSchemaVersion, `${path}.metadataSchemaVersion`, 64),
scorerVersion: text(entry.scorerVersion, `${path}.scorerVersion`, 64),
catalogSchemaVersion: text(entry.catalogSchemaVersion, `${path}.catalogSchemaVersion`, 64),
};
}
@@ -230,7 +228,7 @@ function checkDepth(root: unknown): void {
function parseStack(value: unknown): StackManifestReview {
const root = record(value, 'stack');
const keys = ['schemaVersion', 'name', 'catalog', 'targets', 'intent', 'policy', 'skills'];
const keys = ['schemaVersion', 'name', 'catalog', 'targets', 'profile', 'skills'];
exactKeys(root, keys, keys, 'stack');
const name = text(root.name, 'stack.name', 128);
if (!NAME_PATTERN.test(name)) fail('stack.name contains unsupported characters.');
@@ -238,8 +236,6 @@ function parseStack(value: unknown): StackManifestReview {
const targets = root.targets.map((target, index) => parseTarget(target, `stack.targets[${index}]`));
const targetKeys = targets.map((target) => `${target.host}:${target.scope}`);
if (new Set(targetKeys).size !== targetKeys.length) fail('stack.targets must not contain duplicates.');
const intent = record(root.intent, 'stack.intent');
exactKeys(intent, ['goals'], ['goals'], 'stack.intent');
if (!Array.isArray(root.skills) || root.skills.length > 128) fail('stack.skills must contain at most 128 entries.');
const skills = root.skills.map((skill, index) => {
const entry = record(skill, `stack.skills[${index}]`);
@@ -248,12 +244,11 @@ function parseStack(value: unknown): StackManifestReview {
});
if (new Set(skills.map((skill) => skill.id)).size !== skills.length) fail('stack.skills must not contain duplicate IDs.');
return {
schemaVersion: literal(root.schemaVersion, 1, 'stack.schemaVersion'),
schemaVersion: literal(root.schemaVersion, 2, 'stack.schemaVersion'),
name,
catalog: parseCatalog(root.catalog, 'stack.catalog') as CatalogIdentity,
targets: targets as Target[],
intent: { goals: stringArray(intent.goals, 'stack.intent.goals', { min: 1, max: 32, ids: true }) },
policy: parsePolicy(root.policy, 'stack.policy'),
profile: parseProfile(root.profile, 'stack.profile'),
skills,
};
}
@@ -279,14 +274,13 @@ function parseOperation(value: unknown, path: string): PlanOperation {
function parseOverride(value: unknown, path: string): PlanOverride {
const entry = record(value, path);
const keys = ['kind', 'skillId', 'reasonCodes', 'unknownFields'];
const keys = ['kind', 'skillId', 'reasonCodes'];
exactKeys(entry, keys, keys, path);
if (typeof entry.kind !== 'string' || !OVERRIDE_KINDS.has(entry.kind)) fail(`${path}.kind is unsupported.`);
if (entry.kind !== 'managedDrift') fail(`${path}.kind must equal "managedDrift".`);
return {
kind: entry.kind as PlanOverride['kind'],
kind: 'managedDrift',
skillId: id(entry.skillId, `${path}.skillId`),
reasonCodes: stringArray(entry.reasonCodes, `${path}.reasonCodes`, { min: 1, max: 128 }),
unknownFields: stringArray(entry.unknownFields, `${path}.unknownFields`, { max: 128 }),
};
}
@@ -294,7 +288,7 @@ function parsePlan(value: unknown): PlanReview {
const root = record(value, 'plan');
exactKeys(root, ['schemaVersion', 'kind', 'digest', 'payload'], ['schemaVersion', 'kind', 'digest', 'payload'], 'plan');
const payload = record(root.payload, 'plan.payload');
const payloadKeys = ['schemaVersion', 'kind', 'versions', 'manifestDigest', 'catalog', 'runtime', 'target', 'installedState', 'desiredSkills', 'policy', 'operations', 'overrides', 'stateCommit'];
const payloadKeys = ['schemaVersion', 'kind', 'versions', 'manifestDigest', 'catalog', 'runtime', 'target', 'installedState', 'desiredSkills', 'profile', 'operations', 'overrides', 'stateCommit'];
exactKeys(payload, payloadKeys, payloadKeys, 'plan.payload');
const installedState = record(payload.installedState, 'plan.payload.installedState');
@@ -317,11 +311,11 @@ function parsePlan(value: unknown): PlanReview {
exactKeys(stateCommit, ['previousDigest', 'nextDigest', 'position'], ['previousDigest', 'nextDigest', 'position'], 'plan.payload.stateCommit');
return {
schemaVersion: literal(root.schemaVersion, 1, 'plan.schemaVersion'),
schemaVersion: literal(root.schemaVersion, 2, 'plan.schemaVersion'),
kind: literal(root.kind, 'aas.stack-plan', 'plan.kind'),
digest: digest(root.digest, 'plan.digest'),
payload: {
schemaVersion: literal(payload.schemaVersion, 1, 'plan.payload.schemaVersion'),
schemaVersion: literal(payload.schemaVersion, 2, 'plan.payload.schemaVersion'),
kind: literal(payload.kind, 'aas.stack-plan.payload', 'plan.payload.kind'),
versions: parseVersions(payload.versions, 'plan.payload.versions'),
manifestDigest: digest(payload.manifestDigest, 'plan.payload.manifestDigest'),
@@ -333,7 +327,7 @@ function parsePlan(value: unknown): PlanReview {
entries: installedEntries,
},
desiredSkills: stringArray(payload.desiredSkills, 'plan.payload.desiredSkills', { max: 128, ids: true }),
policy: parsePolicy(payload.policy, 'plan.payload.policy'),
profile: parseProfile(payload.profile, 'plan.payload.profile'),
operations: payload.operations.map((operation, index) => parseOperation(operation, `plan.payload.operations[${index}]`)),
overrides: payload.overrides.map((override, index) => parseOverride(override, `plan.payload.overrides[${index}]`)),
stateCommit: {