diff --git a/.changeset/rename-clerk-cli-skill.md b/.changeset/rename-clerk-cli-skill.md new file mode 100644 index 00000000..c40d0c76 --- /dev/null +++ b/.changeset/rename-clerk-cli-skill.md @@ -0,0 +1,5 @@ +--- +"clerk": minor +--- + +Rename the bundled agent skill from `clerk` to `clerk-cli` for more clarity during install. After upgrading, `clerk skill install` (and the install step in `clerk init`) writes the skill to `/skills/clerk-cli/` instead of `/skills/clerk/`. Existing `skills/clerk/` directories from prior installs are left in place; remove them manually if you want to avoid duplicate context. diff --git a/.claude/skills/audit-clerk-skill/SKILL.md b/.claude/skills/audit-clerk-skill/SKILL.md index 0f6369d5..cbaf09f9 100644 --- a/.claude/skills/audit-clerk-skill/SKILL.md +++ b/.claude/skills/audit-clerk-skill/SKILL.md @@ -1,22 +1,22 @@ --- name: audit-clerk-skill -description: Audits the Clerk CLI source tree and proposes updates to the bundled `clerk` skill so it stays in sync with the binary. Use when the user says "audit the clerk skill", "update the clerk skill", "check the skill against the code", "resync clerk skill", or after adding/renaming/removing CLI commands, flags, or agent-mode behavior. +description: Audits the Clerk CLI source tree and proposes updates to the bundled `clerk-cli` skill so it stays in sync with the binary. Use when the user says "audit the clerk-cli skill", "update the clerk-cli skill", "check the skill against the code", "resync clerk-cli skill", or after adding/renaming/removing CLI commands, flags, or agent-mode behavior. effort: high user-invocable: true disable-model-invocation: true argument-hint: "[--apply]" --- -# Audit the clerk Skill +# Audit the clerk-cli Skill -Cross-check `skills/clerk/` against the actual CLI source in `packages/cli-core/` and propose precise edits wherever they have drifted. The binary is the source of truth; the skill is documentation that must track it. +Cross-check `skills/clerk-cli/` against the actual CLI source in `packages/cli-core/` and propose precise edits wherever they have drifted. The binary is the source of truth; the skill is documentation that must track it. **ultrathink** on this task. It requires building a full command tree, comparing two representations of it, and making judgment calls about what belongs in the skill vs. in `references/*.md` vs. in `--help`. Shallow passes miss drift. ## Inputs - **Source of truth**: `packages/cli-core/src/commands/**` (one directory per top-level command), plus `packages/cli-core/src/cli.ts`, `cli-program.ts`, `mode.ts`, and anything in `packages/cli-core/src/lib/` referenced by commands (runner preference, agent mode, doctor checks, key resolution). -- **Target**: `skills/clerk/SKILL.md` and `skills/clerk/references/*.md`. +- **Target**: `skills/clerk-cli/SKILL.md` and `skills/clerk-cli/references/*.md`. - **Template markers**: the skill uses `{{CLI_VERSION}}` placeholders substituted at install time by `clerk skill install`. Preserve them; do not expand. ## Workflow @@ -37,7 +37,7 @@ Read the per-command `README.md` (`packages/cli-core/src/commands//README. - Flag commands or sub-paths marked mocked/stubbed (blockquote at top of the README). The skill should not document these as production-ready. - Cross-check Clerk API endpoint claims in `references/recipes.md`. -Do **not** propose bundling the READMEs into `skills/clerk/references/` (symlinks or text imports). They ship internal detail agents do not need, and inflate the compiled binary. They are a reference for the audit, not for the skill. +Do **not** propose bundling the READMEs into `skills/clerk-cli/references/` (symlinks or text imports). They ship internal detail agents do not need, and inflate the compiled binary. They are a reference for the audit, not for the skill. Also capture cross-cutting behavior: @@ -50,7 +50,7 @@ Don't memorize output. Prefer reading the source directly over running the binar ### 2. Extract the skill's current claims -Read `skills/clerk/SKILL.md` and each file under `skills/clerk/references/`. Extract every concrete claim: +Read `skills/clerk-cli/SKILL.md` and each file under `skills/clerk-cli/references/`. Extract every concrete claim: - Every command mentioned in the "Core commands at a glance" table and the Invoking-the-CLI table. - Every flag called out by name. @@ -92,7 +92,7 @@ If a new reference file is warranted (e.g. a `references/commands.md` table), pr Emit a review-ready proposal. For each change: -- Path (`skills/clerk/SKILL.md` or `skills/clerk/references/.md`). +- Path (`skills/clerk-cli/SKILL.md` or `skills/clerk-cli/references/.md`). - Why (source citation: `packages/cli-core/src/commands//.ts:`). - Either a unified diff (preferred) or a before/after block for prose sections. - Severity: `drift` (factually wrong today), `gap` (missing coverage), `polish` (clearer wording, better placement, or cuts that route the agent to `--help` instead of duplicating it). @@ -118,18 +118,18 @@ If invoked as `/audit-clerk-skill --apply`, apply `drift` and `gap` edits direct Return the proposal as: ``` -# clerk skill audit — +# clerk-cli skill audit — ## Summary -## skills/clerk/SKILL.md +## skills/clerk-cli/SKILL.md ###
- [drift|gap|polish] - source: packages/cli-core/src/commands/<...>: - -## skills/clerk/references/.md +## skills/clerk-cli/references/.md ... ## New files (if any) diff --git a/packages/cli-core/src/cli-program.test.ts b/packages/cli-core/src/cli-program.test.ts index e1ee982d..50ec753f 100644 --- a/packages/cli-core/src/cli-program.test.ts +++ b/packages/cli-core/src/cli-program.test.ts @@ -257,15 +257,15 @@ describe("help: clerk skill install tip", () => { }); for (const dir of STANDARD_AGENT_DIRS) { - test(`hides the tip when ${dir}/skills/clerk/SKILL.md exists under HOME`, () => { - const target = join(tmpHome, dir, "skills/clerk"); + test(`hides the tip when ${dir}/skills/clerk-cli/SKILL.md exists under HOME`, () => { + const target = join(tmpHome, dir, "skills/clerk-cli"); mkdirSync(target, { recursive: true }); writeFileSync(join(target, "SKILL.md"), "ok"); expect(renderHelp()).not.toContain(TIP_SUBSTR); }); - test(`hides the tip when ${dir}/skills/clerk/SKILL.md exists under cwd`, () => { - const target = join(tmpCwd, dir, "skills/clerk"); + test(`hides the tip when ${dir}/skills/clerk-cli/SKILL.md exists under cwd`, () => { + const target = join(tmpCwd, dir, "skills/clerk-cli"); mkdirSync(target, { recursive: true }); writeFileSync(join(target, "SKILL.md"), "ok"); expect(renderHelp()).not.toContain(TIP_SUBSTR); diff --git a/packages/cli-core/src/commands/init/README.md b/packages/cli-core/src/commands/init/README.md index 8cdea2d5..5fd75711 100644 --- a/packages/cli-core/src/commands/init/README.md +++ b/packages/cli-core/src/commands/init/README.md @@ -185,17 +185,17 @@ After scaffolding (and after env keys are pulled or keyless instructions are pri - **Human mode**: prompts `Install agent skills? (...)` defaulting to yes. Pass `--no-skills` to suppress the prompt entirely, or `-y/--yes` to accept it without confirmation. When more than one runner is available, a second prompt picks which one to use (the project's package manager wins by default). - **Agent mode**: skills are installed non-interactively with `-y -g` flags (no prompt shown). Pass `--no-skills` to skip entirely. -- **`--prompt`**: exits before the skills step runs. Agent users should run `skills add clerk/skills` via their preferred runner manually; the bundled `clerk` skill is only installable via `clerk init` itself, since its source lives inside the CLI binary. +- **`--prompt`**: exits before the skills step runs. Agent users should run `skills add clerk/skills` via their preferred runner manually; the bundled `clerk-cli` skill is only installable via `clerk init` itself, since its source lives inside the CLI binary. Two install commands run, sharing one runner: -### 1. The bundled `clerk` skill +### 1. The bundled `clerk-cli` skill -The `clerk` skill ships **inside the CLI binary**. Its markdown files at [`/skills/clerk/`](../../../../../skills/clerk/) are pulled into [`skills.ts`](./skills.ts) as [text imports](https://bun.com/docs/bundler/loaders#text) (`import md from "./SKILL.md" with { type: "text" }`) and embedded by `bun build --compile`, so the skill content always matches the binary running it. No network, no tag, no version fallback. +The `clerk-cli` skill ships **inside the CLI binary**. Its markdown files at [`/skills/clerk-cli/`](../../../../../skills/clerk-cli/) are pulled into [`skills.ts`](./skills.ts) as [text imports](https://bun.com/docs/bundler/loaders#text) (`import md from "./SKILL.md" with { type: "text" }`) and embedded by `bun build --compile`, so the skill content always matches the binary running it. No network, no tag, no version fallback. At install time, [`skills.ts`](./skills.ts) stages the bundled content into a fresh temp directory (`mkdtemp`) and invokes ` skills add --copy`. The `--copy` flag is required: the default symlink mode would point each agent's skill dir at the temp dir, which we delete immediately after the install completes. -The `skills` CLI writes the installed files into each agent's skill directory (`.claude/skills/clerk/`, `.cursor/skills/clerk/`, etc.) and records the entry in the project's `skills-lock.json` with `sourceType: "local"`, which correctly excludes it from `skills update` (the skill can only change when the CLI itself is upgraded). +The `skills` CLI writes the installed files into each agent's skill directory (`.claude/skills/clerk-cli/`, `.cursor/skills/clerk-cli/`, etc.) and records the entry in the project's `skills-lock.json` with `sourceType: "local"`, which correctly excludes it from `skills update` (the skill can only change when the CLI itself is upgraded). ### 2. The upstream skills @@ -223,7 +223,7 @@ These skills version independently of the CLI, so no pin is applied. ### Failure handling -The two install commands fail independently: a problem with the bundled `clerk` skill install (e.g. the `skills` CLI can't be fetched by the runner) does not block the upstream skills install, and vice versa. Each failure prints its own yellow warning with a manual install command (where applicable — the bundled `clerk` skill has no standalone manual command, since its source lives in the binary). Init continues and exits successfully either way. +The two install commands fail independently: a problem with the bundled `clerk-cli` skill install (e.g. the `skills` CLI can't be fetched by the runner) does not block the upstream skills install, and vice versa. Each failure prints its own yellow warning with a manual install command (where applicable — the bundled `clerk-cli` skill has no standalone manual command, since its source lives in the binary). Init continues and exits successfully either way. Implementation lives in [`skills.ts`](./skills.ts). Note that the E2E fixture setup runs `clerk init --yes --no-skills` because the framework template skills reference auto-generated types (e.g. React Router's `./+types/root`) that don't exist outside a real app directory and would break the fixture's `tsc` step. diff --git a/packages/cli-core/src/commands/skill/README.md b/packages/cli-core/src/commands/skill/README.md index 166b3544..aa98d301 100644 --- a/packages/cli-core/src/commands/skill/README.md +++ b/packages/cli-core/src/commands/skill/README.md @@ -1,17 +1,19 @@ # Skill Command -Manages the bundled `clerk` agent skill. The skill is embedded in the CLI binary at compile time via text imports from `skills/clerk/`, so it always matches the version of the CLI in use. +Manages the bundled `clerk-cli` agent skill. The skill is embedded in the CLI binary at compile time via text imports from `skills/clerk-cli/`, so it always matches the version of the CLI in use. ## Subcommands ### `clerk skill install` -Installs the bundled `clerk` skill for any locally detected AI agents (Claude Code, Cursor, etc.). The actual agent detection and scope selection is delegated to the external [`skills`](https://www.npmjs.com/package/skills) CLI, which is invoked via the preferred package runner on PATH (`bunx`, `pnpm dlx`, `yarn dlx`, or `npx`). +Installs the bundled `clerk-cli` skill for any locally detected AI agents (Claude Code, Cursor, etc.). The actual agent detection and scope selection is delegated to the external [`skills`](https://www.npmjs.com/package/skills) CLI, which is invoked via the preferred package runner on PATH (`bunx`, `pnpm dlx`, `yarn dlx`, or `npx`). Interactive mode hands off entirely to the `skills` CLI picker. Non-interactive mode (`-y`, agent mode, or no TTY) passes `-y -g` so the skills CLI runs unattended against global scope with auto-detected agents. This command is delegated to by `clerk init` as part of its post-scaffold agent skills step; running it standalone is useful when adding the skill to an existing project that was set up before the skill was bundled, or when reinstalling after upgrading the CLI. +> Prior to v1, the bundled skill was named `clerk`. It is now `clerk-cli` to make the name unambiguous during install. If you previously installed the `clerk` skill, you can remove the old `skills/clerk/` directory under any agent dir (`.claude/`, `.cursor/`, etc.) — the new install lives at `skills/clerk-cli/`. + ## Usage ```sh diff --git a/packages/cli-core/src/commands/skill/install.test.ts b/packages/cli-core/src/commands/skill/install.test.ts index 73b13be1..05a95da2 100644 --- a/packages/cli-core/src/commands/skill/install.test.ts +++ b/packages/cli-core/src/commands/skill/install.test.ts @@ -40,15 +40,15 @@ describe("buildSkillsArgs", () => { expect(buildSkillsArgs(upstream, skills, false, false)).not.toContain("--agent"); }); - test("empty skillNames omits --skill flags (used for the clerk source)", () => { - const stageDir = "/tmp/clerk-skill-abc"; + test("empty skillNames omits --skill flags (used for the clerk-cli source)", () => { + const stageDir = "/tmp/clerk-cli-skill-abc"; const args = buildSkillsArgs(stageDir, [], true, true); expect(args).toEqual(["skills", "add", stageDir, "--copy"]); expect(args).not.toContain("--skill"); }); - test("copy=true appends --copy flag (required for the staged clerk dir)", () => { - const args = buildSkillsArgs("/tmp/clerk-skill-xyz", [], false, true); + test("copy=true appends --copy flag (required for the staged clerk-cli dir)", () => { + const args = buildSkillsArgs("/tmp/clerk-cli-skill-xyz", [], false, true); expect(args).toContain("--copy"); // --copy should trail -y / -g, not replace them. expect(args).toContain("-y"); @@ -62,20 +62,23 @@ describe("withStagedClerkSkill", () => { await withStagedClerkSkill(undefined, async (dir) => { const files = { - "clerk/SKILL.md": await readFile(join(dir, "clerk/SKILL.md"), "utf-8"), - "clerk/references/auth.md": await readFile(join(dir, "clerk/references/auth.md"), "utf-8"), - "clerk/references/recipes.md": await readFile( - join(dir, "clerk/references/recipes.md"), + "clerk-cli/SKILL.md": await readFile(join(dir, "clerk-cli/SKILL.md"), "utf-8"), + "clerk-cli/references/auth.md": await readFile( + join(dir, "clerk-cli/references/auth.md"), "utf-8", ), - "clerk/references/agent-mode.md": await readFile( - join(dir, "clerk/references/agent-mode.md"), + "clerk-cli/references/recipes.md": await readFile( + join(dir, "clerk-cli/references/recipes.md"), + "utf-8", + ), + "clerk-cli/references/agent-mode.md": await readFile( + join(dir, "clerk-cli/references/agent-mode.md"), "utf-8", ), }; observed = { dir, files }; - const entry = await stat(join(dir, "clerk")); + const entry = await stat(join(dir, "clerk-cli")); expect(entry.isDirectory()).toBe(true); }); @@ -89,7 +92,7 @@ describe("withStagedClerkSkill", () => { } // SKILL.md should at least contain the YAML frontmatter marker. - expect(files["clerk/SKILL.md"]).toContain("---"); + expect(files["clerk-cli/SKILL.md"]).toContain("---"); // Temp dir is removed once the callback returns. expect(existsSync(dir)).toBe(false); @@ -111,10 +114,10 @@ describe("withStagedClerkSkill", () => { }); const ALL_BUNDLED_FILES = [ - "clerk/SKILL.md", - "clerk/references/auth.md", - "clerk/references/recipes.md", - "clerk/references/agent-mode.md", + "clerk-cli/SKILL.md", + "clerk-cli/references/auth.md", + "clerk-cli/references/recipes.md", + "clerk-cli/references/agent-mode.md", ] as const; describe("withStagedClerkSkill version rendering", () => { @@ -145,7 +148,7 @@ describe("bundled SKILL.md frontmatter", () => { // `clerk skill install` fail with "No valid skills found". test("parses as YAML with name and description strings", async () => { await withStagedClerkSkill(undefined, async (stageDir) => { - const content = await readFile(join(stageDir, "clerk/SKILL.md"), "utf8"); + const content = await readFile(join(stageDir, "clerk-cli/SKILL.md"), "utf8"); const frontmatter = content.match(/^---\n([\s\S]*?)\n---/)?.[1]; expect(frontmatter, "SKILL.md must have YAML frontmatter").toBeDefined(); diff --git a/packages/cli-core/src/commands/skill/install.ts b/packages/cli-core/src/commands/skill/install.ts index 8e865649..108adf09 100644 --- a/packages/cli-core/src/commands/skill/install.ts +++ b/packages/cli-core/src/commands/skill/install.ts @@ -36,22 +36,22 @@ import { import { isNonEmpty } from "../../lib/helpers/arrays.js"; import { detectPackageManager, type PackageManager } from "../../lib/package-manager.js"; -import clerkSkillMd from "../../../../../skills/clerk/SKILL.md" with { type: "text" }; -import clerkAuthMd from "../../../../../skills/clerk/references/auth.md" with { type: "text" }; -import clerkRecipesMd from "../../../../../skills/clerk/references/recipes.md" with { type: "text" }; -import clerkAgentModeMd from "../../../../../skills/clerk/references/agent-mode.md" with { type: "text" }; +import clerkSkillMd from "../../../../../skills/clerk-cli/SKILL.md" with { type: "text" }; +import clerkAuthMd from "../../../../../skills/clerk-cli/references/auth.md" with { type: "text" }; +import clerkRecipesMd from "../../../../../skills/clerk-cli/references/recipes.md" with { type: "text" }; +import clerkAgentModeMd from "../../../../../skills/clerk-cli/references/agent-mode.md" with { type: "text" }; /** - * The bundled clerk skill, as `(relativePath, content)` pairs. Text - * imports resolve live from `/skills/clerk/` during + * The bundled clerk-cli skill, as `(relativePath, content)` pairs. Text + * imports resolve live from `/skills/clerk-cli/` during * `bun run dev` and get embedded into the compiled binary by * `bun build --compile`, so the content always matches the CLI being run. */ const BUNDLED_CLERK_SKILL: ReadonlyArray = [ - ["clerk/SKILL.md", clerkSkillMd], - ["clerk/references/auth.md", clerkAuthMd], - ["clerk/references/recipes.md", clerkRecipesMd], - ["clerk/references/agent-mode.md", clerkAgentModeMd], + ["clerk-cli/SKILL.md", clerkSkillMd], + ["clerk-cli/references/auth.md", clerkAuthMd], + ["clerk-cli/references/recipes.md", clerkRecipesMd], + ["clerk-cli/references/agent-mode.md", clerkAgentModeMd], ]; /** @@ -82,7 +82,7 @@ export async function withStagedClerkSkill( version: string | undefined, fn: (stageDir: string) => Promise, ): Promise { - const stageDir = await mkdtemp(join(tmpdir(), "clerk-skill-")); + const stageDir = await mkdtemp(join(tmpdir(), "clerk-cli-skill-")); try { for (const [rel, content] of BUNDLED_CLERK_SKILL) { const dest = join(stageDir, rel); @@ -223,7 +223,7 @@ export async function installClerkSkillCore( interactive: boolean, ): Promise { return withStagedClerkSkill(resolveCliVersion(), (stageDir) => - runSkillsAdd(runner, cwd, stageDir, [], interactive, true, "clerk skill"), + runSkillsAdd(runner, cwd, stageDir, [], interactive, true, "clerk-cli skill"), ); } @@ -248,6 +248,6 @@ export async function skillInstall(options: SkillInstallOptions): Promise const ok = await installClerkSkillCore(runner, cwd, interactive); if (ok) { log.blank(); - log.success("clerk skill installed. AI agents now have Clerk context in this project."); + log.success("clerk-cli skill installed. AI agents now have Clerk context in this project."); } } diff --git a/packages/cli-core/src/lib/skill-detection.ts b/packages/cli-core/src/lib/skill-detection.ts index 6569c441..3bf44ee3 100644 --- a/packages/cli-core/src/lib/skill-detection.ts +++ b/packages/cli-core/src/lib/skill-detection.ts @@ -5,8 +5,8 @@ import { join } from "node:path"; /** * Agents that host skills under the uniform * `/skills//SKILL.md` layout. Each is checked under - * both `$HOME//skills/clerk/SKILL.md` (global) and - * `//skills/clerk/SKILL.md` (project-local). + * both `$HOME//skills/clerk-cli/SKILL.md` (global) and + * `//skills/clerk-cli/SKILL.md` (project-local). */ export const STANDARD_AGENT_DIRS = [ ".claude", // Claude Code @@ -18,7 +18,7 @@ export const STANDARD_AGENT_DIRS = [ ".cline", // Cline VS Code extension ] as const; -const STANDARD_SKILL_REL = "skills/clerk/SKILL.md"; +const STANDARD_SKILL_REL = "skills/clerk-cli/SKILL.md"; /** * Paths for agents that don't follow the uniform @@ -27,12 +27,12 @@ const STANDARD_SKILL_REL = "skills/clerk/SKILL.md"; * `clerk skill install` does not install these layouts globally. */ export const EXTRA_REL_PATHS = [ - ".vscode/skills/clerk/SKILL.md", // VS Code (project-local) - ".github/prompts/clerk.md", // GitHub Copilot (project-local) + ".vscode/skills/clerk-cli/SKILL.md", // VS Code (project-local) + ".github/prompts/clerk-cli.md", // GitHub Copilot (project-local) ] as const; /** - * Best-effort synchronous check for whether the bundled `clerk` skill + * Best-effort synchronous check for whether the bundled `clerk-cli` skill * is installed for at least one local agent. Returns `true` on the first * hit. A missed match just means the install tip keeps showing — no * false positives harm the user. diff --git a/skills/clerk/SKILL.md b/skills/clerk-cli/SKILL.md similarity index 99% rename from skills/clerk/SKILL.md rename to skills/clerk-cli/SKILL.md index c4362d72..44d17be1 100644 --- a/skills/clerk/SKILL.md +++ b/skills/clerk-cli/SKILL.md @@ -1,5 +1,5 @@ --- -name: clerk +name: clerk-cli description: >- Operate the Clerk CLI (`clerk` binary) for authentication, user/org/session management, instance config, env keys, and any Clerk Backend or Platform API call. Use when the user @@ -186,7 +186,7 @@ See [references/recipes.md](references/recipes.md) for concrete patterns: listin | `clerk api ls [filter]` | Discover endpoints from the bundled OpenAPI catalog. | `--platform` | | `clerk completion [shell]` | Print a shell completion script (`bash`, `zsh`, `fish`, `powershell`). | — | | `clerk update` | Update the CLI to the latest version. | `--channel`, `-y`, `--all` | -| `clerk skill install` | Reinstall the bundled `clerk` skill. Run after upgrading the CLI so the skill matches the new binary. | `-y`, `--pm` | +| `clerk skill install` | Reinstall the bundled `clerk-cli` skill. Run after upgrading the CLI so the skill matches the new binary. | `-y`, `--pm` | **`clerk --help` is the source of truth for flags.** This table is a hint, not a spec. Before running an unfamiliar command or flag combination, run `clerk --help` once per session. Every command also defines `setExamples([...])` in source, which `--help` renders as a copy-pasteable Examples block, so you rarely need to guess syntax. diff --git a/skills/clerk/references/agent-mode.md b/skills/clerk-cli/references/agent-mode.md similarity index 100% rename from skills/clerk/references/agent-mode.md rename to skills/clerk-cli/references/agent-mode.md diff --git a/skills/clerk/references/auth.md b/skills/clerk-cli/references/auth.md similarity index 100% rename from skills/clerk/references/auth.md rename to skills/clerk-cli/references/auth.md diff --git a/skills/clerk/references/recipes.md b/skills/clerk-cli/references/recipes.md similarity index 100% rename from skills/clerk/references/recipes.md rename to skills/clerk-cli/references/recipes.md