Agent skill

Optique CLI Parser Patterns

by dahlia in dahlia/optique

Guides writing command-line interfaces with the Optique TypeScript library: composing parsers, choosing value types, subcommands and avoiding common mistakes.

MITAuto-check passedDevelopment

Install Optique CLI Parser Patterns

skills CLI
$ npx skills add dahlia/optique --skill optique -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install dahlia/optique optique --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/dahlia/optique.git skills-src && mkdir -p .claude/skills && cp -r skills-src/packages/core/skills/optique .claude/skills/optique && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
optique
GitHub stars
737
Token cost
~3.7k tokens
SKILL.md length
1,097 words
Files
2
Skills in repo
2
Repo updated
First seen
Licence
MIT

At a glance

Guides writing command-line interfaces with the Optique TypeScript library: composing parsers, choosing value types, subcommands and avoiding common mistakes.

  • Building a new command-line tool's argument parsing with Optique
  • Runs TypeScript scripts from its folder
  • Adding a subcommand or new flag to an existing Optique-based CLI
  • Choosing the right value parser for validating a CLI argument

What it does

Lays out when to use `run()` from the run package for a full application versus `parse()` or `runParser()` to embed parsing elsewhere, and how `onError` and `help.onShow` callbacks supply structured error and help output rather than printing directly. Parsers are composed from combinators such as `object()`, `tuple()`, `seq()`, `or()` and `merge()` rather than hand-written argument scanning.

It also covers value parsers like `integer()`, `choice()`, `biject()`, `regExp()`, `url()` and `uuid()` for validating input as it is parsed instead of afterward, plus modifiers such as `optional()`, which yields undefined, and `withDefault()` for a fallback value. Testing has its own helpers: `parseArgs()` for parser results, `captureRun()` for runner output and exit codes, and `createCliRunner()` for exercising a real CLI end to end.

When your agent uses it

  • Building a new command-line tool's argument parsing with Optique
  • Adding a subcommand or new flag to an existing Optique-based CLI
  • Choosing the right value parser for validating a CLI argument
  • Writing tests for a CLI's parsing and help output

Example prompts

  • “Add a --format flag to this CLI that only accepts json, yaml or table.”
  • “Write a test that checks my CLI prints the right help text with no args.”
  • “Split this single parser into a deploy subcommand and a rollback subcommand.”

Requirements

  • The @optique/core and @optique/run packages

What it can do on your machine

Read from SKILL.md and the folder at commit f162fe0. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships script files (TypeScript), which the agent can run.

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • optique.dev

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Optique CLI Parser Patterns loads about 3.7k tokens when it runs. Until then it costs about 131 tokens; SKILL.md has 1,097 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~131
When it runs · the whole SKILL.md, loaded when a task matches
~3.7k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from dahlia/optique at commit f162fe0, republished under its MIT licence (© dahlia). 1,097 words, ~3,688 tokens.

Download SKILL.mdSave it as .claude/skills/optique/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
optique
description
Use this skill when writing any code that builds a command-line interface with Optique in TypeScript or JavaScript. Covers the combinatorial parser model, choosing @optique/core vs @optique/run, value parsers, structured messages, optional()/withDefault()/multiple(), subcommands with command() and or(), shell completion, async parsing, the integration packages, and common mistakes to avoid. Trigger whenever the user is parsing command-line arguments, building a CLI, or adding options or subcommands to a tool.
license
MIT

Start at https://optique.dev/llms.txt online; these rules also work offline.

Core rules

  • Use run() from @optique/run for apps, parse()/runParser() to embed.
  • With runParser(), onError(exitCode, error) supplies a structured Message; help.onShow(exitCode, page) supplies the final DocPage. Both follow output. Supply stdout: () => {} for custom help rendering. See https://optique.dev/concepts/runners.md#structured-help-callbacks.
  • In tests, use parseArgs()/parseArgsSync() from @optique/testing/parser for parser results, captureRun() from @optique/testing/run for runner output/exits, captureProgramRun() from @optique/testing/discover for dispatch, and createCliRunner() from @optique/testing/cli for real CLIs. Pin colors/maxWidth in tests; defaults use terminal and environment.
  • Compose parsers with object(), tuple(), seq(), or(), merge(), and modifiers. Do not hand-write argument scanners around Optique parsers.
  • For command/option help headings, set the runner's helpSections: { commands: "Commands", options: "Options" }. It groups untitled entries only on pages with visible commands. See https://optique.dev/cookbook.md#command-and-option-headings-in-help.
  • Let TypeScript infer results unless another API needs a separate interface.
  • Parsers usually require input. optional(p) yields undefined; use withDefault(p, value) or withDefault(flag("-v"), false) for fallbacks.
  • Use semantic message helpers; keep canonical errors unthemed. Since 1.3.0, theme/messageFormatter should preserve initialWidth, quoting, and width options. flag() has static/callback errors.unexpectedValue since 1.4.0. Mismatch callbacks may be skipped; avoid side effects.
  • Use value parsers such as integer(), choice(), biject(), regExp(), url(), origin(), and uuid() instead of validating raw strings after parsing. Use regExp({ flags }) for user-supplied sources, biject() for one-to-one mappings, transform() for mapped results, and choice(values, { key }) for custom string matching that returns the declared spelling. Use normalizeInput() for raw-string cleanup and path() from @optique/run/valueparser for file-system paths. Write a custom value parser only when these tools do not cover the domain.
  • Since 1.4.0, -p8080/-vp8080 accept attached values. Values consume the literal suffix (-p=5 gives "=5"); full single-dash names win.
  • Async value parsers like @optique/git make containing parsers async. Await run()/parse()/runParser() or, for bindKeyring(), runAsync().
  • Use dependency() when one value parser controls another's valid values. For a multi-level chain, wrap the middle derivation too: dependency(source.deriveSync(...)). Optique resolves such chains by dependency order, independently of object/tuple field order.
  • Use derivePromptConfig(source, resolver) (from @optique/prompt, re-exported by @optique/inquirer and @optique/clack) when a prompt's choices or message depend on another parsed value. The resolver may be async and runs only at the real prompt fallback, after the named sources resolve; pass [sourceA, sourceB] when it reads several sources. The resolver's prompt kind must return the wrapped parser's value type. Derive the wrapped parser separately when the CLI domain should change, and make it a dependency source only if another consumer needs its answer. Pass a lone resolver for fetched choices, forwarding its signal to the fetch.
  • Pass { validate, maxAttempts, signal } as a generated prompt wrapper's third argument, including prompt() from @optique/inquirer and @optique/clack. The validator returns undefined to accept the prompted value or a structured Message to retry, synchronously or asynchronously. Attempt limits must be positive integers and default to unlimited retries. Selection prompts keep their config and use the shared validate option.
  • Implement a custom adapter's execute(config, context) so retries can show context.previousValidationMessage, and forward context.signal when the prompt library supports aborting active work. Adapter-native validation remains separate and completes inside one shared attempt.
  • Build subcommands with command() combined by or(); add a literal field such as command: constant("serve") per branch for a discriminated union. Show hidden aliases in help with showAliases on command() or runner.
  • Use run(parser, { completion: "both" }) for completion, or the object form with completion.errors for custom shell errors. Do not hand-write scripts.
  • Use usageLine: [{ type: "ellipsis" }] in runner options when a large root synopsis should become a compact Usage: myapp ... line. This applies only to root full help; use command()'s usageLine for subcommand help.
  • Use showUsage: false in runner options when full help should show the brief and command or option sections without the Usage: synopsis. For deeply nested command trees, add commandList: "top-level" when root help should list only first-level command groups.
  • Use termWidth: "auto" in runner options when descriptions should align after the widest visible help term. Optique measures terminal display width after adding built-in help/version/completion entries.

Canonical app shape

typescript
import { object } from "@optique/core/constructs";
import { message } from "@optique/core/message";
import { withDefault } from "@optique/core/modifiers";
import { argument, flag, option } from "@optique/core/primitives";
import { integer, string } from "@optique/core/valueparser";
import { run } from "@optique/run";

const parser = object({
  input: argument(string({ metavar: "FILE" }), {
    description: message`Input file to process.`,
  }),
  port: withDefault(
    option("--port", integer({ min: 1, max: 65535 }), {
      description: message`Port to listen on.`,
    }),
    3000,
  ),
  verbose: withDefault(
    flag("-v", "--verbose", { description: message`Enable verbose logging.` }),
    false,
  ),
});

const config = run(parser, {
  brief: message`Process a file.`,
  completion: "both",
  showDefault: true,
  termWidth: "auto",
});

console.log(`Processing ${config.input} on port ${config.port}.`);
Show full SKILL.md (443 more words)Show less

Subcommands

Use command() for each branch and or() to require exactly one matching subcommand. Use optional(or(...)) only when no subcommand is valid.

typescript
import { object, or } from "@optique/core/constructs";
import { withDefault } from "@optique/core/modifiers";
import { parse } from "@optique/core/parser";
import { command, constant, flag, option } from "@optique/core/primitives";
import { integer } from "@optique/core/valueparser";

const parser = or(
  command("build", object({
    command: constant("build"),
    watch: withDefault(flag("--watch"), false),
  })),
  command("serve", object({
    command: constant("serve"),
    port: withDefault(option("--port", integer({ min: 1 })), 3000),
  })),
);

const result = parse(parser, ["serve", "--port", "8080"]);

if (result.success) {
  switch (result.value.command) {
    case "build":
      result.value.watch;
      break;
    case "serve":
      result.value.port;
      break;
  }
}

Custom value parsers

Prefer the built-in catalog first. If a one-to-one dictionary can describe the input tokens and domain values, use biject(). If an existing parser already accepts the right input syntax, wrap it with transform() before writing a custom parser:

typescript
import { biject, choice, transform } from "@optique/core/valueparser";

const exitCode = biject({
  ok: 0,
  warning: 1,
  error: 2,
});

const logLevel = transform(choice(["debug", "info", "warn", "error"] as const), {
  map(value) {
    return value.toUpperCase() as "DEBUG" | "INFO" | "WARN" | "ERROR";
  },
  unmap(value) {
    return value.toLowerCase() as "debug" | "info" | "warn" | "error";
  },
});

When a custom domain is needed, keep the validation in a value parser so help, errors, defaults, prompts, and completion all see the same typed value.

typescript
import { message } from "@optique/core/message";
import type { ValueParser, ValueParserResult } from "@optique/core/valueparser";

const levels = ["debug", "info", "warn", "error"] as const;
type Level = typeof levels[number];

function isLevel(input: string): input is Level {
  return (levels as readonly string[]).includes(input);
}

function logLevel(): ValueParser<"sync", Level> {
  return {
    mode: "sync",
    metavar: "LEVEL",
    placeholder: "info",
    parse(input: string): ValueParserResult<Level> {
      if (isLevel(input)) return { success: true, value: input };
      return { success: false, error: message`Invalid log level: ${input}.` };
    },
    format(value: Level): string {
      return value;
    },
  };
}

const parser = logLevel();

Common mistakes checklist

  • Pass parsers to run() for apps; use explicit argument arrays with parse() in tests and embedded use. Do not pre-parse process.argv.
  • Do not treat or(a, b) as “zero or more alternatives.” It requires one matching branch unless the whole or() is wrapped in optional() or withDefault().
  • Do not use object() for mutually exclusive subcommands. Use or(command(...), command(...)).
  • Do not forget that flag("--x") is required. Wrap it in optional() or withDefault(..., false) for ordinary optional flags.
  • Do not expect multiple(p) to fail when absent; it returns []. Wrap with nonEmpty() when at least one value is required.
  • Do not confuse free-order parsing with seq(). Most constructs let child parsers compete by priority; use seq() only for truly ordered grammars.
  • Use structured message values for errors and descriptions.
  • Register contexts for bindEnv(), bindConfig(), bindDerivedDefault(), and bindKeyring() in the runner's contexts option.
  • Use bindEnv().readFallback() for env/default in error handlers.
  • Enable showEnvironment for env-only help; set documentation.description.
  • Keep multi-level dependency graphs with dependency() rather than duplicating one-level factories.
  • Do not probe runtime capabilities eagerly before constructing a prompt parser. Put synchronous or asynchronous checks in the prompt config's when field and provide a typed otherwise value. The check then runs only if parsing reaches the prompt fallback.

For the detailed maintained guide, use https://optique.dev/pitfalls.md.

Integration packages

PackageUse forDocs
@optique/envEnvironment variable fallbackshttps://optique.dev/integrations/env.md
@optique/keyringAsync OS credential-store password fallbackhttps://optique.dev/integrations/keyring.md
@optique/configConfiguration file fallbackshttps://optique.dev/integrations/config.md
@optique/derived-defaultsDefaults computed from first-pass resultshttps://optique.dev/concepts/derived-defaults.md
@optique/promptGeneric prompt adapter foundationhttps://optique.dev/integrations/prompt.md
@optique/clackClack interactive fallback promptshttps://optique.dev/integrations/clack.md
@optique/inquirerInquirer.js interactive fallback promptshttps://optique.dev/integrations/inquirer.md
@optique/standard-schemaPortable schema-backed value parsinghttps://optique.dev/integrations/standard-schema.md
@optique/zodZod-backed value parsinghttps://optique.dev/integrations/zod.md
@optique/valibotValibot-backed value parsinghttps://optique.dev/integrations/valibot.md
@optique/temporalTemporal date and time parsershttps://optique.dev/integrations/temporal.md
@optique/gitAsync Git reference validationhttps://optique.dev/integrations/git.md
@optique/logtapeLogTape levels and formatter/output optionshttps://optique.dev/integrations/logtape.md
@optique/manMan page generationhttps://optique.dev/concepts/man.md
@optique/discoverFile-based command discoveryhttps://optique.dev/concepts/discover.md
@optique/testingLayered CLI testing at a chosen boundaryhttps://optique.dev/concepts/testing.md

© dahlia, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in packages/core/skills/optique of dahlia/optique.

  • SKILL.md
  • SKILL.test.ts

Open the folder on GitHubat commit f162fe0

Compare with similar skills

Optique CLI Parser Patterns next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Optique CLI Parser Patterns compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Optique CLI Parser Patterns this skilldahlia/optique737—~3.7kAutomated safety check: PassMIT
Code Review ChecklistshareAI-lab/learn-claude-code78k5 repos~1.1kAutomated safety check: PassMIT
Install Anti-Slop Oxlint Rulesdmmulroy/anti-slop5.3k1 repos~2.2kAutomated safety check: PassMIT
Generate Release Notesteambit/bit18k—~2.2kAutomated safety check: PassCustom licence
Pnpm Engineteambit/bit18k—~1.9kAutomated safety check: PassCustom licence
Convert Internal Package to TypeScriptTryGhost/Ghost55k—~1.2kAutomated safety check: PassMIT

Similar skills

  • Code Review Checklist

    shareAI-lab/learn-claude-code

    Reviews code against a five-part checklist covering security, correctness, performance, maintainability and testing, and reports findings in a fixed format.

    78k GitHub starsUsed in 5 repos~1.1k tokens
    DevelopmentAuto-check passed
  • Installs, updates or migrates the vendored anti-slop Oxlint plugin in a repository, keeping local rule changes and the plugin's license and provenance files.

    5.3k GitHub starsUsed in 1 repo~2.2k tokens
    DevelopmentAuto-check passed
  • Generate comprehensive release notes for Bit from git commits and pull requests.

    18k GitHub stars~2.2k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Pnpm Engine

    teambit/bit

    Work on the pnpm Rust engine (@pnpm/napi, the pacquet crates) that bit install runs through.

    18k GitHub stars~1.9k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Moves a legacy internal Ghost package from JavaScript and CommonJS to TypeScript and ESM in three focused commits that keep git file history intact.

    55k GitHub stars~1.2k tokensUpdated today
    DevelopmentAuto-check passed
  • Measures a code port between languages or frameworks with jscpd's function-level comparison, porting tests before code and tracking what is left unmatched.

    6.4k GitHub stars~5k tokensUpdated yesterday
    DevelopmentAuto-check passed

More from dahlia/optique

  • Release

    dahlia/optique

    Create and publish releases for the Optique project. An agent skill from dahlia/optique.

    737 GitHub stars~1.9k tokensUpdated 2 days ago
    Auto-check passed

Categories

Questions about Optique CLI Parser Patterns

What does Optique CLI Parser Patterns do?

Guides writing command-line interfaces with the Optique TypeScript library: composing parsers, choosing value types, subcommands and avoiding common mistakes. onShow` callbacks supply structured error and help output rather than printing directly. Parsers are composed from combinators such as `object()`, `tuple()`, `seq()`, `or()` and `merge()` rather than hand-written argument scanning.

When should I use Optique CLI Parser Patterns?

Optique CLI Parser Patterns fits situations like: building a new command-line tool's argument parsing with Optique; adding a subcommand or new flag to an existing Optique-based CLI; choosing the right value parser for validating a CLI argument; writing tests for a CLI's parsing and help output.

How do I install Optique CLI Parser Patterns in Claude Code?

Run `npx skills add dahlia/optique --skill optique -a claude-code`. Or copy the skill folder (packages/core/skills/optique in dahlia/optique) into .claude/skills/optique in your project. Claude Code loads it when a task matches its description.

How do I install Optique CLI Parser Patterns in Codex?

Run `npx skills add dahlia/optique --skill optique -a codex`. Or copy the skill folder (packages/core/skills/optique in dahlia/optique) into .agents/skills/optique in your project. Codex loads it when a task matches its description.

Can I use Optique CLI Parser Patterns in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add dahlia/optique --skill optique -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/optique, .gemini/skills/optique, .github/skills/optique and .opencode/skills/optique in your project.

What does Optique CLI Parser Patterns need to run?

Going by SKILL.md and its folder, Optique CLI Parser Patterns needs TypeScript for the scripts in its folder. Our summary lists: The @optique/core and @optique/run packages.

Does Optique CLI Parser Patterns access the network?

SKILL.md names 1 domain. As links in the text: optique.dev. This is read from the text; nothing was executed.

Is Optique CLI Parser Patterns safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Optique CLI Parser Patterns use?

Optique CLI Parser Patterns is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Optique CLI Parser Patterns use?

About 3.7k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Optique CLI Parser Patterns?

Skills that share tags, products or a category with Optique CLI Parser Patterns: Code Review Checklist (shareAI-lab/learn-claude-code, 78k stars), Install Anti-Slop Oxlint Rules (dmmulroy/anti-slop, 5.3k stars), Generate Release Notes (teambit/bit, 18k stars) and Pnpm Engine (teambit/bit, 18k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Optique CLI Parser Patterns?

dahlia (a GitHub user) maintains it in dahlia/optique, which has 737 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on October 6, 2026.

Source: dahlia/optique on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.