Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7215313
feat(core): add specify core info --json command (#4215)
nicolehaugen Aug 20, 2026
0946f63
Potential fix for pull request finding 'Unused import'
nicolehaugen Aug 20, 2026
e295871
Align core info contract references
Copilot Aug 20, 2026
6048674
Fix core command inventory namespacing
Copilot Aug 20, 2026
f08de91
Fix core inventory command source
Copilot Aug 20, 2026
9755a38
Update core info command test
Copilot Aug 20, 2026
994bbc7
Fix ruff unused import in core info test
Copilot Aug 20, 2026
0368835
Fix ruff unused import in core info test
Copilot Aug 20, 2026
71c2f98
Fix non-boolean optional test fixture (PyYAML 1.1 'yes' bool coercion)
Copilot Aug 20, 2026
72767ac
Potential fix for pull request finding
nicolehaugen Aug 20, 2026
a98ce13
Potential fix for pull request finding
nicolehaugen Aug 20, 2026
35565b8
docs: fix core-info.md example to match actual plan.md output
Copilot Aug 20, 2026
f947d98
Fix sourcePath leak of absolute filesystem path in frontmatter parser
Copilot Aug 20, 2026
29094d4
docs: fix broken schema link in core-info.md
Copilot Aug 20, 2026
831a37c
Document core asset omission risk
Copilot Aug 20, 2026
3cf152c
docs+core: remove req-id/companion-issue references; fix inaccurate f…
Copilot Aug 20, 2026
f5a6c7e
docs: move silent-omission note into Failure Modes intro paragraph
Copilot Aug 20, 2026
930d87b
Potential fix for pull request finding
nicolehaugen Aug 20, 2026
4e09941
fix(tests): strip ANSI codes in core info CLI assertions
Copilot Aug 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

<!-- insert new changelog below this comment -->

- feat(core): add `specify core info --json` command that emits the baked-in commands, templates, and scripts as a deterministic JSON inventory (#4215)

## [0.16.5] - 2026-08-19

### Changed
Expand Down
96 changes: 96 additions & 0 deletions docs/reference/core-info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Core Info

The `specify core` command group exposes read-only information about Spec Kit's baked-in ("core") baseline — the commands, templates, and helper scripts that ship inside the CLI package itself. Presets, extensions, integrations, and project-scoped assets are intentionally **not** included; use their dedicated commands (`specify preset`, `specify extension`, `specify integration`) for those.

Core info output is deterministic and byte-identical across runs, so downstream tools can safely diff, hash, or cache it.

## Inspect Core Info

```bash
specify core info --json
```

| Option | Description |
| ------------- | -------------------------------------------------------------------- |
| `--json` | **Required.** Emit core info as JSON on stdout. |

The `--json` flag is mandatory. A human-readable table format is intentionally not offered — the command is designed for programmatic consumption by external tools and other Spec Kit surfaces. Invoking `specify core info` without `--json` exits non-zero with a hint pointing at the flag.

### Output shape

The response is a JSON object with three top-level arrays, always in this order and always sorted alphabetically by `name` within each array:

```json
{
"commands": [ /* baseline slash-commands (e.g. speckit.plan) */ ],
"templates": [ /* markdown templates (spec, plan, tasks, ...) */ ],
"scripts": [ /* helper scripts (bash/powershell/python) */ ]
}
```

Every entry carries a stable identifier suitable for cross-referencing:

- `id`: `core:_:<kind>:<name>` (`<kind>` is `command`, `template`, or `script`)
- `name`: the logical artifact name. Commands are namespaced as `speckit.<stem>`; templates use their filename stem; scripts use a hyphenated stem (for example, `setup-plan`, not `setup_plan`).
- `description`: short human-readable summary
- `sourcePath`: package-relative, forward-slash path (e.g. `templates/commands/plan.md`)

Kind-specific fields:

- **`commands[]`** also include `artifact` (string or `null`), `optional` (boolean, defaults to `false`), and `handoffs` (list of downstream command identifiers, may be empty).
- **`scripts[]`** also include `runtimes`: a sorted list of the runtimes that ship a variant of that script, drawn from `bash`, `powershell`, and `python`. Every script has at least a `bash` variant — that is the canonical source.

### Example

```bash
specify core info --json | jq '.commands[] | select(.name == "speckit.plan")'
```

```json
{
"id": "core:_:command:speckit.plan",
"name": "speckit.plan",
"description": "Execute the implementation planning workflow using the plan template to generate design artifacts.",
"sourcePath": "templates/commands/plan.md",
"artifact": null,
"optional": false,
"handoffs": ["speckit.tasks", "speckit.checklist"]
}
```

## When to Use It

- Building tools that need to know what the shipped baseline contains without unpacking the wheel by hand.
- Auditing which commands, templates, or scripts a given Spec Kit release ships.
- Cross-referencing baseline artifacts against extension- or preset-provided ones.

## Determinism Guarantees

- Alphabetical ordering by `name` within each section.
- Fixed top-level key order: `commands`, `templates`, `scripts`.
- Fields inside each entry are emitted in a fixed order.
- Path separators are always forward-slashes, even on Windows.

## Failure Modes

The command fails fast on packaging errors it can detect at read time — unparseable frontmatter, a mistyped field, or a script missing its canonical bash variant — rather than silently emitting a malformed inventory. On any such error it exits with code `1` and prints a JSON error envelope on stderr. Note that templates and scripts are enumerated from whatever files are present on disk, so an asset that is missing entirely from the installation is simply omitted from the output rather than raised as an error.

```json
{
"error": "core_inventory.frontmatter_parse",
"message": "Could not parse YAML frontmatter of command 'plan': ...",
"artifact": { "kind": "command", "name": "plan", "sourcePath": "templates/commands/plan.md" }
}
```

Common `error` codes:

| Code | Meaning |
| ----------------------------------- | -------------------------------------------------------------- |
| `core_inventory.assets_missing` | Neither the wheel-shipped `core_pack/` nor the source checkout was found. |
| `core_inventory.frontmatter_parse` | YAML frontmatter on a baseline file could not be parsed, or a field has the wrong type. |
| `core_inventory.missing_description`| A baseline command or template has no usable description. |
| `core_inventory.missing_canonical` | A script ships a non-bash variant but no canonical bash one. |
| `core_inventory.invalid_source_path`| An emitted `sourcePath` failed the shape check (absolute or contained a backslash). |

These conditions represent packaging bugs and should be reported.
2 changes: 2 additions & 0 deletions docs/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
href: reference/overview.md
- name: Core Commands
href: reference/core.md
- name: Core Info
href: reference/core-info.md
- name: Integrations
href: reference/integrations.md
- name: Extensions
Expand Down
7 changes: 7 additions & 0 deletions src/specify_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,13 @@ def _require_specify_project() -> Path:
raise typer.Exit(1)


# ===== Core Info Commands =====

# specify core * — see specify_cli/core/_commands.py
from .core._commands import register as _register_core_cmds # noqa: E402
_register_core_cmds(app)


# ===== Preset Commands =====

# Moved to presets/_commands.py — registered here to preserve CLI surface.
Expand Down
Loading