CLI Output Contract v1 (Incur-aligned)
Status: Revised after incur behavior validation
Scope: All @spectratools/*-cli packages
1) Purpose
This document defines the output contract we expect across spectra-tools CLIs without re-implementing behavior already provided by incur.
v1 policy is now split into:
- Framework contract (inherited from incur) — required as-is.
- Spectra package policy — conventions we enforce in docs/tests and package command design.
2) Incur-native runtime contract (required)
These are framework semantics and must be treated as source-of-truth unless we intentionally upgrade/change incur.
2.1 Global built-ins (do not reimplement)
Every CLI already gets:
- Built-in commands:
completions,mcp add,skills add - Built-in flags:
--format,--json,--verbose,--llms,--mcp,--schema,--filter-output,--token-count,--token-limit,--token-offset,--help,--version
2.2 Output format defaults
- Default format is
toon. --jsonis alias for--format json.- Supported formats are framework-defined (
toon,json,yaml,md,jsonl).
2.3 Envelope semantics
In CLI mode:
--format json(or--json) without--verbose:- success →
dataonly - error →
errorobject only
- success →
--format json --verbose:- full envelope (
ok,data|error,meta)
- full envelope (
Representative verbose JSON shape:
{
"ok": true,
"data": { "...": "..." },
"meta": {
"command": "registration create",
"duration": "1ms"
}
}Notes:
meta.ctamay be present when command returns CTA viac.ok(..., { cta })/c.error(..., { cta }).meta.nextOffsetmay be present with token truncation (--token-limit+--verbose).
2.4 Error/exit behavior
- Framework errors serialize through the same output channel selected by format.
- Non-success exits are framework-managed (commonly
1unless explicitly overridden). - Domain-specific codes (e.g.
NO_PRIVATE_KEY,INVALID_IDENTIFIER) remain valuable and should stay stable.
2.5 Discovery and integration
skills add,mcp add,--llms, and--mcpare built-in and should be documented/used directly.
3) Spectra package policy (v1)
3.1 Machine-consumption profiles
We support two explicit machine profiles:
- Data profile (default for scripts):
--json- parse direct data on success, direct error object on failure.
- Envelope profile (for orchestration/telemetry):
--json --verbose- parse
ok/data/error/metaenvelope.
- parse
3.2 Human default
- Keep incur default
toonoutput for interactive usage. - Do not force a cross-repo default switch to JSON.
3.3 Pagination policy
- Use incur token pagination when output-size pagination is needed:
--token-count,--token-limit,--token-offset
- Keep command/domain pagination flags (
--limit,--max-results,--page,--offset, cursor args) command-specific. - Do not introduce new cross-cutting global page flags in v1.
3.4 Mutating commands and dry-run
--dry-runis a package-level feature, not an incur global.- Add it only on mutating commands where preview semantics are clear and testable.
- When implemented, docs/tests must prove no side effects occur.
3.5 CTA usage
- Prefer incur-native CTA support (
c.ok/c.errormetadata) rather than custom top-level CTA envelope shims.
4) Incur Alignment Notes
tableis not an incur global output mode; do not define contract requirements around it.- A custom always-on envelope (
ok/data/meta/error) in non-verbose JSON would fight framework defaults. skills add,mcp add, and--llmsare first-class built-ins; do not duplicate them in package code.- Global verbosity/quiet policy should not assume flags that incur does not provide globally.
5) Explicit "do not duplicate framework features"
Do not build repo-level abstractions that duplicate or override incur unless there is a versioned product decision to diverge. Specifically, do not add:
- custom global flag parser for built-in incur flags
- custom output envelope wrapper that changes non-verbose JSON semantics
- custom replacements for
skills add,mcp add, or--llms - synthetic global pagination flags when token pagination already exists
If we need behavior beyond incur, document it as an intentional extension with package scope and tests.
6) Contract examples
6.1 Data profile
erc8004 registration create --name Test --json{
"name": "Test",
"erc8004": { "version": "0.1.0" }
}6.2 Envelope profile
erc8004 registration create --name Test --json --verbose{
"ok": true,
"data": {
"name": "Test",
"erc8004": { "version": "0.1.0" }
},
"meta": {
"command": "registration create",
"duration": "1ms"
}
}7) Backward compatibility impact
This revision reduces migration risk versus the earlier draft by aligning with current runtime behavior:
- no forced default-format change to JSON
- no mandatory custom envelope layer
- no immediate global pagination/quiet flag refactor
Primary follow-on work is docs/test alignment plus targeted command-level improvements (dry-run where it matters, stable domain error codes, CTA consistency).