Skip to content

feat(workflows): add per-step reasoning effort and context size settings - #5248

Open
sukanth wants to merge 3 commits into
github:mainfrom
sukanth:feat/4916-dispatch-settings
Open

sukanth wants to merge 3 commits into
github:mainfrom
sukanth:feat/4916-dispatch-settings

Conversation

@sukanth

@sukanth sukanth commented Nov 5, 2026 •

Copy link
Copy Markdown

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 command and prompt steps can now set reasoning_effort and context_size for one CLI invocation. workflow.reasoning_effort and workflow.context_size set 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

  • Resolution works like 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.
  • Values must be safe to pass to a CLI. A value must be a string that matches [A-Za-z0-9][A-Za-z0-9._-]{0,63} (checked with fullmatch). This blocks a leading - (flag injection), whitespace, newlines, control characters, and .cmd-shim metacharacters.
    • Literals are checked when the workflow is validated, and expression results when the step runs.
    • An error about a malformed value never includes its text: it reports a non-string's type, or a malformed string's length. The value can come from captured agent output, which Spec Kit does not print to the terminal or write to log.jsonl.
  • Integrations opt in through a host-owned gate, check_dispatch_settings() in integrations/base.py, which runs before executable detection.
    • An integration declares supported_dispatch_settings on the class that implements the method receiving the settings: build_exec_args(), or dispatch_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 raise DispatchSettingsError rather than drop a setting they cannot translate.
    • Two optional hooks let an integration refine values and errors: validate_dispatch_setting(name, value) and dispatch_setting_hint(setting).
  • Errors name the setting and where it was set. For example: 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.
  • The unset path is unchanged. Hosts pass the new keywords only when a setting is set, so argv, integration keyword arguments, status, errors, and exceptions match main. The one difference: once a command or prompt step reaches dispatch, its output also includes reasoning_effort and context_size, which are null when unset. A step that fails earlier on invalid configuration, such as a bad timeout, keeps its previous output shape. record() is unchanged.
  • Compatibility:
    • The new StepContext fields are appended, so positional construction is unchanged.
    • The installer's required adapter signature is unchanged.
    • There is no schema bump. Older Spec Kit versions ignore unknown step keys, as they did for capture, integration_args, and strict, and the docs say so. requires.speckit_version remains advisory.
  • Docs:
    • docs/workflow-steps/types.md:
      • a new "Reasoning Effort and Context Size" section;
      • a note that a command step's options are recorded but not passed to the CLI, as the issue requested.
    • docs/workflows/api.md: schema rows for the defaults, and corrected workflow.options wording.
    • docs/workflow-steps/api.md: the new StepContext fields.
    • 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.
    • The issue's checklist names docs/reference/workflows.md, which docs: consolidate and correct workflow documentation #5225 removed, and workflows/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.

  1. Integrations, versions, and values. The CLI arguments were checked locally:

    • GitHub Copilot CLI 1.0.106: --reasoning-effort none|minimal|low|medium|high|xhigh|max and --context default|long_context. Invalid values are rejected.
    • Claude Code 2.1.318: --effort low|medium|high|xhigh|max. Unknown values only produce a warning, so the integration PR validates them.
    • Codex CLI 0.165.0: -c model_reasoning_effort="<v>" and -c model_context_window=<i64>.

    Spec Kit does not normalize vocabularies across integrations.

  2. 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.

  3. 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.

  4. Failure and compatibility behavior.

    • Unsupported settings fail the step, including settings inherited from workflow defaults.
    • A CLI's own rejection fails the step like any CLI error. The error reports the exit code, and the CLI's message goes to the terminal, or to output.stderr with capture: true.
    • Older Spec Kit versions ignore the fields; see "Compatibility" above.
  5. 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 on main 47114315, in a clean worktree, without the integration PR, except where a result names an earlier head. Before the rebase onto 47114315, this PR's first two commits were 62cd20d0 and 6a8ae513, on ec9a6f3b. They are now 9a98075f and 964adcbd, with identical src/ and tests/ changes (git range-diff); the only difference is the resolved conflict in docs/workflow-steps/api.md.

  • Tested locally with uv run specify --help: exit 0. The environment's package index is a proxy, so the command ran without syncing.
  • Ran existing tests with uv sync && uv run pytest, in an equivalent .venv. Results are below.
  • Tested with a sample project. See "Manual test results".
Command Result
uvx [email protected] check src tests All checks passed
npx [email protected] on the six changed docs, plus a relative link and anchor check 0 issues; all 73 relative links and anchors resolve
git diff --check clean
.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 6259 passed, 8 skipped
.venv/bin/python -m pytest -q -n 6 (full suite), then a serial re-run of every failure Under -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 on main 47114315 here because Rich wraps this machine's long virtualenv path. It passes with COLUMNS=400.

New tests:

  • tests/workflows/test_dispatch_settings.py covers command and prompt steps:
    • resolution and the opt-out;
    • literal and resolved value validation, including a 1 MiB untrusted value with control characters;
    • a run in which a malformed value read from captured output stays out of the step error and log.jsonl;
    • unsupported integrations failing before executable detection, with source attribution;
    • the ownership negatives: an inherited format-base builder, a legacy **kwargs override, a str declaration, and forwarding to super();
    • attribution with continue_on_error;
    • strict-signature stubs proving that unset settings pass no new keywords;
    • a malformed EXTRA_ARGS still raising from a prompt step;
    • native rejections, captured and streamed;
    • workflow-default validation;
    • run, resume, child-call, and fan-out wiring;
    • StepContext positional compatibility.
  • tests/integrations/test_base.py covers the contract itself:
    • the value rules, including an error that reports only a malformed value's type and length, and the ownership rule;
    • the gate's order and attribution;
    • the base and format-base builders;
    • base dispatch_command forwarding;
    • the specify check probe.
  • tests/specify_cli/integrations/test_installed_adapters.py runs an installed external adapter in a fresh specify process, through workflow run and workflow resume. It covers an adapter that declares support and a legacy adapter that does not.

Test selection reasoning

Changed file Affects Test Why
src/specify_cli/workflows/step/command/__init__.py, step/prompt/__init__.py, step/_dispatch_settings.py, engine.py, _execution.py, workflows/base.py specify workflow run and specify workflow resume T1, T2, T4 Step resolution, validation, dispatch, and engine context wiring
src/specify_cli/integrations/base.py Integration dispatch and the specify check probe T1, T2, T3, T4 Shared builder and dispatch contract
docs/**, design/integration.md none none Documentation only

No 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 run through 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 with specify init --integration copilot. T1–T3 ran on 62cd20d0, before the rebase. This PR's later commits change only the malformed-value error text, which they do not quote, and docs.

Command tested Notes
T1 specify workflow run with a Copilot command step and prompt step, no settings, on main and on this PR Both completed. The argv logs are byte-identical (cmp): ["-p", "/speckit-plan add OAuth login", "--yolo"] and ["-p", "Review the plan for gaps", "--yolo"]. Step outputs record reasoning_effort: null and context_size: null.
T2 specify workflow run: unsupported settings, opt-out, unsafe literal This PR adds no mappings, so Copilot does not support either setting yet. workflow.reasoning_effort: medium failed the command step before the CLI ran (no argv logged), ending with (set by workflow.reasoning_effort). A prompt step's context_size: long_context failed the same way, ending with (set by step). A step whose reasoning_effort expression resolved to "" ran with unchanged argv despite an unsupported workflow default. The literal reasoning_effort: "-rf" failed workflow validation.
T3 specify check Output identical to main; exit 0
T4 specify workflow run on 62cd20d0, on 6a8ae513, and on 553667f3: a prompt step captures the CLI's output, and the next step reads it as reasoning_effort The captured text (GitHub Copilot CLI 1.0.106…) fails the format check, so the second step fails before its CLI runs. On 62cd20d0, the terminal error and the step_failed event in log.jsonl both included ('GitHub Copilot CLI 1.0.1'…). On 6a8ae513 and 553667f3, both end with got a string of length N. (set by step) (73, then 74 after a CLI update), and the captured text appears only in state.json, as documented. This run used a bare project with only .specify/workflows/.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

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 (now 964adcbd) 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 onto 47114315 to resolve a conflict with #5296, and wrote 553667f3, which documents the adapter opt-in contract in the integration API reference that #5296 added.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 options are 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)

Comment thread src/specify_cli/integrations/base.py Resolved
Copilot AI auto review requested due to automatic review settings November 5, 2026 09:01
@sukanth

sukanth commented Nov 5, 2026

Copy link
Copy Markdown
Author

Commit 6a8ae513 addresses the Copilot review of 62cd20d0 (thread). An error about a malformed dispatch setting value now reports only got a string of length N. and contains no part of the value; the 24-character preview is removed from dispatch_setting_value_error(). design/integration.md and the validate_dispatch_setting() docstring tell adapters to keep the value out of their own errors, and the "Values" paragraph in docs/workflow-steps/types.md states the behavior.

Two regression tests cover it: test_malformed_values_report_only_type_and_length in tests/integrations/test_base.py, and test_rejected_captured_output_stays_out_of_the_error_and_log in tests/workflows/test_dispatch_settings.py, which runs WorkflowEngine on captured output and checks the step error and log.jsonl. The 97 affected test cases fail against 62cd20d0 and pass on 6a8ae513. The PR description has the updated suite results and a before-and-after specify workflow run with Copilot CLI 1.0.106.

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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)

Comment thread src/specify_cli/integrations/base.py Resolved
@mnriem mnriem added the triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review label Nov 5, 2026
Sukanth Gunda and others added 3 commits November 6, 2026 13:09
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]>
@sukanth
sukanth force-pushed the feat/4916-dispatch-settings branch from 6a8ae51 to 553667f Compare November 6, 2026 19:28
Copilot AI auto review requested due to automatic review settings November 6, 2026 19:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new dispatch-settings ownership rules, validation gate, and adapter API changes alter a public integration contract and require maintainer sign-off.

No open issues 🎉

1 resolved since last review

Review effort: Max (auto)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new public adapter contract and workflow schema fields require maintainer approval of the architecture, especially given the lack of line-by-line human review.

No open issues 🎉

Review effort: Max (auto)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants