heyspex 0.2.2 → 0.2.4
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 +2 -1
- package/README.md +11 -0
- package/bin/hs-vault-binding.mjs +157 -0
- package/bin/hs.mjs +83 -79
- package/bin/spexcode.mjs +91 -0
- package/dev-factory/engine/worktree.mjs +36 -7
- package/dev-factory/lib/epic-detect.mjs +2 -2
- package/dev-factory/lib/fleet-readiness.mjs +3 -5
- package/dev-factory/lib/fleet-state.mjs +2 -2
- package/dev-factory/lib/sufficiency-score.mjs +3 -5
- package/dist/cli/hs-check.mjs +76 -46
- package/dist/cli/hs-claim.mjs +63 -33
- package/dist/cli/hs-connect.mjs +520 -214
- package/dist/cli/hs-defer.mjs +161 -19
- package/dist/cli/hs-dev.mjs +11 -5
- package/dist/cli/hs-env.mjs +187 -161
- package/dist/cli/hs-index-rebuild.mjs +123 -78
- package/dist/cli/hs-index-reconcile.mjs +203 -107
- package/dist/cli/hs-init.mjs +426 -179
- package/dist/cli/hs-install.mjs +759 -437
- package/dist/cli/hs-join.mjs +590 -383
- package/dist/cli/hs-vault-pull.mjs +359 -254
- package/dist/cli/hs-vault-push.mjs +151 -113
- package/dist/cli/hs-vault.mjs +271 -104
- package/dist/cli/hs-workspace.mjs +90 -57
- package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +178 -91
- package/docs/copilot-plugin-install.md +200 -177
- package/docs/driving-heyspex-from-copilot.md +174 -165
- package/docs/mcp-client-config.md +93 -25
- package/package.json +257 -250
- package/plugins/heyspex/.claude-plugin/plugin.json +13 -12
- package/plugins/heyspex/.cursor-plugin/plugin.json +16 -15
- package/plugins/heyspex/.mcp.json +3 -4
- package/plugins/heyspex/README.md +323 -312
- package/plugins/heyspex/assets/heyspex-glyph-128.png +0 -0
- package/plugins/heyspex/assets/heyspex-glyph-256.png +0 -0
- package/plugins/heyspex/assets/heyspex-glyph.svg +12 -0
- package/plugins/heyspex/bin/launch-mcp.mjs +21 -7
- package/plugins/heyspex/mcp.json +12 -13
- package/scripts/check-mcp-freshness.mjs +6 -4
- package/scripts/claude-hooks/_intent-classifier-router.mjs +518 -456
- package/scripts/claude-hooks/intent-classifier-trigger.mjs +305 -279
- package/scripts/claude-hooks/research-method-guard.mjs +2 -2
- package/scripts/claude-hooks/wip-checkpoint.mjs +33 -9
- package/scripts/claude-statusline/fonts/HeySpexIcons.ttf +0 -0
- package/scripts/claude-statusline/statusline-command.mjs +1073 -0
- package/scripts/copilot-statusline.mjs +130 -0
- package/scripts/dev-server-status.mjs +3 -2
- package/scripts/dev-server-stop.mjs +3 -2
- package/scripts/hs-capture-cli.mjs +2 -2
- package/scripts/hs-settings.mjs +2 -2
- package/scripts/hs-view.mjs +3 -2
- package/scripts/install-copilot-hooks.mjs +152 -36
- package/scripts/lib/copilot-cli.mjs +108 -0
- package/scripts/lib/customer-kit.mjs +223 -30
- package/scripts/lib/dev-mode.mjs +28 -2
- package/scripts/lib/shared-path-helpers.mjs +32 -0
- package/scripts/lib/standalone-doctor.mjs +131 -32
- package/scripts/wip-ledger-health.mjs +3 -2
- package/spexharness/src/gates/vault-mirror-catchup.mjs +113 -24
- package/spexharness/src/gates/vault-mirror-catchup.runner.mjs +52 -0
- package/spexharness/src/intent-directive.mjs +839 -626
- package/spexharness/src/rule-table.mjs +1 -1
- package/vendor/heyspex-mcp/cli-verbs.mjs +16 -2
- package/vendor/heyspex-mcp/cli.mjs +20 -4
- package/vendor/heyspex-mcp/console-fetch.mjs +15 -3
- package/vendor/heyspex-mcp/dev-tools.mjs +11 -4
- package/vendor/heyspex-mcp/events-tools.mjs +1 -1
- package/vendor/heyspex-mcp/factory-run-status.mjs +42 -0
- package/vendor/heyspex-mcp/http-transport.mjs +6 -1
- package/vendor/heyspex-mcp/mcp-config.mjs +4 -2
- package/vendor/heyspex-mcp/server-identity.mjs +13 -0
- package/vendor/heyspex-mcp/spec-edit-tools.mjs +26 -1
- package/vendor/heyspex-mcp/test-helpers.mjs +5 -2
- package/vendor/heyspex-mcp/tool-catalog.mjs +12 -0
- package/vendor/heyspex-mcp/tool-dispatch.mjs +63 -23
- package/vendor/heyspex-mcp/usable-dir-env.mjs +82 -0
- package/vendor/heyspex-mcp/vault-binding.mjs +839 -0
- package/vendor/heyspex-mcp/vault-resolve.mjs +353 -245
|
@@ -1,165 +1,174 @@
|
|
|
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
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
|
146
|
-
|
|
|
147
|
-
| `
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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 rows `hs install` commits into `.claude/settings.json` are the one case that resolves itself: they run through
|
|
124
|
+
the committed launcher `.claude/heyspex/run-hook.mjs` (marker `// yields-to-plugin: v1`), which exits 0 silently
|
|
125
|
+
when a heyspex plugin is enabled on this machine (installed in `~/.claude/plugins/installed_plugins.json`, enabled in
|
|
126
|
+
`enabledPlugins`, or present under `~/.copilot/installed-plugins` / `~/.copilot/plugins`) — so the plugin's copy fires
|
|
127
|
+
and the repo's does not. `enabledPlugins["heyspex@..."] === false` (user or project settings) means the plugin is off for
|
|
128
|
+
that harness and the repo rows run; `HEYSPEX_REPO_HOOKS=1` never yields. The doctor reports `ok` for a repo whose every
|
|
129
|
+
`.claude/settings*.json` row goes through a yielding launcher. `.github/hooks/*.json` rows never use the launcher: for
|
|
130
|
+
those, plugin OR hooks stays a real choice.
|
|
131
|
+
|
|
132
|
+
The Copilot **cloud agent** loads no plugins: its only hook source is `.github/hooks/*.json` on the **default branch**.
|
|
133
|
+
`npm run hooks:write-github` generates `.github/hooks/heyspex.json` (bash `command` entries only, camelCase events,
|
|
134
|
+
resolving `node_modules/heyspex/scripts/claude-hooks/_run.mjs` then `./scripts/claude-hooks/_run.mjs`, else exit 0).
|
|
135
|
+
Requirements: the sandbox must contain `node_modules/heyspex` (install it in `copilot-setup-steps`), the firewall must
|
|
136
|
+
allow the console URL (claim heartbeats), and MCP is configured in repository settings (tools only, no OAuth).
|
|
137
|
+
|
|
138
|
+
### Gates that are weaker or absent on Copilot
|
|
139
|
+
|
|
140
|
+
Generated from `scripts/lib/hook-dispositions.mjs` (a test fails when this block is stale). The MCP preflight refusals
|
|
141
|
+
(`heyspex_claim_spec`, `heyspex_submit_for_review`, `heyspex_save_research`) are the hook-independent hard floor on every
|
|
142
|
+
surface that connects the MCP server.
|
|
143
|
+
|
|
144
|
+
<!-- hook-dispositions:copilot:begin (generated by scripts/lib/hook-dispositions.test.mjs; UPDATE_HOOK_DOCS=1 refreshes) -->
|
|
145
|
+
| Gate | Disposition | Compensating control / what is lost |
|
|
146
|
+
| --- | --- | --- |
|
|
147
|
+
| `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. |
|
|
148
|
+
| `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. |
|
|
149
|
+
| `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 |
|
|
150
|
+
| `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 |
|
|
151
|
+
| `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. |
|
|
152
|
+
| `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. |
|
|
153
|
+
| `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. |
|
|
154
|
+
| `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. |
|
|
155
|
+
| `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. |
|
|
156
|
+
| `diagnose-capture-reminder` | advisory-degraded | Copilot preToolUse has no context channel for an inject, so this advisory is silent (lost). |
|
|
157
|
+
<!-- hook-dispositions:copilot:end -->
|
|
158
|
+
|
|
159
|
+
Plan mode: Copilot has no `ExitPlanMode` tool, so the plan gates cannot fire. State the plan in chat and claim the spec
|
|
160
|
+
before editing code (`.github/copilot-instructions.md`); the HS-20SW claim-before-build deny backs that up.
|
|
161
|
+
|
|
162
|
+
**Unverified** (no official page read, or not run live): the VS Code 128-tool per-request cap (the microsoft/vscode issue
|
|
163
|
+
below is the only source); the spelling of MCP tool names inside hook payloads (hooks match by suffix); whether
|
|
164
|
+
`${CLAUDE_PLUGIN_ROOT}` expands in the plugin `.mcp.json` under the Copilot CLI (documented for VS Code only); how the MCP
|
|
165
|
+
server learns the Copilot session id (its preflight marker falls back to a 4 hour TTL); whether the CLI reads a Claude-format
|
|
166
|
+
`hookSpecificOutput` deny.
|
|
167
|
+
|
|
168
|
+
## Sources
|
|
169
|
+
|
|
170
|
+
- [[HS-RDG9-RES-github-copilot-and-vs-code-mcp-support-t]] — Copilot MCP support verified mid-2026 (cloud agent = tools only).
|
|
171
|
+
- [[HS-TACM-RES-tool-agnostic-mcp-compatibility-matrix-2026-05-27]] — cross-tool compatibility matrix (Copilot row being amended).
|
|
172
|
+
- [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.
|
|
173
|
+
- [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.
|
|
174
|
+
- [Hard tool limit (128) in VS Code agent mode — microsoft/vscode#290356](https://github.com/microsoft/vscode/issues/290356) — 128-tool per-request cap.
|
|
@@ -91,10 +91,7 @@ Project scope — `.mcp.json` in the root of the repository you want HeySpex to
|
|
|
91
91
|
"heyspex": {
|
|
92
92
|
"type": "stdio",
|
|
93
93
|
"command": "heyspex-mcp",
|
|
94
|
-
"args": []
|
|
95
|
-
"env": {
|
|
96
|
-
"HEYSPEX_VAULT_ROOT": "."
|
|
97
|
-
}
|
|
94
|
+
"args": []
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
97
|
}
|
|
@@ -108,15 +105,18 @@ If you did not install globally, use the no-install form instead:
|
|
|
108
105
|
"heyspex": {
|
|
109
106
|
"type": "stdio",
|
|
110
107
|
"command": "npx",
|
|
111
|
-
"args": ["--yes", "--package", "heyspex", "heyspex-mcp"]
|
|
112
|
-
"env": {
|
|
113
|
-
"HEYSPEX_VAULT_ROOT": "."
|
|
114
|
-
}
|
|
108
|
+
"args": ["--yes", "--package", "heyspex", "heyspex-mcp"]
|
|
115
109
|
}
|
|
116
110
|
}
|
|
117
111
|
}
|
|
118
112
|
```
|
|
119
113
|
|
|
114
|
+
No `HEYSPEX_VAULT_ROOT` here: the server resolves its vault from the folder the
|
|
115
|
+
client launches it in (the vault checkout itself, or a code repo bound with
|
|
116
|
+
`hs vault bind`; see [Which vault the server reads](#which-vault-the-server-reads)).
|
|
117
|
+
Set `HEYSPEX_VAULT_ROOT` only to point at a vault checkout on purpose; pointing it
|
|
118
|
+
at anything else is refused (`VAULT_NOT_FOUND`).
|
|
119
|
+
|
|
120
120
|
User scope, from any directory:
|
|
121
121
|
|
|
122
122
|
```sh
|
|
@@ -133,10 +133,7 @@ same object:
|
|
|
133
133
|
"mcpServers": {
|
|
134
134
|
"heyspex": {
|
|
135
135
|
"command": "heyspex-mcp",
|
|
136
|
-
"args": []
|
|
137
|
-
"env": {
|
|
138
|
-
"HEYSPEX_VAULT_ROOT": "."
|
|
139
|
-
}
|
|
136
|
+
"args": []
|
|
140
137
|
}
|
|
141
138
|
}
|
|
142
139
|
}
|
|
@@ -202,21 +199,92 @@ shipped fix.
|
|
|
202
199
|
|
|
203
200
|
## Which vault the server reads
|
|
204
201
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
202
|
+
**Contract.** There is no single "active" vault. Every vault is active at
|
|
203
|
+
once: a process writes to the vault that belongs to the folder it was launched
|
|
204
|
+
in (owner ruling 2026-10-14, HS-TYJA). The MCP server, `hs`, `spexcode` and
|
|
205
|
+
dev-factory share one resolver (`vendor/heyspex-mcp/vault-resolve.mjs`); the
|
|
206
|
+
console's TypeScript twin (`spex-console/src/lib/vault-resolve/index.ts`)
|
|
207
|
+
follows the same order, checked by one shared fixture
|
|
208
|
+
(`spex-console/src/lib/vault-resolve/precedence-fixtures.json`). The full
|
|
209
|
+
contract is the header of `vendor/heyspex-mcp/vault-binding.mjs`.
|
|
210
|
+
|
|
211
|
+
### Resolution order (first match wins)
|
|
212
|
+
|
|
213
|
+
| # | Source | Rule |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| 1 | Explicit vault id: `hs --vault <id> <cmd>` | Must name a vault registered on this machine. Otherwise `VAULT_NOT_FOUND`; it never falls through to another vault. |
|
|
216
|
+
| 2 | `HEYSPEX_VAULT_ROOT` (repo root) / `HEYSPEX_VAULT_DIR` (the `specs/` folder) | A deliberate override, above everything on disk. It must name a vault: a checkout on disk (`specs/` or a vault-marker `heyspex.yaml`) or a root registered as a vault in `~/.heyspex/registry.json`. Anything else, such as an unregistered code repo, is `VAULT_NOT_FOUND` and is never silently accepted. |
|
|
217
|
+
| 3 | The launch folder, walking up to the filesystem root | Symlinks and junctions are resolved first, and the nearest folder wins. At each level, in this order: a satellite pin in `.mcp.json` / `.cursor/mcp.json`, then a vault checkout (`specs/`, or a vault-marker `heyspex.yaml`), then a repo binding (`heyspex.yaml` with `kind: repo-binding`). A linked git worktree that matches nothing resolves like its main checkout. |
|
|
218
|
+
| 4 | Nothing | `VAULT_UNBOUND`. The MCP server still boots and lists its tools, but every vault-scoped call is refused locally with the code and the fix. Nothing is sent. |
|
|
219
|
+
|
|
220
|
+
The launch folder is the client's project dir (`CLAUDE_PROJECT_DIR`) when the
|
|
221
|
+
client sets one, and otherwise the process's working directory. The
|
|
222
|
+
registry's `active_vault_id` (and the per-account pointers) are **never read**
|
|
223
|
+
by local resolution. `hs vault switch` still writes the pointer for the cloud
|
|
224
|
+
console and prints a deprecation note saying so.
|
|
225
|
+
|
|
226
|
+
### Two files called heyspex.yaml, never confused
|
|
227
|
+
|
|
228
|
+
| File | Lives in | Written by | Keys | Commit it? |
|
|
229
|
+
|---|---|---|---|---|
|
|
230
|
+
| Vault marker | a vault checkout's root | `hs init` | `schema_version`, `vault_root: specs/`, `vault_id` | yes (it is the vault) |
|
|
231
|
+
| Repo binding | a code repo's root | `hs vault bind` | `kind: repo-binding`, `binding_version`, `vault: {id, name, remote}` | **yes**. It holds no machine path. |
|
|
232
|
+
|
|
233
|
+
The binding names the vault by identity only:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
kind: repo-binding
|
|
237
|
+
binding_version: 1
|
|
238
|
+
vault:
|
|
239
|
+
id: 800f39cb-9245-412e-b957-e42fb80e2d8b
|
|
240
|
+
name: heyspex-specs
|
|
241
|
+
remote: github.com/pwhermanson/heyspex-specs
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Where that vault is checked out is per machine. The resolver goes from the
|
|
245
|
+
binding's `id` to the registry row with that id in `~/.heyspex/registry.json`
|
|
246
|
+
(`vaults[].repo_root_abs`), and from there to the folder. If this machine has
|
|
247
|
+
no such row, the result is `VAULT_BINDING_BROKEN`. It never guesses. If the
|
|
248
|
+
row exists but its folder is gone, the id still resolves (with a notice), so
|
|
249
|
+
cloud tools keep working. Disk-tier tools refuse until the vault is cloned
|
|
250
|
+
back. The registry's `linked_repos[]` is a per-machine reverse index
|
|
251
|
+
of the folders bound on this machine; resolution does not need it.
|
|
252
|
+
|
|
253
|
+
### Commands
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
hs vault bind --vault <name|id> [--repo <dir>] [--force] [--dry-run] [--json]
|
|
257
|
+
Run inside the code repo. Writes heyspex.yaml (kind: repo-binding) and the
|
|
258
|
+
registry linked_repos[] row. Both writes are atomic, and the registry is
|
|
259
|
+
backed up once to registry.json.bak-pre-linked-repos. Idempotent: an
|
|
260
|
+
unchanged re-run writes nothing. It refuses to re-point a bound repo
|
|
261
|
+
without --force, and refuses inside a vault checkout.
|
|
262
|
+
hs vault bindings [--json]
|
|
263
|
+
Every binding on this machine, health-checked (ok / repo-missing /
|
|
264
|
+
marker-missing / marker-differs / vault-unknown), plus how this folder
|
|
265
|
+
resolves.
|
|
266
|
+
hs vault resolve [--json]
|
|
267
|
+
Which vault an agent launched here writes to, and why. Exit code 0 when
|
|
268
|
+
resolved, 1 with the typed error. The --json shape is stable:
|
|
269
|
+
{ ok: true, cwd, source, vault_id, vault_root, bound_repo?, worktree_of? }
|
|
270
|
+
{ ok: false, cwd, source: "unbound", error, code, message, from, fix, details }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Errors
|
|
274
|
+
|
|
275
|
+
Every resolution error carries `code`, `message`, `from` (the folder the
|
|
276
|
+
resolver walked from) and `fix` (the exact command). MCP tool refusals carry
|
|
277
|
+
the same `refusal` code plus `fix` and `from`.
|
|
209
278
|
|
|
210
|
-
|
|
|
279
|
+
| Code | Meaning | `fix` |
|
|
211
280
|
|---|---|---|
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
work, and why they do not depend on the active pointer.
|
|
281
|
+
| `VAULT_UNBOUND` | The folder is in no vault checkout and no bound repo. | `hs vault bind --vault <name\|id>` |
|
|
282
|
+
| `VAULT_BINDING_BROKEN` | `heyspex.yaml` binds a vault id this machine has no registry row for. | Clone it (or `hs pull` in an existing checkout), run `hs vault register <path>`, then `hs vault bind --vault <id>`. |
|
|
283
|
+
| `VAULT_NOT_FOUND` | `--vault` names no registered vault, `HEYSPEX_VAULT_ROOT` / `HEYSPEX_VAULT_DIR` names neither a checkout nor a registered vault root, or `bind --vault X` names no registered vault. | `hs vault list`, `unset HEYSPEX_VAULT_ROOT`, or `hs vault register <path>` |
|
|
284
|
+
| `VAULT_BINDING_CONFLICT` | `bind` would re-point a repo that is already bound. | `hs vault bind --vault <id> --force` |
|
|
285
|
+
| `VAULT_BIND_TARGET_IS_VAULT` | `bind` ran inside a vault checkout. | `hs vault resolve` (nothing to bind) |
|
|
286
|
+
| `REPO_NOT_FOUND` | The `--repo` folder does not exist. | `hs vault bind --repo <existing folder> --vault <name\|id>` |
|
|
287
|
+
| `REGISTRY_UNREADABLE` | `registry.json` does not parse. `bind` never overwrites it. | `hs doctor --fix` |
|
|
220
288
|
|
|
221
289
|
## Satellite repos: code here, specs elsewhere
|
|
222
290
|
|