跳到正文
cccskills
免费在 GitHub 公开

meta-planning-cli-planning

CLI specification frameworks — flag contracts, prompt flows, config precedence, exit codes, output per context (TTY, piped, JSON), error and help text, signals and cross-platform behaviour. Use when a spec adds or changes a command surface, an interactive flow, a config key, an exit path or what a command prints.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(3)

  • SKILL.md20.5 KB
  • examples/core.md22.7 KB
  • metadata.yaml524 B

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

CLI Planning Patterns

Quick Guide: A command's flags, exit codes, output streams and config keys are contracts that humans, scripts and CI all branch on, so the spec states each one the feature touches — user-facing text verbatim — and leaves out the sections it does not touch. Four facts change the answer more often than taste does: a secret never takes a flag value; Ctrl+C at a key-reading prompt is a keypress, not a signal; exiting 130 is not the same as dying by SIGINT; and prompts render on stdout unless the spec moves them.

Detailed Resources:

  • examples/core.md — a fill-in template for each section below, and a worked specification for a deploy command that uses them

Which sections the spec needs

Each section governs one kind of contract. Include it only when the spec touches that contract — a section filled with placeholders reads as a decision nobody made.

  • Adds or changes a command, argument or flag — Command Surface, Exit-Code Contract and Output Contract (Patterns 1, 4 and 5).
  • Adds or changes a prompt or a wizard step — Interactive Flow (Pattern 2).
  • Adds or changes a config key — Configuration Precedence (Pattern 3), one table per key.
  • Changes only messages, help or diagnostics — Error Messages and Help Text (Pattern 6).
  • Runs longer than an instant, or writes anything — Signal Handling and Cancellation (Pattern 7), on top of whatever else applies.
  • Touches paths, files or terminal capabilities — Cross-Platform Concerns (Pattern 8).

When none of these holds, the feature has no CLI contract and the spec carries no CLI section.


<critical_requirements>

Before specifying a CLI change

Read the closest existing command first, and reuse its flag names, prompt helpers, config resolver, exit-code constants and output helpers. They are the vocabulary the spec has to speak; a spec that invents its own ships a CLI with two conventions, and leaves the developer to pick which one is wrong.

Give every prompted value a non-interactive twin, and state what happens with no TTY and no twin. A value only a prompt can supply makes the command unusable in CI, and nobody finds out until a pipeline hangs.

Give every terminating path an exit code, named by its constant, with cancellation kept apart from failure. Scripts branch on the code, so a path the spec leaves open exits with a number the developer chose and nobody documented.

Specify output for every context — TTY, piped, --json, quiet, verbose — and which stream carries the payload. stdout is what a pipe captures, so anything else written there corrupts the consumer's input.

State config precedence per key as a table, with the merge rule for arrays and objects. "Merged" without a rule gets implemented as replace in one place and concatenate in another.

</critical_requirements>


Auto-detection: CLI spec, command surface, subcommand design, flag contract, --json output, --dry-run, --yes, --no-input, non-interactive mode, prompt flow, wizard step, exit codes, exit status 130, SIGINT, SIGTERM, NO_COLOR, FORCE_COLOR, config precedence, help text, flag deprecation

Applies to:

  • Specifying a new command or subcommand — arguments, flags, aliases, help
  • Specifying an interactive flow — prompt order, keys, cancellation, the non-interactive path
  • Config keys and the order they resolve in
  • Exit codes, output per context, error text and signal behaviour
  • Changing an existing surface without breaking the scripts that call it

Handled elsewhere:

  • Implementing the command — parser declarations, prompt code and rendering belong to the implementation; this skill fixes the contract they implement.
  • The spec's general sections — goal, scope fence, file references and success criteria — belong to whoever writes the spec; this skill supplies the CLI sections that sit inside it.
  • Contracts for an HTTP API or a UI — status codes, request shapes and UI states are planned with frameworks of their own.

<philosophy>

Philosophy

A CLI's public API is bigger than its code. Flags, exit codes, output streams and config keys are what humans, scripts and CI branch on, and a contract the spec leaves implicit is one the developer invents and nobody documents.

So the spec answers three callers at once: a human at a TTY, a script piping the output, and CI with no TTY at all. User-facing text is written verbatim, because approximate wording produces a CLI that words one failure five ways. Cancellation and cleanup are stated as invariants a tester can assert, not as intentions.

The spec's size follows the surface it changes. A flag-only change needs no prompt-flow table, a new exit code is proposed only when no existing class fits, and a new subcommand only when a flag on an existing command cannot do the job. Handler bodies and parser wiring stay out — the spec fixes contracts, not code.

</philosophy>

<decision_framework>

Argument, flag, subcommand or prompt

Decided by the value's role, not by preference:

Is the value the thing the command acts on, and supplied in almost every call?
├─ YES → positional argument (app deploy <environment>)
└─ NO  → Does it change how the command behaves?
    ├─ YES → flag (--dry-run, --force, --concurrency=4)
    └─ NO  → Does it select a different operation altogether?
        ├─ YES → subcommand (app config get | app config set)
        └─ NO  → Can only the human at the terminal supply it?
            ├─ YES → prompt, with a twin that supplies the same value
            └─ NO  → derive it from config or the filesystem; do not ask

Prompt, derive or refuse

Can the value come from a flag, config or the filesystem?
├─ YES → derive it; do not prompt
└─ NO  → Is stdin a TTY, with prompting not switched off?
    ├─ NO  → usage error naming the twin that supplies the value
    └─ YES → Is the action destructive or expensive?
        ├─ YES → confirm, skippable with --yes
        └─ NO  → prompt, pre-filled with the best default

</decision_framework>


<patterns>

Core patterns

Pattern 1: Command Surface

Each flag is a row carrying what its parser declaration needs: long and short name, type and unit, default, env var, and conflicts — the combinations that are a usage error rather than a silent winner. Whether it is required, which flags it implies and whether help hides it go with it where they apply.

| Long        | Short | Type    | Default | Env Var       | Conflicts | Description                    |
| ----------- | ----- | ------- | ------- | ------------- | --------- | ------------------------------ |
| `--dry-run` | -n    | boolean | false   | —             | —         | Print the plan, change nothing |
| `--timeout` | —     | seconds | 300     | `APP_TIMEOUT` | —         | Per-phase timeout              |

The spec also states:

  • Short flags only for flags used constantly, checked against every sibling command — a one-letter collision is found by a user, not a reviewer.
  • Booleans default to false; --no-<flag> exists only where the default is true.
  • Repetition — whether --tag a --tag b accumulates or the last one wins.
  • Aliases, with the canonical name help shows.
  • Prefix matching — whether the parser accepts an unambiguous prefix of a long flag.
  • Names and depth — commands lowercase, in the codebase's existing verb or noun-verb form; long flags spelled out in kebab-case; subcommands at most two levels deep (noun, then verb) unless the existing commands already go deeper.
  • Compatibility, for every renamed or removed flag: what old invocations do now, the deprecation warning on stderr, the release that drops the alias, and whether the exit code changes.

Template: examples/core.md

Pattern 2: Interactive Flow

Prompt only for what cannot be derived, and give each step a table that ends in its non-interactive twin.

| Element      | Specification                                     |
| ------------ | ------------------------------------------------- |
| Reached when | No environment from the argument or config        |
| Prompt type  | select                                            |
| Message      | `Deploy to which environment?`                    |
| On cancel    | stderr `Cancelled.`, exit 130, nothing written    |
| Twin         | positional `environment`, or `defaultEnvironment` |

The spec also states:

  • A secret's twin — stdin or a file (--password-file), never a flag value. Whether an environment variable is accepted as well is a decision to write down: CI tooling expects one, and every child process can read it.
  • The switch that turns prompting off even at a TTY — --no-input, or the codebase's existing equivalent.
  • Accelerator keys — whether they are case sensitive, and whether they go inert while a text input or filter has focus; a live accelerator swallows the characters the field needed.
  • Keys — when a step adds any beyond the defaults, what arrows, Space, Enter, Tab, Escape, Ctrl+C and any single-letter accelerator do there; a key the spec leaves out does whatever the prompt code happens to do.
  • Terminal size — the minimum usable width, what degrades first — for a grid or table, the order its columns drop in — and whether the flow redraws on resize.
  • Back and forward — which steps are revisitable, and what survives the return.
  • Resumability — whether partial progress persists, where, and what a re-run does with it. "Nothing persisted" is a decision; leaving the line out is not.

Template: examples/core.md

Pattern 3: Configuration Precedence

Config is a table per key, because the resolution order is the contract and prose leaves it to be inferred.

| Precedence  | Source               | Identifier                              |
| ----------- | -------------------- | --------------------------------------- |
| 1 (highest) | Flag                 | `--region`                              |
| 2           | Environment variable | `APP_REGION`                            |
| 3           | Project config       | `region` in `./app.config.ts`           |
| 4           | User config          | `region` in `~/.config/app/config.json` |
| 5 (lowest)  | Built-in default     | `us-east-1`                             |

The spec also states, per key:

  • The layers it participates in — not every key exists at every layer.
  • Merge semantics — scalars take the highest layer that sets them; arrays and objects say replace, concatenate, or shallow or deep merge.
  • Absent versus empty — whether --tag "" or tags: [] overrides a lower layer or counts as unset.
  • Discovery — which filenames, searched from where, how far up, and the tie-break when two match.
  • Validation — on load or on use, and the exit code an invalid value produces.
  • Write-back — which file and layer a write lands in, whether comments and key order survive, and whether the write is atomic.

Template: examples/core.md

Pattern 4: Exit-Code Contract

Every terminating path gets a code and every code a documented meaning; scripts branch on them as they do on flags.

| Code     | Meaning                                                              |
| -------- | -------------------------------------------------------------------- |
| 0        | Success                                                              |
| 1        | Generic runtime failure                                              |
| 2        | Usage error — bad flag, missing argument                             |
| 3–125    | Domain classes the codebase defines                                  |
| 126, 127 | Set by the shell: found but not executable, not found                |
| 128+N    | Set by the shell: killed by signal N — 130 is SIGINT, 143 is SIGTERM |

Domain codes stay inside 3–125: a status is truncated to its low 8 bits, and the shell already gives 126 and above a meaning of its own.

The spec also states:

  • Existing constants reused — a new code only where no class fits, named by its constant rather than its number.
  • One code per failure class a caller acts on differently — two failures a script handles alike share a code.
  • Cancellation apart from failure — Ctrl+C and a declined confirmation exit with a code no failure uses.
  • Partial success — fail the run, or succeed with a code that says some items failed; either way, decided.
  • --dry-run exits 0 on a valid plan and with the real run's failure code otherwise, or CI cannot trust a passing dry run.

Template: examples/core.md

Pattern 5: Output Contract

stdout carries the data the caller asked for; stderr carries everything else — progress, warnings, diagnostics and prompts — so progress survives piping without corrupting the pipe.

| Context         | Progress            | Colour  | Payload                          |
| --------------- | ------------------- | ------- | -------------------------------- |
| TTY, default    | Spinner or progress | Yes     | Human-readable summary, stdout   |
| Piped (non-TTY) | Plain lines, stderr | No ANSI | Same payload, no decoration      |
| `--json`        | None                | None    | One JSON document, stdout        |
| `--quiet`       | None                | None    | Payload only; errors still shown |
| `--verbose`     | Per-step detail     | On TTY  | Payload plus diagnostics         |

The spec also states:

  • The --json shape, the error shape included — valid JSON on failure too, and nothing else on stdout.
  • Colour — off when the stream is not a TTY, TERM is dumb, --no-color is passed, or NO_COLOR is set to a non-empty value; a flag or user config overrides NO_COLOR. FORCE_COLOR is a convention rather than a standard — Node, for one, lets it override NO_COLOR — so the spec says which wins when both are set.
  • The quiet and verbose ladder — what each level suppresses or adds, whether each combines with --json, and which wins when they do not.
  • Progress — which operations show it and what each phase says: a spinner for waits of a few seconds, a count or percentage for longer ones.
  • No-op output — the exact message when a re-run has nothing to do, or silence written down as the decision. A short message such as Already up to date. is usually the better default, because silence leaves the user unsure whether anything ran.
  • A closed pipe — what the command does when the reader exits early (app list | head -1), and with which code.

Template: examples/core.md

Pattern 6: Error Messages and Help Text

Each error has four parts, written verbatim: what failed, named as the user named it; why, in the user's vocabulary; how to fix it, as a concrete command or edit; and where to look, when a file, config key or doc page is involved.

BAD:  Error: ENOENT
GOOD: Error: config file not found at ./app.config.ts.
      Run 'app init' to create one, or pass --config <path>.

The spec also states:

  • Errors on stderr, with no stack trace by default — and the flag or env var that reveals one.
  • Unknown commands and flags — whether a "did you mean" suggestion appears, and its matching rule. It suggests; it never runs the guess.
  • Validation errors naming the offending value and the accepted set.
  • Another tool's failure quoted as that tool reported it, not paraphrased.
  • Help per command — summary, usage line with argument arity, arguments, grouped flags, at least two real invocations and related commands, reachable as --help, -h and help <command>.

Template: examples/core.md

Pattern 7: Signal Handling and Cancellation

For a command that runs longer than an instant or writes anything, cleanup is an invariant a tester can assert:

After SIGINT during upload, no `.staging/` prefix remains under the target,
and the caller sees the process killed by SIGINT (status 130).

The spec settles each of:

  • SIGINT — the message, how fast it returns, and the exit status: a code, or the signal re-raised after cleanup.
  • SIGTERM — the same path as SIGINT, or a distinct one.
  • In-flight work — finished, abandoned or rolled back.
  • Partial writes — which files can be left half-written, and how a re-run recovers (atomic rename, lock file).
  • Terminal restoration — cursor, raw mode, alternate screen, colour reset.
  • Cleanup — temp files, lock files, child processes, open handles.
  • A second Ctrl+C — skips cleanup and exits now, or is ignored; the first one says which.
  • Prompt cancellation — what a cancelled prompt does: the same message and exit as SIGINT, or its own. A prompt that reads single keys has to be routed there explicitly, because raw mode turns Ctrl+C into a keypress the SIGINT handler never sees.

Template: examples/core.md

Pattern 8: Cross-Platform Concerns

Include the ones that apply, and name the ones deliberately out of scope.

  • Paths joined with the platform separator; user-supplied paths resolved against the cwd or against the config file, stated.
  • Home and config directories from the platform API, which reads USERPROFILE on Windows and HOME elsewhere; the config location per platform where they differ.
  • Case — whether two names differing only by case collide: distinct on Linux, one file by default on macOS and Windows.
  • Line endings written, and whether input endings survive.
  • Shell quoting in help examples, valid in every shell the project supports.
  • Executable bits on any file the command creates that has to run.
  • Long paths and reserved names for generated file names on Windows.
  • Unicode — the fallback glyphs where the terminal lacks it.

Template: examples/core.md

</patterns>

<red_flags>

Red flags

Breaks at runtime:

  • A secret accepted as a flag value — it lands in ps output and shell history. Read it from stdin or a file.
  • Prompts left on their default stream — prompt libraries and line-input builtins commonly render on stdout, so app init > plan.txt writes the questions into the file and leaves the user at a blank wait. Name stderr in the spec.
  • Prompt cancellation specified as "handled by the SIGINT handler" — a prompt that reads single keys puts the terminal in raw mode, where Ctrl+C arrives as a byte and no signal fires. Give the prompt's cancel its own path.
  • Exiting 130 after catching SIGINT, in a command that scripts call — a normal exit with 130 is not a death by SIGINT, so the calling shell script runs its next command. Specify re-raising the signal after cleanup.
  • A domain exit code above 125 — 126, 127 and 128+N already mean something to the shell, and the status is truncated to 8 bits, so 256 reads as success. Keep domain codes within 3–125.
  • A closed pipe left unspecified — the next write fails with EPIPE, a runtime that ignores SIGPIPE raises it as an error, and app list | head prints a stack trace. State the quiet exit.
  • A --json mode with no error shape — the consumer's parser fails on exactly the run it most needs to read.
  • A flag renamed or removed with no deprecation path — the scripts that used it break, and nobody reports it.
  • A writing command with no cancellation invariant — Ctrl+C leaves half-written files and a hidden cursor.
  • "Follows existing patterns" with no file reference — nothing verified the pattern exists, so the developer invents one and the CLI gains a second convention.

Surprising behaviour:

  • NO_COLOR set to an empty string leaves colour on; only a non-empty value disables it.
  • A parser that accepts unambiguous long-flag prefixes makes each new flag a potential break: --verb resolves to --verbose until --verbatim ships, and then it is an ambiguity error in every script that used it.

</red_flags>

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

中文简介正在准备中。当前显示原文说明。

agents-inc/skills252026年10月17日 更新

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

中文简介正在准备中。当前显示原文说明。

agents-inc/skills252026年10月17日 更新

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

中文简介正在准备中。当前显示原文说明。

agents-inc/skills252026年10月17日 更新

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

中文简介正在准备中。当前显示原文说明。

agents-inc/skills252026年10月17日 更新

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

中文简介正在准备中。当前显示原文说明。

agents-inc/skills252026年10月17日 更新

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

中文简介正在准备中。当前显示原文说明。

agents-inc/skills252026年10月17日 更新

查看 agents-inc 的全部技能

报告此技能的问题