diff --git a/CHANGELOG.md b/CHANGELOG.md index 632335f..27eddb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Format: [Keep a Changelog](https://keepachangelog.com). Versioning: semver — for skills *and* for this CLI, breaking prompt changes are breaking changes. +## [0.17.0] — 2026-08-08 + +The eleventh target — and it's the one the whole industry just agreed on. On 2026-08-06 OpenAI, Amazon, Microsoft, Cursor and Vercel published **Agent Plugins v1.0** (agent-plugins.org, Google core-maintaining): a vendor-neutral package format — a `plugin.json` manifest plus a `skills//SKILL.md` folder — that ChatGPT/Codex, Cursor, Copilot, Kiro and VS Code all read. It is a *packaging* standard by design: it defines no permission model, no trust or provenance, no sandboxing, and no measurement. That absence is exactly the layer Kitbash already is. So rather than treat the standard as a competitor, Kitbash compiles to it. + +### Added +- **`agent-plugins` compile target** — the eleventh adapter. `kitbash compile` emits a spec-shaped Agent Plugin: `agent-plugin/plugin.json` (the `$schema` + package name the standard requires) and one `agent-plugin/skills//SKILL.md` per skill, with `name` + `description` frontmatter so clients inject only the metadata and lazy-load the body. The skill drops into any Agent-Plugins client having *already* passed Kitbash's install gate, its declared token budget, and its drift check — the trust and measurement the format itself leaves out. Unlike the ten auto-detected targets this one is **opt-in**: it does not fire on a fresh repo, because publishing a plugin is a choice. Turn it on with `agent-plugins` under `[project].targets`, or once an `agent-plugin/plugin.json` exists it is detected on its own. The compiler owns `plugin.json` (one repo-level manifest, not per-skill), writes it only when it changes, and prunes a removed skill's `SKILL.md` from the plugin's `skills/` folder on the next compile. + ## [0.16.0] — 2026-08-07 The on-ramp for repos that already have the copy-per-agent mess — and an honesty correction. Grounded in a landscape scan: the strongest, most-cited pain for teams running several coding agents is config drift and painful onboarding across agents (named verbatim by five-plus independently-built sync tools). Kitbash made you author a fresh skill; now it can start from what you already have. diff --git a/README.md b/README.md index cae7aa5..c096f2a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Kitbash is a compiler for AI agent skills that measures what a skill costs your context window every session — before you install it. -You write the skill once in one open format ([KSF](spec/SPEC.md)) and compile it to the native format of ten coding agents — Claude Code, Cursor, Copilot, Zed, Cline, Devin, Gemini CLI, Aider, the vendor-neutral `.agents/skills/` path, and the `AGENTS.md` floor. While compiling, it measures each output's **standing** cost: the tokens the skill parks in context on every request, whether or not it ever gets used. +You write the skill once in one open format ([KSF](spec/SPEC.md)) and compile it to the native format of ten coding agents — Claude Code, Cursor, Copilot, Zed, Cline, Devin, Gemini CLI, Aider, the vendor-neutral `.agents/skills/` path, and the `AGENTS.md` floor — plus an opt-in eleventh target, the [Agent Plugins](https://agent-plugins.org) v1.0 package format. While compiling, it measures each output's **standing** cost: the tokens the skill parks in context on every request, whether or not it ever gets used. ```bash npm install -g kitbash # or: brew install singhharsh1708/tap/kitbash @@ -23,7 +23,7 @@ In a repo that already has `.claude/` and `.cursor/`, that last command prints: → AGENTS.md ℹ prereview → agentsmd: agentsmd is eager and cannot lazy-load, so this skill adds ~560 tokens standing every session (a lazy target pays 0; declared limit 60) compiled 1 skill for 3 targets - 7 more target(s) available — add agents, zed, copilot, … under [project].targets in kitbash.toml, or create their agent dirs. + 8 more target(s) available — add agents, zed, copilot, … under [project].targets in kitbash.toml, or create their agent dirs. ``` ### The `ℹ` line is why this is a compiler, not a converter @@ -32,7 +32,7 @@ The identical instructions cost ~40 standing tokens on a target that lazy-loads Those numbers are measured, not asserted: the method and the full per-target table are in [docs/benchmarks/README.md](docs/benchmarks/README.md), and `npm run bench` inside `packages/cli` regenerates them. A converter would translate the format and stop. Kitbash reads the skill and tells you what it will cost you. I have not found another tool that surfaces that number. -Kitbash always compiles to the cheapest loading mode a target actually supports — eight of the ten lazy-load; Aider's `CONVENTIONS.md` and the `AGENTS.md` floor cannot, and carry the whole body every session. `--strict` turns budget overruns and degradation warnings into build failures. +Kitbash always compiles to the cheapest loading mode a target actually supports — nine of the eleven lazy-load; Aider's `CONVENTIONS.md` and the `AGENTS.md` floor cannot, and carry the whole body every session. `--strict` turns budget overruns and degradation warnings into build failures. ### Why not a sync script? @@ -62,7 +62,7 @@ Already carrying a hand-written `CLAUDE.md`, `.cursor/rules/`, `AGENTS.md`, and

npm version CI - 10 agent targets + 11 agent targets zero runtime dependencies Apache-2.0

@@ -194,7 +194,7 @@ v0.1 is intentionally a thin slice: KSF, `compile`, three adapters, and one skil No. It's a compiler, a package manager, and a format spec. Prompt collections are the thing that gets compiled. **I already use skills.sh / Claude skills.** -Keep them. They install directly with `kitbash install owner/repo`. You pick up ten targets, a lockfile, and a token-cost report, and you don't give anything up. +Keep them. They install directly with `kitbash install owner/repo`. You pick up eleven targets, a lockfile, and a token-cost report, and you don't give anything up. **What if I stop using Kitbash?** Nothing breaks. The compiled output is plain files in your repo. Delete `kitbash.toml` and everything keeps working the way it does now. diff --git a/docs/roadmap.md b/docs/roadmap.md index cea02ea..5f85e05 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -48,7 +48,7 @@ Deferred out of v0.1 on purpose: more adapters, more skills, index, evals tier 2 - Community index (registry repo, Homebrew-tap model): `kitbash install prereview` short names, `kitbash search`. - `kitbash publish` (validates, tags, points the index). - Loadouts: `kitbash install loadout:oss-maintainer`. -- ✅ Remaining adapters, landed early: `windsurf` (now Devin Desktop), `cline`, `aider`, `agents` — the vendor-neutral `.agents/skills/` path that Codex, Cursor, Copilot, Gemini CLI, Roo, Amp, OpenCode and Antigravity all read — and `zed`, which shares that path but detects `.zed/` and enforces Zed's own frontmatter rules. 10 targets total. +- ✅ Remaining adapters, landed early: `windsurf` (now Devin Desktop), `cline`, `aider`, `agents` — the vendor-neutral `.agents/skills/` path that Codex, Cursor, Copilot, Gemini CLI, Roo, Amp, OpenCode and Antigravity all read — and `zed`, which shares that path but detects `.zed/` and enforces Zed's own frontmatter rules. Plus `agent-plugins`, the opt-in eleventh target that emits the industry-standard Agent Plugins package (agent-plugins.org). 11 targets total. - Docs site with the skill catalog + measured eval results per skill. - Skill badges, measurement-only: eval pass rate, compiled token cost, auto-derived compatibility matrix, signed status. No star ratings — measurement over popularity, by design. - **Launch moment.** The demo is one command turning a bare repo into a four-assistant, team-standard setup. Ponytail proved a single good skill can pull 75k stars; ours ride on infrastructure others can build on, which is the durable version of that story. diff --git a/packages/cli/package.json b/packages/cli/package.json index d504a7f..3bf0fd0 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "kitbash", - "version": "0.16.0", + "version": "0.17.0", "description": "The package manager and compiler for AI agent skills — write once, run in every coding agent", "license": "Apache-2.0", "author": "Harsh Singh", diff --git a/packages/cli/scripts/benchmark.mjs b/packages/cli/scripts/benchmark.mjs index c180141..0efe0e7 100644 --- a/packages/cli/scripts/benchmark.mjs +++ b/packages/cli/scripts/benchmark.mjs @@ -25,10 +25,17 @@ const repoRoot = resolve(here, "../../.."); const cli = join(here, "../dist/index.js"); const fixture = join(repoRoot, "examples/skills/prereview"); +// agent-plugins is an opt-in publishing target (agent-plugins.org): it is not part +// of a repo's auto-detected fan-out and would not fire in this fixture's compile +// (no plugin.json). It is lazy, so it carries the same stub cost as every other +// lazy target and adds no standing-tax story — this benchmark measures the +// always-on tax across the targets a repo compiles to by default, so it is excluded. +const BENCH_ADAPTERS = ADAPTERS.filter((a) => a.id !== "agent-plugins"); + // How each target loads a skill, read from the adapters themselves rather than // restated here — a second copy of this map is exactly how the published numbers // drift away from what the compiler actually emits. -const LOADING = Object.fromEntries(ADAPTERS.map((a) => [a.id, a.loading])); +const LOADING = Object.fromEntries(BENCH_ADAPTERS.map((a) => [a.id, a.loading])); function run(args, cwd) { const r = spawnSync("node", [cli, ...args], { cwd, encoding: "utf8" }); diff --git a/packages/cli/scripts/test.mjs b/packages/cli/scripts/test.mjs index 9a0693f..b5e1eb3 100644 --- a/packages/cli/scripts/test.mjs +++ b/packages/cli/scripts/test.mjs @@ -1330,6 +1330,63 @@ try { rmSync(imp, { recursive: true, force: true }); } +// ── Agent Plugins target (agent-plugins.org package format) ────────────────── +// One KSF skill → a spec-shaped plugin (plugin.json + skills//SKILL.md), with +// the trust/budget/drift layer the standard omits living in the KSF source. +const ap = mkdtempSync(join(tmpdir(), "kitbash-agentplugins-")); +try { + const apSrc = join(ap, "greet-src"); + mkdirSync(apSrc, { recursive: true }); + writeFileSync( + join(apSrc, "skill.toml"), + '[skill]\nname = "greet"\nversion = "0.1.0"\ndescription = "Greet the user warmly and concisely"\n[context]\nbudget = 500\nstanding = 80\n', + ); + writeFileSync(join(apSrc, "SKILL.md"), "# Greet\n\nSay hello. Be brief.\n"); + + // Not detected by default: no plugin.json, not in [project].targets. The other + // adapters must still fan out; agent-plugins must NOT force itself onto a repo. + writeFileSync(join(ap, "kitbash.toml"), '[project]\ntargets = ["claude-code"]\n'); + run(["install", `file:${apSrc}`, "--yes"], ap); + const noAp = run(["compile"], ap); + check("agent-plugins: opt-out repo does not emit a plugin", !existsSync(join(ap, "agent-plugin")), noAp.out); + + // Opt in via [project].targets and recompile. + writeFileSync(join(ap, "kitbash.toml"), '[project]\ntargets = ["claude-code", "agent-plugins"]\n'); + const apc = run(["compile"], ap); + check("agent-plugins: compile exits 0", apc.status === 0, apc.out); + check("agent-plugins: emits the skill under skills//SKILL.md", existsSync(join(ap, "agent-plugin/skills/greet/SKILL.md")), apc.out); + check("agent-plugins: emits plugin.json", existsSync(join(ap, "agent-plugin/plugin.json")), apc.out); + + const manifest = readFileSync(join(ap, "agent-plugin/plugin.json"), "utf8"); + let parsed = null; + try { + parsed = JSON.parse(manifest); + } catch { + parsed = null; + } + check("agent-plugins: plugin.json is valid JSON", parsed !== null, manifest); + check("agent-plugins: manifest declares the spec $schema + a name", !!parsed && typeof parsed.name === "string" && parsed.name.length > 0 && String(parsed.$schema).includes("agent-plugins.org"), manifest); + + const skillMd = readFileSync(join(ap, "agent-plugin/skills/greet/SKILL.md"), "utf8"); + check("agent-plugins: SKILL.md carries name + description frontmatter", skillMd.startsWith("---\nname: greet\n") && skillMd.includes("description:"), skillMd); + + // Once a plugin.json exists the target is sticky: detection fires even with no + // targets list, so a follow-up compile keeps regenerating the plugin. + writeFileSync(join(ap, "kitbash.toml"), ""); + const sticky = run(["compile"], ap); + check("agent-plugins: auto-detected once a plugin.json exists", existsSync(join(ap, "agent-plugin/skills/greet/SKILL.md")) && sticky.out.includes("agent-plugin/skills/greet/SKILL.md"), sticky.out); + + // plugin.json is not rewritten when unchanged (no needless churn/diff). + check("agent-plugins: plugin.json not rewritten when unchanged", !sticky.out.includes("→ agent-plugin/plugin.json"), sticky.out); + + // Removing the skill prunes its SKILL.md from the plugin's skills/ folder. + run(["remove", "greet"], ap); + const pruned = run(["compile"], ap); + check("agent-plugins: removed skill is pruned from the plugin", !existsSync(join(ap, "agent-plugin/skills/greet/SKILL.md")), pruned.out); +} finally { + rmSync(ap, { recursive: true, force: true }); +} + if (failures) { console.error(`\n${failures} test(s) failed`); process.exit(1); diff --git a/packages/cli/src/adapters.ts b/packages/cli/src/adapters.ts index 0aeba3f..9cd28da 100644 --- a/packages/cli/src/adapters.ts +++ b/packages/cli/src/adapters.ts @@ -8,7 +8,7 @@ */ import { existsSync, readFileSync } from "node:fs"; -import { join } from "node:path"; +import { basename, join } from "node:path"; import { estimateTokens, type LoadedSkill } from "./ksf.js"; export interface CompiledFile { @@ -366,7 +366,46 @@ const aider = mergedFileAdapter( /** The floor: everything that reads AGENTS.md (Codex and many others). */ const agentsmd = mergedFileAdapter("agentsmd", "AGENTS.md", () => true); -export const ADAPTERS: Adapter[] = [claudeCode, cursor, agents, zed, copilot, cline, windsurf, gemini, aider, agentsmd]; +/** + * Agent Plugins (agent-plugins.org) — the vendor-neutral package format ratified + * 2026-08-06 by OpenAI, Amazon, Microsoft, Cursor, Vercel, with Google as core + * maintainer. A plugin is a directory with a `plugin.json` manifest and a + * `skills/` folder whose subdirectories each hold a SKILL.md. First-wave clients: + * ChatGPT/Codex, Cursor, Copilot, Kiro, VS Code. + * + * The spec is a package format ONLY — it explicitly defines no permission model, + * trust, provenance, sandboxing, or measurement. That is exactly the layer + * Kitbash adds around it: compile here and the skill drops into any Agent-Plugins + * client, having already passed the install gate, the token budget, and the + * drift check that the standard leaves out. `plugin.json` is written by the + * compiler (see cmdCompile). Opt in via [project].targets; auto-detected once a + * plugin.json exists. + */ +export const AGENT_PLUGIN_DIR = "agent-plugin"; +const agentPlugins = skillDirAdapter( + "agent-plugins", + `${AGENT_PLUGIN_DIR}/skills`, + (root) => existsSync(join(root, "plugin.json")) || existsSync(join(root, AGENT_PLUGIN_DIR)), +); + +/** The Agent Plugins package manifest (spec §plugin.json). Minimal + valid; skills/ is auto-discovered. */ +export function agentPluginManifest(root: string): string { + const name = basename(root).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent-plugin"; + return ( + JSON.stringify( + { + $schema: "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + name, + version: "1.0.0", + description: "Agent Plugin compiled by kitbash — install-gate, token budget, and drift checks live in the KSF source.", + }, + null, + 2, + ) + "\n" + ); +} + +export const ADAPTERS: Adapter[] = [claudeCode, cursor, agents, zed, copilot, cline, windsurf, gemini, aider, agentsmd, agentPlugins]; /** Replace or append a skill's marker-delimited section in shared-file content. */ export function mergeSection(existing: string, name: string, section: string): string { diff --git a/packages/cli/src/commands.ts b/packages/cli/src/commands.ts index 8d9bfa1..1e38183 100644 --- a/packages/cli/src/commands.ts +++ b/packages/cli/src/commands.ts @@ -5,7 +5,7 @@ import { execFileSync } from "node:child_process"; import { createInterface } from "node:readline"; import { tmpdir } from "node:os"; import { basename, dirname, join, resolve, sep } from "node:path"; -import { ADAPTERS, GENERATED_MARK, mergeSection, pruneSections, readFileIfExists, type CompiledFile } from "./adapters.js"; +import { ADAPTERS, AGENT_PLUGIN_DIR, agentPluginManifest, GENERATED_MARK, mergeSection, pruneSections, readFileIfExists, type CompiledFile } from "./adapters.js"; import { dropLock, integrityOf, readLock, upsertLock, walk, LOCK_FILE } from "./lock.js"; import { fileChanges, manifestDelta, textOf, unifiedDiff } from "./diff.js"; import { collectImports, driftGroups, type ImportedSource } from "./importers.js"; @@ -902,6 +902,20 @@ export async function cmdCompile(args: string[]): Promise { writeFileSync(abs, f.content.endsWith("\n") ? f.content : `${f.content}\n`); console.log(`→ ${f.path}`); } + // Agent Plugins: the skills/ folder is written per-skill by its adapter above. + // The plugin.json manifest that makes that folder a valid plugin is one + // repo-level file describing the whole package, so the compiler — not any one + // skill — owns it. Written only when the target is active and something compiled. + if (adapters.some((a) => a.id === "agent-plugins") && skills.length) { + const rel = `${AGENT_PLUGIN_DIR}/plugin.json`; + const manifest = agentPluginManifest(root); + if (readFileIfExists(root, rel) !== manifest) { + const abs = join(root, rel); + mkdirSync(dirname(abs), { recursive: true }); + writeFileSync(abs, manifest); + console.log(`→ ${rel}`); + } + } // Shared marker files not rewritten this compile still need stale sections pruned. // Nothing wrote to this file, so none of its kitbash sections are current — whether // the last skill writing there was removed, the target was dropped from kitbash.toml, @@ -1474,6 +1488,7 @@ const MANAGED_DIRS: { dir: string; suffix: string; wholeDir?: boolean }[] = [ { dir: ".agents/skills", suffix: "/SKILL.md", wholeDir: true }, { dir: ".gemini/skills", suffix: "/SKILL.md", wholeDir: true }, { dir: ".github/skills", suffix: "/SKILL.md", wholeDir: true }, + { dir: `${AGENT_PLUGIN_DIR}/skills`, suffix: "/SKILL.md", wholeDir: true }, { dir: ".cursor/rules", suffix: ".mdc" }, { dir: ".clinerules", suffix: ".md" }, { dir: ".windsurf/rules", suffix: ".md" }, diff --git a/site/404.html b/site/404.html index d469bb8..ca1c6fa 100644 --- a/site/404.html +++ b/site/404.html @@ -101,7 +101,7 @@

CLI reference

Adapters & targets

-

All ten targets and what each one supports, from Claude Code down to the AGENTS.md fallback.

+

All eleven targets and what each one supports, from Claude Code down to the AGENTS.md fallback.

Benchmark

diff --git a/site/benchmark.html b/site/benchmark.html index c381678..d14a8e7 100644 --- a/site/benchmark.html +++ b/site/benchmark.html @@ -241,7 +241,7 @@

#Keep reading

Adapters & targets

-

Which of the ten targets are lazy, which are eager, and what each one supports.

+

Which of the eleven targets are lazy, which are eager, and what each one supports.

Budgets in the format

diff --git a/site/changelog.html b/site/changelog.html index 580e3ea..c8ecac3 100644 --- a/site/changelog.html +++ b/site/changelog.html @@ -91,7 +91,7 @@

Changelog

Releases follow Keep a Changelog and semver — for skills and for this CLI, breaking prompt changes are breaking changes. The CLI is published to npm as kitbash and to Homebrew via singhharsh1708/tap. Tagged builds are on the GitHub releases page.

-
v0.16.0Current CLI version
+
v0.17.0Current CLI version
8Compile targets
Apache-2.0License
@@ -105,10 +105,20 @@

Changelog

Confirm with kitbash --version, which reads the installed package.json. Install and uninstall routes are covered on the installation page.

+
+
+

v0.17.0

+ 2026-08-08latest +
+

The eleventh target — and it's the one the whole industry just agreed on. On 2026-08-06 OpenAI, Amazon, Microsoft, Cursor and Vercel published Agent Plugins v1.0 (agent-plugins.org, Google core-maintaining): a vendor-neutral package format — a plugin.json manifest plus a skills/<name>/SKILL.md folder — that ChatGPT/Codex, Cursor, Copilot, Kiro and VS Code all read. It is a packaging standard by design: it defines no permission model, no trust or provenance, no sandboxing, and no measurement. That absence is exactly the layer Kitbash already is. So rather than treat the standard as a competitor, Kitbash compiles to it.

+

Added

+
  • agent-plugins compile target — the eleventh adapter. kitbash compile emits a spec-shaped Agent Plugin: agent-plugin/plugin.json (the $schema + package name the standard requires) and one agent-plugin/skills/<name>/SKILL.md per skill, with name + description frontmatter so clients inject only the metadata and lazy-load the body. The skill drops into any Agent-Plugins client having already passed Kitbash's install gate, its declared token budget, and its drift check — the trust and measurement the format itself leaves out. Unlike the ten auto-detected targets this one is opt-in: it does not fire on a fresh repo, because publishing a plugin is a choice. Turn it on with agent-plugins under [project].targets, or once an agent-plugin/plugin.json exists it is detected on its own. The compiler owns plugin.json (one repo-level manifest, not per-skill), writes it only when it changes, and prunes a removed skill's SKILL.md from the plugin's skills/ folder on the next compile.
+
+

v0.16.0

- 2026-08-07latest + 2026-08-07

The on-ramp for repos that already have the copy-per-agent mess — and an honesty correction. Grounded in a landscape scan: the strongest, most-cited pain for teams running several coding agents is config drift and painful onboarding across agents (named verbatim by five-plus independently-built sync tools). Kitbash made you author a fresh skill; now it can start from what you already have.

Added

diff --git a/site/docs/adapters.html b/site/docs/adapters.html index d87b910..f7e3cd9 100644 --- a/site/docs/adapters.html +++ b/site/docs/adapters.html @@ -4,16 +4,16 @@ Adapters & targets — Kitbash docs - + - + - + @@ -105,20 +105,20 @@

Project

kitbash / docs / adapters

Adapters & targets

-

Ten compile targets, each with its own output path, detection rule, loading mode, and capability set. This page is the reference for what every one of them actually writes.

+

Eleven compile targets, each with its own output path, detection rule, loading mode, and capability set. This page is the reference for what every one of them actually writes.

-

An adapter turns one installed skill into the native format of one coding agent. kitbash compile runs every detected adapter over every installed skill and writes the result. Two emission styles exist: per-skill files (Claude Code, Cursor, the vendor-neutral .agents/skills/ path that Cline and Zed also read, Copilot, Devin, Gemini CLI) and marker-merged sections in a shared file (AGENTS.md, CONVENTIONS.md).

+

An adapter turns one installed skill into the native format of one coding agent. kitbash compile runs every detected adapter over every installed skill and writes the result. Two emission styles exist: per-skill files (Claude Code, Cursor, the vendor-neutral .agents/skills/ path that Cline and Zed also read, Copilot, Devin, Gemini CLI, and the opt-in Agent Plugins package) and marker-merged sections in a shared file (AGENTS.md, CONVENTIONS.md).

Lazy vs eager

The single most important property of a target is how it loads a compiled skill.

    -
  • lazy The target keeps the skill out of the context window until it is invoked. Only a standing stub — a name and description the agent can match against — is resident. Claude Code SKILL.md files, Cursor agent-requested rules, the vendor-neutral .agents/skills/ path, the .github/skills/ and .gemini/skills/ directories Copilot and Gemini CLI read, the four skill directories Cline scans, and Devin rules with a model_decision trigger all work this way.
  • +
  • lazy The target keeps the skill out of the context window until it is invoked. Only a standing stub — a name and description the agent can match against — is resident. Claude Code SKILL.md files, Cursor agent-requested rules, the vendor-neutral .agents/skills/ path, the .github/skills/ and .gemini/skills/ directories Copilot and Gemini CLI read, the four skill directories Cline scans, Devin rules with a model_decision trigger, and the opt-in Agent Plugins package all work this way.
  • eager The target has no mechanism for deferred loading, so the entire compiled body sits in context every session. AGENTS.md and CONVENTIONS.md work this way.
-

Kitbash compiles to the cheapest loading mode each target actually supports, so eight of the ten carry only a stub. The standing token tax is what a skill costs on the targets whose only mode is eager: a skill authored with disclosure = "lazy" cannot lazy-load there — the target simply has nowhere to put a stub. Kitbash refuses to let that happen quietly: on every eager target, a lazy-authored skill produces a warning that names the real cost and the limit the author declared.

+

Kitbash compiles to the cheapest loading mode each target actually supports, so nine of the eleven carry only a stub. The standing token tax is what a skill costs on the targets whose only mode is eager: a skill authored with disclosure = "lazy" cannot lazy-load there — the target simply has nowhere to put a stub. Kitbash refuses to let that happen quietly: on every eager target, a lazy-authored skill produces a warning that names the real cost and the limit the author declared.

⚠ prereview → agentsmd: agentsmd is eager and cannot lazy-load;
   this skill costs ~560 tokens standing every session (declared limit: 60)

Multiply that by the number of installed skills and it is the whole context budget problem. The benchmark page quantifies the gap between lazy and eager delivery of the same skill.

@@ -199,13 +199,20 @@

Capability matrix

eager none + + agent-plugins + agent-plugin/skills/<name>/SKILL.md
agent-plugin/plugin.json + agent-plugin/ or plugin.json exists (opt-in) + lazy + none +
-

No adapter declares any capability today. emit() writes a SKILL.md — plus slash-command shims on Claude Code — but it does not copy a skill's scripts/, install a hook, or wire a subagent, so claiming any of those would report full support for output referencing files the compiler never produced. Because every capability set is empty, any non-empty targets.requires — scripts, hooks, subagents, or network — degrades on every one of the ten targets, Claude Code included. A capability will be re-added only alongside the emit code that delivers its primitive.

+

No adapter declares any capability today. emit() writes a SKILL.md — plus slash-command shims on Claude Code — but it does not copy a skill's scripts/, install a hook, or wire a subagent, so claiming any of those would report full support for output referencing files the compiler never produced. Because every capability set is empty, any non-empty targets.requires — scripts, hooks, subagents, or network — degrades on every one of the eleven targets, Claude Code included. A capability will be re-added only alongside the emit code that delivers its primitive.

Detection can be overridden. Set targets under [project] in kitbash.toml and Kitbash compiles exactly that list instead of probing the filesystem; an unknown id there is a hard error. See project config.

-

The ten adapters

+

The eleven adapters

Every emitted file carries a generated-file header naming the source skill and version, which is what makes stale output safe to delete on the next compile:

<!-- generated by kitbash — do not edit; source: .kitbash/skills/prereview @ 0.1.0 -->
@@ -222,7 +229,7 @@

agents

Detection is deliberately narrow: .agents/ or .codex/. Agents that also have a native path already get their own adapter, and emitting both would duplicate the skill for no benefit. It writes only SKILL.md and declares no capabilities.

zed

-

Zed reads the same vendor-neutral path, so this target writes the byte-identical file agents does — a repo with both .zed/ and .agents/ compiles that skill once, not twice. Ten targets, nine output files.

+

Zed reads the same vendor-neutral path, so this target writes the byte-identical file agents does — a repo with both .zed/ and .agents/ compiles that skill once, not twice. Eleven targets, ten output files.

What makes it its own target is detection and a constraint check. .zed/ is the only marker a Zed-only repo carries, and without this adapter such a repo compiled to nothing but the eager AGENTS.md floor — paying a skill's whole body every session on an agent that can lazy-load it for free.

Zed's skill loader is stricter about frontmatter than KSF is, and it fails silently: a skill that breaches either rule is dropped at load with no diagnostic in the UI. Kitbash says what Zed will not, at compile and in explain:

    @@ -256,6 +263,11 @@

    aider

    agentsmd

    Merges into AGENTS.md. This is the floor: its detect function returns true unconditionally, so every repo gets AGENTS.md output whether or not any agent-specific directory exists. Codex and a long tail of other tools read it.

    +

    agent-plugins

    +

    Writes agent-plugin/skills/<name>/SKILL.md with the same name and quoted description frontmatter the other skill-directory targets use, plus one repo-level agent-plugin/plugin.json manifest — a $schema reference and the package name — that the compiler writes to make the folder a valid plugin. This is the Agent Plugins v1.0 package format, published 2026-08-06 by OpenAI, Amazon, Microsoft, Cursor and Vercel, with Google core-maintaining; first-wave clients are ChatGPT/Codex, Cursor, Copilot, Kiro and VS Code. Clients inject only the name and description and load the body on demand, so the target is lazy.

    +

    Alone among the eleven it is opt-in: its detection probe does not fire on a fresh repo. Turn it on by adding agent-plugins to [project].targets in kitbash.toml, or it auto-detects once an agent-plugin/ package (a plugin.json) already exists — so a repo never gains a published package it did not ask for.

    +

    Agent Plugins is a packaging standard only: it defines no permission model, no trust or provenance, no sandboxing, and no measurement. That is exactly the layer Kitbash adds around it. A skill compiled to this target drops into any Agent-Plugins client having already passed Kitbash's install-gate safety lints, its declared token budget, and the drift check the standard itself leaves out.

    +

    How marker merging works

    The two shared-file adapters — agentsmd and aider — do not own their file. Each skill gets a marker-delimited section:

    <!-- kitbash:begin prereview -->
    @@ -278,7 +290,7 @@ 

    Degradation

    mode = "skill"

    At compile time each required capability is checked against the adapter's capability list. Anything missing produces a warning naming the skill, the target, and the capability:

    ⚠ verify → cursor: target lacks "scripts"; compiled instruction-only (degraded)
    -

    Because every adapter's capability set is currently empty, this is not a per-target quirk: any value in requires degrades on every one of the ten targets. Kitbash's emit() writes instructions — a SKILL.md, and slash-command shims on Claude Code — but it does not yet deliver the underlying primitives: it does not copy a skill's scripts/, install a hook, or wire a subagent, and no adapter reaches the network. Declaring the capability the compiler cannot honor would report full support for output that references files it never produced, which is exactly the silent capability loss the spec forbids.

    +

    Because every adapter's capability set is currently empty, this is not a per-target quirk: any value in requires degrades on every one of the eleven targets. Kitbash's emit() writes instructions — a SKILL.md, and slash-command shims on Claude Code — but it does not yet deliver the underlying primitives: it does not copy a skill's scripts/, install a hook, or wire a subagent, and no adapter reaches the network. Declaring the capability the compiler cannot honor would report full support for output that references files it never produced, which is exactly the silent capability loss the spec forbids.

    Degraded means the instructions still compile and still ship — the agent gets the prose, it just does not get the deterministic helper the skill wanted to run. That is often acceptable. What is never acceptable is not being told.

    Spec §2. A compiler lacking a required capability MUST either emit a degraded variant with a visible warning, or fail under --strict. Silent degradation is a conformance violation.

    diff --git a/site/docs/authoring.html b/site/docs/authoring.html index 85e8cf7..214b582 100644 --- a/site/docs/authoring.html +++ b/site/docs/authoring.html @@ -190,7 +190,7 @@

    targets

    [targets]
     requires = []
     mode = "skill"
    -

    requires declares capabilities the skill needs: scripts, hooks, subagents, network. No adapter delivers any of them today — emit() writes instructions but does not copy a skill's scripts/, install a hook, or wire a subagent — so any value here degrades on every one of the ten targets, and each produces a visible warning at compile:

    +

    requires declares capabilities the skill needs: scripts, hooks, subagents, network. No adapter delivers any of them today — emit() writes instructions but does not copy a skill's scripts/, install a hook, or wire a subagent — so any value here degrades on every one of the eleven targets, and each produces a visible warning at compile:

    ⚠ test-gaps → cursor: target lacks "scripts"; compiled instruction-only (degraded)

    Under --strict that warning becomes a build failure. Silent degradation is a conformance violation — leave requires empty unless the skill genuinely cannot function without the capability.

    mode is skill or gate. A gate-mode skill must route its verdict through a script exit code or a schema-validated artifact. A bare model opinion is not a gate verdict.

    @@ -397,7 +397,7 @@

    Where to go next

    diff --git a/site/docs/cli.html b/site/docs/cli.html index 2066031..5f52a40 100644 --- a/site/docs/cli.html +++ b/site/docs/cli.html @@ -385,7 +385,7 @@

    compile

    doctor

    kitbash doctor

    -

    The repo health check. It reports which of the ten adapters were detected, how many skills are installed, the total standing context cost of their stubs, the worst-case active cost if every skill fired in one session, and then verifies the lockfile.

    +

    The repo health check. It reports which of the eleven adapters were detected, how many skills are installed, the total standing context cost of their stubs, the worst-case active cost if every skill fired in one session, and then verifies the lockfile.

    Three integrity conditions are checked: skills installed with no kitbash.lock at all, a locked skill whose files on disk no longer match their recorded hash, and a skill present on disk but absent from the lockfile. All three mean the code your agents load is not the code somebody reviewed.

    If [policy] is configured, doctor rechecks it against everything already installed — using each skill's recorded source from the lockfile. That catches skills that predate the policy or were copied in without going through kitbash install.

      @@ -396,12 +396,14 @@

      doctor

      ✓ claude-code ✓ cursor ✗ agents + ✗ zed ✗ copilot ✗ cline ✗ windsurf ✗ gemini ✗ aider ✓ agentsmd (floor: Codex, Gemini CLI, anything reading AGENTS.md) + ✗ agent-plugins (opt-in: name it in [project].targets) installed skills: 2 standing context cost: ~98 tokens (stubs); worst-case active: 3700 tokens (budgets) lock integrity: ok @@ -559,23 +561,23 @@

      lint

      explain

      kitbash explain <skill-name | path | source> <adapter>

      -

      Answers one question: what does this skill lose on that agent? Both arguments are positional and both are required. The first resolves the same way as lint's target — path, installed name, or fetchable source. The second names an adapter: claude-code, cursor, agents, copilot, cline, windsurf, gemini, aider, or agentsmd.

      +

      Answers one question: what does this skill lose on that agent? Both arguments are positional and both are required. The first resolves the same way as lint's target — path, installed name, or fetchable source. The second names an adapter: claude-code, cursor, agents, zed, copilot, cline, windsurf, gemini, aider, agentsmd, or agent-plugins.

      Explain reports two independent kinds of loss. Capability degradation: each entry in the skill's targets.requires that the adapter does not support, which compiles down to instruction-only. And loading degradation: a skill authored for lazy disclosure on an eager adapter, which pays its full body as standing context in every session.

      • <target> Required, first positional. Path, installed name, or uninstalled source.
      • -
      • <adapter> Required, second positional. One of the ten adapter ids.
      • +
      • <adapter> Required, second positional. One of the eleven adapter ids.
      $ kitbash explain prereview agentsmd
       prereview → agentsmd: no capability degradation
         ⚠ loading: agentsmd is eager — skill costs ~560 tokens standing every session (declared limit: 60)
      -

      No adapter declares a capability today — emit() writes instructions but does not copy scripts/, install a hook, or wire a subagent — so a skill that requires any of scripts, hooks, subagents, or network reports degraded on every one of the ten targets, Claude Code included:

      +

      No adapter declares a capability today — emit() writes instructions but does not copy scripts/, install a hook, or wire a subagent — so a skill that requires any of scripts, hooks, subagents, or network reports degraded on every one of the eleven targets, Claude Code included:

      $ kitbash explain prereview cursor
       prereview → cursor: degraded
         ✗ requires "scripts" — not supported by cursor; compiled instruction-only

      Missing arguments print the usage line and the adapter list:

      $ kitbash explain prereview
       usage: kitbash explain <skill-name-or-path-or-source> <adapter>
      -  adapters: claude-code, cursor, agents, copilot, cline, windsurf, gemini, aider, agentsmd
      + adapters: claude-code, cursor, agents, zed, copilot, cline, windsurf, gemini, aider, agentsmd, agent-plugins

      Exit codes: 0 whether or not degradation was found — explain reports, it does not judge. 1 when an argument is missing, the adapter name is unknown, the target cannot be resolved or loaded, or the body's template references cannot be resolved.

      diff --git a/site/docs/config.html b/site/docs/config.html index f447825..b368f95 100644 --- a/site/docs/config.html +++ b/site/docs/config.html @@ -139,7 +139,7 @@

      targets

      An array of adapter ids. Omit the key and Kitbash autodetects — every adapter whose detection probe finds evidence of that agent in the repo. Set it and detection is bypassed entirely: the listed targets are compiled whether or not the agent's directory exists.

      [project]
       targets = ["claude-code", "cursor", "agentsmd"]
      -

      The ten valid ids, and what autodetection looks for:

      +

      The eleven valid ids, and what autodetection looks for:

      @@ -154,12 +154,14 @@

      targets

      +
      idDetected when the repo contains
      geminiGEMINI.md or .gemini/
      aiderCONVENTIONS.md or .aider.conf.yml
      agentsmdalways — it is the floor
      agent-pluginsan agent-plugin/ package or a plugin.json — opt-in (see below)
      +

      Unlike the other ten, agent-plugins is opt-in: its probe does not fire on a fresh repo, so a fresh repo never compiles to it until you either name it in targets or it finds an agent-plugin/ package (a plugin.json) you already created. It emits the vendor-neutral Agent Plugins package format, and the compiler also writes its repo-level plugin.json manifest. See adapters & targets.

      An unrecognised id is a hard error, not a warning. kitbash compile writes nothing and exits 1:

      unknown target(s) in kitbash.toml: claude (known: claude-code, cursor,
      -agents, zed, copilot, cline, windsurf, gemini, aider, agentsmd)
      +agents, zed, copilot, cline, windsurf, gemini, aider, agentsmd, agent-plugins)

      That is deliberate. A typo'd target silently dropping an agent from every compile is worse than a failed build.

      Note that kitbash doctor reports detection, not configuration — its "detected targets" list runs the probes regardless of what targets says. If the two disagree, targets is what compile obeys.

      What each adapter emits, which capabilities it supports, and whether it loads lazily or eagerly is covered in adapters & targets.

      @@ -334,7 +336,7 @@

      What to commit, what to ignore

      Where to go next

        -
      • Adapters & targets — what each of the ten ids actually emits, and what degrades.
      • +
      • Adapters & targets — what each of the eleven ids actually emits, and what degrades.
      • Trust & review — designing a [policy] your team can live with.
      • CLI reference — every command, flag, and exit code.
      • Skill format (KSF) — the manifest keys [policy] gates on.
      • diff --git a/site/docs/format.html b/site/docs/format.html index f60bb76..4462636 100644 --- a/site/docs/format.html +++ b/site/docs/format.html @@ -217,7 +217,7 @@

        [targets]

    -

    requires is the input to the compatibility matrix, which is derived and never hand-written: targets.requires crossed with each adapter's capability set yields full, degraded, or unsupported per assistant. A compiler missing a required capability must either emit a degraded variant with a visible warning or fail under --strict. Silent degradation is a conformance violation. In the reference compiler today every adapter's capability set is empty — emit() writes instructions but does not yet copy scripts/, install a hook, or wire a subagent — so any value in requires degrades on every one of the ten targets, Claude Code included.

    +

    requires is the input to the compatibility matrix, which is derived and never hand-written: targets.requires crossed with each adapter's capability set yields full, degraded, or unsupported per assistant. A compiler missing a required capability must either emit a degraded variant with a visible warning or fail under --strict. Silent degradation is a conformance violation. In the reference compiler today every adapter's capability set is empty — emit() writes instructions but does not yet copy scripts/, install a hook, or wire a subagent — so any value in requires degrades on every one of the eleven targets, Claude Code included.

    mode = "gate" means the skill produces a verdict that can block — a pre-push check, a CI step. Gates must ground that verdict in a script exit code or a schema-validated artifact. A gate-mode skill with no scripts/ directory and no artifacts.produces has nothing to produce a verdict from, and fails the gate-verdict check under lint and test.

    [lore]

    diff --git a/site/docs/index.html b/site/docs/index.html index eb33355..6ba2fc0 100644 --- a/site/docs/index.html +++ b/site/docs/index.html @@ -151,7 +151,7 @@

    Project config

    Adapters & targets

    -

    All ten targets, which are lazy or eager, and where compilation degrades.

    +

    All eleven targets, which are lazy or eager, and where compilation degrades.

    Trust & review

    @@ -215,7 +215,7 @@

    Working today

  • lint, preview, explain, test — read-only inspection. The first three also accept an uninstalled source, so you can read a stranger's skill before it touches your disk.
  • update — refetch each skill's pinned source and apply changes only after the full review diff: manifest deltas with permission escalations flagged, then a unified diff of every file. Install's safety lints and [policy] are re-enforced, and a non-interactive run never applies without --yes. diff is the same review, read-only — against the pinned source or between any two skills.
  • Sources: gh:owner/repo[/path][@ref], bare owner/repo, and file:path.
  • -
  • Ten adapters: claude-code, cursor, agents, zed, copilot, cline, windsurf, gemini, aider, and the agentsmd floor.
  • +
  • Eleven adapters: claude-code, cursor, agents, zed, copilot, cline, windsurf, gemini, aider, the agentsmd floor, and the opt-in agent-plugins package target.
  • Budget and standing enforcement at compile time, degradation warnings, and --strict.
  • kitbash.lock with directory content hashes, drift detection in doctor, and stale-output pruning after remove.
  • Pre-install review with --yes for scripts, and the [policy] allowlist as a hard gate that --yes does not bypass.
  • diff --git a/site/docs/quickstart.html b/site/docs/quickstart.html index 7911bd3..b839aec 100644 --- a/site/docs/quickstart.html +++ b/site/docs/quickstart.html @@ -178,7 +178,7 @@

    Where to go next

    diff --git a/site/index.html b/site/index.html index da6b7d8..6cabd34 100644 --- a/site/index.html +++ b/site/index.html @@ -151,7 +151,7 @@
    -

    Open format for AI agent skills · v0.16.0 · stable spec (RFC 0002)

    +

    Open format for AI agent skills · v0.17.0 · stable spec (RFC 0002)

    Write an agent skill once. Run it everywhere.

    Get started @@ -237,7 +237,7 @@

    Review the diff

    Honest degradation

    -

    An agent that can't run scripts gets an instruction-only build with a visible warning, never a quiet downgrade. Nine targets today, from Claude Code to the AGENTS.md fallback.

    +

    An agent that can't run scripts gets an instruction-only build with a visible warning, never a quiet downgrade. Eleven targets today, from Claude Code to the AGENTS.md fallback.

@@ -259,6 +259,7 @@

#Pick a target

+
@@ -417,6 +418,21 @@

#Pick a target

The floor: Codex and everything else that reads AGENTS.md. Updates replace only the section between the markers — the rest of your file is untouched.

+ +

Run it yourself: kitbash preview prereview — with lint and explain, new in the CLI.

@@ -486,7 +502,7 @@

Trust & review

Adapters & targets

-

All ten targets, what each agent supports, and which ones pay a standing token tax.

+

All eleven targets, what each agent supports, and which ones pay a standing token tax.

Manifesto ↗

diff --git a/site/skills.html b/site/skills.html index 372e4fa..722a7c8 100644 --- a/site/skills.html +++ b/site/skills.html @@ -206,7 +206,7 @@

#Install a skill from anywhere

#Already have skills?

-

A plain SKILL.md folder — the skills.sh and Claude Skills convention — installs directly. It is KSF without the manifest, so Kitbash applies conservative defaults and marks it unmanifested, because nobody declared a budget or permissions for it. You still get compilation to all ten targets, the lockfile, and the standing-cost warning.

+

A plain SKILL.md folder — the skills.sh and Claude Skills convention — installs directly. It is KSF without the manifest, so Kitbash applies conservative defaults and marks it unmanifested, because nobody declared a budget or permissions for it. You still get compilation to all eleven targets, the lockfile, and the standing-cost warning.

kitbash install owner/repo
 kitbash lint owner/repo   # or lint it before installing