Skip to content

[Feature]: Per step integration configuration in workflows #4275

Description

@nervgh

Problem Statement

Workflow steps currently allow specifying an integration, but do not provide a way to configure that integration independently for a particular step.

This is limiting for integrations whose CLI requires additional runtime arguments or options. For example, Docker Agent may be launched like:

docker-agent run ./agent.yaml --exec "<prompt>"

The ./agent.yaml path must be passed before the prompt as a positional argument. Also, an integration may require additional key-value options such as:

--agent root
--model provider/model
--safety balanced

The current SPECKIT_INTEGRATION_<KEY>_EXTRA_ARGS environment variable applies to the entire process rather than to an individual workflow step. This prevents a workflow from using different integration configurations for different steps and makes the effective configuration invisible in the workflow definition.

Proposed Solution

Add per-step integration configuration to the workflow step definition.

The existing integration field remains a string containing the integration key:

- id: specify
  command: speckit.specify
  integration: docker-agent
  input:
    args: "{{ inputs.spec }}"

Add two optional fields:

- id: specify
  command: speckit.specify
  integration: docker-agent
  integration_args:
    - ./agent.yaml
  integration_options:
    agent: root
    safety: balanced
  input:
    args: "{{ inputs.spec }}"

Where

integration_args

integration_args is an ordered list of positional arguments passed to the selected integration before the generated prompt.

For Docker Agent:

integration_args:
  - ./agent.yaml

should produce a command equivalent to:

docker-agent run ./agent.yaml --exec --json "<prompt>"

The order of values in integration_args must be preserved.

integration_options

integration_options is a mapping of key-value options passed to the selected integration.

integration_options:
  agent: root
  safety: balanced

The integration is responsible for translating these options into its native CLI representation:

--agent root --safety balanced

Integration-specific options should be validated by the selected integration. Unknown options must result in an actionable validation error.

Runtime API

The workflow runner should resolve and pass these values only to the current step:

integration.dispatch_command(
    command,
    args=command_args,
    project_root=project_root,
    model=model,
    integration_args=resolved_integration_args,
    integration_options=resolved_integration_options,
)

The integration API should expose the values to command construction:

def build_exec_args(
    self,
    prompt: str,
    *,
    model: str | None = None,
    output_json: bool = True,
    integration_args: Sequence[str] | None = None,
    integration_options: Mapping[str, Any] | None = None,
) -> list[str] | None:
    ...

The existing integrations must remain compatible. Integrations that do not use per-step configuration should ignore empty integration_args and integration_options.

Alternatives Considered

Global environment variables

export SPECKIT_INTEGRATION_DOCKER_AGENT_EXTRA_ARGS=./agent.yaml
specify workflow run speckit -i spec="..."

This is already available for some use cases, but it applies to the whole workflow process. It cannot express different configurations for individual steps and hides important workflow configuration outside the workflow definition.

Step-level environment variables

- id: specify
  type: command
  env:
    SPECKIT_INTEGRATION_DOCKER_AGENT_EXTRA_ARGS: ./agent.yaml

This would require adding per-step environment handling and carefully isolating child-process environments. It also retains the ambiguity of treating a path as an untyped arbitrary environment string.

A dedicated agent_config field

integration:
  name: docker-agent
  agent_config: ./agent.yaml

This is clear for Docker Agent, but introduces an integration-specific field into the common workflow schema. It does not generalize well to integrations that need multiple positional arguments or different key-value options.

Changing integration from a string to a mapping

integration:
  name: docker-agent
  options:
    ...

This could express the desired configuration, but would change the existing type and break compatibility with current workflow definitions that use:

integration: docker-agent

Keeping integration as a string and adding integration_args and integration_options avoids that breaking change.

Component

Agent integrations (command files, workflows)

AI Agent (if applicable)

None

Use Cases

No response

Acceptance Criteria

  • Workflow steps accept an optional integration_args list.
  • Workflow steps accept an optional integration_options mapping.
  • integration_args values are resolved using the existing workflow expression mechanism.
  • integration_options values are resolved using the existing workflow expression mechanism.
  • Positional arguments preserve their declared order.
  • Integration arguments are passed only to the step where they are declared.
  • Integration options are passed only to the step where they are declared.
  • Integrations that do not use these fields continue to work unchanged.
  • Unknown or malformed integration options produce actionable validation errors.
  • Relative file paths are resolved relative to the workflow project root where appropriate.
  • Per-step integration configuration is persisted in workflow run state so resume behavior is deterministic.
  • Configuration values are not interpolated into shell commands as unescaped strings.
  • Existing SPECKIT_INTEGRATION_<KEY>_EXTRA_ARGS behavior remains backward compatible.
  • Tests cover:
    • no per-step configuration;
    • positional arguments;
    • key-value options;
    • expression-based values;
    • separate configurations across multiple steps;
    • workflow resume.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions