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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Format: [Keep a Changelog](https://keepachangelog.com). Versioning: semver — for skills *and* for this CLI, breaking prompt changes are breaking changes.

## [0.24.1] — 2026-08-12

### Fixed
- **A skill name with a doubled or trailing hyphen was only ever flagged for Zed.** KSF's own name rule permits `tidy--commits` and `tidy-`, but the [Agent Skills spec](https://agentskills.io/specification) — the shared authority every skills-directory target defers to, Claude Code, Codex, Copilot, Cline, Zed, Gemini CLI and Agent Plugins alike — forbids a leading, trailing or consecutive hyphen outright. So a name that only Zed complained about could in fact be refused by all of them, and several refuse without saying anything. It is now reported once against the skill, at `install`, `lint` and `test`, naming the spec rather than a single target. A warning, not a failure: the name is valid KSF and still compiles, and `--strict` escalates it like any other warning.

## [0.24.0] — 2026-08-12

A verification pass over every claim the compiler makes about the agents it targets, checked against each client's own source or documentation. **All eleven loading modes are correct** — the 14×–47× standing-cost benchmark stands — but three claims around them were overstated, and one of them was in the published numbers.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Already have skills? A plain SKILL.md folder — the skills.sh / Claude Skills c

Already carrying a hand-written `CLAUDE.md`, `.cursor/rules/`, `AGENTS.md`, and the rest of the copy-per-agent set? `kitbash import` reads them back into a single skill, measures what each one costs in standing context, and reports where the copies have drifted apart — so `kitbash compile` can regenerate them all from that one source. It touches nothing on disk until you remove the originals yourself.

**Status.** v0.24.0, on npm and Homebrew, zero runtime dependencies, Node 20+. The KSF core is frozen and additive-only within the major version ([RFC 0002](rfcs/0002-ksf-1.0-stabilization.md)). Everything around it is early and labeled as such: `init`, `import`, `install`, `remove`, `list`, `compile`, `doctor`, `update`, `diff`, `lint`, `preview`, `explain`, and `test` work today; `audit`, `gate`, `search`, `publish`, `lore`, and `run` exit `7` and are on the [roadmap](docs/roadmap.md). One first-party skill ships (`prereview`); six more are specified but not built. Adoption is single-digit stars — if the measurement above is what you want, you are early.
**Status.** v0.24.1, on npm and Homebrew, zero runtime dependencies, Node 20+. The KSF core is frozen and additive-only within the major version ([RFC 0002](rfcs/0002-ksf-1.0-stabilization.md)). Everything around it is early and labeled as such: `init`, `import`, `install`, `remove`, `list`, `compile`, `doctor`, `update`, `diff`, `lint`, `preview`, `explain`, and `test` work today; `audit`, `gate`, `search`, `publish`, `lore`, and `run` exit `7` and are on the [roadmap](docs/roadmap.md). One first-party skill ships (`prereview`); six more are specified but not built. Adoption is single-digit stars — if the measurement above is what you want, you are early.

<p align="center">
<a href="https://www.npmjs.com/package/kitbash"><img src="https://img.shields.io/npm/v/kitbash?color=ffb454" alt="npm version"></a>
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kitbash",
"version": "0.24.0",
"version": "0.24.1",
"description": "The package manager and compiler for AI agent skills — write once, run in every coding agent",
"license": "Apache-2.0",
"author": "Harsh Singh",
Expand Down
30 changes: 30 additions & 0 deletions packages/cli/scripts/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,36 @@ try {
rmSync(nameTmp, { recursive: true, force: true });
}

// ── the Agent Skills naming rule, checked once per skill ────────────────────
// KSF permits `tidy--commits` and `tidy-`; the Agent Skills spec every skills
// directory target follows does not. Several hosts drop such a skill silently,
// so it is worth saying once about the skill rather than once per target.
const nmTmp = mkdtempSync(join(tmpdir(), "kitbash-specname-"));
try {
const bad = join(nmTmp, "bad");
mkdirSync(bad, { recursive: true });
writeFileSync(join(bad, "skill.toml"), '[skill]\nname = "tidy--commits"\nversion = "1.0.0"\ndescription = "A skill whose name has a doubled hyphen"\n[context]\nbudget = 1500\n');
writeFileSync(join(bad, "SKILL.md"), "# Tidy\n\nBody.\n");
const l = run(["lint", `file:${bad}`], nmTmp);
check("spec-name: a doubled hyphen is reported", l.out.includes("name-convention"), l.out);
check("spec-name: it warns rather than fails", l.status === 0 && l.out.includes("0 failure(s)"), l.out);
check("spec-name: --strict escalates it", run(["lint", "--strict", `file:${bad}`], nmTmp).status === 1);

const trail = join(nmTmp, "trail");
mkdirSync(trail, { recursive: true });
writeFileSync(join(trail, "skill.toml"), '[skill]\nname = "tidy-"\nversion = "1.0.0"\ndescription = "A skill whose name ends with a hyphen"\n[context]\nbudget = 1500\n');
writeFileSync(join(trail, "SKILL.md"), "# Tidy\n\nBody.\n");
check("spec-name: a trailing hyphen is reported", run(["lint", `file:${trail}`], nmTmp).out.includes("name-convention"));

const ok = join(nmTmp, "ok");
mkdirSync(ok, { recursive: true });
writeFileSync(join(ok, "skill.toml"), '[skill]\nname = "tidy-commits"\nversion = "1.0.0"\ndescription = "A skill with a spec-clean name"\n[context]\nbudget = 1500\n');
writeFileSync(join(ok, "SKILL.md"), "# Tidy\n\nBody.\n");
check("spec-name: a clean name is silent", !run(["lint", `file:${ok}`], nmTmp).out.includes("name-convention"));
} finally {
rmSync(nmTmp, { recursive: true, force: true });
}

if (failures) {
console.error(`\n${failures} test(s) failed`);
process.exit(1);
Expand Down
25 changes: 25 additions & 0 deletions packages/cli/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ const VERSION: string = createRequire(import.meta.url)("../package.json").versio
*/
// "mcp" is here because a declared MCP server is a request to run third-party
// code with the agent's permissions — a heavier ask than anything in a body.
/**
* The Agent Skills naming rule (agentskills.io/specification): 1-64 chars,
* lowercase alphanumerics and hyphens, no leading, trailing or consecutive
* hyphen. KSF's NAME_RE is stricter in some ways (must start with a letter,
* capped at 41) and looser in exactly one: it permits `tidy--commits` and
* `tidy-`. This is the spec's rule, used to warn about that gap.
*/
const SPEC_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;

const SAFETY_LINTS = new Set(["visible-text", "dynamic-context", "remote-exec", "secrets", "mcp"]);

const INIT_CONFIG = `# kitbash project configuration — https://github.com/singhharsh1708/kitbash
Expand Down Expand Up @@ -1115,6 +1124,22 @@ function staticChecks(skill: LoadedSkill): Check[] {

checks.push({ name: "manifest", ok: true, warn: skill.bare, detail: skill.bare ? "unmanifested (SKILL.md only) — defaults applied" : `${m.skill.name}@${m.skill.version}` });

// KSF's own name rule is looser than the Agent Skills spec every skills
// directory target follows: the spec forbids a leading, trailing or doubled
// hyphen, so `tidy--commits` and `tidy-` are legal KSF names that Claude Code,
// Codex, Copilot, Cline, Zed, Gemini and Agent Plugins may all refuse. Some of
// them refuse silently, which makes this worth saying once about the skill
// rather than once per target. A warning, not a failure — the name is valid
// KSF, and the compiler will still emit it.
if (!SPEC_NAME_RE.test(m.skill.name)) {
checks.push({
name: "name-convention",
ok: true,
warn: true,
detail: `"${m.skill.name}" has a leading, trailing or doubled hyphen. The Agent Skills spec allows neither, so hosts reading a skills directory may drop it — several without saying so.`,
});
}

// templates / dead references
let body: string | undefined;
try {
Expand Down
13 changes: 11 additions & 2 deletions site/changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ <h1>Changelog</h1>
<p>Releases follow <a href="https://keepachangelog.com" target="_blank" rel="noopener">Keep a Changelog</a> and semver — for skills <em>and</em> for this CLI, breaking prompt changes are breaking changes. The CLI is published to npm as <a href="https://www.npmjs.com/package/kitbash" target="_blank" rel="noopener"><code>kitbash</code></a> and to Homebrew via <code>singhharsh1708/tap</code>. Tagged builds are on the <a href="https://github.com/singhharsh1708/kitbash/releases" target="_blank" rel="noopener">GitHub releases page</a>.</p>

<div class="stat-row">
<div class="stat"><b><span data-version>v0.24.0</span></b><span>Current CLI version</span></div>
<div class="stat"><b><span data-version>v0.24.1</span></b><span>Current CLI version</span></div>
<div class="stat"><b>8</b><span>Compile targets</span></div>
<div class="stat"><b>Apache-2.0</b><span>License</span></div>
</div>
Expand All @@ -105,10 +105,19 @@ <h1>Changelog</h1>
<p>Confirm with <code>kitbash --version</code>, which reads the installed package.json. Install and uninstall routes are covered on the <a href="docs/install">installation page</a>.</p>

<!-- changelog:begin -->
<article class="release" id="v0.24.1">
<div class="release-head">
<h2><a href="#v0.24.1">v0.24.1</a></h2>
<span class="release-date">2026-08-12</span><span class="release-tag">latest</span>
</div>
<h3 class="group">Fixed</h3>
<ul><li><strong>A skill name with a doubled or trailing hyphen was only ever flagged for Zed.</strong> KSF's own name rule permits <code>tidy--commits</code> and <code>tidy-</code>, but the <a href="https://agentskills.io/specification" target="_blank" rel="noopener">Agent Skills spec</a> — the shared authority every skills-directory target defers to, Claude Code, Codex, Copilot, Cline, Zed, Gemini CLI and Agent Plugins alike — forbids a leading, trailing or consecutive hyphen outright. So a name that only Zed complained about could in fact be refused by all of them, and several refuse without saying anything. It is now reported once against the skill, at <code>install</code>, <code>lint</code> and <code>test</code>, naming the spec rather than a single target. A warning, not a failure: the name is valid KSF and still compiles, and <code>--strict</code> escalates it like any other warning.</li></ul>
</article>

<article class="release" id="v0.24.0">
<div class="release-head">
<h2><a href="#v0.24.0">v0.24.0</a></h2>
<span class="release-date">2026-08-12</span><span class="release-tag">latest</span>
<span class="release-date">2026-08-12</span>
</div>
<p class="release-intro">A verification pass over every claim the compiler makes about the agents it targets, checked against each client's own source or documentation. <strong>All eleven loading modes are correct</strong> — the 14×–47× standing-cost benchmark stands — but three claims around them were overstated, and one of them was in the published numbers.</p>
<h3 class="group">Fixed</h3>
Expand Down
2 changes: 1 addition & 1 deletion site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
<circle cx="256" cy="256" r="238" fill="none" stroke="#ffb454" stroke-width="5"/>
</svg>
</div>
<p class="eyebrow">Open format for AI agent skills · <span data-version>v0.24.0</span> · stable spec (RFC 0002)</p>
<p class="eyebrow">Open format for AI agent skills · <span data-version>v0.24.1</span> · stable spec (RFC 0002)</p>
<h1>Write an agent skill once. Run it <em>everywhere</em>.</h1>
<div class="actions">
<a class="button" href="docs/quickstart">Get started</a>
Expand Down
Loading