mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-09-14 20:16:53 +08:00
5.6 KiB
5.6 KiB
openspec change vs spec: behavior differences and recommendations
This document compares how openspec change and openspec spec behave today (focused on show and list) and recommends a raw-first, minimal standard to keep behavior simple and predictable before adding smarter formatting later.
Summary of key differences and recommendations
| Area | Current: change | Current: spec | Recommendation |
|---|---|---|---|
| Invocation (show) | openspec change show [change-name] auto-picks when only one active change |
openspec spec show <spec-id> requires id |
Require explicit IDs for both. If change-name is omitted, print available IDs and a short hint (e.g., use openspec change list) and exit non-zero. No auto-pick. No interactive picker. |
| Default text output (show) | Raw proposal.md content |
Formatted summary | Default both to RAW: print the underlying Markdown file as-is. Provide a future --pretty flag (non-default) for formatted output. |
| Filtering flags (show) | --requirements-only affects text and JSON |
--requirements, --no-scenarios, -r/--requirement |
Raw-first: in TEXT mode, no filtering. All filtering applies only to JSON output. Deprecate text-mode filters. Keep minimal JSON filters only. |
| JSON shape (show) | Full change object; --requirements-only can return an array |
Filtered object | Always return an OBJECT. Minimal, stable shape. Change: { id, title, deltaCount, deltas, taskStatus? }. Spec: { id, title, overview, requirementCount, requirements, metadata }. No top-level arrays. |
| Text output (list) | "Active Changes" with progress | "Available Specifications" with teaser | Default both to RAW/minimal: print IDs only by default. Add --long to show id + title and minimal details (counts). No teasers. |
| JSON shape (list) | [{ name, title, deltas, taskStatus }] |
[{ id, title, overview, requirementCount }] |
Unify minimal keys: id, title, counts only. Change: deltaCount, taskStatus. Spec: requirementCount. Drop overview from list JSON. Sort by id. |
| Error/exit policy | Spinner + process.exit(1) in some paths |
exitCode in others |
Raw-first: no spinners in errors. Use console.error + process.exitCode = 1 consistently. |
| Empty states (list) | Graceful | Errors if specs missing | Raw-first: graceful empty state everywhere. Print "No items found" and exit 0. |
| Multi-selection (change show) | Auto-pick single; error when multiple | N/A | Keep auto-pick single. If multiple, print IDs inline and exit non-zero. No interactive prompts. |
| Colors/TTY | Mixed | Chalk only | Raw-first: minimal color; honor NO_COLOR and add --no-color. |
Detailed guidance
1) Unify flags and semantics (raw-first)
- Text mode: no filters; just raw file content.
- JSON mode: allow minimal filters only.
- Specs:
--jsonreturns the structured spec. Optional:-r/--requirement <n>and--requirements-onlyapply to JSON only. - Changes:
--jsonreturns the structured change. Optional:--deltas-onlyapplies to JSON only.
- Specs:
- Deprecate text-mode filtering flags across both commands.
- Optional future:
--pretty(text formatting) as a non-default enhancement.
2) Normalize JSON contracts (minimal and stable)
- Show (change):
{ id, title, deltaCount, deltas: [...], taskStatus?: { total, completed } } - Show (spec):
{ id, title, overview, requirementCount, requirements: [...], metadata: { format, version } } - List (change):
[{ id, title, deltaCount, taskStatus }] - List (spec):
[{ id, title, requirementCount }] - Notes:
- No top-level arrays for filtered show responses; always objects.
- Avoid derived/pretty fields (e.g., teasers, percentages). Counts only.
3) Standardize text UI (minimal)
- Show: print raw Markdown file contents.
- List (default): print IDs only, one per line.
- List (
--long): printid: titleplus minimal counts where relevant. - Keep colors minimal; support
--no-colorand respectNO_COLOR.
4) Consistent error handling and empty states
- Use
console.error+process.exitCode = 1. Avoidprocess.exit(1). - No spinners (
ora) in raw-first mode. - Empty states print a simple message and exit 0.
5) Discoverability and UX
- No
change-nameprovided: print IDs inline and a short hint; exit non-zero. No auto-pick. No interactive prompts. - Add
--no-colorfor deterministic logs and pipelines.
6) Backwards compatibility and deprecation
- Keep legacy flags as aliases for one minor release.
- Print a clear deprecation warning when a legacy flag is used.
- Update CLI docs/README/specs to reflect raw-first behavior.
7) Test coverage updates
- Add tests asserting raw text outputs (file passthrough) for
show. - Add tests for minimal list outputs (IDs by default,
--longfor details). - Add JSON contract tests asserting minimal, stable shapes and JSON-only filtering.
8) Library alignment with existing commands
- No new dependencies.
- Do not use
@inquirer/promptsinchange/specshow/list (keep non-interactive). Interaction remains limited toinit,diff, andarchivewhere already in use. - Do not use
orainchange/spec(including validate). Useconsole.errorandprocess.exitCode. - Use
chalkminimally; support--no-colorand respectNO_COLOR. - Keep using the shared
Validatorwhere applicable. - Do not introduce
jest-diffintochange/spec(remains specific todiff).
Why this approach
- Keeps the system raw and predictable; easy to compose in scripts.
- Minimizes UI/formatting logic until real needs emerge.
- Stabilizes JSON for tooling and avoids top-level arrays.
- Simple to extend later with
--prettyand richer filtering if needed.