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
Fixes#4797, both the dispatch and the prompt names. Workflow command and prompt steps with integration: kiro-cli ran kiro-cli -p "<prompt>", inherited from MarkdownIntegration.build_exec_args(). Kiro CLI rejects that at argument parsing, so every such step failed:
▸ [constitution] speckit.constitution …
error: unexpected argument '-p' found
Status: failed
Error: Command exited with code 2
KiroCliIntegration.build_exec_args() now builds kiro-cli chat --no-interactive --trust-all-tools [--model M] [--output-format stream-json] <prompt>, following kiro-cli chat --help on Kiro CLI 2.26.0:
chat --no-interactive runs one prompt headless, with the prompt as the positional input.
--trust-all-tools: headless mode can't ask for tool approval, so without it every write is denied (tool permission approval is not supported in non-interactive mode. Use --trust-all-tools to auto-approve.) and the run still exits 0. Same role as Copilot's --yolo and Cursor's --force.
Kiro has no json output format, so output_json=True maps to --output-format stream-json (JSON Lines), like Amp's --stream-json.
Extra args from SPECKIT_INTEGRATION_KIRO_CLI_EXTRA_ARGS go after the chat flags and before the prompt.
Kiro CLI also doesn't run dotted slash names: /speckit.constitution is rejected as "not a built-in Kiro CLI slash command", while /speckit-constitution runs .kiro/prompts/speckit-constitution.md. So the Kiro integration now follows Junie (#4073) and Cline:
Prompts install as .kiro/prompts/speckit-<command>.md, and dispatch sends /speckit-<command> (format_kiro_command_name, command_filename, build_command_invocation).
invoke_separator = "-", so shared templates and scripts render /speckit-plan. format_name in registrar_config gives extension and preset prompts the same names, e.g. speckit-git-commit.md.
Migration: specify integration upgrade kiro-cli stale-removes the old core speckit.*.md prompts through the manifest. If one was modified, the upgrade stops and lists it, and the file stays until --force. Enabled extension prompts are tracked in the extension registry, not the manifest, so upgrade re-registers them under the new names and then removes each old file only once its replacement exists. One that can't be re-registered keeps its old prompt and its registry entry. While presets have commands registered for Kiro, upgrade refuses the rename before changing files, like the Kilo command-root and command↔skills layout guards, and says to remove the preset, upgrade and add it back.
docs/reference/integrations.md: the Kiro row says prompts are hyphenated and why.
Headless Kiro still drops any text after /speckit-<name>, so a step's input.args doesn't reach the model. That's the Kiro limitation the existing prose fallback already covers (#1926).
Reproduction with the workflow from #4797, Kiro CLI 2.26.0, logged in:
main: fails with the error above.
Dispatch fix only (88c9c13): the step runs, but Kiro rejects /speckit.constitution, and the model then finds and reads the prompt file itself.
This branch: Kiro expands /speckit-constitution directly. The model's first tool calls are the prompt's own steps (the hook check, resolve-template.sh), .specify/memory/constitution.md is written, and the workflow ends with Status: completed.
Upgrade: a project initialized on main with the git extension had 15 speckit.*.md prompts. specify integration upgrade kiro-cli on this branch printed "Removed 10 stale file(s) from previous install" (the core prompts) and left 15 speckit-*.md prompts. With the git extension's manifest corrupted, its 5 dotted prompts stayed and the registry still tracked them. With a preset overriding speckit.plan also installed, the upgrade stopped before changing anything; preset remove, the upgrade and preset add then left 15 speckit-*.md prompts with the override in speckit-plan.md.
Testing
Tested locally with uv run specify --help
Ran existing tests with uv sync && uv run pytest
Tested with a sample project (if applicable)
New tests in tests/integrations/test_integration_kiro_cli.py: the headless chat argv, --model plus stream-json, and extra-args placement; the name formatter, filenames and invocation; a CommandStep dispatch test with the exact Kiro argv; the hook note and handoffs; and hyphenated overrides of the base inventory tests. In tests/specify_cli/integrations/test_command_upgrade.py, test_upgrade_replaces_dotted_kiro_prompts, test_upgrade_refuses_kiro_prompt_rename_while_presets_are_installed and test_upgrade_keeps_dotted_kiro_prompts_when_reregistration_fails cover the migration, and test_command_file_names_changed_needs_a_rename covers rename detection. The new tests fail on main, and 12 of them still fail with only the dispatch fix (88c9c13).
Full suite: 8777 passed, 251 skipped (Linux, Python 3.13).
ruff check src tests (0.15.0): clean.
Sample project: specify init --integration kiro-cli, then the workflow above on main and on this branch.
AI Disclosure
I did not use AI assistance for this contribution
I did use AI assistance (fill in the disclosure below)
AI disclosure: Claude Code (Claude Opus 5.5, autonomous agent mode) was used to investigate Kiro CLI, run the reproductions, and write the code changes, the tests and this description.
Kiro CLI runs /name from .kiro/prompts/name.md only when the name has
no dots, so the installed /speckit.plan is rejected as an unrecognized
slash command. Install speckit-<command>.md and dispatch
/speckit-<command>, following the Junie and Cline integrations, so
workflow steps run the prompt instead of relying on the model to find
the file. Upgrade stale-removes the old dotted prompts.
Refs github#4797
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
Pushed 86afed7, which adds the second half of #4797: Kiro prompts are now hyphenated. The assessment on #4797 says the argv change alone is not a complete fix, and I agree. With only 88c9c13, a workflow step sends /speckit.constitution, and Kiro answers that it "is not a built-in Kiro CLI slash command". The step then passes only because the model searches for and reads .kiro/prompts/speckit.constitution.md on its own.
format_kiro_command_name and the command_filename, build_command_invocation and invoke_separator = "-" overrides, so shared templates and scripts render /speckit-plan.
format_name in registrar_config, so extension and preset prompts get the same names. The bundled git extension installs speckit-git-commit.md.
This also resolves the Copilot finding. The build_exec_args docstring now says a /speckit-* input runs the prompt file, which is true once the files are hyphenated.
New tests:
the formatter, filenames and invocation;
a CommandStep dispatch test asserting the exact Kiro argv with /speckit-constitution;
the hook note and handoffs;
hyphenated overrides of the base Markdown inventory tests;
test_upgrade_replaces_dotted_kiro_prompts.
12 of these fail with the previous kiro_cli/__init__.py.
docs/reference/integrations.md: the Kiro row now says prompts are hyphenated and why.
Answers to the assessment's open questions
Output format. Workflow command steps call dispatch_command() with the default stream=True, and prompt steps pass output_json=False. So Kiro gets no --output-format and prints text, which the runner streams without parsing. If a caller does ask for JSON, output_json=True maps to --output-format stream-json (JSON Lines), since Kiro has no plain json format.
--trust-all-tools. It's always added. Headless Kiro can't ask for approval, so without it every write is denied while the run still exits 0. A workflow step would then report success with nothing written. Copilot's --yolo and Cursor's --force do the same job in their integrations.
Migration.specify integration upgrade kiro-cli stale-removes the dotted prompts through the existing manifest contract.
I ran it on a project initialized with the code before this PR. Output: "Removed 10 stale file(s) from previous install", and all 10 prompts are now speckit-*.md.
If a dotted prompt was modified, the upgrade stops and lists it, and the file stays until --force is used. test_upgrade_replaces_dotted_kiro_prompts covers both cases.
Kiro dispatch exited 2 before this PR, so nothing that worked before depended on the dotted names being dispatched.
Versions. I tested only Kiro CLI 2.26.0, the current stable download, and added no version gate.
Real run (Kiro CLI 2.26.0, specify workflow run with a speckit.constitution step and a shell step)
With this commit, Kiro expands the prompt itself. The model's first tool calls are the prompt's own steps: the extensions.yml hook check and resolve-template.sh. It never opens .kiro/prompts, and the run ends Status: completed.
The full suite passes: 8771 passed, 251 skipped. ruff check src tests is clean.
One correction: 88c9c13 is missing the Assisted-by: trailer. The same agent made it, and 86afed7 carries the trailer.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent wrote the code, tests and this comment, and ran the Kiro CLI and upgrade checks above.
I updated the title and description for Copilot's scope finding. They now cover the prompt rename, the integration upgrade migration of the old speckit.*.md files, and the docs row, and they say Fixes #4797 because both halves are in this PR. The code is unchanged since 86afed7.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent rewrote the PR title and description and wrote this comment.
test_upgrade_replaces_dotted_kiro_prompts restored the edited prompt
with write_text(), which writes CRLF on Windows. Integration files are
written as LF bytes, so the restored file no longer matched its
manifest hash and the second upgrade was still blocked as modified
(pytest on windows-latest). Read and write the prompt as bytes.
Refs github#4797
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
Fixed the Windows pytest failure in cb898ce. The problem was in the test I added, not the Kiro change.
test_upgrade_replaces_dotted_kiro_prompts edits .kiro/prompts/speckit.plan.md to check that upgrade stops on a modified prompt, then restores it. It restored the file with write_text(), which writes CRLF on Windows. write_file_and_record() writes LF bytes, so the restored file no longer matched its manifest hash, and the second upgrade was still blocked. The test now reads and writes the prompt as bytes.
The macOS 3.13 job was cancelled by fail-fast after the Windows failure; it didn't fail itself. The upgrade and Kiro test modules pass locally (75).
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent diagnosed the CI failure from the job logs, fixed the test and wrote this comment.
Existing extension and preset prompts are not migrated. On upgrade, this formatter makes re-registration write new hyphenated files, but command_upgrade.py:314-345 only unregisters old registrations when the command directory changes; Kiro's directory remains .kiro/prompts. Those artifacts are tracked outside the integration manifest, so their old speckit.*.md copies remain beside the replacements. Add same-directory naming-migration cleanup before re-registration and cover an upgrade with an installed extension and preset.
Document that headless Kiro workflow dispatch always passes --trust-all-tools, which auto-approves tool use. This is a security-relevant runtime default introduced by this PR; unlike the MiniMax row below, the current Kiro row only describes prompt naming and argument substitution, so users cannot discover the permission behavior from the integration reference.
Upgrade only unregistered enabled extension commands when the command
directory changed. Kiro keeps .kiro/prompts but renamed its files, and
extension prompts are tracked in the extension registry rather than the
manifest, so upgrading a project with the git extension left the five
speckit.git.*.md prompts beside the new speckit-git-*.md ones. Treat a
same-directory rename of the core command files like a directory change,
so the existing cleanup removes them before re-registration.
Also document that headless Kiro dispatch passes --trust-all-tools.
Refs github#4797
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
Extension prompts on upgrade. Confirmed and fixed. I initialized a project with the code before this PR and added the bundled git extension, then ran specify integration upgrade kiro-cli on the branch. The 10 core prompts were replaced, but the five speckit.git.*.md prompts stayed beside the new speckit-git-*.md ones. That happened because upgrade only calls _unregister_enabled_extension_commands_for_agent() when the command directory changes. _command_file_names_changed() now also triggers it when the core command files were renamed inside the same directory. unregister_commands() already removes both the formatted name and the raw registered name, so the existing cleanup deletes the dotted files before re-registration. The real upgrade now leaves 15 speckit-*.md prompts and no dotted ones. test_upgrade_replaces_dotted_kiro_prompts now installs the git extension under the old naming and fails without the fix.
Preset prompts. I didn't reproduce a leftover here. With the bundled lean preset installed under the old naming, upgrade --force (the preset overrides make a plain upgrade stop as "modified", same as on main) left the lean content in the hyphenated core prompts and no dotted copies.
--trust-all-tools. The Kiro row in docs/reference/integrations.md now says headless dispatch runs kiro-cli chat --no-interactive --trust-all-tools, which auto-approves every tool call, and why.
The full suite passes: 8771 passed, 251 skipped. ruff check src tests and markdownlint are clean.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent reproduced the upgrade cases, made the change and wrote this comment.
_command_file_names_changed() now needs a removed command file and an
added one with the same name up to "."/"-" separators, so a release that
adds one command and drops another no longer unregisters extension
commands. When the rename does happen on the active integration, preset
commands are unregistered before re-registration too, so dotted preset
prompts such as speckit.fakeext.cmd.md don't survive the upgrade.
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
Both findings from the latest Copilot pass are addressed in 569a1bd.
Rename detection._command_file_names_changed() no longer treats "some files added, some removed" as a rename. It only fires when a removed command file and an added one have the same name once . and - are treated as the same separator, as with speckit.plan.md → speckit-plan.md. A release that adds speckit.new.md and drops speckit.old.md no longer unregisters extension commands. test_command_file_names_changed_needs_a_rename covers the rename case, the add-and-drop case, and an add-only case.
Preset commands. When that rename happens on the active integration, upgrade now calls _unregister_presets_for_agent() before the existing _register_presets_for_agent(), the same pairing switch uses. test_upgrade_replaces_dotted_kiro_prompts now installs a preset with a custom speckit.fakeext.cmd command under the old naming. After the upgrade, it checks that no speckit.*.md prompt is left and that speckit-fakeext-cmd.md has the preset content. Without the change, that test fails with speckit.fakeext.cmd.md still in .kiro/prompts.
tests/specify_cli/integrations, tests/integrations and tests/specify_cli/presets pass (3668 passed, 6 skipped), and ruff is clean on the changed files.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent reproduced both findings, made the change and wrote this comment.
…t of the Kiro rename
The Kiro prompt rename now only unregisters enabled presets before
re-registering them. Disabled presets keep their files until removal, as
`specify preset disable` promises; PresetManager.unregister_agent_artifacts
gains the same enabled_only switch ExtensionManager already has.
_command_file_names_changed() compares whole manifest paths instead of
file names, so skill layouts (every file is SKILL.md) no longer read an
added and a dropped command as a rename.
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
Two more fixes in 268a908. The second one is Copilot's finding on 569a1bd; another review pass over the whole PR turned up both:
Disabled presets keep their prompts. The rename path unregistered every preset for the agent, but only enabled ones get re-registered. So integration upgrade kiro-cli deleted a disabled preset's prompt and never put it back, although specify preset disable says registered commands stay until the preset is removed. PresetManager.unregister_agent_artifacts() now has the same enabled_only switch as ExtensionManager's, and upgrade passes enabled_only=True. Covered by test_upgrade_keeps_disabled_preset_kiro_prompts.
Rename check on skill layouts._command_file_names_changed() compared file names only. In skill layouts every file is SKILL.md, so adding one command and dropping another still looked like a rename. It now compares whole manifest paths, keeping the parent directory as Copilot suggested. There's a new SKILL.md case in test_command_file_names_changed_needs_a_rename.
tests/specify_cli/integrations, tests/integrations, tests/specify_cli/presets and tests/extensions pass (4055 passed, 112 skipped), and ruff check src tests is clean.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent verified the review findings, made the change and wrote this comment.
…ements exist
The Kiro prompt rename unregistered enabled extension and preset commands
before re-registering them. Re-registration is best-effort, so an
extension or preset whose manifest couldn't be loaded lost its dotted
prompt without getting a hyphenated one, and its registry entry with it.
Upgrade now re-registers first, then removes each old speckit.*.md file
only when the file under the new name exists: the replacement-before-
retirement rule of _retire_legacy_flat_extension_commands(). The
enabled_only switch 268a908 added to PresetManager.unregister_agent_artifacts()
has no caller left, so it is reverted.
Refs github#4797
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
Addressed Copilot's finding on 268a908 in cc91560. I reproduced it: with the git extension's extension.yml and a preset's preset.yml corrupted, specify integration upgrade kiro-cli on 268a908 exited 0 but left neither the dotted nor the hyphenated prompts for either of them, and both registries stopped tracking kiro-cli.
What changed
For the Kiro rename, upgrade no longer unregisters anything before re-registration. It re-registers enabled extensions and presets as before. Then _retire_renamed_command_files() removes each old speckit.*.md file only when the file under the new name exists. This is the replacement-before-retirement rule from _retire_legacy_flat_extension_commands() and test_upgrade_layout_change_preserves_extension_artifacts_when_reregistration_fails. It still runs only when _command_file_names_changed() finds a real rename, and only for the active integration.
With nothing unregistered up front, the enabled_only switch that 268a908 added to PresetManager.unregister_agent_artifacts() has no caller. presets/_manager_commands.py is back to main. Disabled extensions and presets aren't re-registered, so they keep their files; test_upgrade_keeps_disabled_preset_kiro_prompts still passes.
Test:test_upgrade_keeps_dotted_kiro_prompts_when_reregistration_fails corrupts both manifests and then upgrades. The dotted git and preset prompts and both registry entries must survive. It fails on 268a908 and passes now.
Real run. The project was made by main with the git extension and a custom preset command, and the upgrade ran offline:
git and preset prompts gone under both names; registries no longer track kiro-cli
the 6 dotted git and preset prompts kept; both registries still track them
Full suite: 8777 passed, 251 skipped. ruff check src tests (0.15.0) is clean. I also updated the Migration and Upgrade lines in the description.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent reproduced the finding, made the change and wrote this comment.
The reason will be displayed to describe this comment to others. Learn more.
I checked this with real upgrades. The project was made by main with the git extension and a preset that overrides core speckit.plan and the extension's speckit.git.commit. Then I corrupted the preset's preset.yml. A plain upgrade stops with "modified since installation" on main and on this branch, because the override changed a core prompt. After specify integration upgrade kiro-cli --force:
Upgrade with
speckit.plan
speckit.git.commit
main
speckit.plan.md, default content
speckit.git.commit.md, default content
cc91560 with _retire_renamed_command_files() disabled
speckit-plan.md, default content
speckit-git-commit.md, default content, plus the dotted file with the override
The core-override example doesn't reach this helper. The old manifest tracks the dotted speckit.plan.md, so the Phase 2 stale cleanup removes it before re-registration. The result is the same with the helper disabled.
For a preset that overrides an extension command, the helper does remove the dotted copy once the extension has written the new path. On main, the same upgrade leaves default content in the shared speckit.git.commit.md, so the failed preset's override is lost there too.
With the preset intact (the same --force upgrade), both overrides move to speckit-plan.md and speckit-git-commit.md.
Keeping a failed preset's override when another layer shares its path would need provenance tracking through extension and preset re-registration. main doesn't do that for any integration. I'd rather keep it out of the Kiro fix and do it as a follow-up if it's wanted.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent ran the upgrade comparisons above and wrote this reply.
@mnriem Copilot's latest finding is about a preset that can't be re-registered during integration upgrade. main already loses that preset's overrides in the same case. The core-override example it gives is removed by the existing stale cleanup before this code runs. The real-run comparison is in my reply on the thread.
Would you take this PR as it is, with a follow-up PR that keeps a failed preset's overrides when another layer shares the path? Or do you want that in this PR?
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent wrote this comment.
@kartsan03 Because you are touching shared code it can surface pre-existing bugs and as such I do think we should address those at the time they surface because if we do not it might be hiding other new bugs we might have introduced with the current set of changes. So please address the Copilot feedback. Thanks a lot for workng on this!
…stalled
A preset override shares its path with the command it overrides, and its
rescaffold is best-effort. If the preset couldn't be re-registered during
the rename, Phase 2 stale cleanup (core commands) or the extension's new
file (extension commands) left only the other layer's prompt, and the
override was gone.
Upgrade now refuses the rename before changing files while presets have
commands registered for the integration, like the Kilo command-root and
command/skills layout guards, and says to remove the preset, upgrade and
add it back. The rename is detected before setup by comparing the old
manifest with the files setup will write (_planned_command_files). With
presets out of the way, _retire_renamed_command_files only handles
extension commands.
Refs github#4797
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
Addressed Copilot's finding on cc91560 in f53b21f, per your note. Rather than add more cleanup logic, I reused the guard integration upgrade already has for this class of problem.
What changed
While presets have commands registered for the integration, upgrade now refuses the Kiro rename before changing any files. It's the same guard as for the Kilo command-root move and the command↔skills layout change (review feat: update Bob integration to skills-based layout for Bob 2.0 #3415). A preset override shares its path with the command it overrides, and its rescaffold is best-effort. If the preset can't be re-registered, Phase 2 stale cleanup (for a core command) or the extension's new file (for an extension command) leaves only the other layer's prompt. The message says to remove the preset, upgrade, and add it back.
The rename is detected before setup. _command_file_names_changed() now compares the old manifest with _planned_command_files(), the files setup will write.
Presets no longer reach _retire_renamed_command_files(), so it only handles extension commands. It still removes an old file only once its replacement exists.
Test:test_upgrade_refuses_kiro_prompt_rename_while_presets_are_installed is the regression Copilot asked for. A preset overrides core speckit.plan, its installed source is removed, and upgrade --force must refuse and leave every prompt byte-identical. On cc91560 the upgrade exits 0 and the override is gone. It passes now. The two extension tests now install only the git extension.
Real runs (offline; project made by main with the git extension and a preset overriding speckit.plan and speckit.git.commit):
exit 0; speckit-plan.md has the default content, the override is gone
exit 1 with the remove/upgrade/add steps; all 15 prompts byte-identical
Following the message with an intact preset: preset remove, then integration upgrade kiro-cli (no --force needed), then preset add. The result is 15 speckit-*.md prompts with both overrides.
With only the git extension, all 15 prompts move to speckit-*.md. With its manifest corrupted, its 5 dotted prompts stay and are still tracked.
The check finds no rename on a fresh install of each of 41 integrations (all but generic, which has no fixed command dir). It also finds none for the 15 integrations with a --skills or --legacy-commands mode, installed in that mode. So the new guard can't block their ordinary upgrades.
Full suite: 8777 passed, 251 skipped. ruff check src tests (0.15.0) is clean. The Migration and Upgrade lines in the description are updated.
Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous). The agent made the change, ran the upgrade comparisons above and wrote this comment.
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
triage-can-waitVerdict: valid and in-scope but deprioritized; held behind the evidence gate
3 participants
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
Fixes #4797, both the dispatch and the prompt names. Workflow
commandandpromptsteps withintegration: kiro-clirankiro-cli -p "<prompt>", inherited fromMarkdownIntegration.build_exec_args(). Kiro CLI rejects that at argument parsing, so every such step failed:KiroCliIntegration.build_exec_args()now buildskiro-cli chat --no-interactive --trust-all-tools [--model M] [--output-format stream-json] <prompt>, followingkiro-cli chat --helpon Kiro CLI 2.26.0:chat --no-interactiveruns one prompt headless, with the prompt as the positional input.--trust-all-tools: headless mode can't ask for tool approval, so without it every write is denied (tool permission approval is not supported in non-interactive mode. Use --trust-all-tools to auto-approve.) and the run still exits 0. Same role as Copilot's--yoloand Cursor's--force.jsonoutput format, sooutput_json=Truemaps to--output-format stream-json(JSON Lines), like Amp's--stream-json.SPECKIT_INTEGRATION_KIRO_CLI_EXTRA_ARGSgo after thechatflags and before the prompt.Kiro CLI also doesn't run dotted slash names:
/speckit.constitutionis rejected as "not a built-in Kiro CLI slash command", while/speckit-constitutionruns.kiro/prompts/speckit-constitution.md. So the Kiro integration now follows Junie (#4073) and Cline:.kiro/prompts/speckit-<command>.md, and dispatch sends/speckit-<command>(format_kiro_command_name,command_filename,build_command_invocation).invoke_separator = "-", so shared templates and scripts render/speckit-plan.format_nameinregistrar_configgives extension and preset prompts the same names, e.g.speckit-git-commit.md.specify integration upgrade kiro-clistale-removes the old corespeckit.*.mdprompts through the manifest. If one was modified, the upgrade stops and lists it, and the file stays until--force. Enabled extension prompts are tracked in the extension registry, not the manifest, so upgrade re-registers them under the new names and then removes each old file only once its replacement exists. One that can't be re-registered keeps its old prompt and its registry entry. While presets have commands registered for Kiro, upgrade refuses the rename before changing files, like the Kilo command-root and command↔skills layout guards, and says to remove the preset, upgrade and add it back.docs/reference/integrations.md: the Kiro row says prompts are hyphenated and why.Headless Kiro still drops any text after
/speckit-<name>, so a step'sinput.argsdoesn't reach the model. That's the Kiro limitation the existing prose fallback already covers (#1926).Reproduction with the workflow from #4797, Kiro CLI 2.26.0, logged in:
main: fails with the error above./speckit.constitution, and the model then finds and reads the prompt file itself./speckit-constitutiondirectly. The model's first tool calls are the prompt's own steps (the hook check,resolve-template.sh),.specify/memory/constitution.mdis written, and the workflow ends withStatus: completed.mainwith the git extension had 15speckit.*.mdprompts.specify integration upgrade kiro-clion this branch printed "Removed 10 stale file(s) from previous install" (the core prompts) and left 15speckit-*.mdprompts. With the git extension's manifest corrupted, its 5 dotted prompts stayed and the registry still tracked them. With a preset overridingspeckit.planalso installed, the upgrade stopped before changing anything;preset remove, the upgrade andpreset addthen left 15speckit-*.mdprompts with the override inspeckit-plan.md.Testing
Tested locally with
uv run specify --helpRan existing tests with
uv sync && uv run pytestTested with a sample project (if applicable)
New tests in
tests/integrations/test_integration_kiro_cli.py: the headlesschatargv,--modelplusstream-json, and extra-args placement; the name formatter, filenames and invocation; aCommandStepdispatch test with the exact Kiro argv; the hook note and handoffs; and hyphenated overrides of the base inventory tests. Intests/specify_cli/integrations/test_command_upgrade.py,test_upgrade_replaces_dotted_kiro_prompts,test_upgrade_refuses_kiro_prompt_rename_while_presets_are_installedandtest_upgrade_keeps_dotted_kiro_prompts_when_reregistration_failscover the migration, andtest_command_file_names_changed_needs_a_renamecovers rename detection. The new tests fail onmain, and 12 of them still fail with only the dispatch fix (88c9c13).Full suite: 8777 passed, 251 skipped (Linux, Python 3.13).
ruff check src tests(0.15.0): clean.Sample project:
specify init --integration kiro-cli, then the workflow above onmainand on this branch.AI Disclosure
AI disclosure: Claude Code (Claude Opus 5.5, autonomous agent mode) was used to investigate Kiro CLI, run the reproductions, and write the code changes, the tests and this description.