Skip to content

[Bug]: [Copilot/VS Code] Automatic hooks cannot invoke sub-agents #2330

@Huljo

Description

@Huljo

Bug Description

While building a local Spec Kit extension that logs execution timestamps for each Spec Kit command in a project, I registered before_* hooks with optional: false to silently record a start time before each command runs. The hooks are registered correctly in .specify/extensions.yml and the target command is valid but in VS Code Copilot, mandatory hooks never execute. The model skips them entirely at runtime with error "Cannot auto-execute in this context."

Impact

  • Any extension relying on optional: false before/after hooks for automated, silent side effects (e.g. timing, logging, git commits) is entirely broken on VS Code Copilot.
  • optional: true hooks do display a prompt ("To execute: /cmd"), but require the user to manually trigger them defeating the purpose of automatic hooks.
  • The only current workaround for Copilot is to inject standing instructions into .github/copilot-instructions.md so the inline agent context performs the side effect directly. A fragile, non-composable approach that doesn't scale.

Steps to Reproduce

Environment

  • AI agent: VS Code Copilot (GitHub Copilot Chat, agent mode)
  • Hook type: optional: false (mandatory/automatic)
  • optional: true hooks: work partially: prompt is shown but user must manually invoke

Steps

  1. Install Spec Kit in a project and set up VS Code Copilot as the AI agent.

  2. Create a local extension with a mandatory before hook:

hooks:
  before_specify:
    command: myext.do-something
    optional: false
  1. Install the extension:
specify extension add --dev ./my-extension
  1. Open VS Code Copilot agent mode and run /speckit.specify some feature description.

  2. Observe that the model outputs something like:

"Cannot auto-execute in this context. Proceeding with spec creation."

  1. Confirm that myext.do-something was never invoked: no files written, no scripts called, no side effects of any kind.

Expected Behavior

Hooks registered with optional: false execute automatically when a Spec Kit command runs, regardless of the invocation pattern used.

If the current named agent context cannot support sub-agent invocation, Spec Kit should document a supported invocation pattern where hooks actually fire on Copilot, or provide an alternative mechanism for extensions to run side effects in that context.

Actual Behavior

Given an extension with a before_specify hook:

hooks:
  before_specify:
    command: myext.do-something
    optional: false

When the user runs /speckit.specify in VS Code Copilot, the model outputs "Cannot auto-execute in this context" and moves on. The hook command never runs. No script is called, no sub-agent is invoked.

Specify CLI Version

0.7.4

AI Agent

GitHub Copilot

Operating System

Ubuntu 24.04

Python Version

3.12.3

Error Logs

Cannot auto-execute in this context.

Additional Context

Suggested fix / investigation

VS Code Copilot's agent mode supports invoking other agents via the agent frontmatter field and handoff prompts. It may be possible to express the hook invocation as a structured handoff or tool call rather than a free-text instruction so Copilot's runtime can act on it programmatically rather than treating it as prose.

Alternatively, Spec Kit could generate a Copilot-specific hook invocation format (e.g. a <!-- @invoke --> directive or a structured YAML block) that maps to whatever mechanism Copilot does support for chained agent calls.

My current workaround (for extension authors targeting VS Code Copilot)

Inject instructions into .github/copilot-instructions.md, which is included in every Copilot agent session:

<!-- MYEXT START -->
At the very beginning of any `/speckit.*` command, silently write <file> with <data>.
<!-- MYEXT END -->

The problem of this approach:

  1. It mutates a project file. .github/copilot-instructions.md belongs to the project, not to the extension. An extension injecting content into it creates a coupling that is hard to audit, update, or remove cleanly — especially when multiple extensions do the same thing.
  2. It breaks extension isolation. The whole point of the extension system is that logic lives in the extension, not scattered across project files. With this workaround, uninstalling an extension doesn't cleanly remove its behaviour and the injected block stays in copilot-instructions.md unless the user manually cleans it up.

The correct fix is for Spec Kit (or Copilot's agent runtime) to provide a mechanism for hooks to execute that does not rely on the model voluntarily invoking a sub-agent mid-session.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions