Skip to content

Add init workflow step to bootstrap projects like specify init#2838

Merged
mnriem merged 15 commits into
mainfrom
copilot/add-init-step-bootstrap-project
Jun 17, 2026
Merged

Add init workflow step to bootstrap projects like specify init#2838
mnriem merged 15 commits into
mainfrom
copilot/add-init-step-bootstrap-project

Conversation

Copilot AI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Workflows had no way to scaffold a project; users had to run specify init manually before any workflow could drive the spec-driven process. This adds an init step type so a workflow can bootstrap (or merge into) a project itself.

Changes

  • New InitStep (type: init) in src/specify_cli/workflows/steps/init/ — runs the bundled specify init command in-process against context.project_root, capturing exit_code/stdout/stderr and returning FAILED on non-zero exit.
    • Config fields (all optional): project, here, integration, integration_options, script, force, ignore_agent_tools, preset; string fields resolve {{ }} expressions.
    • Integration falls back to the workflow-level default, then to DEFAULT_INIT_INTEGRATION (copilot); defaults to --ignore-agent-tools since workflows run unattended.
    • When only engine-owned directories (.specify/) exist, --force is implicitly added so init proceeds unattended.
    • validate() rejects script values other than sh/ps.
  • Registration — added to STEP_REGISTRY and the engine's valid-step-types fallback.
  • Docsworkflows/ARCHITECTURE.md and workflows/README.md updated (step table, module tree, new "Init Steps" section).
  • Tests — coverage for bootstrap, default-integration fallback, project-name subdirectory, invalid-integration failure, engine-owned dir handling, integration_options passthrough, and validation.

Example

- id: bootstrap
  type: init
  here: true
  integration: copilot   # optional; defaults to workflow integration
  integration_options: "--skills"  # optional
  script: sh

Copilot AI requested review from Copilot and removed request for Copilot June 3, 2026 21:49
Copilot AI linked an issue Jun 3, 2026 that may be closed by this pull request
Copilot AI requested review from Copilot and removed request for Copilot June 3, 2026 21:56
Copilot AI changed the title [WIP] Add InitStep for bootstrapping project workflow Add init workflow step to bootstrap projects like specify init Jun 3, 2026
Copilot finished work on behalf of mnriem June 3, 2026 21:58
Copilot AI requested a review from mnriem June 3, 2026 21:58
@mnriem mnriem requested a review from Copilot June 3, 2026 22:41

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.

Pull request overview

Adds a new workflow step type (type: init) so workflows can bootstrap (or merge into) a Spec Kit project by invoking the bundled specify init logic in-process, enabling end-to-end “scaffold → run steps” workflows without requiring a manual pre-step.

Changes:

  • Introduces InitStep (src/specify_cli/workflows/steps/init/) that builds specify init argv from step config, runs it via CliRunner, and captures exit_code/stdout/stderr.
  • Registers the new step type in the workflow step registry and engine’s valid-step-type fallback, and updates architecture/README docs.
  • Adds tests covering argv building, workflow-default integration fallback, directory creation via project, invalid integration failure, and validation.
Show a summary per file
File Description
workflows/README.md Documents the new init step type and provides a YAML example.
workflows/ARCHITECTURE.md Updates step-type counts/table and module tree to include init.
tests/test_workflows.py Adds test coverage for the new InitStep.
src/specify_cli/workflows/steps/init/init.py Implements InitStep execution, expression resolution, and validation.
src/specify_cli/workflows/engine.py Adds init to the engine’s valid step-type fallback set.
src/specify_cli/workflows/init.py Registers InitStep in the built-in STEP_REGISTRY.

Copilot's findings

Tip

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

  • Files reviewed: 6/6 changed files
  • Comments generated: 3

Comment thread workflows/README.md Outdated
Comment thread src/specify_cli/workflows/steps/init/__init__.py
Comment thread src/specify_cli/workflows/steps/init/__init__.py

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 1

Comment thread src/specify_cli/workflows/steps/init/__init__.py

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 3

Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
Comment thread src/specify_cli/workflows/steps/init/__init__.py
Comment thread src/specify_cli/workflows/steps/init/__init__.py Fixed
@mnriem mnriem marked this pull request as ready for review June 8, 2026 19:53
…ne-owned dirs

- Apply DEFAULT_INIT_INTEGRATION fallback when neither step config nor
  workflow context provides an integration, so output.integration always
  reflects the actual integration used.
- Add integration_options config field to support --integration-options
  passthrough (required for generic integration and --skills mode).
- Exclude .specify/ from the non-empty directory fast-fail check so that
  here: true works when the engine has already created its run-state
  directory before steps execute.
- Note: mix_stderr=False is not needed — Click 8.2+ captures stderr
  separately by default and the existing try/except handles access.

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

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 3

Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
Comment thread tests/test_workflows.py
Comment thread src/specify_cli/workflows/steps/init/__init__.py
When the workflow engine creates .specify/workflows/runs/ before steps
execute, the directory is technically non-empty. Previously, specify init
would prompt for confirmation (hanging in unattended mode) unless the
user explicitly set force: true. Now the step detects that only
engine-owned directories (.specify/) are present and implicitly adds
--force so init proceeds without user interaction.

Also fixes the test to exercise the implicit-force path rather than
passing force: True explicitly (which bypassed the check entirely).

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

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 4

Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
Comment thread src/specify_cli/workflows/steps/init/__init__.py
Comment thread src/specify_cli/workflows/steps/init/__init__.py
…rror, include all resolved fields in output

- Derive VALID_SCRIPT_TYPES from SCRIPT_TYPE_CHOICES in _agent_config
  so the valid set cannot drift from the specify init CLI.
- Fail fast with a clear error when os.scandir() raises OSError (e.g.
  permission denied) instead of silently treating the directory as empty.
- Include preset, force, and ignore_agent_tools in all output dicts
  (both fast-fail and normal paths) for consistent interpolation and
  debugging downstream.

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

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
Comment thread workflows/README.md Outdated
…rding

- When Click does not expose result.stderr (older versions where stderr
  is mixed into stdout), use stdout as stderr on non-zero exit so
  workflows can consistently read steps.<id>.output.stderr for errors.
- Update README inline comment for force: wording to say 'when target
  directory already exists' rather than 'non-empty directory', matching
  the actual specify init behavior for the project: form.

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

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 3

Comment thread src/specify_cli/workflows/steps/init/__init__.py
Comment thread src/specify_cli/workflows/steps/init/__init__.py
Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
- Move argv flag-building (--integration, --script, --preset,
  --ignore-agent-tools) before the non-empty-dir and OSError early
  returns so output['argv'] always reflects the complete command.
- --force is appended after the check since it may be set implicitly.
- Replace list comprehension with any() generator expression to
  short-circuit without allocating a full list of DirEntry objects.

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

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 1

Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
A file or symlink named .specify should not be excluded from the
non-empty check. Use entry.is_dir(follow_symlinks=False) to ensure
only an actual directory is considered engine-owned content.

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

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
Comment thread src/specify_cli/workflows/steps/init/__init__.py Outdated
…ack order

- Only set implicit --force when engine-owned directories (.specify/)
  are actually present. A completely empty directory no longer gets
  --force added unnecessarily.
- Fix integration resolution precedence: resolve step config expression
  first, then fall back to workflow default (also resolved), then to
  DEFAULT_INIT_INTEGRATION. Previously, a step expression resolving to
  falsy would bypass the workflow default entirely.

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

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.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new

@mnriem mnriem merged commit 00bff78 into main Jun 17, 2026
13 checks passed
@mnriem mnriem deleted the copilot/add-init-step-bootstrap-project branch June 17, 2026 16:46
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.

Add a InitStep so we can use a workflow to bootstrap a project

3 participants