|
| 1 | +# Copilot Extension Hooks |
| 2 | + |
| 3 | +Copilot Extension Hooks **1.0.0** is an independently configurable, opt-in |
| 4 | +Specify preset for Copilot **skills mode**. It wraps one selected |
| 5 | +`copilot-lean-sdd` or `copilot-full-sdd` baseline without replacing or editing |
| 6 | +its body, metadata, artifact requirements, approval gates, or safeguards. |
| 7 | +It is not a Copilot plugin and does not control Copilot native hooks/events. |
| 8 | + |
| 9 | +Requires released Specify CLI **1.2.3 exactly**, a project initialized by that |
| 10 | +release in Copilot skills mode, and exactly one of those hook-free baselines. |
| 11 | +The version constraint describes the validated composition contract, not the |
| 12 | +version of this preset. Full also requires 1.2.3; Lean's broader requirement is |
| 13 | +compatible with it. Install trusted extensions separately; this preset neither |
| 14 | +installs extensions nor registers hooks. Their installed command skills must be |
| 15 | +available to the Copilot host. |
| 16 | + |
| 17 | +## Install and configure |
| 18 | + |
| 19 | +**Initial release pending.** The catalog reserves a release URL; source addition |
| 20 | +does not publish an asset. For local development in a disposable project: |
| 21 | + |
| 22 | +```bash |
| 23 | +specify --version # must report 1.2.3 |
| 24 | +specify init /path/to/project --integration copilot --integration-options="--skills" --non-interactive --script sh |
| 25 | +cd /path/to/project |
| 26 | +specify preset add --dev /path/to/spec-kit-copilot/spec-kit-presets/copilot-lean-sdd --priority 10 |
| 27 | +# OR install copilot-full-sdd at priority 10, not both baselines. |
| 28 | +specify preset add --dev /path/to/spec-kit-copilot/spec-kit-presets/copilot-extension-hooks --priority 5 |
| 29 | +specify preset resolve speckit.plan |
| 30 | +``` |
| 31 | + |
| 32 | +Use `--script ps` or `--script py` as appropriate. After publication, |
| 33 | +[register the preset catalog](https://github.com/github/spec-kit-copilot/blob/main/spec-kit-presets/README.md#installing-a-preset), then install |
| 34 | +the selected baseline and `specify preset add copilot-extension-hooks --priority 5`. |
| 35 | +See the shared [release guide](https://github.com/github/spec-kit-copilot/blob/main/spec-kit-presets/README.md#versioning--distribution). |
| 36 | + |
| 37 | +**Lower preset numbers have higher precedence.** The hooks layer must precede |
| 38 | +the replacement baseline (for example, hooks `5`, baseline `10`). A higher |
| 39 | +precedence replacement or project-local command override hides this wrapper. |
| 40 | +Equal priorities depend on id ordering; use distinct priorities instead. |
| 41 | +Do not compose with hook-bearing core fallbacks or another hook dispatcher. |
| 42 | +The CLI does not enforce the baseline prerequisite or exclusivity for this |
| 43 | +preset. Confirm the generated `.github/skills/speckit-*/SKILL.md` contains one |
| 44 | +`Copilot extension lifecycle checkpoints` section and the intended baseline. |
| 45 | +All nine commands are covered: constitution, specify, clarify, plan, tasks, |
| 46 | +analyze, checklist, implement, converge. `taskstoissues` is not covered. |
| 47 | + |
| 48 | +Configure individual hooks in the extension-managed `.specify/extensions.yml`: |
| 49 | + |
| 50 | +```yaml |
| 51 | +hooks: |
| 52 | + before_plan: |
| 53 | + - extension: example |
| 54 | + command: speckit.example.prepare |
| 55 | + optional: false |
| 56 | + after_plan: |
| 57 | + - extension: example |
| 58 | + command: speckit.example.review |
| 59 | + enabled: true |
| 60 | + optional: true |
| 61 | + prompt: "Review the completed plan?" |
| 62 | +``` |
| 63 | +
|
| 64 | +Replace example ids with real installed extension commands. Hooks follow the |
| 65 | +core command-template contract: YAML list order (not hook-priority sorting), |
| 66 | +missing `enabled` means enabled, explicit `enabled: false` is skipped, |
| 67 | +optional hooks are presented rather than automatically invoked, and mandatory |
| 68 | +hooks are actually invoked with results awaited sequentially. Missing `optional` |
| 69 | +defaults to optional, matching extension registration. Nonempty `condition` |
| 70 | +expressions are skipped, not interpreted by the agent; this is not |
| 71 | +HookExecutor's condition-evaluating path. The reserved |
| 72 | +`settings.auto_execute_hooks` is not an activation switch. |
| 73 | + |
| 74 | +Hook IDs and invocations are distinct: `speckit.git.commit` identifies the hook, |
| 75 | +while its installed `speckit-git-commit` skill is invoked in Copilot CLI as |
| 76 | +`/speckit-git-commit`. Optional-hook suggestions use the host-supported skill |
| 77 | +invocation; `EXECUTE_COMMAND` retains the configured dotted ID. Unavailable |
| 78 | +optional skills are reported as unavailable, not offered as executable commands. |
| 79 | + |
| 80 | +Invalid YAML is reported with its parser error and the warning that mandatory |
| 81 | +hooks could not be checked, then the workflow continues, as in core. |
| 82 | +An unavailable, denied, or failed mandatory invocation instead stops the |
| 83 | +invocation and reports failure. Completion post-hooks do not run after a |
| 84 | +baseline prerequisite/gate/validation stop. The wrapper preserves each command's |
| 85 | +checkpoint, including a completed Lean convergence assessment that leaves |
| 86 | +existing open tasks unchanged: its reported remaining work is not convergence, |
| 87 | +but it still reaches `after_converge`. Blocked assessments do not. |
| 88 | +It keeps an invocation-local dispatch record to avoid |
| 89 | +duplicate invocation, including report/checklist re-entry. It is prompt guidance, |
| 90 | +not a runtime executor, persistent lock, sandbox, or deterministic host enforcement. |
| 91 | + |
| 92 | +## Changing activation or priority |
| 93 | + |
| 94 | +Specify 1.2.3's `preset enable`, `disable`, and `set-priority` change resolution |
| 95 | +state but **do not regenerate existing skills**. `/skills reload` reloads files; |
| 96 | +it does not reconcile them. Do not claim hooks are off just because resolution |
| 97 | +or registry state changed. |
| 98 | + |
| 99 | +The validated explicit flow, with a surviving enabled baseline, is: |
| 100 | + |
| 101 | +```bash |
| 102 | +# Turn hooks off and restore generated baseline skills: |
| 103 | +specify preset remove copilot-extension-hooks |
| 104 | +
|
| 105 | +# Turn hooks back on, or apply a different wrapper priority: |
| 106 | +specify preset add --dev /path/to/spec-kit-copilot/spec-kit-presets/copilot-extension-hooks --priority 5 |
| 107 | +# After publication, use: specify preset add copilot-extension-hooks --priority 5 |
| 108 | +``` |
| 109 | + |
| 110 | +Inspect generated skills after each change, then run `/skills reload` in the |
| 111 | +current Copilot session (or start a new session). Removal/reinstallation is an |
| 112 | +explicit configuration operation, not an automatic migration; authored workflow |
| 113 | +artifacts are not changed. Use this flow rather than merely toggling an installed |
| 114 | +preset. Reliable installed-but-disabled defaults and automatic reconciliation |
| 115 | +remain shared Specify prerequisites. A future bundle may install this component |
| 116 | +disabled by default; bundle assembly/defaults are not implemented here. |
| 117 | + |
| 118 | +## Source, license, and validation |
| 119 | + |
| 120 | +Hook-handling rules and output blocks are adapted from |
| 121 | +[Spec Kit core commands at `27d14e20c187c1f2916540ea201ecbdc9f8ed588`](https://github.com/github/spec-kit/tree/27d14e20c187c1f2916540ea201ecbdc9f8ed588/templates/commands), |
| 122 | +the source retained by Full before hook removal, and checked against released |
| 123 | +1.2.3. Shared handling is factored into one wrapper; command-specific checkpoint |
| 124 | +placement is retained. Copilot skill invocation, single-dispatch tracking, and |
| 125 | +explicit mandatory-failure reporting are added. Copyright GitHub, Inc.; |
| 126 | +[MIT licensed](LICENSE). |
| 127 | + |
| 128 | +Run `python -m unittest discover -s spec-kit-presets/tests -p 'test_extension_hooks.py' -v` |
| 129 | +with PyYAML installed. Set `HOOKS_SPECIFY_BIN` to Specify 1.2.3 and |
| 130 | +`HOOKS_BASELINES_ROOT` to a source tree's `spec-kit-presets` containing both |
| 131 | +canonical baselines to include real init/install/composition/removal checks. |
| 132 | +Set `HOOKS_PRESET_ARCHIVE` to an externally built release ZIP to compare its |
| 133 | +file names, count, and file bytes with the package, normalizing CRLF to LF on |
| 134 | +both sides while preserving every other byte. This archive check is |
| 135 | +skipped when no ZIP is supplied; creating a ZIP from the expected inventory is |
| 136 | +not release-workflow validation. |
| 137 | +These checks validate files and generation, not model compliance. Bounded |
| 138 | +Copilot CLI marker-hook exercises are opt-in and consume model usage: |
| 139 | + |
| 140 | +```bash |
| 141 | +PYTHONPATH=spec-kit-presets/tests HOOKS_COPILOT_BIN=/absolute/path/to/copilot \ |
| 142 | + python -m unittest test_extension_hooks.CopilotBehaviorTests -v |
| 143 | +``` |
| 144 | + |
| 145 | +Keep the same `HOOKS_SPECIFY_BIN` and `HOOKS_BASELINES_ROOT` environment variables. |
| 146 | +These disposable local exercises cover mandatory invocation/waiting, list order, |
| 147 | +disabled/conditional/optional skipping, duplicate suppression, missing baseline |
| 148 | +inputs, denied execution, mandatory pre/post failure, absent-layer behavior, and |
| 149 | +malformed YAML. Each host process has a five-minute timeout. To retain diagnostic |
| 150 | +transcripts, set `HOOKS_EVIDENCE_DIR` to a private directory outside the repository. |
| 151 | +Rejected forbidden, duplicate, retried, or out-of-order marker calls are recorded |
| 152 | +before failing, so continuing after a tool error cannot hide the attempt. |
| 153 | +The denied-hook case blocks only the hook entry point, not the baseline's Python |
| 154 | +command, and also checks that baseline execution was not attempted. |
| 155 | +Reporting checks inspect final assistant responses for mandatory-hook failures |
| 156 | +and assistant-authored warnings for malformed YAML, not matching tool output. |
| 157 | +Negative transcript cases reject tool-only evidence and contradictory success. |
| 158 | +Separate Lean convergence cases cover existing open work and blocked assessment. |
| 159 | +The marker-hook cases seed registrations and command skills directly; they do |
| 160 | +not exercise extension installation. |
| 161 | + |
| 162 | +For the separate end-to-end installed-extension test, also set |
| 163 | +`HOOKS_SPECIFY_SOURCE` to the extracted Spec Kit **1.2.3** source tree. That test |
| 164 | +installs the unmodified bundled `git` extension with `specify extension add --dev`, |
| 165 | +checks enabled inventory and automatically registered hooks/generated skills, |
| 166 | +then executes `specify` with each baseline. It verifies that the mandatory |
| 167 | +`before_specify` hook actually invokes the extension's branch-creation script |
| 168 | +once using a constrained single-command format with a successful tool result |
| 169 | +and script JSON output, then verifies the resulting local branch. Reading the |
| 170 | +script does not count as an invocation; shell-wrapped attempts and combined |
| 171 | +calls are rejected rather than ignored, including failed retries. Simple `head`, |
| 172 | +`ls`, and numeric-range `sed -n` print inspections are allowed without counting |
| 173 | +as execution; executable `sed` expressions are not. Optional commit |
| 174 | +hooks remain unrequested. All Git operations are confined to throwaway |
| 175 | +repositories without remotes; no existing project or global Git configuration |
| 176 | +is changed. |
| 177 | + |
| 178 | +They are behavioral samples, not proof of enforcement in every host; Copilot App |
| 179 | +behavior is not established by CLI tests. |
0 commit comments