# Unjs Citty

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

- **Type:** Skill
- **Install:** `agentstack add skill-skilld-dev-skilld-unjs-citty`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [skilld-dev](https://agentstack.voostack.com/s/skilld-dev)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [skilld-dev](https://github.com/skilld-dev)
- **Source:** https://github.com/skilld-dev/skilld/tree/main/.claude/skills/unjs-citty
- **Website:** https://skilld.dev

## Install

```sh
agentstack add skill-skilld-dev-skilld-unjs-citty
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# unjs/citty `citty`

**Version:** 0.2.1 (yesterday)
**Tags:** latest: 0.2.1 (yesterday)

**References:** [package.json](./.skilld/pkg/package.json) • [README](./.skilld/pkg/README.md) • [GitHub Issues](./.skilld/issues/_INDEX.md) • [Releases](./.skilld/releases/_INDEX.md)

## Search

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

```bash
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](./releases/v0.2.0.md)

⚠️ **`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](./releases/v0.2.0.md)

⚠️ **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](./releases/v0.2.0.md)

⚠️ **`--no-` negation conditionally printed** — v0.2.0 only shows `--no-` in usage when `negativeDescription` is set; previously always shown [source](./releases/v0.2.0.md)

✨ `type: "enum"` — new arg type in v0.2.0, requires `options: string[]` array. Typed as union of options values [source](./releases/v0.2.0.md)

```ts
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](./releases/v0.2.0.md)

✨ `negativeDescription` — v0.2.0, on boolean args, sets description for the `--no-` variant in usage [source](./releases/v0.2.0.md)

✨ `cleanup` hook — v0.1.4, runs after `run()` completes (mirror of `setup`) [source](./releases/v0.1.4.md)

✨ `createMain(cmd)` — v0.1.4, returns a reusable `(opts?) => Promise` wrapper around `runMain` [source](./releases/v0.1.4.md)

✨ `--version` flag — v0.1.4, auto-handled when `meta.version` is set [source](./releases/v0.1.4.md)

✨ `runMain({ showUsage })` — v0.1.5, accepts custom `showUsage` function to override default help rendering [source](./releases/v0.1.5.md)

⚠️ `--no-` propagation fix — v0.2.1, `--no-` now correctly negates aliases too (was broken in v0.2.0) [source](./releases/v0.2.1.md)

## 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](./.skilld/pkg/dist/index.mjs)

```ts
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](./.skilld/releases/v0.2.0.md)

```ts
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](./.skilld/releases/v0.2.0.md)

```ts
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](./.skilld/pkg/dist/index.mjs)

```ts
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](./.skilld/pkg/dist/index.mjs)

```ts
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](./.skilld/pkg/dist/index.d.mts)

```ts
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](./.skilld/pkg/dist/index.mjs)

✅ `--version` only works as the sole argument — citty checks `rawArgs.length === 1 && rawArgs[0] === "--version"`, so `--version --verbose` won't trigger it; set `meta.version` on the root command [source](./.skilld/pkg/dist/index.mjs)

✅ 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](./.skilld/pkg/dist/index.mjs)

```ts
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](./.skilld/issues/issue-41.md)

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [skilld-dev](https://github.com/skilld-dev)
- **Source:** [skilld-dev/skilld](https://github.com/skilld-dev/skilld)
- **License:** MIT
- **Homepage:** https://skilld.dev

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-skilld-dev-skilld-unjs-citty
- Seller: https://agentstack.voostack.com/s/skilld-dev
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
