heyspex 0.2.5 → 0.2.7

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.
Files changed (110) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/bin/hs.mjs +349 -38
  3. package/bin/spexcode.mjs +31 -0
  4. package/dev-factory/lib/dispatch-guard.mjs +75 -0
  5. package/dev-factory/lib/local-firecrawl.mjs +294 -0
  6. package/dev-factory/lib/runner-path.mjs +51 -0
  7. package/dev-factory/lib/seat-context.mjs +20 -4
  8. package/dev-factory/model-catalog.json +222 -222
  9. package/dev-factory/spexcrawl/firecrawl-cli.mjs +755 -0
  10. package/dev-factory/spexcrawl/spexcrawl-cli.mjs +734 -0
  11. package/dist/cli/hs-connect.mjs +40 -3
  12. package/dist/cli/hs-defer.mjs +3817 -3741
  13. package/dist/cli/hs-events.mjs +1296 -0
  14. package/dist/cli/hs-export-events.mjs +1252 -0
  15. package/dist/cli/hs-handoff.mjs +2576 -0
  16. package/dist/cli/hs-index-rebuild.mjs +228 -37
  17. package/dist/cli/hs-index-reconcile.mjs +231 -40
  18. package/dist/cli/hs-init.mjs +22 -3
  19. package/dist/cli/hs-install.mjs +22 -3
  20. package/dist/cli/hs-join.mjs +40 -3
  21. package/dist/cli/hs-next-launch.mjs +2777 -0
  22. package/dist/cli/hs-pin.mjs +1336 -0
  23. package/dist/cli/hs-prereq.mjs +1380 -0
  24. package/dist/cli/hs-revalidate.mjs +3257 -0
  25. package/dist/cli/hs-spawn.mjs +12403 -0
  26. package/dist/cli/hs-test.mjs +1046 -0
  27. package/dist/cli/hs-trash.mjs +362 -0
  28. package/dist/cli/hs-trust.mjs +197 -0
  29. package/dist/cli/hs-vault-pull.mjs +233 -42
  30. package/dist/cli/hs-vault-push.mjs +231 -40
  31. package/dist/cli/hs-vault.mjs +21 -7
  32. package/dist/cli/hs-workspace.mjs +19 -1
  33. package/dist/cli-templates/customer-vault/specs/entity-model.md +1728 -1728
  34. package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +464 -464
  35. package/dist/cli-templates/customer-vault/specs/protocols/destructive-action-checklist.md +122 -122
  36. package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +46 -46
  37. package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +530 -530
  38. package/dist/cli-templates/customer-vault/specs/protocols/spec-summary-authoring.md +83 -83
  39. package/dist/cli-templates/harness-commands/claude/hs-backfill.md +28 -28
  40. package/dist/cli-templates/harness-commands/claude/hs-capture.md +62 -62
  41. package/dist/cli-templates/harness-commands/claude/hs-defer.md +29 -29
  42. package/dist/cli-templates/harness-commands/claude/hs-ground.md +30 -30
  43. package/dist/cli-templates/harness-commands/claude/hs-next.md +29 -29
  44. package/dist/cli-templates/harness-commands/claude/hs-promote.md +70 -70
  45. package/dist/cli-templates/harness-commands/claude/hs-push.md +35 -35
  46. package/dist/cli-templates/harness-commands/claude/hs-qc.md +27 -27
  47. package/dist/cli-templates/harness-commands/claude/hs-res.md +83 -63
  48. package/dist/cli-templates/harness-commands/claude/hs-resolve.md +23 -23
  49. package/dist/cli-templates/harness-commands/claude/hs-view.md +28 -28
  50. package/dist/cli-templates/harness-commands/claude/kill-ports.md +32 -32
  51. package/dist/cli-templates/harness-commands/claude/prototype.md +91 -91
  52. package/dist/cli-templates/harness-commands/cursor/hs-backfill.md +22 -22
  53. package/dist/cli-templates/harness-commands/cursor/hs-capture.md +56 -56
  54. package/dist/cli-templates/harness-commands/cursor/hs-defer.md +23 -23
  55. package/dist/cli-templates/harness-commands/cursor/hs-ground.md +24 -24
  56. package/dist/cli-templates/harness-commands/cursor/hs-next.md +23 -23
  57. package/dist/cli-templates/harness-commands/cursor/hs-promote.md +64 -64
  58. package/dist/cli-templates/harness-commands/cursor/hs-push.md +29 -29
  59. package/dist/cli-templates/harness-commands/cursor/hs-qc.md +21 -21
  60. package/dist/cli-templates/harness-commands/cursor/hs-res.md +78 -58
  61. package/dist/cli-templates/harness-commands/cursor/hs-resolve.md +17 -17
  62. package/dist/cli-templates/harness-commands/cursor/hs-view.md +23 -23
  63. package/dist/cli-templates/harness-commands/cursor/kill-ports.md +26 -26
  64. package/dist/cli-templates/harness-commands/cursor/prototype.md +86 -86
  65. package/docs/copilot-plugin-install.md +9 -2
  66. package/docs/mcp-client-config.md +6 -0
  67. package/package.json +266 -257
  68. package/plugins/heyspex/.claude-plugin/plugin.json +1 -1
  69. package/plugins/heyspex/.cursor-plugin/plugin.json +1 -1
  70. package/plugins/heyspex/README.md +6 -0
  71. package/plugins/heyspex/bin/launch-mcp.mjs +17 -0
  72. package/plugins/heyspex/hooks/hooks.json +418 -418
  73. package/scripts/claude-hooks/_intent-classifier-semantic.mjs +2 -2
  74. package/scripts/claude-hooks/wip-checkpoint.mjs +17 -2
  75. package/scripts/claude-statusline/statusline-command.mjs +287 -27
  76. package/scripts/hs-companion.mjs +41 -3
  77. package/scripts/install-claude-code-hooks.mjs +104 -3
  78. package/scripts/install-copilot-hooks.mjs +21 -1
  79. package/scripts/install-cursor-hooks.mjs +4 -3
  80. package/scripts/lib/capture-execution-guard.mjs +221 -0
  81. package/scripts/lib/companion-install.mjs +768 -0
  82. package/scripts/lib/customer-kit.mjs +53 -3
  83. package/scripts/lib/hs-companion-settings.mjs +26 -0
  84. package/scripts/lib/hs-source-push.mjs +386 -386
  85. package/scripts/record-grounding.mjs +38 -0
  86. package/spexharness/doctrine/baseline/SPEXCODE-DOCTRINE.baseline.json +29 -29
  87. package/spexharness/src/adapters/copilot-models.mjs +179 -0
  88. package/spexharness/src/adapters/harness-detect.mjs +148 -0
  89. package/spexharness/src/gates/directive-obligation-gate.decide.mjs +132 -132
  90. package/spexharness/src/gates/vault-write-tier-guard.decide.mjs +153 -125
  91. package/spexharness/src/seat-context.mjs +10 -5
  92. package/spexharness/src/session-bootstrap.mjs +6 -3
  93. package/vendor/heyspex-mcp/cli.mjs +6 -1
  94. package/vendor/heyspex-mcp/config-seed.yaml +15 -15
  95. package/vendor/heyspex-mcp/dev-factory-overlay.mjs +142 -0
  96. package/vendor/heyspex-mcp/http-transport.mjs +1 -1
  97. package/vendor/heyspex-mcp/memory-tools.mjs +523 -523
  98. package/vendor/heyspex-mcp/on-deck-scheduler.mjs +1708 -1708
  99. package/vendor/heyspex-mcp/procedure-handlers.mjs +327 -327
  100. package/vendor/heyspex-mcp/procedure-tools.mjs +1209 -1181
  101. package/vendor/heyspex-mcp/research-tools.mjs +22 -2
  102. package/vendor/heyspex-mcp/seat-assign-cli.mjs +242 -0
  103. package/vendor/heyspex-mcp/seat-assignment-rules.mjs +96 -0
  104. package/vendor/heyspex-mcp/seat-assignments-client.mjs +265 -0
  105. package/vendor/heyspex-mcp/seat-defaults-cli.mjs +45 -0
  106. package/vendor/heyspex-mcp/seat-defaults.mjs +232 -0
  107. package/vendor/heyspex-mcp/seat-identity.mjs +171 -0
  108. package/vendor/heyspex-mcp/test-helpers.mjs +37 -23
  109. package/vendor/heyspex-mcp/vault-io.mjs +720 -720
  110. package/bin/postinstall.mjs +0 -88
@@ -7,26 +7,26 @@ description: Pull the next on-deck execution prompt from the HeySpex roadmap (fo
7
7
 
8
8
  **Usage:** `/hs-next [handheld|assist|auto] [HS-XXXX-EPIC | HS-XXXX] [--include-horizon] [--ignore-focus] [--claim]`
9
9
 
10
- > **SaaS-safety note:** this file is a thin shim — the workflow orchestration (claim question wording, reply→action mapping, failure-mode handling) lives in `vendor/heyspex-mcp/cli.mjs` (`composeAgentOrchestration`) and is delivered to you as the structured `agent_dispatch` object. **Do not add orchestration prose here.** If a workflow detail needs to change, change it in the MCP server so customer workspaces can't corrupt it. See [[HS-CCKM-J6CD-RES-migrate-slash-command-orchestration-from]] and [[workflow-orchestration-belongs-in-mcp-not-claude-commands]].
11
-
12
- ## What to do
13
-
14
- 1. **Parse `$ARGUMENTS`** (all optional, order-flexible):
15
- - **Run front** (default `handheld`): `handheld` · `assist` | `assisted` · `auto` | `autonomous` → canonical `front` for MCP (`handheld` | `assisted` | `autonomous`; omit when handheld/default)
16
- - bare token `HS-EPIC-*` or `HS-*` → `spec_id`
17
- - bare token `HS-ROADMAP-*` → `roadmap_id`
18
- - `--include-horizon` → `include_horizon: true`
19
- - `--ignore-focus` → `ignore_focus: true`
20
- - `--claim` | `--auto-claim` → `auto_claim: true`. Skips the yes/proceed/confirm handshake and claims immediately — same mechanism `autonomous` front already triggers automatically (`shouldAutoClaimOnDeck` in `run-front.mjs`), just usable standalone at any front. `/hs-next HS-IUQO --claim` claims and starts handheld work with no ask; `/hs-next HS-IUQO assisted --claim` does the same at assisted supervision. (Redundant, never conflicting, with `autonomous` front, which already implies it.)
21
-
22
- 2. **Call** `heyspex_next_on_deck` with `summary: true` plus the parsed args (including `front` when not handheld/default, and `auto_claim: true` when `--claim`/`--auto-claim` was passed).
23
-
24
- 3. **Output the `user_prompt_markdown` field verbatim** to the user. Do not summarize, paraphrase, or trim. **Do NOT echo the `agent_dispatch` field** — it is a structured routing object you decode, not prose you print. (The @deprecated `prompt_markdown` field mirrors `user_prompt_markdown`; either is safe to print, but prefer `user_prompt_markdown`.) Schema: `specs/schemas/agent-dispatch.schema.json`.
25
-
26
- 4. **On the user's reply**, decode `agent_dispatch`:
27
- - Match the reply against each entry's `tokens` array under `on_user_reply` (or `drift_resolution_menu`, when present).
28
- - If the matching entry has `actions`, invoke each `{ tool, args }` in order. If `execute_after: true`, begin executing the work in the same turn — no second permission ask. All listed tools (`heyspex_claim_spec`, `heyspex_record_alignment`, `heyspex_next_on_deck`, `heyspex_release_spec`) are pre-allowlisted.
29
- - If the matching entry has `reply`, respond with that string verbatim.
30
- - If the `default` entry is `"respond_to_user_question"`, treat the reply as a redirect: answer the user's actual question instead of claiming.
31
- - For any tool error, look up its code in `agent_dispatch.failure_modes` and apply the named `handling` only when that error code was **returned by the tool call** — failure_modes are conditional, not a statement that the console is down. Trust `console_status.reachable` on the brief. Never hand-write vault files when `heyspex_file_spec` fails.
32
- - On session hand-off, run the `on_handoff` actions (typically `heyspex_release_spec`).
10
+ > **SaaS-safety note:** this file is a thin shim — the workflow orchestration (claim question wording, reply→action mapping, failure-mode handling) lives in `vendor/heyspex-mcp/cli.mjs` (`composeAgentOrchestration`) and is delivered to you as the structured `agent_dispatch` object. **Do not add orchestration prose here.** If a workflow detail needs to change, change it in the MCP server so customer workspaces can't corrupt it. See [[HS-CCKM-J6CD-RES-migrate-slash-command-orchestration-from]] and [[workflow-orchestration-belongs-in-mcp-not-claude-commands]].
11
+
12
+ ## What to do
13
+
14
+ 1. **Parse `$ARGUMENTS`** (all optional, order-flexible):
15
+ - **Run front** (default `handheld`): `handheld` · `assist` | `assisted` · `auto` | `autonomous` → canonical `front` for MCP (`handheld` | `assisted` | `autonomous`; omit when handheld/default)
16
+ - bare token `HS-EPIC-*` or `HS-*` → `spec_id`
17
+ - bare token `HS-ROADMAP-*` → `roadmap_id`
18
+ - `--include-horizon` → `include_horizon: true`
19
+ - `--ignore-focus` → `ignore_focus: true`
20
+ - `--claim` | `--auto-claim` → `auto_claim: true`. Skips the yes/proceed/confirm handshake and claims immediately — same mechanism `autonomous` front already triggers automatically (`shouldAutoClaimOnDeck` in `run-front.mjs`), just usable standalone at any front. `/hs-next HS-IUQO --claim` claims and starts handheld work with no ask; `/hs-next HS-IUQO assisted --claim` does the same at assisted supervision. (Redundant, never conflicting, with `autonomous` front, which already implies it.)
21
+
22
+ 2. **Call** `heyspex_next_on_deck` with `summary: true` plus the parsed args (including `front` when not handheld/default, and `auto_claim: true` when `--claim`/`--auto-claim` was passed).
23
+
24
+ 3. **Output the `user_prompt_markdown` field verbatim** to the user. Do not summarize, paraphrase, or trim. **Do NOT echo the `agent_dispatch` field** — it is a structured routing object you decode, not prose you print. (The @deprecated `prompt_markdown` field mirrors `user_prompt_markdown`; either is safe to print, but prefer `user_prompt_markdown`.) Schema: `specs/schemas/agent-dispatch.schema.json`.
25
+
26
+ 4. **On the user's reply**, decode `agent_dispatch`:
27
+ - Match the reply against each entry's `tokens` array under `on_user_reply` (or `drift_resolution_menu`, when present).
28
+ - If the matching entry has `actions`, invoke each `{ tool, args }` in order. If `execute_after: true`, begin executing the work in the same turn — no second permission ask. All listed tools (`heyspex_claim_spec`, `heyspex_record_alignment`, `heyspex_next_on_deck`, `heyspex_release_spec`) are pre-allowlisted.
29
+ - If the matching entry has `reply`, respond with that string verbatim.
30
+ - If the `default` entry is `"respond_to_user_question"`, treat the reply as a redirect: answer the user's actual question instead of claiming.
31
+ - For any tool error, look up its code in `agent_dispatch.failure_modes` and apply the named `handling` only when that error code was **returned by the tool call** — failure_modes are conditional, not a statement that the console is down. Trust `console_status.reachable` on the brief. Never hand-write vault files when `heyspex_file_spec` fails.
32
+ - On session hand-off, run the `on_handoff` actions (typically `heyspex_release_spec`).
@@ -7,67 +7,67 @@ description: Promote whatever doc you hand it to its next stage — a capture (H
7
7
 
8
8
  **Usage:** `/hs-promote <HS-CAP-XXXX[,HS-CAP-YYYY...] | HS-RES-XXXX> [rest of args depend on which — see below]`
9
9
 
10
- > **Platform asymmetry — read this, it is load-bearing.** Claude Code delivers only the **first whitespace token** of an MCP prompt's argument (GitHub [#14210](https://github.com/anthropics/claude-code/issues/14210), closed *not planned*), so the namespaced MCP prompts (`/hs-promote-capture`, `/hs-promote-research`) can each carry at most a single token. This **native project command** is the only IDE surface that receives full `$ARGUMENTS`.
11
- >
12
- > **Why one command instead of two.** `/hs-promote-capture` and `/hs-promote-research` used to be separate commands — which meant typing the word "promote" twice (`/hs-promote-capture HS-CAP-XXXX promote`) when the command name already said what it does. There's exactly one verb here — *promote whatever doc you hand it to its next stage* — so there's one command. The **id prefix alone** tells you which flow applies (`HS-CAP-*` vs `HS-RES-*` are mutually exclusive and mechanical to detect); the two flows underneath are otherwise unrelated (different tools, different payload shapes, different two-phase mechanics) and stay fully separate below — only the entrypoint is shared.
13
-
14
- ## Step 0 — identify the doc
15
-
16
- Read the **leading token** of `$ARGUMENTS` (case-insensitive; captures may be a comma/whitespace-separated list):
17
- - Contains `-CAP` as its type label (legacy `HS-CAP-XXXX` or era-3 `HS-<fileKey>-<familyKey>-CAP-<slug>`) → go to **§A. Capture → research**.
18
- - Contains `-RES` the same way → go to **§A2. Research → milestone**.
19
- - **Era-3 short/display forms carry NO type label** — `HS-XV4W` (short id) and `HS-XV4W-HV6H` (file key + family key, the form humans see rendered) name a spec without saying its kind. Resolve the kind by fetching it: `heyspex_active_capture({ spec_id })` succeeding → it's a capture, §A. Otherwise treat it as research and try §A2. The tools accept any of these forms and collapse them to the stored short id themselves — never tell the user their id is wrong just because it carries (or lacks) the family key.
20
- - None of the above → ask the user which doc they mean (don't guess).
21
-
22
- If the capture tools are not already available in this session, call `heyspex_load_tools` first so `heyspex_active_capture` / `heyspex_promote_capture` / `heyspex_promote_capture_to_diagnose` are callable.
23
-
24
- ---
25
-
26
- ## §A. Capture → research (`HS-CAP-*`)
27
-
28
- **1. Parse the rest of `$ARGUMENTS`:**
29
- - Leading token(s) matching `HS-CAP-[A-Z0-9-]{3,}` (comma- and/or whitespace-separated) → `capture_ids` (1 or more).
30
- - Next token: `HS-RES-[A-Z0-9-]{3,}` → `target_research` = that id. Or the literal word `new`/`NEW` (also the default when this token is omitted entirely) → `target_research = "NEW"`; any remaining words up to an `enhances:` token → `new_research_name`.
31
- - A token shaped `enhances:HS-MIL-XXXX` anywhere in the string → `enhances`.
32
-
33
- **2. Route by kind:**
34
- - For each `capture_id`, read its `kind:` via `heyspex_active_capture({ spec_id: capture_id })`.
35
- - Exactly one capture_id AND its `kind: bug-fix` → `heyspex_promote_capture_to_diagnose({ capture_id })` (creates `HS-DIAG-*`). Never mix a bug-fix capture into a multi-capture research promote.
36
- - Otherwise → `heyspex_promote_capture({ capture_ids, target_research, new_research_name?, enhances? })`:
37
- - `target_research === "NEW"` is **two-phase**: first call **omits** `accepted_outline` — it returns a proposed `{ name, outline, tags, enhances_suggestion }`. **Show it to the user and confirm** before calling again with the same args plus `accepted_outline` (Phase 2 performs the writes). Never skip straight to Phase 2.
38
- - An existing `target_research` id is single-phase (direct, idempotent append) — no outline confirm needed.
39
- - A `CAPTURE_INSUFFICIENT` error names the missing elements (core-idea, example, done-criteria, kind, user-stories) — the correct response is to elicit that detail from the user and improve the capture, not to pass `force_promote: true` unless the human explicitly says to promote anyway.
40
- - **Check the outline against the capture's own Notes before presenting it.** Before showing `proposed_outline` (AI-proposed or agent-authored) to the user, walk every verbatim quote in the capture's `## Notes` and state plainly whether the outline addresses it. If a quote asks for something the outline doesn't cover, add a section for it or say so before asking for confirm — a missed verbatim quote is exactly what got two real items dropped from a milestone in this vault's own history ([[HS-GDT5-F16L-DIAG-promote-flow-drafts-research-and-stubs]]).
41
- - **Outline confirm ≠ research done.** Phase 2 only writes the research **stub** — every section body is the literal placeholder `_TBD — fill in this section._`. Confirming the outline approves its *shape* (section headings), not its findings. As the very next step after Phase 2 creates the file, fill in every section with real content **by running the `/hs-res` method** (SpexCrawl gather via the Companion + DeepSeek synthesis — see `.claude/commands/hs-res.md`); **never author the research yourself in the main session** — main-session self-research skips the routed research seats and burns the expensive model on work the fleet owns. Do not report the research as complete, and do not move on to `/hs-promote-research`, until the TBD placeholders are gone. (`heyspex_promote_research` mechanically refuses with `RESEARCH_STILL_STUB` while any remain, but don't rely on that gate — write the research because it's the point of the flow, not because a check will otherwise fail.)
42
-
43
- **3. Report the result** — the research id (created or extended) or diagnose id created, and confirm the capture(s)' `promoted_to` now points at it.
44
-
45
- ---
46
-
47
- ## §A2. Research → milestone (`HS-RES-*`)
48
-
49
- **1. Parse the rest of `$ARGUMENTS`:**
50
- - `research_id` is the leading `HS-RES-*` token (already identified in Step 0).
51
- - Next word matching `spawn|augment|both` → `intent`. Default `spawn` when omitted.
52
- - Next token: `HS-MIL-[A-Z0-9-]{3,}` → `target_milestone` = that id. Or the literal word `new`/`NEW` (also the default when this token is omitted entirely) → `target_milestone = "NEW"`; remaining words → `new_milestone_name`.
53
- - If `intent` includes `augment`, any remaining `HS-EPIC-[A-Z0-9-]{3,}` tokens → `augment_epic_ids` (required in that case — ask for them if `augment` was requested but none were given).
54
-
55
- **2. Default policy:** `target_milestone: "NEW"` unless the user names an **existing `status: open`** milestone that clearly extends the same thesis. Spawning into an `in_progress` milestone is blocked unless the owner explicitly passes `attach_to_in_progress_milestone: true` + `attach_override_reason` (≥40 chars audit trail) — never default to this path or infer the override on the agent's own judgment.
56
-
57
- **3. Phase 1 — proposal.** Call `heyspex_promote_research({ research_id, target_milestone, new_milestone_name?, intent, spawn_epic_count?, augment_epic_ids? })` **without** `accepted_stubs`. Show the user the returned `proposed_stubs[]` and let them edit/remove/approve.
58
- - **If `ai_proposal.ok === false` (e.g. `reason: "no_api_key"`), `proposed_stubs` comes back empty — the agent must author the stubs itself.** This is NOT a shortcut to skip the confirm step; it makes the confirm step *more* necessary, not less, because nothing upstream has vetted these stubs yet. Author them from the research doc's actual content, present them to the user exactly as you would an AI proposal (name/kind/effort/rationale per stub), and wait for a real approval turn before calling Phase 2. **Do not call Phase 2 in the same turn you authored the stubs in** — that is precisely the failure this line exists to prevent (observed 2026-08-12: an agent self-authored 3 epic stubs and executed `accepted_stubs` in the same tool-call batch with no human turn in between).
59
- - **Check the stubs against the SOURCE CAPTURE's own Notes before presenting them.** Before showing `proposed_stubs` (AI-proposed or agent-authored) to the user, walk every verbatim quote in the source capture's `## Notes` — the capture(s) named in the research doc's `sources_captures`, not just the research doc's own prose, since a two-hop drift can lose fidelity the research doc's text won't show — and confirm each is addressed by a stub or explicitly named as out of scope. This check caught two real gaps missed by an agent-authored stub list in this vault's own history ([[HS-GDT5-F16L-DIAG-promote-flow-drafts-research-and-stubs]]).
60
-
61
- **4. Phase 2 — execute (after human confirms).** Call again with the same args plus `accepted_stubs: [...]` (the confirmed, possibly-edited subset) to perform the transactional write.
62
-
63
- **5. Report the result** — the milestone id (new or existing) plus spawned epic ids, or the augmented epic ids. Note that research stays `status: open` (research is evergreen) — only its `enhances:`/`spawned_epics:` links change.
64
-
65
- ---
66
-
67
- ## Hard prohibitions
68
-
69
- - **Never** execute a Phase-2 write (`accepted_outline` or `accepted_stubs`) without the human having seen and confirmed the Phase-1 proposal. For `accepted_stubs` the tool now refuses this mechanically: the proposal turn leaves a marker keyed on the research id, and an execute turn without one returns `STUB_REVIEW_REQUIRED`. If the human replaced every proposed stub, pass `stub_edit_note` (≥40 chars) saying what they changed — otherwise a fully-drifted execute returns `STUB_REVIEW_DRIFT`. As with `RESEARCH_STILL_STUB`, treat the mechanical refusal as the backstop, not the first line of defense.
70
- - **Never** call `heyspex_promote_research` against a research doc that still carries `_TBD — fill in this section._` placeholders — fill it in via the `/hs-res` method first (§A step 2 above), never by authoring the research yourself in the main session. The tool refuses this mechanically (`RESEARCH_STILL_STUB`) but the agent should never rely on that as the first line of defense.
71
- - **Never** route a bug-fix capture through `heyspex_promote_capture` — it goes to `heyspex_promote_capture_to_diagnose` instead.
72
- - **Never** attach a research promote to an `in_progress` milestone without an explicit owner override (`attach_to_in_progress_milestone` + `attach_override_reason`).
73
- - **Never** commit or push.
10
+ > **Platform asymmetry — read this, it is load-bearing.** Claude Code delivers only the **first whitespace token** of an MCP prompt's argument (GitHub [#14210](https://github.com/anthropics/claude-code/issues/14210), closed *not planned*), so the namespaced MCP prompts (`/hs-promote-capture`, `/hs-promote-research`) can each carry at most a single token. This **native project command** is the only IDE surface that receives full `$ARGUMENTS`.
11
+ >
12
+ > **Why one command instead of two.** `/hs-promote-capture` and `/hs-promote-research` used to be separate commands — which meant typing the word "promote" twice (`/hs-promote-capture HS-CAP-XXXX promote`) when the command name already said what it does. There's exactly one verb here — *promote whatever doc you hand it to its next stage* — so there's one command. The **id prefix alone** tells you which flow applies (`HS-CAP-*` vs `HS-RES-*` are mutually exclusive and mechanical to detect); the two flows underneath are otherwise unrelated (different tools, different payload shapes, different two-phase mechanics) and stay fully separate below — only the entrypoint is shared.
13
+
14
+ ## Step 0 — identify the doc
15
+
16
+ Read the **leading token** of `$ARGUMENTS` (case-insensitive; captures may be a comma/whitespace-separated list):
17
+ - Contains `-CAP` as its type label (legacy `HS-CAP-XXXX` or era-3 `HS-<fileKey>-<familyKey>-CAP-<slug>`) → go to **§A. Capture → research**.
18
+ - Contains `-RES` the same way → go to **§A2. Research → milestone**.
19
+ - **Era-3 short/display forms carry NO type label** — `HS-XV4W` (short id) and `HS-XV4W-HV6H` (file key + family key, the form humans see rendered) name a spec without saying its kind. Resolve the kind by fetching it: `heyspex_active_capture({ spec_id })` succeeding → it's a capture, §A. Otherwise treat it as research and try §A2. The tools accept any of these forms and collapse them to the stored short id themselves — never tell the user their id is wrong just because it carries (or lacks) the family key.
20
+ - None of the above → ask the user which doc they mean (don't guess).
21
+
22
+ If the capture tools are not already available in this session, call `heyspex_load_tools` first so `heyspex_active_capture` / `heyspex_promote_capture` / `heyspex_promote_capture_to_diagnose` are callable.
23
+
24
+ ---
25
+
26
+ ## §A. Capture → research (`HS-CAP-*`)
27
+
28
+ **1. Parse the rest of `$ARGUMENTS`:**
29
+ - Leading token(s) matching `HS-CAP-[A-Z0-9-]{3,}` (comma- and/or whitespace-separated) → `capture_ids` (1 or more).
30
+ - Next token: `HS-RES-[A-Z0-9-]{3,}` → `target_research` = that id. Or the literal word `new`/`NEW` (also the default when this token is omitted entirely) → `target_research = "NEW"`; any remaining words up to an `enhances:` token → `new_research_name`.
31
+ - A token shaped `enhances:HS-MIL-XXXX` anywhere in the string → `enhances`.
32
+
33
+ **2. Route by kind:**
34
+ - For each `capture_id`, read its `kind:` via `heyspex_active_capture({ spec_id: capture_id })`.
35
+ - Exactly one capture_id AND its `kind: bug-fix` → `heyspex_promote_capture_to_diagnose({ capture_id })` (creates `HS-DIAG-*`). Never mix a bug-fix capture into a multi-capture research promote.
36
+ - Otherwise → `heyspex_promote_capture({ capture_ids, target_research, new_research_name?, enhances? })`:
37
+ - `target_research === "NEW"` is **two-phase**: first call **omits** `accepted_outline` — it returns a proposed `{ name, outline, tags, enhances_suggestion }`. **Show it to the user and confirm** before calling again with the same args plus `accepted_outline` (Phase 2 performs the writes). Never skip straight to Phase 2.
38
+ - An existing `target_research` id is single-phase (direct, idempotent append) — no outline confirm needed.
39
+ - A `CAPTURE_INSUFFICIENT` error names the missing elements (core-idea, example, done-criteria, kind, user-stories) — the correct response is to elicit that detail from the user and improve the capture, not to pass `force_promote: true` unless the human explicitly says to promote anyway.
40
+ - **Check the outline against the capture's own Notes before presenting it.** Before showing `proposed_outline` (AI-proposed or agent-authored) to the user, walk every verbatim quote in the capture's `## Notes` and state plainly whether the outline addresses it. If a quote asks for something the outline doesn't cover, add a section for it or say so before asking for confirm — a missed verbatim quote is exactly what got two real items dropped from a milestone in this vault's own history ([[HS-GDT5-F16L-DIAG-promote-flow-drafts-research-and-stubs]]).
41
+ - **Outline confirm ≠ research done.** Phase 2 only writes the research **stub** — every section body is the literal placeholder `_TBD — fill in this section._`. Confirming the outline approves its *shape* (section headings), not its findings. As the very next step after Phase 2 creates the file, fill in every section with real content **by running the `/hs-res` method** (SpexCrawl gather via the Companion + DeepSeek synthesis — see `.claude/commands/hs-res.md`); **never author the research yourself in the main session** — main-session self-research skips the routed research seats and burns the expensive model on work the fleet owns. Do not report the research as complete, and do not move on to `/hs-promote-research`, until the TBD placeholders are gone. (`heyspex_promote_research` mechanically refuses with `RESEARCH_STILL_STUB` while any remain, but don't rely on that gate — write the research because it's the point of the flow, not because a check will otherwise fail.)
42
+
43
+ **3. Report the result** — the research id (created or extended) or diagnose id created, and confirm the capture(s)' `promoted_to` now points at it.
44
+
45
+ ---
46
+
47
+ ## §A2. Research → milestone (`HS-RES-*`)
48
+
49
+ **1. Parse the rest of `$ARGUMENTS`:**
50
+ - `research_id` is the leading `HS-RES-*` token (already identified in Step 0).
51
+ - Next word matching `spawn|augment|both` → `intent`. Default `spawn` when omitted.
52
+ - Next token: `HS-MIL-[A-Z0-9-]{3,}` → `target_milestone` = that id. Or the literal word `new`/`NEW` (also the default when this token is omitted entirely) → `target_milestone = "NEW"`; remaining words → `new_milestone_name`.
53
+ - If `intent` includes `augment`, any remaining `HS-EPIC-[A-Z0-9-]{3,}` tokens → `augment_epic_ids` (required in that case — ask for them if `augment` was requested but none were given).
54
+
55
+ **2. Default policy:** `target_milestone: "NEW"` unless the user names an **existing `status: open`** milestone that clearly extends the same thesis. Spawning into an `in_progress` milestone is blocked unless the owner explicitly passes `attach_to_in_progress_milestone: true` + `attach_override_reason` (≥40 chars audit trail) — never default to this path or infer the override on the agent's own judgment.
56
+
57
+ **3. Phase 1 — proposal.** Call `heyspex_promote_research({ research_id, target_milestone, new_milestone_name?, intent, spawn_epic_count?, augment_epic_ids? })` **without** `accepted_stubs`. Show the user the returned `proposed_stubs[]` and let them edit/remove/approve.
58
+ - **If `ai_proposal.ok === false` (e.g. `reason: "no_api_key"`), `proposed_stubs` comes back empty — the agent must author the stubs itself.** This is NOT a shortcut to skip the confirm step; it makes the confirm step *more* necessary, not less, because nothing upstream has vetted these stubs yet. Author them from the research doc's actual content, present them to the user exactly as you would an AI proposal (name/kind/effort/rationale per stub), and wait for a real approval turn before calling Phase 2. **Do not call Phase 2 in the same turn you authored the stubs in** — that is precisely the failure this line exists to prevent (observed 2026-08-12: an agent self-authored 3 epic stubs and executed `accepted_stubs` in the same tool-call batch with no human turn in between).
59
+ - **Check the stubs against the SOURCE CAPTURE's own Notes before presenting them.** Before showing `proposed_stubs` (AI-proposed or agent-authored) to the user, walk every verbatim quote in the source capture's `## Notes` — the capture(s) named in the research doc's `sources_captures`, not just the research doc's own prose, since a two-hop drift can lose fidelity the research doc's text won't show — and confirm each is addressed by a stub or explicitly named as out of scope. This check caught two real gaps missed by an agent-authored stub list in this vault's own history ([[HS-GDT5-F16L-DIAG-promote-flow-drafts-research-and-stubs]]).
60
+
61
+ **4. Phase 2 — execute (after human confirms).** Call again with the same args plus `accepted_stubs: [...]` (the confirmed, possibly-edited subset) to perform the transactional write.
62
+
63
+ **5. Report the result** — the milestone id (new or existing) plus spawned epic ids, or the augmented epic ids. Note that research stays `status: open` (research is evergreen) — only its `enhances:`/`spawned_epics:` links change.
64
+
65
+ ---
66
+
67
+ ## Hard prohibitions
68
+
69
+ - **Never** execute a Phase-2 write (`accepted_outline` or `accepted_stubs`) without the human having seen and confirmed the Phase-1 proposal. For `accepted_stubs` the tool now refuses this mechanically: the proposal turn leaves a marker keyed on the research id, and an execute turn without one returns `STUB_REVIEW_REQUIRED`. If the human replaced every proposed stub, pass `stub_edit_note` (≥40 chars) saying what they changed — otherwise a fully-drifted execute returns `STUB_REVIEW_DRIFT`. As with `RESEARCH_STILL_STUB`, treat the mechanical refusal as the backstop, not the first line of defense.
70
+ - **Never** call `heyspex_promote_research` against a research doc that still carries `_TBD — fill in this section._` placeholders — fill it in via the `/hs-res` method first (§A step 2 above), never by authoring the research yourself in the main session. The tool refuses this mechanically (`RESEARCH_STILL_STUB`) but the agent should never rely on that as the first line of defense.
71
+ - **Never** route a bug-fix capture through `heyspex_promote_capture` — it goes to `heyspex_promote_capture_to_diagnose` instead.
72
+ - **Never** attach a research promote to an `in_progress` milestone without an explicit owner override (`attach_to_in_progress_milestone` + `attach_override_reason`).
73
+ - **Never** commit or push.
@@ -7,32 +7,32 @@ description: Push an epic implementation plan into the HeySpex vault, optionally
7
7
 
8
8
  **Usage:** `/hs-push [<epic name>] [--next] [--reason <focus reason>]`
9
9
 
10
- > **Platform asymmetry — read this, it is load-bearing.** Claude Code delivers only the **first whitespace token** of an MCP prompt's argument (GitHub [#14210](https://github.com/anthropics/claude-code/issues/14210), closed *not planned*), so the namespaced MCP prompts `/hs-push` / `/hs-push-next` can each carry at most a single token — never an epic name plus a `--next` flag plus a focus reason together. This **native project command** is the only IDE surface that receives full `$ARGUMENTS`. It also **consolidates** the old two-prompt split (`hs-push` vs `hs-push-next`) into one command: both ultimately call the same `heyspex_push_plan` tool with only `on_deck` differing, so there is no behavior lost by merging them here — just one flag instead of two command names.
11
-
12
- ## What to do
13
-
14
- **1. Parse `$ARGUMENTS`:**
15
- - `--next` (anywhere, case-insensitive) → `on_deck = true`. Absent → `on_deck = false` (file the epic without pinning focus).
16
- - `--reason <text>` → `focus_reason` (only meaningful when `on_deck` is true; rest of that flag's value up to the next `--` flag or end of string).
17
- - Remaining leading, non-flag text → an `epic_name` hint. Optional — if omitted, derive the title from the plan under discussion in chat.
18
-
19
- **2. Gather the rest of the payload from the conversation** (a Cursor/proprietary `.plan.md` the user pasted or referenced, or a plan already discussed in chat):
20
- - `summary` — required plain-language frontmatter summary (spec-summary-authoring contract).
21
- - `plan_markdown` — epic body markdown (goal, phases, acceptance criteria).
22
- - `milestone` — **required**: the parent `HS-MIL-*` wikilink. Ask the user if it isn't obvious from context; the tool call fails without it.
23
- - `source_plan_paths` — any `.plan.md` file paths referenced (auto-detected from `plan_markdown` too).
24
- - `kind` / `effort` / `tags` / `related` — optional scheduler/classification fields.
25
-
26
- **3. Call** `heyspex_push_plan({ epic_name, summary, plan_markdown, milestone, on_deck, focus_reason?, source_plan_paths?, kind?, effort?, tags?, related? })`. This writes the epic **only** — `children: []`; tasks are never filed here, only later via `/hs-next` breakdown.
27
-
28
- **4. After the call:**
29
- - `on_deck: true` → the epic is set `in_progress`, `.heyspex/focus.yaml` is written, and a NEXT STEP block is added. Tell the user to run `/hs-next` next.
30
- - `on_deck: false` → tell the user to re-run `/hs-push --next` (or `/hs-next <the new epic id>`) when ready to start work.
31
-
32
- **5. Conflict handling:** if the tool returns a behavioral-conflict block against `related` specs and `on_deck` was requested, the write is blocked by default (no files written, no focus pinned). Surface the conflicts to the user — only pass `skip_conflict_check: true` on their explicit say-so, and note a `conflict_override` should be recorded afterward.
33
-
34
- ## Hard prohibitions
35
-
36
- - **Never** file tasks here — epics only (`children: []`); tasks are just-in-time via `/hs-next` breakdown.
37
- - **Never** silently bypass a conflict block — surface it and let the human decide.
38
- - **Never** commit or push git.
10
+ > **Platform asymmetry — read this, it is load-bearing.** Claude Code delivers only the **first whitespace token** of an MCP prompt's argument (GitHub [#14210](https://github.com/anthropics/claude-code/issues/14210), closed *not planned*), so the namespaced MCP prompts `/hs-push` / `/hs-push-next` can each carry at most a single token — never an epic name plus a `--next` flag plus a focus reason together. This **native project command** is the only IDE surface that receives full `$ARGUMENTS`. It also **consolidates** the old two-prompt split (`hs-push` vs `hs-push-next`) into one command: both ultimately call the same `heyspex_push_plan` tool with only `on_deck` differing, so there is no behavior lost by merging them here — just one flag instead of two command names.
11
+
12
+ ## What to do
13
+
14
+ **1. Parse `$ARGUMENTS`:**
15
+ - `--next` (anywhere, case-insensitive) → `on_deck = true`. Absent → `on_deck = false` (file the epic without pinning focus).
16
+ - `--reason <text>` → `focus_reason` (only meaningful when `on_deck` is true; rest of that flag's value up to the next `--` flag or end of string).
17
+ - Remaining leading, non-flag text → an `epic_name` hint. Optional — if omitted, derive the title from the plan under discussion in chat.
18
+
19
+ **2. Gather the rest of the payload from the conversation** (a Cursor/proprietary `.plan.md` the user pasted or referenced, or a plan already discussed in chat):
20
+ - `summary` — required plain-language frontmatter summary (spec-summary-authoring contract).
21
+ - `plan_markdown` — epic body markdown (goal, phases, acceptance criteria).
22
+ - `milestone` — **required**: the parent `HS-MIL-*` wikilink. Ask the user if it isn't obvious from context; the tool call fails without it.
23
+ - `source_plan_paths` — any `.plan.md` file paths referenced (auto-detected from `plan_markdown` too).
24
+ - `kind` / `effort` / `tags` / `related` — optional scheduler/classification fields.
25
+
26
+ **3. Call** `heyspex_push_plan({ epic_name, summary, plan_markdown, milestone, on_deck, focus_reason?, source_plan_paths?, kind?, effort?, tags?, related? })`. This writes the epic **only** — `children: []`; tasks are never filed here, only later via `/hs-next` breakdown.
27
+
28
+ **4. After the call:**
29
+ - `on_deck: true` → the epic is set `in_progress`, `.heyspex/focus.yaml` is written, and a NEXT STEP block is added. Tell the user to run `/hs-next` next.
30
+ - `on_deck: false` → tell the user to re-run `/hs-push --next` (or `/hs-next <the new epic id>`) when ready to start work.
31
+
32
+ **5. Conflict handling:** if the tool returns a behavioral-conflict block against `related` specs and `on_deck` was requested, the write is blocked by default (no files written, no focus pinned). Surface the conflicts to the user — only pass `skip_conflict_check: true` on their explicit say-so, and note a `conflict_override` should be recorded afterward.
33
+
34
+ ## Hard prohibitions
35
+
36
+ - **Never** file tasks here — epics only (`children: []`); tasks are just-in-time via `/hs-next` breakdown.
37
+ - **Never** silently bypass a conflict block — surface it and let the human decide.
38
+ - **Never** commit or push git.
@@ -7,24 +7,24 @@ description: Post-plan QC gut-check — stress-test a drafted plan before execut
7
7
 
8
8
  **Usage:** `/hs-qc [--plan <path>] (defaults to the most recent plan)`
9
9
 
10
- > **Where this sits.** `/hs-ground` (pre-plan) → draft → `heyspex_plan_review` → **`/hs-qc`** → `ExitPlanMode`. Both plan-review + QC markers required ([[HS-R4OY]]).
11
-
12
- ## What to do
13
-
14
- **0. Mandatory drift passes** — Axis A (as-built code) + Axis B (design supersession per [[drift-is-two-axes-as-built-and-design-supersession]]). Re-run `heyspex_plan_review`; read `axis_b_drift`. Do not trust parent epic AC over newer memory decisions.
15
-
16
- **0b. When `axis_b_drift` is non-empty — ask the user before recording QC:**
17
-
18
- Present each conflict. **Default (Recommended):** re-scope the plan (remove dead work). **Override:** user explicitly confirms proceed anyway → `heyspex_plan_qc({ axis_b_user_confirmed: true, axis_b_confirmation_note: "…" })`. Tool returns `QC_AXIS_B_DRIFT` until resolved or user-confirmed. **The override is currently broken** per [[HS-EP8E-C1L2-DIAG-heyspex-plan-qc-override-path-ignores-ax]] (reproduced twice) — until fixed, `HEYSPEX_PLAN_QC_GATE_OFF=1` is the only working escape, and its use should be reported to the owner.
19
-
20
- **1. Run the gut-check (verbatim — the owner's standard).**
21
-
22
- Wonderful work! Can you please do a quality check and a gut-check? … *(full questions unchanged)*
23
-
24
- **2. Act on what you find.** Fold findings into the plan; re-run `heyspex_plan_review` if material.
25
-
26
- **3. Record Proof-of-Use.** `heyspex_plan_qc` with substantive `findings_summary` including **`Axis B:`** line.
27
-
28
- **4. Then `ExitPlanMode`.**
29
-
30
- (Break-glass: `HEYSPEX_PLAN_QC_GATE_OFF=1`.)
10
+ > **Where this sits.** `/hs-ground` (pre-plan) → draft → `heyspex_plan_review` → **`/hs-qc`** → `ExitPlanMode`. Both plan-review + QC markers required ([[HS-R4OY]]).
11
+
12
+ ## What to do
13
+
14
+ **0. Mandatory drift passes** — Axis A (as-built code) + Axis B (design supersession per [[drift-is-two-axes-as-built-and-design-supersession]]). Re-run `heyspex_plan_review`; read `axis_b_drift`. Do not trust parent epic AC over newer memory decisions.
15
+
16
+ **0b. When `axis_b_drift` is non-empty — ask the user before recording QC:**
17
+
18
+ Present each conflict. **Default (Recommended):** re-scope the plan (remove dead work). **Override:** user explicitly confirms proceed anyway → `heyspex_plan_qc({ axis_b_user_confirmed: true, axis_b_confirmation_note: "…" })`. Tool returns `QC_AXIS_B_DRIFT` until resolved or user-confirmed. **The override is currently broken** per [[HS-EP8E-C1L2-DIAG-heyspex-plan-qc-override-path-ignores-ax]] (reproduced twice) — until fixed, `HEYSPEX_PLAN_QC_GATE_OFF=1` is the only working escape, and its use should be reported to the owner.
19
+
20
+ **1. Run the gut-check (verbatim — the owner's standard).**
21
+
22
+ Wonderful work! Can you please do a quality check and a gut-check? … *(full questions unchanged)*
23
+
24
+ **2. Act on what you find.** Fold findings into the plan; re-run `heyspex_plan_review` if material.
25
+
26
+ **3. Record Proof-of-Use.** `heyspex_plan_qc` with substantive `findings_summary` including **`Axis B:`** line.
27
+
28
+ **4. Then `ExitPlanMode`.**
29
+
30
+ (Break-glass: `HEYSPEX_PLAN_QC_GATE_OFF=1`.)
@@ -7,61 +7,81 @@ description: Confidence-ladder research method's entrypoint — SpexCrawl via th
7
7
 
8
8
  **Usage:** `/hs-res [research question/topic]`
9
9
 
10
- # Research (`/hs-res`)
11
-
12
- > Parity: `.commandcode/skills/hs-res/SKILL.md` · `.cursor/skills/hs-res/SKILL.md` · `.agents/skills/hs-res/SKILL.md`
13
-
14
- ## What to do
15
-
16
- 1. **Take the question.** `$ARGUMENTS` is the research question/topic. If empty, load the
17
- console doc-toolbar Promote pin via `heyspex_active_research`
18
- (`.heyspex/research-focus.yaml` → `source_idea_id`, `scope`, `spec_path`) and read the source
19
- capture body as the question. Either way, restate the scope and confirm with the user.
20
-
21
- 2. **Gather via SpexCrawl (the Companion) — the PRIMARY method** (owner ruling 2026-08-14,
22
- [[spexcrawl-through-the-companion-is-the]]: "Companion > SpexCrawl is now default method
23
- for research"). Decompose into a few independent search angles, then per angle:
24
- `node dev-factory/spexcrawl/spexcrawl-cli.mjs search "<query>" --json` — one call
25
- searches AND returns the cleaned pages of the top results. Specific extra URLs:
26
- `node dev-factory/spexcrawl/spexcrawl-cli.mjs scrape "<url>" --json`.
27
- Prerequisites: the Companion running and paired to the console. LAN mode
28
- (`npm run console:log:lan`) is needed ONLY when the Companion runs on a DIFFERENT
29
- machine than the console — since HS-V9WH the Companion polls loopback consoles too
30
- ([[a-queue-is-dead-if-its-only-consumer]]: the LAN line was a bug workaround
31
- misdocumented as a requirement). When missing, the CLI exits 3 with
32
- `SPEXCRAWL_UNAVAILABLE` naming the fix; a silent hang means the Companion is not
33
- running or not polling this console.
34
-
35
- **Fallback — self-hosted Firecrawl, AUTOMATIC, no permission needed (owner ruling
36
- 2026-08-22).** When the SpexCrawl path malfunctions, times out, hits a gate, or is otherwise
37
- unavailable, fall back immediately: `node dev-factory/spexcrawl/firecrawl-cli.mjs
38
- search "<query>" --json` and `node dev-factory/spexcrawl/firecrawl-cli.mjs scrape
39
- "<url>" --json`. May run on any fleet machine (coffee-geek, basement-geek, spec-ops) —
40
- prefer other reachable machines over the one the orchestrating session runs on; check
41
- `docker info`, start Docker/the stack if needed, poll the real endpoint for readiness before
42
- use. If this task's changed/claimed files are SpexCrawl-related, skip SpexCrawl entirely and
43
- go straight to Firecrawl. Hosted `api.firecrawl.dev` credits are unchanged — still
44
- ask-before-spend every time. Full contract: `.commandcode/skills/hs-res/SKILL.md`.
45
-
46
- 3. **Assemble a numbered sources block** (`[S1]`, `[S2]`, …) from the gathered
47
- `{title, url, snippet, markdown}` results, write it plus the question and cite-only
48
- instructions to a temp prompt file.
49
-
50
- 4. **Synthesize via DeepSeek** —
51
- `node dev-factory/spexcrawl/synthesize-cli.mjs --prompt-file <path> --json`
52
- (defaults `--max-tokens` to 32000 and auto-escalates ×3 up to a 96000 ceiling if DeepSeek's
53
- default-on "thinking" mode burns the whole budget on reasoning — never pass a lower
54
- `--max-tokens` yourself; the CLI self-heals this failure mode. Exhausted escalation exits 3
55
- with `SYNTHESIZE_UNAVAILABLE`).
56
-
57
- 5. **Save** via `heyspex_save_research` (or `heyspex_complete_research` under the console pin
58
- pipeline), with `sources` populated from the gathered URLs.
59
-
60
- **Never fall back** to `deep-research`/`deep-research-quick|medium|thorough`, the
61
- `Workflow({ scriptPath: '.claude/workflows/deep-research-*.js' })` launch, or native
62
- `WebSearch`/`WebFetch` for this method. Self-hosted Firecrawl fallback is automatic (no
63
- permission needed, 2026-08-22 ruling); hosted `api.firecrawl.dev` credits still need the
64
- user's explicit per-run permission, every time. If a CLI reports unavailable
65
- (`SPEXCRAWL_UNAVAILABLE` / `FIRECRAWL_UNAVAILABLE` / `SYNTHESIZE_UNAVAILABLE`, exit 3),
66
- **stop** and tell the user — never silently substitute another backend. Full method,
67
- escalation rule, and hard prohibitions: `.commandcode/skills/hs-res/SKILL.md`.
10
+ # Research (`/hs-res`)
11
+
12
+ > Parity: `.commandcode/skills/hs-res/SKILL.md` · `.cursor/skills/hs-res/SKILL.md` · `.agents/skills/hs-res/SKILL.md`
13
+
14
+ ## What to do
15
+
16
+ 1. **Take the question.** `$ARGUMENTS` is the research question/topic. If empty, load the
17
+ console doc-toolbar Promote pin via `heyspex_active_research`
18
+ (`.heyspex/research-focus.yaml` → `source_idea_id`, `scope`, `spec_path`) and read the source
19
+ capture body as the question. Either way, restate the scope and confirm with the user.
20
+
21
+ 2. **Gather via SpexCrawl (the Companion) — the PRIMARY method** (owner ruling 2026-08-14,
22
+ [[spexcrawl-through-the-companion-is-the]]: "Companion > SpexCrawl is now default method
23
+ for research"). Decompose into a few independent search angles, then per angle:
24
+ `node dev-factory/spexcrawl/spexcrawl-cli.mjs search "<query>" --json` — one call
25
+ searches AND returns the cleaned pages of the top results. Specific extra URLs:
26
+ `node dev-factory/spexcrawl/spexcrawl-cli.mjs scrape "<url>" --json`.
27
+ Prerequisites: the Companion running and paired to the console. LAN mode
28
+ (`npm run console:log:lan`) is needed ONLY when the Companion runs on a DIFFERENT
29
+ machine than the console — since HS-V9WH the Companion polls loopback consoles too
30
+ ([[a-queue-is-dead-if-its-only-consumer]]: the LAN line was a bug workaround
31
+ misdocumented as a requirement). When missing, the CLI exits 3 with
32
+ `SPEXCRAWL_UNAVAILABLE` naming the fix; a silent hang means the Companion is not
33
+ running or not polling this console.
34
+
35
+ **Fallback — self-hosted Firecrawl, AUTOMATIC, no permission needed (owner ruling
36
+ 2026-08-22).** When the SpexCrawl path malfunctions, times out, hits a gate, or is otherwise
37
+ unavailable, fall back immediately: `node dev-factory/spexcrawl/firecrawl-cli.mjs
38
+ search "<query>" --json` and `node dev-factory/spexcrawl/firecrawl-cli.mjs scrape
39
+ "<url>" --json`. May run on any self-hosted fleet machine or this machine's own Docker —
40
+ prefer other reachable machines over the one the orchestrating session runs on; check
41
+ `docker info`, start Docker/the stack if needed, poll the real endpoint for readiness before
42
+ use. If this task's changed/claimed files are SpexCrawl-related, skip SpexCrawl entirely and
43
+ go straight to Firecrawl. Hosted `api.firecrawl.dev` credits are unchanged — still
44
+ ask-before-spend every time. Full contract: `.commandcode/skills/hs-res/SKILL.md`.
45
+
46
+ **In a repo that uses the `heyspex` npm package** (not a HeySpex platform checkout — the
47
+ CLIs above resolve under `node_modules/heyspex/`; owner ruling 2026-10-17). Prerequisite:
48
+ Docker Desktop running a self-hosted Firecrawl stack on this machine. No env var and no API
49
+ key: the Firecrawl CLI finds it by itself (`docker ps`, then localhost:3002). The method is
50
+ Firecrawl for URLs, SpexCrawl for pages, your own model for the write-up:
51
+ 1. **Find URLs** — `node dev-factory/spexcrawl/firecrawl-cli.mjs search "<query>" --json`
52
+ per angle.
53
+ 2. **Fetch every URL you will cite** with SpexCrawl:
54
+ `node dev-factory/spexcrawl/spexcrawl-cli.mjs scrape "<url>" --json`.
55
+ SpexCrawl needs the HeySpex Companion; when it exits 3
56
+ `SPEXCRAWL_UNAVAILABLE`, fetch the same URL from the same local Firecrawl:
57
+ `node dev-factory/spexcrawl/firecrawl-cli.mjs scrape "<url>" --json`.
58
+ 3. **Synthesize yourself** — skip steps 3–4 below (the DeepSeek CLI `synthesize-cli.mjs` is
59
+ HeySpex-platform only and not in the package). From the fetched pages only, write a
60
+ cited **Executive Summary** (every claim tagged `[S1]`, `[S2]`, …) and a numbered
61
+ **Sources** list (title + URL per `[Sn]`).
62
+ 4. **Save** as in step 5, `sources` filled from the fetched URLs.
63
+ If the Firecrawl CLI exits 3 `FIRECRAWL_UNAVAILABLE`, stop and relay its message to the
64
+ user (it says to start Docker Desktop and the Firecrawl stack, with the steps).
65
+
66
+ 3. **Assemble a numbered sources block** (`[S1]`, `[S2]`, …) from the gathered
67
+ `{title, url, snippet, markdown}` results, write it plus the question and cite-only
68
+ instructions to a temp prompt file.
69
+
70
+ 4. **Synthesize via DeepSeek** —
71
+ `node dev-factory/spexcrawl/synthesize-cli.mjs --prompt-file <path> --json`
72
+ (defaults `--max-tokens` to 32000 and auto-escalates ×3 up to a 96000 ceiling if DeepSeek's
73
+ default-on "thinking" mode burns the whole budget on reasoning — never pass a lower
74
+ `--max-tokens` yourself; the CLI self-heals this failure mode. Exhausted escalation exits 3
75
+ with `SYNTHESIZE_UNAVAILABLE`).
76
+
77
+ 5. **Save** via `heyspex_save_research` (or `heyspex_complete_research` under the console pin
78
+ pipeline), with `sources` populated from the gathered URLs.
79
+
80
+ **Never fall back** to `deep-research`/`deep-research-quick|medium|thorough`, the
81
+ `Workflow({ scriptPath: '.claude/workflows/deep-research-*.js' })` launch, or native
82
+ `WebSearch`/`WebFetch` for this method. Self-hosted Firecrawl fallback is automatic (no
83
+ permission needed, 2026-08-22 ruling); hosted `api.firecrawl.dev` credits still need the
84
+ user's explicit per-run permission, every time. If a CLI reports unavailable
85
+ (`SPEXCRAWL_UNAVAILABLE` / `FIRECRAWL_UNAVAILABLE` / `SYNTHESIZE_UNAVAILABLE`, exit 3),
86
+ **stop** and tell the user — never silently substitute another backend. Full method,
87
+ escalation rule, and hard prohibitions: `.commandcode/skills/hs-res/SKILL.md`.
@@ -7,20 +7,20 @@ description: Pull the top open item from the HeySpex Resolution lane (conflicts,
7
7
 
8
8
  **Usage:** `/hs-resolve [HS-XXXX-EPIC | <item-key> | --ignore-focus]`
9
9
 
10
- Invoke the `heyspex_next_resolution` MCP tool to fetch the top open resolution item from the HeySpex vault, then paste the returned `prompt_markdown` verbatim so the user can act on the fix brief.
11
-
12
- Argument parsing for `$ARGUMENTS` (all optional; if empty, call the tool with no parameters):
13
-
14
- - A token containing `:` (e.g. `dangling_ref:hs-epic-x:hs-task-y`) → pass as `item_key` (fetch that specific item's brief; bypasses the focus pin).
15
- - A bare spec id matching `HS-EPIC-*` / `HS-TASK-*` / `HS-MIL-*` / `HS-*-*` → pass as `scope` (deck-aware: restrict detection to that spec so its gating prerequisite/conflicts surface). This is what the On-Deck `resolve_command: /hs-resolve <epic-id>` passes.
16
- - `--ignore-focus` → set `ignore_focus: true` (skip the Neon resolution focus pin; lead with the top-ranked open item).
17
-
18
- Resolution precedence (built into the tool — do not re-implement): `item_key` → `scope`/`ignore_focus` (top-ranked of the open list) → the Neon focus pin (server-applied) → top-ranked open item. Items are ordered with **gating** and **errors first** (`orderResolutionItems`).
19
-
20
- After the tool returns, output the `prompt_markdown` field as-is, then on a final line state the source: `_Source: {source} · {item.kind} · {item.key}_`. Do not summarize, paraphrase, or start executing actions from the brief without the user's go-ahead.
21
-
22
- This is the surviving `/hs-resolve` (the legacy conflict-only prompt that errored **"Not an Epic"** on a milestone has been retired — the resolver is item-centric and never type-checks the target). Authority from the brief's resolution menu: **Re-scan / clear** is agent-autonomous; **Switch to this**, **Defer**, **edge removal**, and **override** require explicit user confirmation. `stale_index` items expose **only** re-scan/clear — never an edge-mutating action.
23
-
24
- Detection is HTTP-only (the tool reads the console aggregator — the one detection path — it does not re-detect). If the tool errors with `CONSOLE_UNREACHABLE`, tell the user to **start the console dev server (port 3000, or run `hs server status` to see which port it actually bound)** — this only happens on a dev machine; SaaS console is always up. On `CONSOLE_TIMEOUT`, suggest retrying shortly (the server may be cold-compiling). On `ITEM_NOT_FOUND`, the `item_key` is not in the open set — list items with `/hs-resolve` (no args).
25
-
26
- This skill does NOT claim or build anything; it presents the fix brief. Sibling skills: `/hs-next` (build pipeline), `/hs-review` (review pipeline), `/hs-resolve` (this — resolution lane). See [[HS-0EJ6-RMCP-EPIC-hs-resolve-mcp-tool-and-skill]] and [[HS-I8FM-RSRF-EPIC-resolution-surface-api-and-pin]].
10
+ Invoke the `heyspex_next_resolution` MCP tool to fetch the top open resolution item from the HeySpex vault, then paste the returned `prompt_markdown` verbatim so the user can act on the fix brief.
11
+
12
+ Argument parsing for `$ARGUMENTS` (all optional; if empty, call the tool with no parameters):
13
+
14
+ - A token containing `:` (e.g. `dangling_ref:hs-epic-x:hs-task-y`) → pass as `item_key` (fetch that specific item's brief; bypasses the focus pin).
15
+ - A bare spec id matching `HS-EPIC-*` / `HS-TASK-*` / `HS-MIL-*` / `HS-*-*` → pass as `scope` (deck-aware: restrict detection to that spec so its gating prerequisite/conflicts surface). This is what the On-Deck `resolve_command: /hs-resolve <epic-id>` passes.
16
+ - `--ignore-focus` → set `ignore_focus: true` (skip the Neon resolution focus pin; lead with the top-ranked open item).
17
+
18
+ Resolution precedence (built into the tool — do not re-implement): `item_key` → `scope`/`ignore_focus` (top-ranked of the open list) → the Neon focus pin (server-applied) → top-ranked open item. Items are ordered with **gating** and **errors first** (`orderResolutionItems`).
19
+
20
+ After the tool returns, output the `prompt_markdown` field as-is, then on a final line state the source: `_Source: {source} · {item.kind} · {item.key}_`. Do not summarize, paraphrase, or start executing actions from the brief without the user's go-ahead.
21
+
22
+ This is the surviving `/hs-resolve` (the legacy conflict-only prompt that errored **"Not an Epic"** on a milestone has been retired — the resolver is item-centric and never type-checks the target). Authority from the brief's resolution menu: **Re-scan / clear** is agent-autonomous; **Switch to this**, **Defer**, **edge removal**, and **override** require explicit user confirmation. `stale_index` items expose **only** re-scan/clear — never an edge-mutating action.
23
+
24
+ Detection is HTTP-only (the tool reads the console aggregator — the one detection path — it does not re-detect). If the tool errors with `CONSOLE_UNREACHABLE`, tell the user to **start the console dev server (port 3000, or run `hs server status` to see which port it actually bound)** — this only happens on a dev machine; SaaS console is always up. On `CONSOLE_TIMEOUT`, suggest retrying shortly (the server may be cold-compiling). On `ITEM_NOT_FOUND`, the `item_key` is not in the open set — list items with `/hs-resolve` (no args).
25
+
26
+ This skill does NOT claim or build anything; it presents the fix brief. Sibling skills: `/hs-next` (build pipeline), `/hs-review` (review pipeline), `/hs-resolve` (this — resolution lane). See [[HS-0EJ6-RMCP-EPIC-hs-resolve-mcp-tool-and-skill]] and [[HS-I8FM-RSRF-EPIC-resolution-surface-api-and-pin]].
@@ -7,26 +7,26 @@ description: Open one console surface in a chromeless app-mode browser window (s
7
7
 
8
8
  **Usage:** `/hs-view [surface] [doc id] [--width N] [--height N] [--browser edge|chrome]`
9
9
 
10
- # HeySpex solo-surface viewer (`/hs-view`)
11
-
12
- > Parity: `.commandcode/skills/hs-view/SKILL.md` · `.cursor/skills/hs-view/SKILL.md` · `.agents/skills/hs-view/SKILL.md`
13
-
14
- Optional macro over the one core ([[capability-three-faces-no-per-capability-slash]]): shell to `hs view`, never reimplement it. Design: [[HS-RU2R-I87U-RES-solo-surface-cli-launcher-single]].
15
-
16
- ## What to do
17
-
18
- 1. **Resolve `$ARGUMENTS` by smart first-token detection** — grammar is positional, token-identical with the CLI:
19
- - First token is not a surface slug → it is the doc id, in any form (`hlfj`, `hs-hlfj`, `HS-HLFJ`, a full basename); opens the inspector on its Pipeline tab. Pass it through as typed — the CLI normalises it.
20
- - First token is a surface slug (`inspector`, `docs`, `whats-next`, `captures`, `session-log`, `settings`) → second token, if present, is the doc id (anchors `inspector` and `docs` only).
21
- - `pipeline` is accepted but is not its own window: it is the inspector on its Pipeline tab.
22
- - `docs` opens two panes: the doc beside the inspector on its Pipeline tab.
23
- - No arguments → the inspector on its Pipeline tab, anchored on the focus pin (live-follow).
24
- - Pass `--width` / `--height` / `--browser edge|chrome` through unchanged.
25
- 2. **Run it yourself** from the repo root:
26
- ```bash
27
- node bin/hs.mjs view [<surface>] [<doc-id>] [flags]
28
- ```
29
- 3. The verb probes ground-truth dev-server status first — if the console is down, relay its message and offer `npm run dev` (don't start the server unprompted).
30
- 4. Relay the one-line result (URL + window size); closing the window closes it, re-running reopens it.
31
-
32
- Never hand-build `msedge --app=…` invocations — the CLI verb owns server probing, URL resolution, and browser mechanics.
10
+ # HeySpex solo-surface viewer (`/hs-view`)
11
+
12
+ > Parity: `.commandcode/skills/hs-view/SKILL.md` · `.cursor/skills/hs-view/SKILL.md` · `.agents/skills/hs-view/SKILL.md`
13
+
14
+ Optional macro over the one core ([[capability-three-faces-no-per-capability-slash]]): shell to `hs view`, never reimplement it. Design: [[HS-RU2R-I87U-RES-solo-surface-cli-launcher-single]].
15
+
16
+ ## What to do
17
+
18
+ 1. **Resolve `$ARGUMENTS` by smart first-token detection** — grammar is positional, token-identical with the CLI:
19
+ - First token is not a surface slug → it is the doc id, in any form (`hlfj`, `hs-hlfj`, `HS-HLFJ`, a full basename); opens the inspector on its Pipeline tab. Pass it through as typed — the CLI normalises it.
20
+ - First token is a surface slug (`inspector`, `docs`, `whats-next`, `captures`, `session-log`, `settings`) → second token, if present, is the doc id (anchors `inspector` and `docs` only).
21
+ - `pipeline` is accepted but is not its own window: it is the inspector on its Pipeline tab.
22
+ - `docs` opens two panes: the doc beside the inspector on its Pipeline tab.
23
+ - No arguments → the inspector on its Pipeline tab, anchored on the focus pin (live-follow).
24
+ - Pass `--width` / `--height` / `--browser edge|chrome` through unchanged.
25
+ 2. **Run it yourself** from the repo root:
26
+ ```bash
27
+ node bin/hs.mjs view [<surface>] [<doc-id>] [flags]
28
+ ```
29
+ 3. The verb probes ground-truth dev-server status first — if the console is down, relay its message and offer `npm run dev` (don't start the server unprompted).
30
+ 4. Relay the one-line result (URL + window size); closing the window closes it, re-running reopens it.
31
+
32
+ Never hand-build `msedge --app=…` invocations — the CLI verb owns server probing, URL resolution, and browser mechanics.