Expand description
What a command writes, and how a consumer should read it.
A spec has always described a command’s inputs exhaustively and its outputs not at
all. Across the jdx.dev fleet that gap is 123 hand-written flag declarations in three
incompatible spellings — mise and pitchfork say -J --json, hk says
--format=human|json|jsonl, aube says both --json and
--reporter=default|append-only|ndjson|silent — and not one of them says what the
JSON contains.
cmd "check" {
output "human" default=#true help="Human-readable report"
output "json" media_type="application/json" framing="json" help="One report object" { schema #"""{…}"""# }
output "xml" media_type="application/xml" help="One XML document"
output "jsonl" framing="jsonl" help="One event per line" { schema #"""{…}"""# }
select "--format"
}§Name, media type, and framing are not the same thing
The positional is the token a user types, media_type identifies the content, and
SpecOutput::framing says how a consumer reads the stream. They are separate because
XML and prose are both read to the end despite having different media types, while aube spells its line-delimited output
ndjson and hk spells the identical wire format jsonl: a generated SDK that keyed
off the name would offer exec_ndjson() for one and exec_jsonl() for the other, and
a caller would be back to knowing which CLI they were talking to — the thing this
exists to delete.
§Two ways to ask, one model
A command-level select "--format" names a flag whose value picks an output. An
output "json" select="--json" names a boolean flag whose presence picks that one.
Both are common in the wild and both lower here; SpecOutput::select_argv answers
“which words pick this” so no consumer has to know which spelling was used.
§Selection is resolved, not just recorded
[resolve_selectors] runs once after the whole document is read and fills the
selecting flag’s choices from the output names. That is what lets completion, the
docs renderers, the fig exporter and the SDK choice types all work without any of them
learning about outputs. Two consequences worth knowing before reading a re-emitted
spec, both documented on docs/spec/reference/output.md:
- the choices appear in the output even though the source did not write them, the same
way
includeandflagsetexpansion do not survive a round trip; - a
selectnaming an inherited global gets a narrowed copy of that flag inside the command, because two commands under one global rarely produce the same outputs.
Resolution is idempotent: a second pass sees choices that already match and validates them instead of rewriting, so a spec that has been through it round-trips unchanged.
Structs§
- Spec
Output - One thing a command can write.
Enums§
- Framing
- The wire format of what a command writes to stdout.
- Selector
- How a command’s output is asked for.
Functions§
- effective_
outputs - The outputs in effect for a command, CLI-wide declarations folded in.
- effective_
outputs_ ref - Reference-based form used by tree walkers that already hold the command chain.
- effective_
select - The value-taking selector in effect for a command, if it reaches that command.
- effective_
select_ ref - Reference-based form used by tree walkers that already hold the command chain.
- has_
outputs - Whether anything at all is declared, so a consumer can skip the whole concept.