Skip to content

fix(workflows): auto-detect project integration instead of hardcoding "copilot"#2502

Open
markuswondrak wants to merge 2 commits intogithub:mainfrom
markuswondrak:fix/workflow-auto-detect-integration
Open

fix(workflows): auto-detect project integration instead of hardcoding "copilot"#2502
markuswondrak wants to merge 2 commits intogithub:mainfrom
markuswondrak:fix/workflow-auto-detect-integration

Conversation

@markuswondrak
Copy link
Copy Markdown

Description

Fixes the hardcoded "copilot" default in workflow.yml that caused the workflow engine to dispatch to Copilot even when the project was initialized with a different integration (e.g. opencode).

Introduces an "auto" sentinel for the integration input: when auto is the resolved value, the engine reads .specify/integration.json to determine the active integration at runtime.

Changes:

  • integration_state.py — new read_integration_state() function with typed error classes (IntegrationStateError, IntegrationStateSchemaError)
  • __init__.py_read_integration_json() now delegates to read_integration_state() instead of inlining the logic
  • workflows/engine.py_resolve_default() / _resolve_workflow_integration() resolve the "auto" sentinel at runtime
  • workflow.yml — default changed from "copilot" to "auto"; added opencode to requires.integrations.any
  • Tests extended for state reader and engine auto-detection

Fixes #2406

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest

AI Disclosure

  • I did use AI assistance (describe below)

GitHub Copilot assisted with code generation and test scaffolding.

… "copilot"

Resolves the hardcoded "copilot" default in workflow.yml by introducing
an "auto" sentinel that reads the active integration from
.specify/integration.json at runtime.

- Add read_integration_state() to integration_state.py with typed errors
- Refactor _read_integration_json() in __init__.py to use it
- Add _resolve_default() / _resolve_workflow_integration() to engine
- Change workflow.yml default from "copilot" to "auto"
- Add "opencode" to supported integrations list
- Extend tests for state reader and engine auto-detection

Fixes github#2406

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 8, 2026 15:02
@markuswondrak markuswondrak requested a review from mnriem as a code owner May 8, 2026 15:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the workflow system to avoid hardcoding the "copilot" integration by introducing an "auto" sentinel that resolves the active integration from project metadata (primarily .specify/integration.json) at runtime, with fallback to legacy init options.

Changes:

  • Switches the bundled Speckit workflow’s integration input default from "copilot" to "auto" and allows opencode in workflow requirements.
  • Adds integration state reading/resolution helpers (with typed error classes) and wires the workflow engine to resolve "auto" during input/default integration resolution.
  • Extends tests to cover integration auto-detection behavior (including persistence across resume) and integration state reader behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
workflows/speckit/workflow.yml Changes default integration input to "auto" and adds opencode to allowed integrations.
src/specify_cli/integration_state.py Adds read_integration_state() / resolve_project_integration() plus typed errors for invalid/unreadable state.
src/specify_cli/workflows/engine.py Resolves "auto" for inputs/workflow integration, persists resolved integration in run state, and uses it on resume.
src/specify_cli/init.py Delegates integration.json loading to the new integration state reader and maps typed errors to CLI output/exit.
tests/integrations/test_integration_state.py Adds unit tests for reading/validating integration state and project integration resolution.
tests/test_workflows.py Adds workflow-engine tests for "auto" integration resolution and run/resume pinning behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/specify_cli/workflows/engine.py Outdated
Comment thread src/specify_cli/integration_state.py Outdated
- integration_state.py: distinguish 'does not exist' (return None) from
  'exists but not a regular file' (raise IntegrationStateError), restoring
  the behavior of the old inline code that used path.exists() + caught OSError

- engine.py: call _coerce_input() on resolved defaults so enum validation
  and type coercion apply to default values, matching the path for
  user-provided inputs; previously the auto-sentinel resolved via
  _resolve_default() bypassed _coerce_input() entirely

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment on lines +197 to +199
raise IntegrationStateError(f"Could not read {path}") from exc
except json.JSONDecodeError as exc:
raise IntegrationStateError(f"{path} contains invalid JSON") from exc
Comment on lines 1930 to 1939
try:
data = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
console.print(f"[red]Error:[/red] {path} contains invalid JSON.")
console.print(f"Please fix or delete {INTEGRATION_JSON} and retry.")
console.print(f"[dim]Details:[/dim] {exc}")
raise typer.Exit(1)
except OSError as exc:
console.print(f"[red]Error:[/red] Could not read {path}.")
console.print(f"Please fix file permissions or delete {INTEGRATION_JSON} and retry.")
console.print(f"[dim]Details:[/dim] {exc}")
state = _read_integration_state(project_root)
except _IntegrationStateSchemaError as exc:
console.print(f"[red]Error:[/red] {exc}")
console.print("Please upgrade Spec Kit before modifying integrations.")
raise typer.Exit(1)
if not isinstance(data, dict):
console.print(f"[red]Error:[/red] {path} must contain a JSON object, got {type(data).__name__}.")
except _IntegrationStateError as exc:
console.print(f"[red]Error:[/red] {exc}")
console.print(f"Please fix or delete {INTEGRATION_JSON} and retry.")
raise typer.Exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Workflow engine hardcodes "copilot" default, ignoring project's initialized integration (e.g., opencode)

2 participants