Skip to content

feat: add --allow-model-invocation flag for agent-orchestrated workflows#2099

Open
srobroek wants to merge 1 commit intogithub:mainfrom
srobroek:feat/allow-model-invocation
Open

feat: add --allow-model-invocation flag for agent-orchestrated workflows#2099
srobroek wants to merge 1 commit intogithub:mainfrom
srobroek:feat/allow-model-invocation

Conversation

@srobroek
Copy link
Copy Markdown

@srobroek srobroek commented Apr 5, 2026

Summary

  • Add --allow-model-invocation flag to specify init
  • Persist choice in .specify/init-options.json
  • build_skill_frontmatter() reads the option and conditionally sets disable-model-invocation
  • Extension and preset installs automatically respect the persisted option

Implementation Details

The flag defaults to false (skills disabled for model invocation) to maintain backward compatibility. When a user runs:

specify init --integration claude --allow-model-invocation

The generated SKILL.md files will have disable-model-invocation: false, allowing the AI model to invoke speckit skills programmatically for agent-orchestrated workflows.

Changes

  • CLI: Added --allow-model-invocation option to specify init command
  • Persistence: Flag stored in .specify/init-options.json for consistent behavior
  • Skill Generation: CommandRegistrar.build_skill_frontmatter() now accepts optional project_root parameter and reads init-options to determine the flag value
  • Integration Setup: ClaudeIntegration.setup() conditionally injects disable-model-invocation based on the persisted option
  • Extensions & Presets: All skill generation paths (init, extension install, preset install) respect the setting
  • Tests: Added comprehensive test coverage for all scenarios

Testing

All existing tests pass, plus 4 new tests covering:

  1. Default behavior (disable-model-invocation: true)
  2. Flag enabled behavior (disable-model-invocation: false)
  3. build_skill_frontmatter() respects init-options.json
  4. Preset installs respect the setting
pytest tests/integrations/test_integration_claude.py::TestAllowModelInvocation -xvs
# 4 passed

Fixes #2098

AI Disclosure (per CONTRIBUTING.md): Claude Code was used for code generation. Changes were reviewed and tested by the submitter.

Add `--allow-model-invocation` flag to `specify init` that controls
whether generated SKILL.md files get `disable-model-invocation: false`
(allowing the AI model to invoke skills programmatically) or `true`
(requiring explicit user invocation).

Changes:
- Add `--allow-model-invocation` CLI option to `specify init` command
- Persist flag in `.specify/init-options.json`
- Update `build_skill_frontmatter()` to read `allow_model_invocation`
  from init-options and conditionally set `disable-model-invocation`
- Update `ClaudeIntegration.setup()` to conditionally inject the flag
  based on the persisted option
- Extension and preset installs automatically respect the setting
- Add comprehensive test coverage for the new functionality

The flag defaults to false (skills disabled for model invocation) to
maintain backward compatibility and prevent unexpected behavior.

Fixes github#2098
@srobroek srobroek requested a review from mnriem as a code owner April 5, 2026 05:39
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 6, 2026

In order to not bleed in integration specific options into the CLI we have added a singular --integration-options flag that should be used that then subsequently shunts it into the integration. For your case it should look like --integration-optons="--allow-model-invocation". Also note that the integration is solely responsible for this additional flag and we should probably make sure CommandRegistry renders the skill altogether (we might not be there yet, but that is where we will end up).

Copy link
Copy Markdown
Collaborator

@mnriem mnriem left a comment

Choose a reason for hiding this comment

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

Please address comments above

@kennedy-whytech
Copy link
Copy Markdown

support for the option to --allow-model-invocation, so there's more potential for integration.

@mnriem mnriem requested a review from Copilot April 13, 2026 12:30
@mnriem mnriem self-assigned this Apr 13, 2026
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

Adds an opt-in --allow-model-invocation initialization flag that’s persisted to .specify/init-options.json and then used to control whether generated Claude SKILL.md files set disable-model-invocation to false (allowing agent-orchestrated auto-invocation). This setting is propagated through skill generation paths so extensions/presets produce consistent frontmatter.

Changes:

  • Add --allow-model-invocation to specify init and persist the choice in .specify/init-options.json.
  • Make CommandRegistrar.build_skill_frontmatter() optionally read persisted init options (via project_root) to set disable-model-invocation.
  • Update Claude integration post-processing + extension/preset skill generators to respect the persisted setting; add tests for default vs enabled behavior.
Show a summary per file
File Description
tests/integrations/test_integration_claude.py Adds end-to-end and unit tests covering default and opt-in model invocation behavior across init/frontmatter/preset install paths.
src/specify_cli/init.py Introduces the --allow-model-invocation init flag and persists init options earlier so integrations can read them during setup.
src/specify_cli/agents.py Extends skill frontmatter builder to optionally consult init-options and conditionally set disable-model-invocation.
src/specify_cli/integrations/claude/init.py Reads persisted init options during setup to inject disable-model-invocation appropriately into generated skills.
src/specify_cli/extensions.py Passes project_root into skill frontmatter generation so extension skill overrides inherit the persisted setting.
src/specify_cli/presets.py Passes project_root into skill frontmatter generation so preset skill overrides inherit the persisted setting.

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: 1

Comment on lines +1145 to +1149
# Persist allow_model_invocation flag if specified
if allow_model_invocation:
init_opts["allow_model_invocation"] = True
save_init_options(project_path, init_opts)

Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

init-options.json is written before resolved_integration.setup(). If setup() (or any later step) fails while running in --here mode, the project directory is not cleaned up, so this file can be left behind even though initialization failed. Since other commands use init-options to infer project state (e.g., script type / skills dirs), consider either (a) writing a temporary init-options file and only finalizing it after init completes successfully, or (b) explicitly removing/rolling back .specify/init-options.json in the exception path when init fails.

See below for a potential fix:

            init_options_path = project_path / ".specify" / "init-options.json"
            save_init_options(project_path, init_opts)

            try:
                resolved_integration.setup(
                    project_path, manifest,
                    parsed_options=integration_parsed_options or None,
                    script_type=selected_script,
                    raw_options=integration_options,
                )
                manifest.save()

                # Write .specify/integration.json
                script_ext = "sh" if selected_script == "sh" else "ps1"
                integration_json = project_path / ".specify" / "integration.json"
                integration_json.parent.mkdir(parents=True, exist_ok=True)
                integration_json.write_text(json.dumps({
                    "integration": resolved_integration.key,
                    "version": get_speckit_version(),
                    "scripts": {
                        "update-context": f".specify/integrations/{resolved_integration.key}/scripts/update-context.{script_ext}",
                    },
                }, indent=2) + "\n", encoding="utf-8")
            except Exception:
                init_options_path.unlink(missing_ok=True)
                raise

Copilot uses AI. Check for mistakes.
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 13, 2026

You must use --integration-options="--allow-model-invocation" and not parse them in the top level init.py. Each integration is responsible for its own options.

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.

[Feature]: add --allow-model-invocation flag for agent-orchestrated workflows

5 participants