You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a preview, command-specific machine-readable contract to root specify init through a new --json option.
JSON mode implies non-interactive execution even when stdin is a TTY, applies only safe documented defaults, and never grants destructive or trust authorization. Successful runs emit exactly one JSON object on stdout; failures emit exactly one structured error object on stderr. The result reports the resolved project operation, defaulted selections, component outcomes, warnings, and machine-usable next steps.
The implementation preserves the existing human-mode path, validates URL-extension trust before filesystem mutation, retains new-target rollback guarantees, surfaces optional-component failures, and documents the preview compatibility policy. It does not change MCP exposure or unrelated JSON commands.
Regression coverage also verifies that conflicting Copilot (--skills --commands) and Bob (--skills --legacy-commands) integration options return invalid_integration_options without Rich/prose leakage or target mutation.
Testing
Tested locally with uv run specify --help
Ran existing tests with uv sync && uv run pytest (used the repository-required worktree commands uv sync --extra test and .venv/bin/python -m pytest -q)
I did use AI assistance (fill in the disclosure below)
AI disclosure: Implemented with GitHub Copilot using GPT-5.6 Sol in autonomous mode; assistance covered code generation, tests, documentation, debugging, validation, review, commit preparation, and PR drafting.
Direct bundle initialization now passes explicit callback booleans, and root init enters JSON mode only for the literal boolean True.
Forced JSON reinitialization now persists the newly resolved active integration/mode before extension and preset re-registration reads project state.
Added regressions for bundle human-output preservation and Copilot commands-to-skills re-registration ordering.
Validation:
Focused bundle/init regressions: 48 passed
Broader bundle/init suites: 446 passed
Full suite: 9,577 passed, 19 skipped, 62 warnings; 9,596 collected
Scoped Ruff checks and git diff --check: passed
Posted on behalf of @mnriem by GitHub Copilot using GPT-5.6 Sol in autonomous mode; AI assistance covered implementation, tests, validation, review responses, and this review-round summary.
Addressed the target-ownership finding in 9ac61340:
New JSON-init targets are atomically claimed only after all non-mutating preflight validation succeeds.
Rollback now depends on explicit ownership rather than the earlier existence snapshot.
Added a race regression that creates a target and marker between planning and claim, verifies initialization does not start, and verifies the concurrent directory is preserved.
Validation:
JSON init contract suite: 32 passed
Broader bundle/init suites: 447 passed
Full suite: 9,578 passed, 19 skipped, 62 warnings; 9,597 collected
Ruff and git diff --check: passed
Posted on behalf of @mnriem by GitHub Copilot using GPT-5.6 Sol in autonomous mode; AI assistance covered implementation, tests, validation, review response, and this review-round summary.
Full suite: 9,579 passed, 19 skipped, 62 warnings; 9,598 collected
Scoped Ruff checks and git diff --check: passed
Posted on behalf of @mnriem by GitHub Copilot using GPT-5.6 Sol in autonomous mode; AI assistance covered implementation, tests, validation, review response, and this review-round summary.
This stable-code description omits creation failures. _claim_new_target() also returns target_unavailable when mkdir() fails, so consumers following this contract cannot interpret the code as inspection-only. Document both inspection and creation failures.
Full suite: 9,580 passed, 19 skipped, 62 warnings; 9,599 collected
Ruff, git diff --check, and the documentation lint invocation: passed
Posted on behalf of @mnriem by GitHub Copilot using GPT-5.6 Sol in autonomous mode; AI assistance covered implementation, tests, documentation, validation, review response, and this review-round summary.
Full suite: 9,582 passed, 19 skipped, 62 warnings; 9,601 collected
Ruff, git diff --check, and the documentation lint invocation: passed
Posted on behalf of @mnriem by GitHub Copilot using GPT-5.6 Sol in autonomous mode; AI assistance covered implementation, tests, documentation, validation, review response, and this review-round summary.
Empty integration incorrectly reported as explicitly selected
src/specify_cli/_command_init_json.py:460
An explicitly empty value (--integration "") falls back to the default integration via or, but this field remains False. The success payload therefore says the integration was explicitly selected even though the documented default was used. Derive defaulted from the same truthiness condition (or reject blank values) and cover this input in the contract tests.
Empty script incorrectly reported as explicitly selected
src/specify_cli/_command_init_json.py:515
Likewise, --script "" selects the OS default through or while reporting script.defaulted: false. This breaks the contract's promise that callers can distinguish defaulted selections from explicit ones. Use the same condition for selection and reporting, and add an empty-value regression case.
Re-registration failures do not have a component outcome: _re_register_existing_artifacts only appends extension_reregistration_failed or preset_reregistration_failed warnings. The compatibility documentation currently promises both an outcome and a warning for those failures, so consumers may look for a field that is never emitted. Either add a re-registration component result or narrow this paragraph to state that re-registration failures are warning-only.
Addressed all three Previously missed items from review 5419077753 in affce838:
Empty integration selection:--integration "" now uses the safe default and reports integration.defaulted: true.
Empty script selection:--script "" now uses the platform default and reports script.defaulted: true.
Re-registration contract: clarified that best-effort extension/preset re-registration failures are represented as structured warnings only, not component outcomes; added regression coverage proving both warning codes are emitted.
Validation:
JSON init contract suite: 38 passed
Broader init suites: 55 passed
Full suite: 9,584 passed, 19 skipped, 62 warnings; 9,603 collected
Ruff, git diff --check, and documentation lint: passed
This review contained no inline threads to resolve.
Posted on behalf of @mnriem by GitHub Copilot using GPT-5.6 Sol in autonomous mode; AI assistance covered implementation, tests, documentation, validation, and this review-round summary.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
Generic artifact re-registration uses stale integration state, and parser detection mishandles -- end-of-options semantics.
Review effort: Balanced Findings: None
Previously missed (2)
In code that hasn't changed since last review
Respect the -- marker when detecting JSON mode
src/specify_cli/_command_init_json.py:57
This raw membership check ignores Click's -- end-of-options marker. For example, specify init -- --json extra uses --json as the positional project name and never enables JSON mode, but its extra-argument parse failure is nevertheless converted to the JSON error contract. Limit detection to arguments before the first --, and add a parser regression so human-mode invocations cannot unexpectedly change output format.
Persist generic settings before re-registering artifacts
src/specify_cli/_command_init_json.py:1136
Generic artifact re-registration runs before the new generic runtime settings are persisted. When a forced init switches an existing project from another integration to generic, CommandRegistrar(project_root) resolves registration_directory(), which reads .specify/integration.json; at this point that file still has no generic commands_dir, so extension re-registration fails with a warning and existing extension artifacts are never scaffolded into the requested generic directory. Persist settings first, then re-register, and add a switch-to-generic regression with an enabled extension or preset.
Addressed both Previously missed comments from review 5419294284 in 25059ef6:
Respect -- during JSON detection: parse-error contract detection now considers only arguments before Click’s end-of-options marker. Regression: specify init -- --json extra remains a human-mode usage error and does not emit a JSON envelope.
Persist generic settings before artifact re-registration:.specify/integration.json is now written before extension/preset re-registration. Regression: initialize Copilot with the enabled bundled git extension, force-switch to generic, verify no re-registration warning, and verify speckit.git.*.md artifacts appear under the requested generic command directory.
Validation:
JSON init contract suite: 40 passed
Broader generic/extension/init suites: 476 passed
Full suite: 9,586 passed, 19 skipped, 62 warnings; 9,605 collected
Ruff and git diff --check: passed
This review contained no inline threads to resolve.
Posted on behalf of @mnriem by GitHub Copilot using GPT-5.6 Sol in autonomous mode; AI assistance covered implementation, regression tests, validation, and this review-round summary.
Capture integration mode validation output before mutation so conflicting Copilot and Bob layout flags produce the documented invalid_integration_options error without leaking Rich output.
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Require an explicit boolean opt-in for JSON init callbacks, pass direct bundle callback defaults explicitly, and save the resolved active mode before extension and preset re-registration.
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Atomically create new init targets after preflight and record ownership so rollback only removes directories claimed by the current invocation.
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Resolve and validate generic integration command destinations before JSON init claims a target, while reusing the same containment check during setup.
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reject command-to-skills layout changes through JSON init before mutation and direct callers to the integration upgrade path, preserving existing manifests and artifacts.
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Commit 328b35050068cf1220c6538932822444465f0bd4 replaces the parallel JSON initializer with a machine-output adapter over the existing init callback. Human and JSON invocations now share target handling, integration setup, shared infrastructure, workflows, presets, extensions, constitution setup, persistence, permissions, and rollback. JSON mode differs only at invocation/output boundaries: non-interactive preflight, prompt/trust authorization, Rich output suppression, error translation, and one UTF-8 JSON document on the appropriate stream.
The complete generated project tree is compared between human and JSON modes for defaults, explicit integration/script choices, generic integration, presets/extensions, --here, force merge, and reinitialization. The latest change also prevents JSON success from constructing the human setup/completion panels; its UI regression test fails if picker, confirmation, banner, Live, or Panel APIs are invoked.
Collection: 9,759 tests, 52 more than upstream/main (51 in the new JSON suite and one bundle callback regression)
AI disclosure: GitHub Copilot, GPT-5.6 Sol, autonomous mode, performed the implementation replacement, code review, test authoring, validation, rebase, commit, and this review-round summary on behalf of @mnriem.
Commit 45378e63f66510178bdac4bac28b69ff88bd9a63 addresses the four implementation/test findings from review 5421122560:
Rollback stages the claimed directory at a private sibling path before identity verification and deletion, so a replacement at the public target path is preserved.
Human and JSON preflight reject unsupported external HTTP extension URLs before mutation; localhost HTTP remains supported.
Shared integration preflight rejects escaped generic destinations and incompatible active-integration, installed-set, layout, or generic-destination reinitialization before mutation, with integration switch/integration upgrade guidance.
Resolved init options and integration state are persisted before extension/preset re-registration; regression coverage verifies registrars observe the new active integration/mode.
The documentation expansion was intentionally deferred because the contributor directed this slice to keep the command reference minimal and not add a schema walkthrough or formal contract section. The existing note retains the requested user-facing execution and consent guarantees.
Validation:
Focused review regressions: 59 passed
Broader init/integration suite: 153 passed
Full suite: 9,747 passed, 19 skipped, 62 warnings
Collection: 9,766 tests (59 above upstream/main)
uvx ruff@0.15.0 check src tests — passed
git diff --check — passed
AI disclosure: GitHub Copilot, GPT-5.6 Sol, autonomous mode, performed the implementation, review analysis, test authoring, validation, commit, push, inline replies, and this review-round summary on behalf of @mnriem.
Commit 4f22fb2e3143308335bafb494d1cc8d018754877 addresses all four new findings from review 5421378252:
SystemExit is handled at the JSON boundary with structured stderr and stream purity preserved.
Rollback reporting now uses explicit shared claim/cleanup state; the stale preflight operation snapshot was removed.
Extension machine status is independent of human-facing wording, while the existing string helper remains compatible.
Forced reinitialization exposes extension and preset re-registration failures as structured warnings instead of discarding captured human warnings.
The two repeated open findings in the review overview—unsafe integration-transition preflight and registrar visibility of newly persisted state—were implemented in 45378e63 and already have dedicated regressions and inline replies.
Validation:
Focused latest-review suites: 180 passed
Broader init/integration suites: 197 passed
Full suite: 9,751 passed, 19 skipped, 62 warnings
Collection: 9,770 tests (63 above upstream/main)
uvx ruff@0.15.0 check src tests — passed
git diff --check — passed
AI disclosure: GitHub Copilot, GPT-5.6 Sol, autonomous mode, performed the implementation, review analysis, test authoring, validation, commit, push, inline replies, and this review-round summary on behalf of @mnriem.
Preserve integration option diagnostics in JSON mode
src/specify_cli/_command_init_json.py:270
Malformed, unknown, and missing-value integration options reach this branch as typer.Exit, but _parse_integration_options() only prints the specific diagnostic before raising that exit and does not attach it to the exception. Because JSON mode captures and discards that print, clients receive only the generic Integration options are invalid plus an exit-derived reason, so they cannot determine which option was wrong. Preserve the parser's diagnostic in a typed exception (while human mode may still render it) and serialize that message here.
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Add a preview, command-specific machine-readable contract to root
specify initthrough a new--jsonoption.JSON mode implies non-interactive execution even when stdin is a TTY, applies only safe documented defaults, and never grants destructive or trust authorization. Successful runs emit exactly one JSON object on stdout; failures emit exactly one structured error object on stderr. The result reports the resolved project operation, defaulted selections, component outcomes, warnings, and machine-usable next steps.
The implementation preserves the existing human-mode path, validates URL-extension trust before filesystem mutation, retains new-target rollback guarantees, surfaces optional-component failures, and documents the preview compatibility policy. It does not change MCP exposure or unrelated JSON commands.
Regression coverage also verifies that conflicting Copilot (
--skills --commands) and Bob (--skills --legacy-commands) integration options returninvalid_integration_optionswithout Rich/prose leakage or target mutation.Testing
uv run specify --helpuv sync && uv run pytest(used the repository-required worktree commandsuv sync --extra testand.venv/bin/python -m pytest -q)Exact validation:
uv sync --extra test— passeduv run specify --help— passed.venv/bin/python -m pytest tests/specify_cli/test_command_init.py tests/specify_cli/test_command_init_json.py -q— 45 passed.venv/bin/python -m pytest -q -k powershell— 181 passed, 5 skipped.venv/bin/python -m pytest -q— 9,575 passed, 19 skipped, 62 warnings; 9,594 collectedruff check src/specify_cli/_command_init_json.py tests/specify_cli/test_command_init_json.py— passedgit diff --check— passedAI Disclosure
AI disclosure: Implemented with GitHub Copilot using GPT-5.6 Sol in autonomous mode; assistance covered code generation, tests, documentation, debugging, validation, review, commit preparation, and PR drafting.