mcpbeat Sign in

Unjs Citty Agent Skill

ALWAYS use when writing code importing \"citty\". Consult for debugging, best practices, or modifying citty.

1k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
307
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/skilld-dev/skilld --skill unjs-citty

The instruction itself

4 sections, as written by the author

unjs/citty citty

Version: 0.2.1 (yesterday)

Tags: latest: 0.2.1 (yesterday)

References: package.json • README • GitHub Issues • Releases

Use npx -y skilld search instead of grepping .skilld/ directories — hybrid semantic + keyword search across all indexed docs, issues, and releases.

npx -y skilld search "query" -p citty
npx -y skilld search "issues:error handling" -p citty
npx -y skilld search "releases:deprecated" -p citty

Filters: docs:, issues:, releases: prefix narrows by source type.

API Changes

⚠️ ESM-only — v0.2.0 ships ESM only, require('citty') no longer works source

⚠️ node:util.parseArgs internally — v0.2.0 replaced custom parser with Node.js native util.parseArgs, edge cases around arg parsing may differ from v0.1.x source

⚠️ Optional args type T | undefined — v0.2.0 improved type inference: args without required: true or default now correctly type as T | undefined instead of T source

⚠️ --no- negation conditionally printed — v0.2.0 only shows --no-<flag> in usage when negativeDescription is set; previously always shown source

type: "enum" — new arg type in v0.2.0, requires options: string] array. Typed as union of options values [source

args: {
  color: {
    type: "enum",
    options: ["red", "blue", "green"] as const,
    description: "Pick a color",
  },
}
// args.color typed as "red" | "blue" | "green" | undefined

meta.hidden — v0.2.0, hides a subcommand from usage/help output source

negativeDescription — v0.2.0, on boolean args, sets description for the --no-<flag> variant in usage source

cleanup hook — v0.1.4, runs after run() completes (mirror of setup) source

createMain(cmd) — v0.1.4, returns a reusable (opts?) => Promise<void> wrapper around runMain source

--version flag — v0.1.4, auto-handled when meta.version is set source

runMain({ showUsage }) — v0.1.5, accepts custom showUsage function to override default help rendering source

⚠️ --no- propagation fix — v0.2.1, --no-<flag> now correctly negates aliases too (was broken in v0.2.0) source

Best Practices

✅ Use setup and cleanup hooks for lifecycle management — undocumented in README but fully supported; cleanup runs in finally block so it executes even on errors source

defineCommand({
  args: { db: { type: "string", default: "mydb" } },
  async setup({ args }) { await connectDb(args.db) },
  async cleanup() { await disconnectDb() },
  async run({ args }) { /* db is connected */ },
})

✅ Use enum type with options for constrained values — validates input and shows allowed values in usage/error messages (v0.2.0+) source

args: {
  format: {
    type: "enum",
    options: ["json", "yaml", "toml"],
    default: "json",
    description: "Output format",
  },
}

✅ Use meta.hidden: true to hide subcommands from usage output — keeps internal/debug commands accessible but invisible (v0.2.0+) source

subCommands: {
  debug: () => defineCommand({ meta: { name: "debug", hidden: true }, run() {} }),
}

✅ Make subCommands values lazy via arrow functions — citty resolves them with resolveValue(), enabling code-splitting and faster startup source

subCommands: {
  deploy: () => import("./commands/deploy").then(m => m.default),
  build: () => import("./commands/build").then(m => m.default),
}

✅ Use negativeDescription on boolean args that default to true — citty auto-generates --no-* flags with separate help text (v0.2.0+) source

args: {
  color: {
    type: "boolean",
    default: true,
    description: "Colorize output",
    negativeDescription: "Disable colored output",
  },
}

✅ Pass custom showUsage to runMain for branded help screens — citty calls your function instead of the built-in one for --help and error display source

runMain(cmd, {
  showUsage: async (cmd, parent) => {
    console.log(await renderUsage(cmd, parent))
    console.log("\nDocs: https://example.com/docs")
  },
})

✅ Arg names auto-alias between camelCase and kebab-case — defining outputDir auto-creates --output-dir and vice versa; don't add redundant aliases source

--version only works as the sole argument — citty checks rawArgs.length === 1 && rawArgs0] === "--version", so --version --verbose won't trigger it; set meta.version on the root command [source

✅ Use runCommand over runMain for programmatic invocation — runMain calls process.exit(1) on errors and handles --help/--version; runCommand returns { result } and lets errors propagate source

const { result } = await runCommand(cmd, { rawArgs: ["build", "--prod"] })

✅ Avoid positional args on commands with subcommands — if a positional value matches a subcommand name, citty routes to the subcommand instead of using it as the arg value source

How to use it

Copy the folder

Take skilld-dev/unjs-citty from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npx. Without those the skill loads but fails at the first command.