# Documenting a command-line interface

To document a command-line tool so an agent can run it correctly, describe it in a file — the way
an HTTP API is described in OpenAPI — and package that. `docspack build --cmdspec` reads the
description and writes one chunk per command, each saying how to run that command and what
running it does:

```bash
npx docspack build --cmdspec ./cmdspec.yaml --name @acme/docspack --pkg-version 1.4.0
```

Combine it with `--from`, and with `--openapi`, to publish prose, an API and a CLI in one package,
or put it in the `docspack` key of the package's `package.json`:

```json
{
  "docspack": {
    "from": "./docs",
    "cmdspec": "./cmdspec.yaml"
  }
}
```

The file is [cmdspec](https://docspack.dev/cmdspec), an open format for describing a command line.
docspack reads two others as well, converting them: a [Usage](https://usage.jdx.dev) spec (KDL),
which many Rust, Go and Python CLIs can export, and an [OpenCLI](https://opencli.org) document.

A Node CLI built with commander, citty or yargs need not be described by hand.
`@docspack/cmdspec/emit` reads the program and writes the document — `fromCommander(program)`,
`await fromCitty(command)`, `await fromYargs(() => buildProgram(), { version })` — with every
command, option and argument the program parses. What a framework does not know, add to the
result: effects, exit statuses, outputs, examples.

## What one chunk contains

Everything needed to run the command, in the shape of a help page, with what help pages leave
out spelled in words: the types and defaults of its inputs, where a value can come from, what the
command changes, what it prints and what its exit statuses mean. The command's own prose comes
first, where a question is matched against it. Shortened, the chunk for `docspack ask`:

```text
docspack ask <question>... [options]
  Answer from the local index — the command to give an agent
  <question>...  words are joined with spaces
  -p, --package <s>  only packages whose name contains this text
  --limit <n>  maximum chunks to return (integer; at least 1; default 3)
  also accepts: --store <path>, --cwd <dir>, --json, -q, --quiet
  effects: read; idempotent
  stdout: text/markdown, the answer; application/json, the chunks and their scores with --json
  exit: 0 success; 1 the command failed; 2 the command was used wrongly; 3 nothing matched, and a docs package is installed but not indexed
  $ docspack ask "how do I verify a webhook signature"
```

`effects` is the line an agent most needs and a help page never has: whether running the command
reads, writes, deletes, talks to the network or runs other programs. A command that does not state
its effects says `effects: not stated`, never nothing, so an agent cannot mistake silence for
safety.

The package also gets an overview chunk: the program's prose, the options every command accepts
with what they do, and one line per command — or the top-level commands only, for a CLI too large
to list in one answer.

## Asking for one command

A command path is a key, not a phrase. Ranked as prose, `git remote add` matches every chunk that
mentions remotes; named in a question, it pins its chunk ahead of anything the ranker found:

```bash
docspack ask "git remote add origin https://example.com/repo.git"
docspack ask "what does git remote rm do"     # an alias reaches its command
```

The longest path the question names wins, so the first question gets `git remote add`, not
`git remote` as well. Paths match exactly, as typed: command names are case-sensitive.

## A CLI you depend on can describe itself

docspack describes its own this way — `docspack --cmdspec` prints the document its parser and its
`--help` are generated from, and [its reference](https://docspack.dev/cli) is rendered from the
same file — and any package can do the same.

A package that ships a CLI can name its cmdspec document in its own `package.json`:

```json
{
  "name": "acme",
  "version": "4.2.0",
  "bin": { "acme": "./bin/acme.js" },
  "cmdspec": "./cmdspec.json"
}
```

`docspack sync` then indexes that CLI for exactly the version installed, beside its type
declarations, and `docspack ask` answers from it — ranked like documentation, and pinned when a
question names a command. A description of a different version than the one installed is
reported and skipped, never indexed: it would answer with a command line the installed program
does not accept.

## What build checks

An invalid description stops the build, listing every problem. One that is valid but answers
worse is built, with a warning for each gap: commands without a summary, without an example,
without stated effects, or a CLI that says nothing about its exit statuses. `docspack doctor` runs
the same checks against the file `docspack.cmdspec` names, so CI catches a description that drifts
after the payload was built.

`npx @docspack/cmdspec validate ./cmdspec.yaml` checks a description on its own, and
`npx @docspack/cmdspec convert` turns a Usage or OpenCLI document into cmdspec.
