Repository navigation
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
A validation error can leak captured sensitive output into log.jsonl, potentially exposing short credentials in full despite the capture guarantee.
1 open issue
What changed in this PR
Adds the shared contract for per-step reasoning effort and context size in Spec Kit workflows. Integration-specific CLI mappings remain follow-up work.
Changes:
- Adds workflow defaults, expression resolution, per-step opt-out, validation, and recorded outputs.
- Introduces integration capability checks and validation hooks while preserving legacy adapter calls when settings are unset.
- Adds workflow and adapter tests, documents compatibility, and clarifies that command-step
optionsare not forwarded.
| File | Description |
|---|---|
tests/workflows/test_dispatch_settings.py |
Covers resolution, rejection, compatibility, and engine wiring. |
tests/specify_cli/integrations/test_installed_adapters.py |
Tests installed adapters through run and resume. |
tests/integrations/test_base.py |
Tests capability ownership, validation, and dispatch forwarding. |
src/specify_cli/workflows/step/prompt/__init__.py |
Resolves, checks, forwards, and records prompt settings. |
src/specify_cli/workflows/step/command/__init__.py |
Resolves, checks, forwards, and records command settings. |
src/specify_cli/workflows/step/_dispatch_settings.py |
Shares validation, resolution, and error-source attribution. |
src/specify_cli/workflows/engine.py |
Validates defaults and supplies run/resume contexts. |
src/specify_cli/workflows/base.py |
Appends dispatch defaults to StepContext. |
src/specify_cli/workflows/_execution.py |
Supplies child workflows with their own defaults. |
src/specify_cli/integrations/base.py |
Defines capability gates, validation hooks, and forwarding rules. |
docs/workflows/api.md |
Documents defaults and corrects options behavior. |
docs/workflow-steps/types.md |
Explains resolution, value rules, support, and compatibility. |
docs/workflow-steps/api.md |
Documents the new StepContext fields. |
docs/integrations/cli.md |
Introduces the shared dispatch-setting contract. |
design/integration.md |
Defines capability ownership and adapter compatibility requirements. |
Review effort: Max (auto)
|
Commit Two regression tests cover it: Posted on behalf of @sukanth by the GitHub Copilot app in agent mode, running autonomously with Claude Opus 5.5 at maximum reasoning effort. AI wrote the fix, tests, docs, and this comment, and the agent ran all of the testing; no human reviewed the change line by line. |
There was a problem hiding this comment.
🟡 Changes recommended
The PR description incorrectly promises a value repr in malformed-value errors, while the implementation reports only a non-string’s type or a malformed string’s length.
1 open issue
1 resolved since last review
Review effort: Max (auto)
Workflow command and prompt steps can set reasoning_effort and context_size, and workflow.reasoning_effort and workflow.context_size set defaults for both. Values resolve like model: the step value, then the workflow default, then unset. An expression that resolves to an empty string or null unsets the setting for that step. Values must be strings that match a host-owned, flag-safe pattern. Malformed values are summarized rather than echoed. An integration receives a setting only if it declares the setting on the class that implements the receiving method (build_exec_args, or dispatch_command when overridden) and translates it. Otherwise the step fails before the CLI runs, with an error that names the setting and its source. The base and format-base builders raise rather than drop a setting. With both settings unset, argv and integration keyword arguments are unchanged. Step outputs record both values. Part of github#4916. Assisted-by: GitHub Copilot (model: Claude Opus 5.5, autonomous) Co-authored-by: Copilot App <[email protected]>
A reasoning_effort or context_size value can come from an expression over captured agent output. When such a value failed the host's format check, the error quoted a 24-character repr prefix of it. Step errors are printed and written to log.jsonl as step_failed events, so captured text could reach both, contrary to the documented guarantee that captured text is neither printed nor written to log.jsonl. The error now reports only the value's type and length. The design doc and the validate_dispatch_setting() docstring tell adapter authors to keep the value out of their own errors for the same reason. Part of github#4916. Assisted-by: GitHub Copilot (model: Claude Opus 5.5, autonomous) Co-authored-by: Copilot App <[email protected]>
…ference github#5296 made docs/integrations/api.md the public reference for the integration adapter contract and replaced the docs' links to design/integration.md. Add the opt-in contract for per-step reasoning_effort and context_size there, condensed from the design document, and point the CLI reference's opt-in link at it. The documented build_exec_args() signature is unchanged: an adapter that does not opt in never receives either keyword. Part of github#4916. Assisted-by: GitHub Copilot (model: Claude Opus 5.5, autonomous) Co-authored-by: Copilot App <[email protected]>
6a8ae51 to
553667f
Compare


Description
Part of #4916. This is the shared prerequisite PR. The GitHub Copilot, Codex CLI, and Claude Code mappings follow in a separate integration PR, #5249, as Integration pull requests requires. This PR stands on its own: any integration, including an external adapter, can opt in to the contract it adds. Its tests use fake integrations and an installed external adapter.
Workflow
commandandpromptsteps can now setreasoning_effortandcontext_sizefor one CLI invocation.workflow.reasoning_effortandworkflow.context_sizeset defaults for both. Values are opaque strings. Spec Kit passes them unchanged to an integration that declares and translates the setting. With any other integration, the step fails before its CLI runs, so a setting is never silently ignored.Behavior
model. The step value wins, then the workflow default, then unset. Expressions are allowed. A missing,null, or""step value inherits the default. An expression that resolves to""or null unsets the setting for that step, with no second fallback; this is the per-step opt-out.[A-Za-z0-9][A-Za-z0-9._-]{0,63}(checked withfullmatch). This blocks a leading-(flag injection), whitespace, newlines, control characters, and.cmd-shim metacharacters.log.jsonl.check_dispatch_settings()inintegrations/base.py, which runs before executable detection.supported_dispatch_settingson the class that implements the method receiving the settings:build_exec_args(), ordispatch_command()when overridden. A subclass that overrides that method must declare support again. This way an inherited declaration cannot vouch for code that does not translate the setting.IntegrationBase.build_exec_args()and the Markdown, TOML, and Skills format-base builders raiseDispatchSettingsErrorrather than drop a setting they cannot translate.validate_dispatch_setting(name, value)anddispatch_setting_hint(setting).Command step 'plan': Integration 'copilot' does not support per-step 'reasoning_effort'. No available integration supports it. … (set by workflow.reasoning_effort). Once integrations opt in, the error lists the ones that support the setting, drawn from the project's pinned registry.main. The one difference: once a command or prompt step reaches dispatch, its output also includesreasoning_effortandcontext_size, which arenullwhen unset. A step that fails earlier on invalid configuration, such as a badtimeout, keeps its previous output shape.record()is unchanged.StepContextfields are appended, so positional construction is unchanged.capture,integration_args, andstrict, and the docs say so.requires.speckit_versionremains advisory.docs/workflow-steps/types.md:optionsare recorded but not passed to the CLI, as the issue requested.docs/workflows/api.md: schema rows for the defaults, and correctedworkflow.optionswording.docs/workflow-steps/api.md: the newStepContextfields.docs/integrations/api.md: the opt-in contract for adapter authors, in the integration API reference.docs/integrations/cli.md: the shared contract, linking to the API reference.design/integration.md: the integration contract and the external adapter note.docs/reference/workflows.md, which docs: consolidate and correct workflow documentation #5225 removed, andworkflows/README.md, which now only links to the published docs. The pages above are their current equivalents.Answers to the feature-assessment clarification questions
The maintainer comment on #4916 asked for these.
Integrations, versions, and values. The CLI arguments were checked locally:
--reasoning-effort none|minimal|low|medium|high|xhigh|maxand--context default|long_context. Invalid values are rejected.--effort low|medium|high|xhigh|max. Unknown values only produce a warning, so the integration PR validates them.-c model_reasoning_effort="<v>"and-c model_context_window=<i64>.Spec Kit does not normalize vocabularies across integrations.
Measurable benefit. The benefit is qualitative: the settings become reviewable and reproducible per step in workflow YAML. The only existing path is the process-wide
SPECKIT_INTEGRATION_<KEY>_EXTRA_ARGS. The feature is opt-in, and behavior does not change when it is unset. No quantitative cost or latency claim is made.Context size in the first release. Yes. Each integration defines its meaning: a tier in Copilot, a token count in Codex. Integrations without a native mapping reject it; Claude Code's error points to
model.Failure and compatibility behavior.
output.stderrwithcapture: true.Further demand. None beyond the issue. It was marked
feature-go.Testing
The agent described in the AI disclosure ran all of the testing below. Nothing was run by hand. Every command ran against this PR's head commit,
553667f3, alone onmain47114315, in a clean worktree, without the integration PR, except where a result names an earlier head. Before the rebase onto47114315, this PR's first two commits were62cd20d0and6a8ae513, onec9a6f3b. They are now9a98075fand964adcbd, with identicalsrc/andtests/changes (git range-diff); the only difference is the resolved conflict indocs/workflow-steps/api.md.uv run specify --help: exit 0. The environment's package index is a proxy, so the command ran without syncing.uv sync && uv run pytest, in an equivalent.venv. Results are below.uvx [email protected] check src testsnpx [email protected]on the six changed docs, plus a relative link and anchor checkgit diff --check.venv/bin/python -m pytest tests/workflows tests/test_workflows.py tests/integrations tests/specify_cli/integrations tests/test_agent_config_consistency.py -q -n 6.venv/bin/python -m pytest -q -n 6(full suite), then a serial re-run of every failure-n 6: 14291 passed, 369 failed, 134 skipped. The failures are in 14 shell-script, parity, and setup suites that fail under parallel load on this machine, none in files this PR changes. A serial re-run of those 369 passed 368. The remaining test,test_version_execution.py::TestWindowsUvToolEnvironment::test_non_windows_uv_tool_dry_run_still_previews_installer, also fails onmain47114315here because Rich wraps this machine's long virtualenv path. It passes withCOLUMNS=400.New tests:
tests/workflows/test_dispatch_settings.pycovers command and prompt steps:log.jsonl;**kwargsoverride, astrdeclaration, and forwarding tosuper();continue_on_error;EXTRA_ARGSstill raising from a prompt step;StepContextpositional compatibility.tests/integrations/test_base.pycovers the contract itself:dispatch_commandforwarding;specify checkprobe.tests/specify_cli/integrations/test_installed_adapters.pyruns an installed external adapter in a freshspecifyprocess, throughworkflow runandworkflow resume. It covers an adapter that declares support and a legacy adapter that does not.Test selection reasoning
src/specify_cli/workflows/step/command/__init__.py,step/prompt/__init__.py,step/_dispatch_settings.py,engine.py,_execution.py,workflows/base.pyspecify workflow runandspecify workflow resumesrc/specify_cli/integrations/base.pyspecify checkprobedocs/**,design/integration.mdNo slash-command templates or scripts changed, so no
/speckit.*command needs an agent run.Manual test results
Agent: GitHub Copilot CLI 1.0.106, invoked by
specify workflow runthrough an argv-logging probe that appends--version. The real CLI parses Spec Kit's argv without making a model call. OS/Shell: macOS / zsh. The project was created withspecify init --integration copilot. T1–T3 ran on62cd20d0, before the rebase. This PR's later commits change only the malformed-value error text, which they do not quote, and docs.specify workflow runwith a Copilot command step and prompt step, no settings, onmainand on this PRcmp):["-p", "/speckit-plan add OAuth login", "--yolo"]and["-p", "Review the plan for gaps", "--yolo"]. Step outputs recordreasoning_effort: nullandcontext_size: null.specify workflow run: unsupported settings, opt-out, unsafe literalworkflow.reasoning_effort: mediumfailed the command step before the CLI ran (no argv logged), ending with(set by workflow.reasoning_effort). A prompt step'scontext_size: long_contextfailed the same way, ending with(set by step). A step whosereasoning_effortexpression resolved to""ran with unchanged argv despite an unsupported workflow default. The literalreasoning_effort: "-rf"failed workflow validation.specify checkmain; exit 0specify workflow runon62cd20d0, on6a8ae513, and on553667f3: a prompt step captures the CLI's output, and the next step reads it asreasoning_effortGitHub Copilot CLI 1.0.106…) fails the format check, so the second step fails before its CLI runs. On62cd20d0, the terminal error and thestep_failedevent inlog.jsonlboth included('GitHub Copilot CLI 1.0.1'…). On6a8ae513and553667f3, both end withgot a string of length N. (set by step)(73, then 74 after a CLI update), and the captured text appears only instate.json, as documented. This run used a bare project with only.specify/workflows/.AI Disclosure
AI disclosure: Implemented with the GitHub Copilot app in agent mode, running autonomously on behalf of @sukanth, who chose the issue and directed the work. An orchestrator and four implementation workers, all Claude Opus 5.5 at maximum reasoning effort with long context, wrote the change. Before implementation, a panel of five models reviewed and approved the plan: Claude Opus 5.5, Claude Sonnet 5.5, GPT-6.1 Sol, and GPT-5.6 Sol at maximum reasoning effort, and Gemini 4 Argon at high reasoning effort, all with long context. The same panel reviewed the code, and the agent fixed the findings it accepted. Extent: AI generated the code, tests, docs, and this description, and the agent ran all of the testing. No human reviewed the change line by line before submission. AI-generated follow-up commits and review replies will carry their own disclosure. Follow-up commit
6a8ae513(now964adcbd) addresses a Copilot code-review finding raised on this PR and on #5249. The same agent (GitHub Copilot app, agent mode, autonomous; Claude Opus 5.5 at maximum reasoning effort) wrote and tested it, without another panel review. The same agent also rebased the branch onto47114315to resolve a conflict with #5296, and wrote553667f3, which documents the adapter opt-in contract in the integration API reference that #5296 added.