heyspex 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +14 -0
- package/bin/hs.mjs +181 -15
- package/dist/cli/hs-check.mjs +88 -46
- package/dist/cli/hs-claim.mjs +84 -39
- package/dist/cli/hs-connect.mjs +583 -129
- package/dist/cli/hs-defer.mjs +251 -30
- package/dist/cli/hs-dev.mjs +20 -8
- package/dist/cli/hs-env.mjs +62 -34
- package/dist/cli/hs-index-rebuild.mjs +288 -83
- package/dist/cli/hs-index-reconcile.mjs +397 -111
- package/dist/cli/hs-init.mjs +2143 -91
- package/dist/cli/hs-install.mjs +628 -106
- package/dist/cli/hs-join.mjs +686 -236
- package/dist/cli/hs-vault-pull.mjs +3189 -179
- package/dist/cli/hs-vault-push.mjs +6433 -0
- package/dist/cli/hs-vault.mjs +396 -178
- package/dist/cli/hs-workspace.mjs +289 -151
- package/dist/cli-templates/harness-commands/claude/hs-backfill.md +28 -28
- package/dist/cli-templates/harness-commands/claude/hs-capture.md +62 -62
- package/dist/cli-templates/harness-commands/claude/hs-defer.md +29 -29
- package/dist/cli-templates/harness-commands/claude/hs-ground.md +30 -28
- package/dist/cli-templates/harness-commands/claude/hs-next.md +29 -29
- package/dist/cli-templates/harness-commands/claude/hs-promote.md +70 -70
- package/dist/cli-templates/harness-commands/claude/hs-push.md +35 -35
- package/dist/cli-templates/harness-commands/claude/hs-qc.md +27 -27
- package/dist/cli-templates/harness-commands/claude/hs-resolve.md +23 -23
- package/dist/cli-templates/harness-commands/claude/hs-review.md +23 -23
- package/dist/cli-templates/harness-commands/claude/hs-view.md +28 -26
- package/dist/cli-templates/harness-commands/claude/kill-ports.md +32 -32
- package/dist/cli-templates/harness-commands/claude/prototype.md +91 -91
- package/dist/cli-templates/harness-commands/cursor/hs-backfill.md +22 -22
- package/dist/cli-templates/harness-commands/cursor/hs-capture.md +56 -56
- package/dist/cli-templates/harness-commands/cursor/hs-defer.md +23 -23
- package/dist/cli-templates/harness-commands/cursor/hs-ground.md +24 -22
- package/dist/cli-templates/harness-commands/cursor/hs-next.md +23 -23
- package/dist/cli-templates/harness-commands/cursor/hs-promote.md +64 -64
- package/dist/cli-templates/harness-commands/cursor/hs-push.md +29 -29
- package/dist/cli-templates/harness-commands/cursor/hs-qc.md +21 -21
- package/dist/cli-templates/harness-commands/cursor/hs-resolve.md +17 -17
- package/dist/cli-templates/harness-commands/cursor/hs-review.md +17 -17
- package/dist/cli-templates/harness-commands/cursor/hs-view.md +24 -22
- package/dist/cli-templates/harness-commands/cursor/kill-ports.md +26 -26
- package/dist/cli-templates/harness-commands/cursor/prototype.md +86 -86
- package/docs/copilot-plugin-install.md +177 -0
- package/docs/driving-heyspex-from-copilot.md +165 -0
- package/package.json +21 -2
- package/plugins/heyspex/.claude-plugin/plugin.json +12 -12
- package/plugins/heyspex/.cursor-plugin/plugin.json +15 -15
- package/plugins/heyspex/README.md +312 -0
- package/plugins/heyspex/bin/run-hook.mjs +20 -2
- package/plugins/heyspex/hooks/cursor-hooks.json +81 -0
- package/plugins/heyspex/hooks/hooks.json +94 -37
- package/scripts/claude-hooks/_intent-classifier-router.mjs +456 -410
- package/scripts/claude-hooks/_intent-classifier-semantic.mjs +5 -0
- package/scripts/claude-hooks/_run.mjs +316 -23
- package/scripts/claude-hooks/capture-execution-gate.mjs +51 -0
- package/scripts/claude-hooks/claim-liveness-shared.mjs +2 -0
- package/scripts/claude-hooks/diagnose-capture-reminder.mjs +11 -0
- package/scripts/claude-hooks/directive-obligation-gate.mjs +11 -0
- package/scripts/claude-hooks/inject-communication-style.mjs +20 -0
- package/scripts/claude-hooks/intent-classifier-trigger.mjs +279 -247
- package/scripts/claude-hooks/session-end.mjs +2 -0
- package/scripts/claude-hooks/vault-mirror-catchup.mjs +11 -0
- package/scripts/claude-hooks/vault-write-tier-guard.mjs +11 -0
- package/scripts/claude-hooks/wip-checkpoint.mjs +5 -1
- package/scripts/cursor-hooks/manifest.mjs +46 -0
- package/scripts/heyspex-mode.mjs +20 -0
- package/scripts/hs-mode.mjs +1 -1
- package/scripts/hs-view.mjs +180 -17
- package/scripts/install-claude-code-hooks.mjs +3 -1
- package/scripts/install-copilot-hooks.mjs +288 -0
- package/scripts/lib/console-url-resolver.mjs +3 -2
- package/scripts/lib/customer-kit.mjs +327 -10
- package/scripts/lib/dev-mode.mjs +7 -6
- package/scripts/lib/directive-obligations.mjs +349 -0
- package/scripts/lib/hook-dispositions.mjs +210 -0
- package/scripts/lib/hook-vault-header.mjs +30 -0
- package/scripts/lib/hs-source-branch.mjs +196 -0
- package/scripts/lib/hs-source-log.mjs +2 -1
- package/scripts/lib/hs-source-preflight.mjs +18 -4
- package/scripts/lib/hs-source-push.mjs +386 -356
- package/scripts/lib/window-placement.mjs +109 -0
- package/spexharness/src/adapters/claude-code.mjs +11 -3
- package/spexharness/src/adapters/copilot.mjs +236 -0
- package/spexharness/src/adapters/detect-harness.mjs +34 -0
- package/spexharness/src/gates/_shell-write-targets.mjs +77 -0
- package/spexharness/src/gates/deep-research-cost-gate.mjs +4 -3
- package/spexharness/src/gates/diagnose-capture-reminder.mjs +112 -0
- package/spexharness/src/gates/directive-obligation-gate.decide.mjs +132 -0
- package/spexharness/src/gates/directive-obligation-gate.mjs +183 -0
- package/spexharness/src/gates/vault-mirror-catchup.mjs +124 -0
- package/spexharness/src/gates/vault-write-tier-guard.decide.mjs +125 -0
- package/spexharness/src/gates/vault-write-tier-guard.mjs +42 -0
- package/spexharness/src/intent-classifier.mjs +4 -2
- package/spexharness/src/intent-directive.mjs +626 -541
- package/spexharness/src/rule-table.mjs +31 -1
- package/vendor/heyspex-mcp/account-switch.mjs +6 -5
- package/vendor/heyspex-mcp/capture-buffer-patches.mjs +31 -3
- package/vendor/heyspex-mcp/capture-console-client.mjs +37 -2
- package/vendor/heyspex-mcp/capture-focus.mjs +26 -2
- package/vendor/heyspex-mcp/capture-outbox.mjs +10 -4
- package/vendor/heyspex-mcp/capture-sources.mjs +195 -0
- package/vendor/heyspex-mcp/capture-tools.mjs +56 -11
- package/vendor/heyspex-mcp/claim-tools.mjs +25 -2
- package/vendor/heyspex-mcp/cli-verbs.mjs +19 -21
- package/vendor/heyspex-mcp/cli.mjs +7 -1
- package/vendor/heyspex-mcp/close-branch-report.mjs +102 -0
- package/vendor/heyspex-mcp/cloud-vault-writes.mjs +197 -7
- package/vendor/heyspex-mcp/console-fetch.mjs +192 -28
- package/vendor/heyspex-mcp/console-transport.mjs +7 -1
- package/vendor/heyspex-mcp/credentials.mjs +9 -8
- package/vendor/heyspex-mcp/dev-tools.mjs +7 -0
- package/vendor/heyspex-mcp/filing-tools.mjs +35 -0
- package/vendor/heyspex-mcp/fleet-queue-tools.mjs +2 -1
- package/vendor/heyspex-mcp/folder-trust-store.mjs +2 -1
- package/vendor/heyspex-mcp/http-transport.mjs +2 -0
- package/vendor/heyspex-mcp/list-tools.mjs +1 -1
- package/vendor/heyspex-mcp/mcp-config.mjs +14 -1
- package/vendor/heyspex-mcp/memory-tools.mjs +523 -523
- package/vendor/heyspex-mcp/obligation-backstop.mjs +103 -0
- package/vendor/heyspex-mcp/occupied-keys.mjs +1 -0
- package/vendor/heyspex-mcp/on-deck-brief.mjs +19 -2
- package/vendor/heyspex-mcp/on-deck-scheduler.mjs +1708 -1708
- package/vendor/heyspex-mcp/plan-push.mjs +3 -2
- package/vendor/heyspex-mcp/preflight-gate.mjs +1 -0
- package/vendor/heyspex-mcp/procedure-handlers.mjs +327 -325
- package/vendor/heyspex-mcp/procedure-tools.mjs +1181 -1159
- package/vendor/heyspex-mcp/promote-capture.mjs +2 -0
- package/vendor/heyspex-mcp/promote-research.mjs +6 -0
- package/vendor/heyspex-mcp/read-path.mjs +162 -6
- package/vendor/heyspex-mcp/request-context.mjs +25 -1
- package/vendor/heyspex-mcp/research-handlers.mjs +6 -4
- package/vendor/heyspex-mcp/roadmap-default.mjs +70 -0
- package/vendor/heyspex-mcp/session-owner.mjs +3 -2
- package/vendor/heyspex-mcp/session-tools.mjs +10 -0
- package/vendor/heyspex-mcp/spec-edit-tools.mjs +8 -1
- package/vendor/heyspex-mcp/split-research.mjs +3 -0
- package/vendor/heyspex-mcp/submit-for-review.mjs +18 -1
- package/vendor/heyspex-mcp/summary-write-tools.mjs +5 -1
- package/vendor/heyspex-mcp/test-helpers.mjs +18 -3
- package/vendor/heyspex-mcp/tool-catalog.mjs +7 -1
- package/vendor/heyspex-mcp/tool-dispatch.mjs +18 -0
- package/vendor/heyspex-mcp/vault-io.mjs +720 -724
- package/vendor/heyspex-mcp/vault-resolve.mjs +197 -9
- package/vendor/heyspex-mcp/whoami.mjs +2 -1
- package/vendor/heyspex-mcp/write-outbox.mjs +512 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Driving HeySpex from GitHub Copilot (and other non-MCP assistants)
|
|
2
|
+
|
|
3
|
+
**Capability table dated: 2026-07-10.** Harness support changes fast; re-verify against the
|
|
4
|
+
sources before relying on a row. Refresh is owned by the harness-integrations pillar.
|
|
5
|
+
|
|
6
|
+
HeySpex is tool-agnostic by construction. Every everyday action reaches the vault through one of
|
|
7
|
+
three write paths, and at least one of them works in **any** assistant that can either speak MCP or
|
|
8
|
+
run a shell command:
|
|
9
|
+
|
|
10
|
+
1. **MCP tools** — `heyspex_*` tools over the Model Context Protocol (richest surface).
|
|
11
|
+
2. **The `hs` CLI** — plain shell commands with stable exit codes and `--json` output. No MCP
|
|
12
|
+
client required; works in any assistant, terminal, or CI runner that can shell out.
|
|
13
|
+
3. **The console web UI** — `localhost:3000`, works in any browser.
|
|
14
|
+
|
|
15
|
+
This guide is the fallback path: how to drive the everyday agent loop when your assistant has
|
|
16
|
+
**no** MCP tool support, using only the `hs` CLI.
|
|
17
|
+
|
|
18
|
+
Grounded in [[HS-RDG9-RES-github-copilot-and-vs-code-mcp-support-t]] (the 2026 verification that
|
|
19
|
+
Copilot now has a real MCP client) and [[HS-TACM-RES-tool-agnostic-mcp-compatibility-matrix-2026-05-27]]
|
|
20
|
+
(the broader cross-tool matrix — note its "VS Code + Copilot = shell-only, no MCP" row is stale as
|
|
21
|
+
of the RDG9 refresh and is being amended separately).
|
|
22
|
+
|
|
23
|
+
## Per-harness capability table (2026-07-10)
|
|
24
|
+
|
|
25
|
+
**Legend** — **MCP**: native MCP client (tools, and sometimes prompts/resources). **`hs` CLI**:
|
|
26
|
+
can shell out to `hs`. **Prompts**: supports MCP prompts exposed as slash commands. **Everyday
|
|
27
|
+
loop**: can do see-next → claim → report progress → submit for review.
|
|
28
|
+
|
|
29
|
+
| Harness | MCP | `hs` CLI | Prompts | Everyday loop | Honest ceiling |
|
|
30
|
+
| -------------------------------------------------------------------- | :----------------------------------------: | :-----------------------: | :--------------------------: | :---------------------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| **VS Code agent mode (Copilot)** | ✓ full (`.vscode/mcp.json`, `servers` key) | ✓ | ✓ (`/mcp.<server>.<prompt>`) | via MCP tools **or** `hs` | Full MCP spec — tools, prompts, resources, sampling, OAuth. Subject to a 128-tool per-request cap; curate the exposed tool subset. |
|
|
32
|
+
| **GitHub Copilot CLI** | ✓ (auto-discovers `.github/mcp.json`) | ✓ | ✓ (`/mcp`) | via MCP tools **or** `hs` | Full MCP client (GA Feb 2026). Honors the org "MCP servers in Copilot" policy gate — admin approval may be required. |
|
|
33
|
+
| **Copilot coding agent (github.com cloud)** | ✓ **tools only** | ✓ if sandbox allows shell | ✗ no prompts | via MCP **tools** **or** `hs` | No MCP prompts, no resources, no OAuth. Servers are configured in repo settings, not a committed file; local/allowlisted servers only. **Do not rely on slash-command prompts here — use tools or the `hs` CLI.** |
|
|
34
|
+
| **Any assistant WITHOUT MCP tool support** | ✗ | ✓ | ✗ | via `hs` CLI only | The `hs` CLI is the complete fallback. Everything in the loop is a plain shell command; nothing is unreachable just because the assistant lacks tool support. |
|
|
35
|
+
| **Claude Code / Cursor / Cline / Continue.dev / Google Antigravity** | ✓ native | ✓ | ✓ | via MCP tools (primary) | First-class MCP today; the `hs` CLI is available as a fallback. See [[HS-TACM-RES-tool-agnostic-mcp-compatibility-matrix-2026-05-27]]. |
|
|
36
|
+
|
|
37
|
+
Design consequence: keep the primary UX in **tools**, not MCP prompts, because the cloud coding
|
|
38
|
+
agent doesn't support prompts. Treat slash-command prompts as a VS Code / Copilot-CLI enhancement,
|
|
39
|
+
and the `hs` CLI as the universal floor. HeySpex does **not** promise native slash-command parity on
|
|
40
|
+
a surface that cannot support prompts.
|
|
41
|
+
|
|
42
|
+
## The everyday loop with the `hs` CLI
|
|
43
|
+
|
|
44
|
+
Run these from anywhere inside the vault (the CLI walks up to find `specs/`; or set
|
|
45
|
+
`HS_VAULT_ROOT`). All four commands are pure shell — no MCP client involved. Add `--json` for
|
|
46
|
+
machine-readable output.
|
|
47
|
+
|
|
48
|
+
### 1. See what's next
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
hs next --summary --json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Returns the on-deck brief (spec id, title, summary, and a claim target). Drop `--json` for the
|
|
55
|
+
human-readable prompt; drop `--summary` for the full post-claim execution brief.
|
|
56
|
+
|
|
57
|
+
### 2. Claim the work
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
hs claim acquire HS-WJ1C-TASK --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Atomic: two concurrent acquires for one spec yield exactly one success and one `already_claimed`
|
|
64
|
+
conflict (exit 9) that names the existing claimant. Release on hand-off with
|
|
65
|
+
`hs claim release HS-WJ1C-TASK`.
|
|
66
|
+
|
|
67
|
+
### 3. Report progress
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
hs claim progress HS-WJ1C-TASK --stage Grounding --ac 0
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`--stage` takes a work-stage verb (Grounding, Breaking down, Drafting, Validating, Testing,
|
|
74
|
+
Reviewing). `--ac <n>` is the 0-based acceptance-criterion index you are on — it drives the live
|
|
75
|
+
checklist on the What's Next surface. Call it again as you move between stages and complete criteria.
|
|
76
|
+
|
|
77
|
+
### 4. Submit for review
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
hs mcp call heyspex_submit_for_review --arg spec_id=HS-WJ1C-TASK --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`hs mcp call` runs a single MCP tool as a **one-shot shell command** — it does not require your
|
|
84
|
+
assistant to be an MCP client. This close-out step validates acceptance-criteria progress against
|
|
85
|
+
your claim, PATCHes the status API (never hand-edit frontmatter `status:`), applies review-grain
|
|
86
|
+
coercion and parent rollup, releases the claim, and returns close-out guidance. A `409` on submit is
|
|
87
|
+
a real reason (e.g. incomplete criteria) — report it, don't work around it.
|
|
88
|
+
|
|
89
|
+
> Why `hs mcp call` and not a dedicated `hs submit` verb: see-next, claim, and report-progress each
|
|
90
|
+
> have a first-class `hs` verb; submit-for-review is reached through the generic one-shot MCP-call
|
|
91
|
+
> escape hatch, which reuses the exact close-out logic the MCP tool runs. It is still a plain shell
|
|
92
|
+
> command with no MCP-client requirement.
|
|
93
|
+
|
|
94
|
+
## Configuring MCP where it IS supported
|
|
95
|
+
|
|
96
|
+
For VS Code agent mode and Copilot CLI you get the richer MCP tool surface. The MCP config
|
|
97
|
+
templates (`.vscode/mcp.json` with the `servers` key, `.github/mcp.json` for Copilot CLI
|
|
98
|
+
auto-discovery) and the Copilot instructions file are owned by the harness-integrations config work
|
|
99
|
+
and documented separately — this guide covers only the universal `hs` CLI fallback.
|
|
100
|
+
|
|
101
|
+
## Hooks under Copilot
|
|
102
|
+
|
|
103
|
+
Copilot CLI runs the HeySpex hooks it finds in `.claude/settings.json` (and the plugin's `hooks/hooks.json`), so the
|
|
104
|
+
gates (capture-on-idea obligation, claim-before-build, naming guards) apply to Copilot agents too. What differs:
|
|
105
|
+
|
|
106
|
+
- **Fail-closed**: Copilot denies a tool call when a `preToolUse` command crashes or exits non-zero. Every registered
|
|
107
|
+
command is therefore a self-locating bootstrap that does not need `$CLAUDE_PROJECT_DIR` and exits 0 when it cannot find
|
|
108
|
+
the HeySpex runtime; `_run.mjs` itself never exits non-zero except for a deliberate deny (translated to Copilot's
|
|
109
|
+
top-level `{"permissionDecision":"deny"}` JSON with exit 0).
|
|
110
|
+
- **Turn it off**: `hs mode off` (all harnesses, per project; `hs mode on|status|toggle`), `HEYSPEX_MODE=off` for one
|
|
111
|
+
shell, or `HEYSPEX_COPILOT_HOOKS_OFF=1` / `agent_behaviors.harness_hooks.copilot.enabled: false` for Copilot only.
|
|
112
|
+
The four always-on security gates (`env-vault-guard`, `research-method-guard`, `research-protocol-gate`,
|
|
113
|
+
`git-identity-guard`) ignore all three.
|
|
114
|
+
- **Stopgap on an older checkout** (before the bootstrap ships): `HEYSPEX_MODE=off` only helps if the hook command can
|
|
115
|
+
start, and the old command needs `CLAUDE_PROJECT_DIR`; export it (`CLAUDE_PROJECT_DIR=<repo>`) alongside `HEYSPEX_MODE=off`.
|
|
116
|
+
|
|
117
|
+
### One source of hooks, and the cloud agent
|
|
118
|
+
|
|
119
|
+
Plugin OR repo hooks, never both: Copilot CLI loads the heyspex plugin AND the repo's `.claude/settings.json` /
|
|
120
|
+
`.github/hooks/*.json`, so a repo with both fires every hook twice. `npm run doctor` (check `hook-double-fire`) warns
|
|
121
|
+
about that and reports `unknown`, not a failure, when it cannot read a plugin registry.
|
|
122
|
+
|
|
123
|
+
The Copilot **cloud agent** loads no plugins: its only hook source is `.github/hooks/*.json` on the **default branch**.
|
|
124
|
+
`npm run hooks:write-github` generates `.github/hooks/heyspex.json` (bash `command` entries only, camelCase events,
|
|
125
|
+
resolving `node_modules/heyspex/scripts/claude-hooks/_run.mjs` then `./scripts/claude-hooks/_run.mjs`, else exit 0).
|
|
126
|
+
Requirements: the sandbox must contain `node_modules/heyspex` (install it in `copilot-setup-steps`), the firewall must
|
|
127
|
+
allow the console URL (claim heartbeats), and MCP is configured in repository settings (tools only, no OAuth).
|
|
128
|
+
|
|
129
|
+
### Gates that are weaker or absent on Copilot
|
|
130
|
+
|
|
131
|
+
Generated from `scripts/lib/hook-dispositions.mjs` (a test fails when this block is stale). The MCP preflight refusals
|
|
132
|
+
(`heyspex_claim_spec`, `heyspex_submit_for_review`, `heyspex_save_research`) are the hook-independent hard floor on every
|
|
133
|
+
surface that connects the MCP server.
|
|
134
|
+
|
|
135
|
+
<!-- hook-dispositions:copilot:begin (generated by scripts/lib/hook-dispositions.test.mjs; UPDATE_HOOK_DOCS=1 refreshes) -->
|
|
136
|
+
| Gate | Disposition | Compensating control / what is lost |
|
|
137
|
+
| --- | --- | --- |
|
|
138
|
+
| `research-method-guard` | unportable | MCP preflight refusal on heyspex_save_research (hard floor, hook-independent) + .github/copilot-instructions.md research rule; Copilot has no Skill or Workflow tool to hook. |
|
|
139
|
+
| `deep-research-cost-gate` | unportable | MCP preflight refusal on heyspex_save_research + .github/copilot-instructions.md cost-confirmation rule; Copilot has no Skill or Workflow tool to hook. |
|
|
140
|
+
| `plan-review-gate` | unportable | MCP preflight refusals (heyspex_claim_spec / heyspex_submit_for_review / heyspex_save_research) + .github/copilot-instructions.md plan rule (state the plan in chat, claim the spec before editing) + HS-20SW directive-obligation-gate claim-before-build deny |
|
|
141
|
+
| `plan-exit-ingest-gate` | unportable | MCP preflight refusals (heyspex_claim_spec / heyspex_submit_for_review / heyspex_save_research) + .github/copilot-instructions.md plan rule (state the plan in chat, claim the spec before editing) + HS-20SW directive-obligation-gate claim-before-build deny |
|
|
142
|
+
| `preflight-reminder` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. Real enforcement is the MCP preflight refusal. |
|
|
143
|
+
| `intent-classifier-trigger` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. The hook still runs and arms obligation state; the HS-20SW directive-obligation-gate turns that state into a hard deny. |
|
|
144
|
+
| `inject-communication-style` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. |
|
|
145
|
+
| `inject-vault-context` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. Per-prompt vault retrieval has no Copilot channel at all. |
|
|
146
|
+
| `claim-before-code-gate` | advisory-degraded | Armed only by plan-exit-ingest-gate, which has no Copilot trigger (no ExitPlanMode tool), so it stays dormant; covered by the HS-20SW claim-before-build rule. |
|
|
147
|
+
| `diagnose-capture-reminder` | advisory-degraded | Copilot preToolUse has no context channel for an inject, so this advisory is silent (lost). |
|
|
148
|
+
<!-- hook-dispositions:copilot:end -->
|
|
149
|
+
|
|
150
|
+
Plan mode: Copilot has no `ExitPlanMode` tool, so the plan gates cannot fire. State the plan in chat and claim the spec
|
|
151
|
+
before editing code (`.github/copilot-instructions.md`); the HS-20SW claim-before-build deny backs that up.
|
|
152
|
+
|
|
153
|
+
**Unverified** (no official page read, or not run live): the VS Code 128-tool per-request cap (the microsoft/vscode issue
|
|
154
|
+
below is the only source); the spelling of MCP tool names inside hook payloads (hooks match by suffix); whether
|
|
155
|
+
`${CLAUDE_PLUGIN_ROOT}` expands in the plugin `.mcp.json` under the Copilot CLI (documented for VS Code only); how the MCP
|
|
156
|
+
server learns the Copilot session id (its preflight marker falls back to a 4 hour TTL); whether the CLI reads a Claude-format
|
|
157
|
+
`hookSpecificOutput` deny.
|
|
158
|
+
|
|
159
|
+
## Sources
|
|
160
|
+
|
|
161
|
+
- [[HS-RDG9-RES-github-copilot-and-vs-code-mcp-support-t]] — Copilot MCP support verified mid-2026 (cloud agent = tools only).
|
|
162
|
+
- [[HS-TACM-RES-tool-agnostic-mcp-compatibility-matrix-2026-05-27]] — cross-tool compatibility matrix (Copilot row being amended).
|
|
163
|
+
- [MCP and GitHub Copilot cloud agent — GitHub Docs](https://docs.github.com/en/copilot/concepts/agents/coding-agent/mcp-and-coding-agent) — cloud coding agent supports MCP tools only.
|
|
164
|
+
- [Adding MCP servers for GitHub Copilot CLI — GitHub Docs](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers) — `.github/mcp.json` auto-discovery.
|
|
165
|
+
- [Hard tool limit (128) in VS Code agent mode — microsoft/vscode#290356](https://github.com/microsoft/vscode/issues/290356) — 128-tool per-request cap.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "heyspex",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "HeySpex CLI + MCP server — connect Claude Code, Cursor, and any MCP client to your HeySpex spec vault",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"heyspex",
|
|
@@ -45,8 +45,11 @@
|
|
|
45
45
|
"scripts/gateway-skills-lib.mjs",
|
|
46
46
|
"scripts/vault-id-lib.mjs",
|
|
47
47
|
"scripts/lib/console-url-resolver.mjs",
|
|
48
|
+
"scripts/lib/window-placement.mjs",
|
|
48
49
|
"scripts/lib/hs-link.mjs",
|
|
50
|
+
"scripts/lib/hook-vault-header.mjs",
|
|
49
51
|
"scripts/lib/dev-mode.mjs",
|
|
52
|
+
"scripts/lib/directive-obligations.mjs",
|
|
50
53
|
"scripts/lib/hs-command.mjs",
|
|
51
54
|
"scripts/lib/shared-path-helpers.mjs",
|
|
52
55
|
"scripts/dev-server-status.mjs",
|
|
@@ -61,12 +64,17 @@
|
|
|
61
64
|
"dev-factory/lib/model-catalog.mjs",
|
|
62
65
|
"dev-factory/model-catalog.json",
|
|
63
66
|
"docs/mcp-client-config.md",
|
|
67
|
+
"docs/copilot-plugin-install.md",
|
|
68
|
+
"docs/driving-heyspex-from-copilot.md",
|
|
69
|
+
"plugins/heyspex/README.md",
|
|
64
70
|
"dist/cli/*.mjs",
|
|
65
71
|
"dist/cli-templates/**",
|
|
66
72
|
"LICENSE",
|
|
67
73
|
"scripts/install-claude-code-hooks.mjs",
|
|
68
74
|
"scripts/install-cursor-hooks.mjs",
|
|
75
|
+
"scripts/install-copilot-hooks.mjs",
|
|
69
76
|
"scripts/lib/customer-kit.mjs",
|
|
77
|
+
"scripts/lib/hook-dispositions.mjs",
|
|
70
78
|
"scripts/lib/template-pin.mjs",
|
|
71
79
|
"scripts/cursor-hooks/manifest.mjs",
|
|
72
80
|
"scripts/dev-server-stop.mjs",
|
|
@@ -94,6 +102,7 @@
|
|
|
94
102
|
"plugins/heyspex/bin/launch-mcp.mjs",
|
|
95
103
|
"plugins/heyspex/bin/run-hook.mjs",
|
|
96
104
|
"plugins/heyspex/.claude-plugin/plugin.json",
|
|
105
|
+
".claude-plugin/marketplace.json",
|
|
97
106
|
"plugins/heyspex/.mcp.json",
|
|
98
107
|
"plugins/heyspex/.cursor-plugin/plugin.json",
|
|
99
108
|
"plugins/heyspex/mcp.json",
|
|
@@ -114,12 +123,19 @@
|
|
|
114
123
|
"spexharness/src/gates/capture-workflow-gate.mjs",
|
|
115
124
|
"spexharness/src/gates/claim-before-code-gate.decide.mjs",
|
|
116
125
|
"spexharness/src/gates/claim-before-code-gate.mjs",
|
|
126
|
+
"spexharness/src/gates/directive-obligation-gate.decide.mjs",
|
|
127
|
+
"spexharness/src/gates/directive-obligation-gate.mjs",
|
|
117
128
|
"spexharness/src/gates/deep-research-cost-gate.mjs",
|
|
118
129
|
"spexharness/src/gates/enforce-session-sequence.mjs",
|
|
119
130
|
"spexharness/src/gates/enforce-vault-naming.mjs",
|
|
120
131
|
"spexharness/src/gates/epic-milestone-phrasing-gate.mjs",
|
|
132
|
+
"spexharness/src/gates/diagnose-capture-reminder.mjs",
|
|
121
133
|
"spexharness/src/gates/git-identity-guard.decide.mjs",
|
|
122
134
|
"spexharness/src/gates/git-identity-guard.mjs",
|
|
135
|
+
"spexharness/src/gates/_shell-write-targets.mjs",
|
|
136
|
+
"spexharness/src/gates/vault-write-tier-guard.decide.mjs",
|
|
137
|
+
"spexharness/src/gates/vault-write-tier-guard.mjs",
|
|
138
|
+
"spexharness/src/gates/vault-mirror-catchup.mjs",
|
|
123
139
|
"spexharness/src/gates/git-reflog-audit.mjs",
|
|
124
140
|
"spexharness/src/gates/git-stash-gate.decide.mjs",
|
|
125
141
|
"spexharness/src/gates/git-stash-gate.mjs",
|
|
@@ -206,6 +222,8 @@
|
|
|
206
222
|
"hooks:check-claude": "node scripts/install-claude-code-hooks.mjs --check",
|
|
207
223
|
"hooks:install-cursor": "node scripts/install-cursor-hooks.mjs",
|
|
208
224
|
"hooks:check-cursor": "node scripts/install-cursor-hooks.mjs --check",
|
|
225
|
+
"hooks:write-github": "node scripts/lib/customer-kit.mjs --write-github-hooks",
|
|
226
|
+
"hooks:check-github": "node scripts/lib/customer-kit.mjs --check-github-hooks",
|
|
209
227
|
"hooks:smoke-cursor": "node scripts/cursor-hooks/_run.smoke.mjs",
|
|
210
228
|
"companion": "pwsh -NoProfile -ExecutionPolicy Bypass -File companion/start.ps1 -Action start",
|
|
211
229
|
"companion:stop": "pwsh -NoProfile -ExecutionPolicy Bypass -File companion/start.ps1 -Action stop",
|
|
@@ -224,8 +242,9 @@
|
|
|
224
242
|
"test:mcp": "node --test vendor/heyspex-mcp/*.test.mjs scripts/lib/*.test.mjs dev-factory/lib/*.test.mjs",
|
|
225
243
|
"test:harness": "node --test spexharness/**/*.test.mjs",
|
|
226
244
|
"verify:package": "node scripts/verify-mcp-package.mjs",
|
|
245
|
+
"smoke:packed-install": "node scripts/packed-install.smoke.mjs",
|
|
227
246
|
"verify:onboarding": "node scripts/verify-onboarding-scenario.mjs --fake",
|
|
228
247
|
"sweep": "node scripts/sweep.mjs"
|
|
229
248
|
},
|
|
230
|
-
"//files": "PUBLISHED SURFACE - every entry is verified by `node scripts/verify-mcp-package.mjs`. It must cover the STATIC import closure of vendor/heyspex-mcp/cli.mjs, plus (since [[HS-LGG2-WW9R-TASK-ship-the-hook-runtime-in-the-npm]]) the customer hook kit: scripts/claude-hooks/_run.mjs, every HOOK_SCOPES customer hook (scripts/lib/customer-kit.mjs) and their static closure under spexharness/src, dev-factory/lib and scripts/ - the hookTargets check names any file that falls out - plus the run-time data files in customer-kit.mjs CUSTOMER_HOOK_DATA (only the baseline edition of SpexCode Doctrine, never the learned spexharness/doctrine/SPEXCODE-DOCTRINE.json; [[HS-A2PO-WW9R-TASK-owner-ruling-does-inject-doctrine-ship]]) - and nothing else. SpexFleet internals (dev-factory/router.mjs, cloud-clients.mjs, cost-tracker.mjs, spexcrawl/) are deliberately absent - research-tools.mjs reaches them through the lazy dev-factory-bridge.mjs. Do not add a path here without re-running the verifier; npm publish is a one-way door ([[HS-ZJSP-0JNK-TASK-ship-the-heyspex-mcp-server-as-an]] / [[HS-8DET-0JNK-TASK-confirm-the-open-core-boundary-and]]). `dist/cli/*.mjs` + `dist/cli-templates/**` are a SEPARATE published surface (`hs-init`, `hs-install`, `hs-claim`, `hs-check`, `hs-env`, `hs-connect`, `hs-join`, `hs-vault`, `hs-workspace`, `hs-defer`, `hs-vault-pull`, `hs-dev`, `hs-index-rebuild`, `hs-index-reconcile` bundled by `scripts/build-cli-bundle.mjs`'s `ENTRIES` array, regenerated fresh every `prepack` - `dist/` itself stays git-ignored) - see that script's doc comment for the entry scope decision and [[HS-JOQX-0JNK-TASK-published-package-runs-hs-init-and-hs]]."
|
|
249
|
+
"//files": "PUBLISHED SURFACE - every entry is verified by `node scripts/verify-mcp-package.mjs`. It must cover the STATIC import closure of vendor/heyspex-mcp/cli.mjs, plus (since [[HS-LGG2-WW9R-TASK-ship-the-hook-runtime-in-the-npm]]) the customer hook kit: scripts/claude-hooks/_run.mjs, every HOOK_SCOPES customer hook (scripts/lib/customer-kit.mjs) and their static closure under spexharness/src, dev-factory/lib and scripts/ - the hookTargets check names any file that falls out - plus the run-time data files in customer-kit.mjs CUSTOMER_HOOK_DATA (only the baseline edition of SpexCode Doctrine, never the learned spexharness/doctrine/SPEXCODE-DOCTRINE.json; [[HS-A2PO-WW9R-TASK-owner-ruling-does-inject-doctrine-ship]]) - and nothing else. SpexFleet internals (dev-factory/router.mjs, cloud-clients.mjs, cost-tracker.mjs, spexcrawl/) are deliberately absent - research-tools.mjs reaches them through the lazy dev-factory-bridge.mjs. Do not add a path here without re-running the verifier; npm publish is a one-way door ([[HS-ZJSP-0JNK-TASK-ship-the-heyspex-mcp-server-as-an]] / [[HS-8DET-0JNK-TASK-confirm-the-open-core-boundary-and]]). `dist/cli/*.mjs` + `dist/cli-templates/**` are a SEPARATE published surface (`hs-init`, `hs-install`, `hs-claim`, `hs-check`, `hs-env`, `hs-connect`, `hs-join`, `hs-vault`, `hs-workspace`, `hs-defer`, `hs-vault-pull`, `hs-vault-push`, `hs-dev`, `hs-index-rebuild`, `hs-index-reconcile` bundled by `scripts/build-cli-bundle.mjs`'s `ENTRIES` array, regenerated fresh every `prepack` - `dist/` itself stays git-ignored) - see that script's doc comment for the entry scope decision and [[HS-JOQX-0JNK-TASK-published-package-runs-hs-init-and-hs]]."
|
|
231
250
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "heyspex",
|
|
3
|
-
"displayName": "SpexCode plugin (for Claude Code)",
|
|
4
|
-
"description": "HeySpex vault integration for Claude Code: MCP server (spec vault tools + hs-* prompts) and lifecycle hooks. Prototype packaging per HS-QTBK — additive; the project-level .mcp.json/settings.json wiring remains the live source of truth until cutover.",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "pwher",
|
|
7
|
-
"email": "paul@monstergrowth.com"
|
|
8
|
-
},
|
|
9
|
-
"
|
|
10
|
-
"license": "UNLICENSED",
|
|
11
|
-
"keywords": ["heyspex", "spec-vault", "mcp", "hooks"]
|
|
12
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "heyspex",
|
|
3
|
+
"displayName": "SpexCode plugin (for Claude Code and GitHub Copilot CLI)",
|
|
4
|
+
"description": "HeySpex vault integration for Claude Code and GitHub Copilot CLI (Claude-format plugin, installed from the same marketplace): MCP server (spec vault tools + hs-* prompts) and lifecycle hooks. Prototype packaging per HS-QTBK — additive; the project-level .mcp.json/settings.json wiring remains the live source of truth until cutover.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "pwher",
|
|
7
|
+
"email": "paul@monstergrowth.com"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://www.npmjs.com/package/heyspex",
|
|
10
|
+
"license": "UNLICENSED",
|
|
11
|
+
"keywords": ["heyspex", "spec-vault", "mcp", "hooks"]
|
|
12
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "heyspex",
|
|
3
|
-
"displayName": "SpexCode plugin (for Claude Code)",
|
|
4
|
-
"version": "0.1.0",
|
|
5
|
-
"description": "HeySpex vault integration for Cursor: MCP server (spec vault tools + hs-* workflows) and the full lifecycle hook set. Prototype packaging — additive; the project-level .cursor/mcp.json and .cursor/hooks.json wiring remains the live source of truth until cutover.",
|
|
6
|
-
"author": {
|
|
7
|
-
"name": "pwher",
|
|
8
|
-
"email": "paul@monstergrowth.com"
|
|
9
|
-
},
|
|
10
|
-
"
|
|
11
|
-
"license": "UNLICENSED",
|
|
12
|
-
"keywords": ["heyspex", "spec-vault", "mcp", "hooks"],
|
|
13
|
-
"mcp": "mcp.json",
|
|
14
|
-
"hooks": "hooks/cursor-hooks.json"
|
|
15
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "heyspex",
|
|
3
|
+
"displayName": "SpexCode plugin (for Claude Code)",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "HeySpex vault integration for Cursor: MCP server (spec vault tools + hs-* workflows) and the full lifecycle hook set. Prototype packaging — additive; the project-level .cursor/mcp.json and .cursor/hooks.json wiring remains the live source of truth until cutover.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "pwher",
|
|
8
|
+
"email": "paul@monstergrowth.com"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://www.npmjs.com/package/heyspex",
|
|
11
|
+
"license": "UNLICENSED",
|
|
12
|
+
"keywords": ["heyspex", "spec-vault", "mcp", "hooks"],
|
|
13
|
+
"mcp": "mcp.json",
|
|
14
|
+
"hooks": "hooks/cursor-hooks.json"
|
|
15
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# SpexCode plugin (for Claude Code and GitHub Copilot CLI) — Claude Code + Copilot CLI + Cursor (prototype)
|
|
2
|
+
|
|
3
|
+
Prototype packaging of HeySpex's agent integration as a self-hosted plugin for **both** hosts,
|
|
4
|
+
implementing migration-path steps 1–2 of [[HS-QTBK-5EK5-RES-claude-code-plugin-packaging-for]].
|
|
5
|
+
**Additive:** the project-level wiring stays live and remains the source of truth
|
|
6
|
+
(`.mcp.json` + `.claude/settings.json` for Claude Code; `.cursor/mcp.json` +
|
|
7
|
+
`.cursor/hooks.json` for Cursor). Nothing here activates until the plugin is explicitly installed.
|
|
8
|
+
|
|
9
|
+
One plugin directory, two manifests — the hosts read different files and never see each other's.
|
|
10
|
+
|
|
11
|
+
## Layout
|
|
12
|
+
|
|
13
|
+
| Path | Host | What it is |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `.claude-plugin/plugin.json` | Claude Code | Plugin manifest (`name: heyspex`). |
|
|
16
|
+
| `.cursor-plugin/plugin.json` | Cursor | Plugin manifest. Names `mcp.json` and `hooks/cursor-hooks.json` EXPLICITLY, because a Cursor manifest path replaces auto-discovery — without it Cursor would find `hooks/hooks.json` and try to read Claude-shaped config. |
|
|
17
|
+
| `.mcp.json` | Claude Code | MCP server declaration — launches `bin/launch-mcp.mjs` via `${CLAUDE_PLUGIN_ROOT}`. |
|
|
18
|
+
| `mcp.json` | Cursor | MCP server declaration. Runs `${CURSOR_PLUGIN_ROOT}/bin/launch-mcp.mjs` (Cursor expands that variable to the plugin install path), the same launcher `.mcp.json` uses, so it boots from a plain `npm install heyspex`; `HEYSPEX_VAULT_ROOT` is `${workspaceFolder}`. |
|
|
19
|
+
| `bin/launch-mcp.mjs` | Claude Code | Resolver shim: locates `vendor/heyspex-mcp/cli.mjs` in the host vault repo (`HEYSPEX_MCP_ENTRY` override → `$CLAUDE_PROJECT_DIR` → `$CURSOR_PROJECT_DIR` → `$HEYSPEX_VAULT_ROOT` → cwd) and hands off in-process. Needed because the server's deps come from the repo's `node_modules`, so it can't yet run from the plugin's versioned cache copy. |
|
|
20
|
+
| `hooks/hooks.json` | Claude Code, Copilot CLI | **Generated** from the customer-scoped rows of `scripts/lib/customer-kit.mjs` (`node scripts/lib/customer-kit.mjs --write-plugin-hooks`; a test fails on drift). Every command is a self-locating inline bootstrap (plugin-root env `CLAUDE_PLUGIN_ROOT`/`COPILOT_PLUGIN_ROOT`/`PLUGIN_ROOT` → `bin/run-hook.mjs`, else a walk up from the cwd to `scripts/claude-hooks/_run.mjs`, else exit 0) that reaches `bin/run-hook.mjs`, which finds the platform checkout (`HEYSPEX_PLATFORM_ROOT` → `HEYSPEX_MCP_ENTRY` → its own checkout → `node_modules/heyspex` → `$CLAUDE_PROJECT_DIR`) — never `$CLAUDE_PROJECT_DIR/scripts`, which only exists in heyspex-app. MCP-tool matchers carry both `mcp__heyspex__*` and `mcp__plugin_heyspex_heyspex__*` names. |
|
|
21
|
+
| `.github/hooks/heyspex.json` (repo root) | Copilot cloud agent | **Generated** by `npm run hooks:write-github`; bash-only, default branch only. See "Copilot cloud agent" below. |
|
|
22
|
+
| `bin/run-hook.mjs` | Claude Code | Hook launcher: resolves the platform shim `scripts/claude-hooks/_run.mjs` and hands off in-process (fail-open, like the shim). |
|
|
23
|
+
| `hooks/cursor-hooks.json` | Cursor | **Generated** from `scripts/cursor-hooks/manifest.mjs` by `npm run hooks:install-cursor`; drift is a `hs doctor` failure. Commands resolve through `$CURSOR_PROJECT_DIR`. |
|
|
24
|
+
|
|
25
|
+
Each host has its own marketplace catalog at the repo root, both pointing at this directory:
|
|
26
|
+
`.claude-plugin/marketplace.json` and `.cursor-plugin/marketplace.json` — the documented
|
|
27
|
+
self-hosted single-repo pattern; no hosted registry involved.
|
|
28
|
+
|
|
29
|
+
## Installing
|
|
30
|
+
|
|
31
|
+
### From the npm package (customers; no heyspex-app checkout)
|
|
32
|
+
|
|
33
|
+
A team that only installs the published `heyspex` package does not have, and does not need, the
|
|
34
|
+
heyspex-app repository. The package carries the marketplace (`node_modules/heyspex/.claude-plugin/marketplace.json`,
|
|
35
|
+
plugin source `./plugins/heyspex`), the hooks and the MCP server. From the root of your own repo:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install heyspex # or: npm install ./heyspex-<version>.tgz
|
|
39
|
+
npx hs login
|
|
40
|
+
npx heyspex setup copilot # GitHub Copilot CLI: plugin route ...
|
|
41
|
+
npx heyspex setup copilot --hooks # ... OR cloud agent: .github/hooks/heyspex.json, never both
|
|
42
|
+
npx heyspex setup copilot --print # paste this to your agent: next command + the full guide
|
|
43
|
+
npx hs install --target . --plugin-apply # Claude Code
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`setup copilot --check` shows which route is active; `--uninstall` removes the hooks file and prints `copilot plugin uninstall heyspex`.
|
|
47
|
+
|
|
48
|
+
Fallback, by hand: `claude plugin marketplace add ./node_modules/heyspex` /
|
|
49
|
+
`copilot plugin marketplace add ./node_modules/heyspex`, then `... plugin install heyspex@heyspex-marketplace`.
|
|
50
|
+
Restart the session (`/restart` in Copilot), then check `copilot plugin list` and `npx hs doctor`.
|
|
51
|
+
Full walkthrough: `node_modules/heyspex/docs/copilot-plugin-install.md`. The sections below describe the same plugin from the
|
|
52
|
+
platform checkout and are for HeySpex developers.
|
|
53
|
+
|
|
54
|
+
### Claude Code
|
|
55
|
+
|
|
56
|
+
One command, from the platform checkout (wraps the manual flow below):
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
node bin/hs.mjs install --target <consumer-repo> --plugin-apply
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`--plugin` prints the commands instead of running them. The equivalent manual flow, inside a
|
|
63
|
+
Claude Code session in the consumer repo — or via the `claude plugin` CLI:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
/plugin marketplace add <path-or-git-url-of-this-repo>
|
|
67
|
+
/plugin install heyspex@heyspex-marketplace
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### GitHub Copilot CLI
|
|
71
|
+
|
|
72
|
+
Copilot CLI installs Claude-format plugins (`.claude-plugin/plugin.json`) from a marketplace
|
|
73
|
+
(`.claude-plugin/marketplace.json` is on its search path). Source of truth for the commands and the
|
|
74
|
+
file layout: <https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-plugin-reference>
|
|
75
|
+
(fetched 2026-10-16). Hook behaviour: <https://docs.github.com/en/copilot/reference/hooks-configuration>.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
copilot plugin marketplace add <owner>/<repo> # or a git URL or a local path to this repo
|
|
79
|
+
copilot plugin install heyspex@heyspex-marketplace # SPECIFICATION is plugin@marketplace
|
|
80
|
+
copilot plugin list # confirm it is enabled
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
For local development: `copilot plugin marketplace add /path/to/heyspex-app`; a path-sourced plugin in a local
|
|
84
|
+
marketplace loads live (`/restart` picks up edits).
|
|
85
|
+
|
|
86
|
+
What gets loaded:
|
|
87
|
+
|
|
88
|
+
| Component | Loaded from | Notes |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| Hooks | `hooks/hooks.json` | Same file Claude Code reads. PascalCase events (`PreToolUse`, `PostToolUse`, `Stop`...) use Claude matcher semantics and snake_case payloads. Every command is a self-locating inline bootstrap: it needs no `$CLAUDE_PROJECT_DIR` and exits 0 when it cannot find the runtime (Copilot turns any non-zero exit into a deny). |
|
|
91
|
+
| MCP | `.mcp.json` | Legacy-plugin MCP file. Its `${CLAUDE_PLUGIN_ROOT}` expansion under Copilot is **not documented** (Copilot documents `${PLUGIN_ROOT}` for Agent Plugins `mcp.json` only) and could not be verified without a Copilot CLI on the build machine. If the server does not start, add it explicitly: `copilot mcp add heyspex -- node <install-path>/plugins/heyspex/bin/launch-mcp.mjs`. |
|
|
92
|
+
| Skills / prompts | MCP prompts (`hs-*`) | Delivered by the MCP server. **The Copilot cloud coding agent has no prompts**; there use the `hs` CLI loop in `docs/driving-heyspex-from-copilot.md`. |
|
|
93
|
+
| Commands | not loaded | Claude Code slash commands are not a Copilot component. |
|
|
94
|
+
|
|
95
|
+
### One source of hooks: plugin OR repo hooks, never both
|
|
96
|
+
|
|
97
|
+
Copilot CLI (and Claude Code) load hooks from the plugin AND from the repository's own registrations
|
|
98
|
+
(`.claude/settings.json`, `.claude/settings.local.json`, `.github/hooks/*.json`). A repo that has both runs every HeySpex
|
|
99
|
+
hook twice. Pick one per repo:
|
|
100
|
+
|
|
101
|
+
- **Plugin** (this directory): `copilot plugin install heyspex@heyspex-marketplace` / `/plugin install ...`. Do not run
|
|
102
|
+
`hs install` hook registration in the same repo, or strip it afterwards.
|
|
103
|
+
- **Repo hooks** (`hs install`, which writes `.claude/settings.json` + the committed launcher): do not also install the plugin.
|
|
104
|
+
|
|
105
|
+
`npm run doctor` has a `hook-double-fire` check: it warns when HeySpex rows in the repo's `.claude/settings*.json` or
|
|
106
|
+
`.github/hooks/*.json` coexist with an installed heyspex plugin, and reports `unknown` (never a failure) when no plugin
|
|
107
|
+
registry can be read. What it looks at: `~/.claude/plugins/installed_plugins.json` (a `heyspex@...` key),
|
|
108
|
+
`enabledPlugins` in `~/.claude/settings.json` and the project's Claude settings, and, best effort, a heyspex directory
|
|
109
|
+
under `~/.copilot/installed-plugins` or `~/.copilot/plugins` (the Copilot plugin list file is not documented; `copilot
|
|
110
|
+
plugin list` is the authority). As a runtime backstop, `_run.mjs` also de-duplicates a repeated Copilot invocation
|
|
111
|
+
(`HEYSPEX_COPILOT_DEDUPE_OFF=1` disables that).
|
|
112
|
+
|
|
113
|
+
### Copilot cloud agent: `.github/hooks/heyspex.json`
|
|
114
|
+
|
|
115
|
+
The Copilot **cloud agent** loads no plugins and no user-level hook files; its only hook source is `.github/hooks/*.json`
|
|
116
|
+
**on the default branch**. `.github/hooks/heyspex.json` is therefore generated from the same customer rows as
|
|
117
|
+
`hooks/hooks.json`, restricted to the hooks whose Copilot disposition is `mapped` (plus `intent-classifier-trigger`, which
|
|
118
|
+
only arms the capture obligation state and whose dropped output does not matter):
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npm run hooks:write-github # node scripts/lib/customer-kit.mjs --write-github-hooks (a test fails on drift)
|
|
122
|
+
npm run hooks:check-github # exit 1 when stale
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- Linux bash only: every entry is `type: "command"` with a `bash` command that resolves
|
|
126
|
+
`node_modules/heyspex/scripts/claude-hooks/_run.mjs`, then `./scripts/claude-hooks/_run.mjs`, else `exit 0` (fail open).
|
|
127
|
+
Events are the camelCase names (`sessionStart`, `preToolUse`, `postToolUse`, `userPromptSubmitted`, `agentStop`,
|
|
128
|
+
`sessionEnd`, `preCompact`); matchers use Copilot tool names (`create|edit|bash|powershell|task`, MCP tools as a
|
|
129
|
+
`.*<tool>` suffix).
|
|
130
|
+
- The cloud sandbox must contain `node_modules/heyspex` (run `npm install` in the `copilot-setup-steps` workflow), or the
|
|
131
|
+
hooks silently no-op.
|
|
132
|
+
- The firewall must allow the console URL (`emit-claim-status` and claim heartbeats call it), or those hooks time out (timeouts fail open).
|
|
133
|
+
- The file only takes effect once it is on the repository's **default branch**.
|
|
134
|
+
- If the repo also carries `.claude/settings.json` HeySpex rows, Copilot CLI reads both files: that is the double-fire case
|
|
135
|
+
above. Use the manifest for the cloud agent only, or rely on the shim de-duplication.
|
|
136
|
+
- MCP is configured in the repository's Copilot settings (tools only, no OAuth), not by a committed file.
|
|
137
|
+
|
|
138
|
+
### Gates that are weaker or absent on Copilot (published list)
|
|
139
|
+
|
|
140
|
+
Parity is not identity. Where Copilot has a trigger the gate is a hard deny or re-drive; the rows below are the exceptions.
|
|
141
|
+
The list is generated from `scripts/lib/hook-dispositions.mjs` (the single three-host table, which also covers Claude Code
|
|
142
|
+
and Cursor) and a test fails when this block is stale. The hard floor under all of it is the MCP server itself:
|
|
143
|
+
`heyspex_claim_spec`, `heyspex_submit_for_review` and `heyspex_save_research` refuse without a preflight marker on every
|
|
144
|
+
surface that connects the MCP server, with no hook involved.
|
|
145
|
+
|
|
146
|
+
<!-- hook-dispositions:copilot:begin (generated by scripts/lib/hook-dispositions.test.mjs; UPDATE_HOOK_DOCS=1 refreshes) -->
|
|
147
|
+
| Gate | Disposition | Compensating control / what is lost |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| `research-method-guard` | unportable | MCP preflight refusal on heyspex_save_research (hard floor, hook-independent) + .github/copilot-instructions.md research rule; Copilot has no Skill or Workflow tool to hook. |
|
|
150
|
+
| `deep-research-cost-gate` | unportable | MCP preflight refusal on heyspex_save_research + .github/copilot-instructions.md cost-confirmation rule; Copilot has no Skill or Workflow tool to hook. |
|
|
151
|
+
| `plan-review-gate` | unportable | MCP preflight refusals (heyspex_claim_spec / heyspex_submit_for_review / heyspex_save_research) + .github/copilot-instructions.md plan rule (state the plan in chat, claim the spec before editing) + HS-20SW directive-obligation-gate claim-before-build deny |
|
|
152
|
+
| `plan-exit-ingest-gate` | unportable | MCP preflight refusals (heyspex_claim_spec / heyspex_submit_for_review / heyspex_save_research) + .github/copilot-instructions.md plan rule (state the plan in chat, claim the spec before editing) + HS-20SW directive-obligation-gate claim-before-build deny |
|
|
153
|
+
| `preflight-reminder` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. Real enforcement is the MCP preflight refusal. |
|
|
154
|
+
| `intent-classifier-trigger` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. The hook still runs and arms obligation state; the HS-20SW directive-obligation-gate turns that state into a hard deny. |
|
|
155
|
+
| `inject-communication-style` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. |
|
|
156
|
+
| `inject-vault-context` | advisory-degraded | Copilot drops command-hook output on userPromptSubmitted (no prompt-time context channel); the text moves to sessionStart / .github/copilot-instructions.md. Per-prompt vault retrieval has no Copilot channel at all. |
|
|
157
|
+
| `claim-before-code-gate` | advisory-degraded | Armed only by plan-exit-ingest-gate, which has no Copilot trigger (no ExitPlanMode tool), so it stays dormant; covered by the HS-20SW claim-before-build rule. |
|
|
158
|
+
| `diagnose-capture-reminder` | advisory-degraded | Copilot preToolUse has no context channel for an inject, so this advisory is silent (lost). |
|
|
159
|
+
<!-- hook-dispositions:copilot:end -->
|
|
160
|
+
|
|
161
|
+
Unverified on Copilot (no official page read, or not run live): the VS Code 128-tool-per-request cap; the spelling of MCP
|
|
162
|
+
tool names inside hook payloads (matched by suffix); `${CLAUDE_PLUGIN_ROOT}` expansion for the plugin `.mcp.json` under
|
|
163
|
+
the Copilot CLI (documented for VS Code only); and how the MCP server learns the Copilot session id (its preflight marker
|
|
164
|
+
falls back to a 4 hour TTL when the runtime exposes none). Also unverified: that a Claude-format `hookSpecificOutput` deny is
|
|
165
|
+
read by the CLI (only the top-level `permissionDecision` form and exit 2 are documented), and where a `matcher` is read
|
|
166
|
+
in the camelCase `.github/hooks` entry shape.
|
|
167
|
+
|
|
168
|
+
### Turning HeySpex on and off (any harness)
|
|
169
|
+
|
|
170
|
+
One switch, `hs mode` (alias `heyspex mode`; from a checkout without `hs` on PATH: `node bin/hs.mjs mode ...`):
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
hs mode status # on | off, and why
|
|
174
|
+
hs mode off # writes <project>/.heyspex/mode.json; every hook exits 0 at once (no restart)
|
|
175
|
+
hs mode on
|
|
176
|
+
hs mode toggle
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- `HEYSPEX_MODE=off` silences hooks for one shell/session without touching a file (wins over the file).
|
|
180
|
+
- `HEYSPEX_COPILOT_HOOKS_OFF=1` (or `agent_behaviors.harness_hooks.copilot.enabled: false` in the vault `.heyspex/config.yaml`)
|
|
181
|
+
silences every hook **only when the caller is GitHub Copilot**; Claude Code and Cursor keep theirs.
|
|
182
|
+
- The switch is read from the PROJECT being worked on (`CLAUDE_PROJECT_DIR`, then the hook payload `cwd`, then upward
|
|
183
|
+
from the working directory), so `hs mode off` in a customer repo works even though the hooks run from `node_modules/heyspex`.
|
|
184
|
+
- Four security gates ignore the switch by design (`env-vault-guard`, `research-method-guard`, `research-protocol-gate`,
|
|
185
|
+
`git-identity-guard`): an agent must not be able to disarm them by writing one JSON file. Their own env-var
|
|
186
|
+
break-glass (set by a human) still applies. The Copilot opt-out does not cover them either unless the owner extends it.
|
|
187
|
+
|
|
188
|
+
### Cursor
|
|
189
|
+
|
|
190
|
+
For local development, symlink or copy this directory into Cursor's local plugin root and
|
|
191
|
+
reload the window (**Developer: Reload Window**):
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
~/.cursor/plugins/local/heyspex
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Otherwise add the repo as a marketplace source from Cursor's plugin surface; the root
|
|
198
|
+
`.cursor-plugin/marketplace.json` catalogs it.
|
|
199
|
+
|
|
200
|
+
**In the platform repo itself you do not need the plugin at all** — `.cursor/hooks.json`,
|
|
201
|
+
`.cursor/mcp.json`, `.cursor/rules/`, `.cursor/skills/` and `.cursor/commands/` are already
|
|
202
|
+
installed and are the live path. The plugin exists for CONSUMER repos.
|
|
203
|
+
|
|
204
|
+
## Running Claude Code against Ollama or DeepSeek
|
|
205
|
+
|
|
206
|
+
Claude Code can be pointed at a local Ollama instance or DeepSeek's cloud API through
|
|
207
|
+
`ANTHROPIC_BASE_URL`: both expose an Anthropic Messages API-compatible endpoint, so Claude
|
|
208
|
+
Code talks to them directly with no proxy. The recipes below are verified against each
|
|
209
|
+
vendor's own docs ([[HS-REF-pointing-claude-code-at-non-anthropic]]).
|
|
210
|
+
|
|
211
|
+
### Ollama (local)
|
|
212
|
+
|
|
213
|
+
Requires Ollama 0.14+, which added a native Anthropic-compatible endpoint. The auth token is
|
|
214
|
+
required but ignored.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# one-shot
|
|
218
|
+
ollama launch claude --model qwen3-coder
|
|
219
|
+
|
|
220
|
+
# manual
|
|
221
|
+
export ANTHROPIC_AUTH_TOKEN=ollama
|
|
222
|
+
export ANTHROPIC_API_KEY=""
|
|
223
|
+
export ANTHROPIC_BASE_URL=http://localhost:11434
|
|
224
|
+
claude --model qwen3-coder
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### DeepSeek (cloud)
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
export ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
|
|
231
|
+
export ANTHROPIC_API_KEY=your-deepseek-api-key
|
|
232
|
+
claude
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The `/anthropic` path is required — the bare host `https://api.deepseek.com` (without
|
|
236
|
+
`/anthropic`) is not the Anthropic-compatible endpoint. DeepSeek's own docs specify
|
|
237
|
+
`ANTHROPIC_API_KEY`, not `ANTHROPIC_AUTH_TOKEN`.
|
|
238
|
+
|
|
239
|
+
### Model name mapping (DeepSeek)
|
|
240
|
+
|
|
241
|
+
There is no `ANTHROPIC_MODEL` var to set manually — model choice is automatic name-mapping:
|
|
242
|
+
Claude Opus names map to `deepseek-v4-pro` (billed at V4 Pro price), while every other Claude
|
|
243
|
+
name (Haiku/Sonnet) and any unmapped name maps to `deepseek-flash`.
|
|
244
|
+
|
|
245
|
+
### Known DeepSeek limitations
|
|
246
|
+
|
|
247
|
+
- `top_p` fixed at 1.0 outside thinking mode (min 0.95 inside it).
|
|
248
|
+
- Unsupported Anthropic content types: documents, search results, redacted thinking, code
|
|
249
|
+
execution results, MCP tool integrations, container uploads.
|
|
250
|
+
- `budget_tokens` in thinking-mode config is ignored.
|
|
251
|
+
|
|
252
|
+
### Enforcement is independent of the backend
|
|
253
|
+
|
|
254
|
+
HeySpex hooks fire regardless of backend: Claude Code hooks fire at session, turn, and
|
|
255
|
+
tool-call points of Claude Code's own loop, so every HeySpex hook in `.claude/settings.json`
|
|
256
|
+
and `plugins/heyspex/hooks/` runs unchanged regardless of backend — see the
|
|
257
|
+
[Claude Code hooks reference](https://code.claude.com/docs/en/hooks).
|
|
258
|
+
|
|
259
|
+
### Launcher
|
|
260
|
+
|
|
261
|
+
`hs next <id> --launch --backend ollama|deepseek` sets the right env vars and execs `claude`.
|
|
262
|
+
This is the supported path, shipping with epic
|
|
263
|
+
[[HS-30JD-94Q5-EPIC-claude-code-launches-against-ollama-or]]; until then, use the manual
|
|
264
|
+
recipe above.
|
|
265
|
+
|
|
266
|
+
## Validating (migration-path step 3)
|
|
267
|
+
|
|
268
|
+
Run the install above in a **fresh clone / separate consumer repo** (avoids the double-hook
|
|
269
|
+
caveat below), after `npm install` in the platform checkout.
|
|
270
|
+
|
|
271
|
+
Then restart the session and confirm:
|
|
272
|
+
|
|
273
|
+
1. The MCP server connects and tools appear as `mcp__plugin_heyspex_heyspex__heyspex_*`.
|
|
274
|
+
2. Hooks fire (SessionStart seat injection, PreToolUse gates) — and only once.
|
|
275
|
+
3. The re-prefix blast radius: anything load-bearing that hardcodes `mcp__heyspex__*`
|
|
276
|
+
(CLAUDE.md, `.claude/settings.json` permission allow/deny lists, procedures, hook scripts)
|
|
277
|
+
still behaves. This is the migration cost the research flags as largest.
|
|
278
|
+
|
|
279
|
+
## Known caveats (by design, this stage)
|
|
280
|
+
|
|
281
|
+
- **Double-fire:** enabling this plugin in a repo that still registers the same hooks project-level
|
|
282
|
+
runs every hook twice. Single-source rule: plugin OR repo hooks, never both (see above; `npm run doctor` warns).
|
|
283
|
+
Validate in a fresh clone, or strip the project hooks first (`node scripts/install-cursor-hooks.mjs --uninstall` for Cursor).
|
|
284
|
+
- **Not standalone:** the plugin requires a HeySpex vault checkout with `npm install` run —
|
|
285
|
+
the MCP server and hook scripts resolve from the host project, not the plugin cache.
|
|
286
|
+
Bundling the server into the plugin is a full-cutover-stage task.
|
|
287
|
+
- **`hs-*` skills stay MCP prompts** (research step 4, unresolved): they travel with the MCP
|
|
288
|
+
server, not as plugin `SKILL.md` files. Commands, rules and agents are deliberately not
|
|
289
|
+
duplicated here to avoid drift and double registration — which matters more for Cursor, whose
|
|
290
|
+
plugin format CAN carry `rules/`, `commands/` and `skills/`. Bundling them is a cutover decision,
|
|
291
|
+
not a packaging one.
|
|
292
|
+
- **Permissions/statusLine are not mirrored** — those remain project-level concerns.
|
|
293
|
+
- **Manual updates are two steps and scope-sensitive:** `claude plugin marketplace update
|
|
294
|
+
heyspex-marketplace` refreshes the catalog only; the installed copy moves on
|
|
295
|
+
`claude plugin update heyspex@heyspex-marketplace --scope project` (the CLI defaults to
|
|
296
|
+
`--scope user` and errors "not installed at scope user" on a project-scoped install).
|
|
297
|
+
Background auto-update does both, and the new version applies at restart or `/reload-plugins`.
|
|
298
|
+
Version/auto-update findings: `specs/memory/decisions/claude-code-plugin-auto-update-third.md`.
|
|
299
|
+
- **Two hooks have no Cursor trigger** (`plan-review-gate`, `plan-exit-ingest-gate`): Cursor
|
|
300
|
+
exposes no `ExitPlanMode` tool call to hooks, so the plan-review gate is enforced by
|
|
301
|
+
`.cursor/rules/plan-review-required.mdc` instead. Tracked in
|
|
302
|
+
`scripts/cursor-hooks/manifest.mjs` → `UNPORTABLE`; hooks that run weaker are in `DEGRADED` there.
|
|
303
|
+
Four hooks have no Copilot trigger (see the published list above).
|
|
304
|
+
- **Backend choice is separate from enforcement:** running the Claude Code host against a local
|
|
305
|
+
or cloud non-Anthropic model disables no hook — see
|
|
306
|
+
[Running Claude Code against Ollama or DeepSeek](#running-claude-code-against-ollama-or-deepseek)
|
|
307
|
+
for the recipes.
|
|
308
|
+
|
|
309
|
+
## Cutover criteria (research steps 4–5)
|
|
310
|
+
|
|
311
|
+
Only after the validation above passes end-to-end and the skills-vs-prompts question is settled
|
|
312
|
+
does removing the project-level wiring (or extending this to customer vaults) become a decision.
|