@gobing-ai/spur 0.4.20 → 0.4.22
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 +1 -1
- package/config/workflows/task-pipeline.yaml +28 -10
- package/package.json +11 -11
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/skills/conflict-finding/SKILL.md +2 -0
- package/plugins/sp/skills/fleet-join/SKILL.md +70 -4
- package/plugins/sp/skills/issue-finding/SKILL.md +2 -0
- package/plugins/sp/skills/reverse-engineering/SKILL.md +2 -0
- package/plugins/sp/skills/spur-cli/references/agent.md +9 -1
- package/plugins/sp/skills/spur-cli/references/self.md +37 -2
- package/plugins/sp/skills/wayfinder/SKILL.md +2 -0
- package/spur.js +53344 -39432
- package/web/_astro/{BoardApp.BDo7Cplz.js → BoardApp.CNBpKuB6.js} +155 -157
- package/web/_astro/{BoardApp.uR1DxOv6.js → BoardApp.DVWLxHcV.js} +1 -1
- package/web/_astro/{TaskDetail.BiGHeRcp.js → TaskDetail.BY6jO_3P.js} +1 -1
- package/web/_astro/arc.CLFbvaU4.js +1 -0
- package/web/_astro/{architectureDiagram-3BPJPVTR.C2BEgSVb.js → architectureDiagram-3BPJPVTR.YYrMKtrm.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.D8G9DLH3.js → blockDiagram-GPEHLZMM.D-Xzu32A.js} +6 -6
- package/web/_astro/{board-facade-react-router-dom.Dy5pjzOw.js → board-facade-react-router-dom.CHNMUrya.js} +1 -1
- package/web/_astro/{board-facade-react-router.DjjqU27_.js → board-facade-react-router.Dob6MDgf.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.dU7HR9k5.js → c4Diagram-AAUBKEIU.Cv7EV8QD.js} +1 -1
- package/web/_astro/channel.DzHZuqj0.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.5BIk-HVp.js → chunk-2J33WTMH.CkAKN-fF.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.BVIKX24s.js → chunk-4BX2VUAB.D-xu2Tgi.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.Bz2tdkGM.js → chunk-55IACEB6.yNQibVGY.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.R0d_FlTN.js → chunk-727SXJPM.DlVIFHHZ.js} +4 -4
- package/web/_astro/{chunk-AQP2D5EJ.C2kK8Ok-.js → chunk-AQP2D5EJ.C-LGFaeS.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.COAncjFn.js → chunk-FMBD7UC4.Df2n26zT.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CeNg5VSN.js → chunk-ND2GUHAM.CV_k83Gj.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.DRGDDzrj.js → chunk-QZHKN3VN.BQQDO3h3.js} +1 -1
- package/web/_astro/chunk-YNUBSHFH.B6ndyWdA.js +7 -0
- package/web/_astro/{classDiagram-4FO5ZUOK.DmM59Lgb.js → classDiagram-4FO5ZUOK.DkSMdA84.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.DmM59Lgb.js → classDiagram-v2-Q7XG4LA2.DkSMdA84.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.BjKuSb1i.js → cose-bilkent-S5V4N54A.CCN7GwAZ.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.DQevIJEc.js → cynefin-OW5HDTMX.CqQCttkM.js} +1 -1
- package/web/_astro/cytoscape.esm.BDkkwuE4.js +321 -0
- package/web/_astro/{dagre-BM42HDAG.CqOK1C5k.js → dagre-BM42HDAG.CCn6iftc.js} +2 -2
- package/web/_astro/diagram-2AECGRRQ.DImUVZK-.js +43 -0
- package/web/_astro/diagram-5GNKFQAL.BYNywZwV.js +10 -0
- package/web/_astro/{diagram-KO2AKTUF.BDC9f2pC.js → diagram-KO2AKTUF.LJZ9DjsJ.js} +3 -3
- package/web/_astro/{diagram-LMA3HP47.D-Mrwnmt.js → diagram-LMA3HP47.CJ3YpVED.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.XXGX1BQ_.js → diagram-OG6HWLK6.CnVtq5_j.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DahWkk7M.js → erDiagram-TEJ5UH35.SdmuzZwT.js} +5 -5
- package/web/_astro/{flowDiagram-I6XJVG4X.DaG5HfPs.js → flowDiagram-I6XJVG4X.C9V-B-nO.js} +4 -4
- package/web/_astro/{ganttDiagram-6RSMTGT7.DZe_CQWm.js → ganttDiagram-6RSMTGT7.DT5v7SL5.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.C4zSw3kS.js → gitGraphDiagram-PVQCEYII.B3qURYBL.js} +1 -1
- package/web/_astro/index.C8LjH5ri.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.CmaEULgT.js → infoDiagram-5YYISTIA.CHO0xT8l.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.DKKhZJ98.js → ishikawaDiagram-YF4QCWOH.buALAOGh.js} +5 -5
- package/web/_astro/{journeyDiagram-JHISSGLW.B6d7TuYQ.js → journeyDiagram-JHISSGLW.DvKuIdbX.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.xiG_jH03.js → kanban-definition-UN3LZRKU.Dvoi9jdN.js} +7 -7
- package/web/_astro/{linear.DsbUmqlh.js → linear.EsEfz8Ex.js} +1 -1
- package/web/_astro/mermaid.core.Vk3ryVC7.js +303 -0
- package/web/_astro/{mindmap-definition-RKZ34NQL.Cm2UvqJQ.js → mindmap-definition-RKZ34NQL.DG1pkymq.js} +2 -2
- package/web/_astro/{pieDiagram-4H26LBE5.COyvnb_Q.js → pieDiagram-4H26LBE5.DAUmIdd6.js} +3 -3
- package/web/_astro/{quadrantDiagram-W4KKPZXB.BdaJr8EI.js → quadrantDiagram-W4KKPZXB.Du3QUozl.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.aS-qeofA.js → requirementDiagram-4Y6WPE33.neRi5GrQ.js} +3 -3
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BxaOWF5N.js → sankeyDiagram-5OEKKPKP.CMUtxA70.js} +4 -4
- package/web/_astro/{sequenceDiagram-3UESZ5HK.CfZPPWA1.js → sequenceDiagram-3UESZ5HK.CfYFLmYH.js} +4 -4
- package/web/_astro/{stateDiagram-AJRCARHV.D6VXy0-M.js → stateDiagram-AJRCARHV.Bn4dmAad.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.DatbDxXn.js → stateDiagram-v2-BHNVJYJU.BMNezvp-.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.BxQ7-VRY.js → timeline-definition-PNZ67QCA.ByaDwsBX.js} +3 -3
- package/web/_astro/{vennDiagram-CIIHVFJN.BJny6MAy.js → vennDiagram-CIIHVFJN.CUYU1Mc9.js} +5 -5
- package/web/_astro/{wardleyDiagram-YWT4CUSO.gzTiYN-4.js → wardleyDiagram-YWT4CUSO.DpZZeJr2.js} +3 -3
- package/web/_astro/{xychartDiagram-2RQKCTM6.DTR_zwDh.js → xychartDiagram-2RQKCTM6.CWwI33U0.js} +1 -1
- package/web/board-runtime.json +6 -2
- package/web/index.html +2 -2
- package/web/_astro/arc.BLw5ykEN.js +0 -1
- package/web/_astro/channel.DSbvfOEf.js +0 -1
- package/web/_astro/chunk-YNUBSHFH.CxeAygfi.js +0 -7
- package/web/_astro/cytoscape.esm.BB4DxJjf.js +0 -321
- package/web/_astro/diagram-2AECGRRQ.B7i8Xbcc.js +0 -43
- package/web/_astro/diagram-5GNKFQAL.DXGFk2rU.js +0 -10
- package/web/_astro/index.DVDW9-eD.css +0 -1
- package/web/_astro/mermaid.core.CihlV6Wy.js +0 -301
|
@@ -660,19 +660,27 @@ states:
|
|
|
660
660
|
# feature credit) is owned by `plugins/sp/agents/super-reviewer.md` Output Format,
|
|
661
661
|
# which this pointer names.
|
|
662
662
|
input: >-
|
|
663
|
-
/sp:dev-review --tasks ${vars.wbs} --auto --focus ${vars.reviewFocus}
|
|
664
|
-
Format
|
|
665
|
-
(`spur task verdict`
|
|
666
|
-
(deriveVerifyConfidence), never the section's disposition level.
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
663
|
+
/sp:dev-review --tasks ${vars.wbs} --auto --focus ${vars.reviewFocus}
|
|
664
|
+
Answer contract: super-reviewer Output Format. Emit the machine-linted artifact, not a prose summary.
|
|
665
|
+
`## Review`: deriveReviewConfidence. Captured answer (`spur task verdict`) has one `Confidence: HIGH|MEDIUM|LOW`
|
|
666
|
+
line (deriveVerifyConfidence), never the section's disposition level.
|
|
667
|
+
End with one `Verdict: PASS|PARTIAL|FAIL` line (plain, final) after
|
|
668
|
+
`| Req | Status | Evidence |` (one row per requirement; MET | PARTIAL | UNMET) and
|
|
669
|
+
`| AC | Status | Evidence Type | Evidence |` (one row per AC; MET | PARTIAL | UNMET | N/A).
|
|
670
|
+
Evidence types (`+` ok): test | command | static-ref | manual-review | llm-judge | n/a.
|
|
671
|
+
Cite repo-root-relative `path:line` (never `/tmp`) or named checks. AC rows use the task's identities or
|
|
672
|
+
a declared `AC-N` alias; a linked scenario covers its task; a task-local criterion needs no feature credit.
|
|
673
|
+
Open P1-P3 blocks completion.
|
|
674
|
+
Also write it to `.spur/run/${vars.__runId}-review-cert.md`.
|
|
672
675
|
# The captured review answer is the run's certification input (and the
|
|
673
676
|
# `task verdict` input below): expectFile fails the step when no answer landed.
|
|
674
677
|
answerFile: .spur/run/${vars.__runId}-review-answer.txt
|
|
675
678
|
expectFile: .spur/run/${vars.__runId}-review-answer.txt
|
|
679
|
+
# The reviewer WRITES this one itself (see (c2)); declared so the composition lint can
|
|
680
|
+
# see the run path the prompt names (1233 R2).
|
|
681
|
+
inputs:
|
|
682
|
+
- path: .spur/run/${vars.__runId}-review-cert.md
|
|
683
|
+
kind: artifact
|
|
676
684
|
# Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
|
|
677
685
|
role: reviewer
|
|
678
686
|
# B7 R3/R6 (0894): declared fresh policy (reviewer default) — the action
|
|
@@ -683,6 +691,16 @@ states:
|
|
|
683
691
|
priority: ${vars.taskPriority}
|
|
684
692
|
compareExecutorWith: implement
|
|
685
693
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
694
|
+
# (c2) The reviewer is asked to WRITE its canonical artifact to `-review-cert.md`, because
|
|
695
|
+
# the captured answer above is the agent's stdout: a reviewer that writes the artifact and
|
|
696
|
+
# then narrates its summary has the artifact overwritten by the narration, and the verdict
|
|
697
|
+
# lint fails work that is actually complete (four such runs in the G74 batch, 2026-10-24).
|
|
698
|
+
# The agent-written cert wins; when it is absent or empty the captured answer is used, so
|
|
699
|
+
# this is a strict widening of accepted inputs, never a new failure mode.
|
|
700
|
+
- kind: shell
|
|
701
|
+
options:
|
|
702
|
+
command: >-
|
|
703
|
+
A=".spur/run/$__runId-review-answer.txt"; C=".spur/run/$__runId-review-cert.md"; [ -s "$C" ] || cp "$A" "$C" 2>/dev/null; exit 0
|
|
686
704
|
# (d) `spur task verdict` owns the answer lint and the verdict derivation (task 1003
|
|
687
705
|
# R2): one complete requirement row per declared requirement, AC identities resolved,
|
|
688
706
|
# status/evidence vocabularies accepted, hedged or uncited evidence rejected. It
|
|
@@ -694,7 +712,7 @@ states:
|
|
|
694
712
|
options:
|
|
695
713
|
id: review-verdict
|
|
696
714
|
executable: "${vars.spurBin}"
|
|
697
|
-
args: ["task", "verdict", "${vars.wbs}", "--from-answer", ".spur/run/${vars.__runId}-review-
|
|
715
|
+
args: ["task", "verdict", "${vars.wbs}", "--from-answer", ".spur/run/${vars.__runId}-review-cert.md"]
|
|
698
716
|
resultFile: .spur/run/${vars.__runId}-review-verdict.status
|
|
699
717
|
softFail: true
|
|
700
718
|
# (e) one fold, one token: PASS requires the typed verdict PASS, the artifact's own
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
4
4
|
"description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spur",
|
|
@@ -57,19 +57,19 @@
|
|
|
57
57
|
"prepublishOnly": "cd ../.. && bun run apps/cli/src/index.ts builder bump-ver --check spur --no-logo"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@commander-js/extra-typings": "
|
|
61
|
-
"@gobing-ai/ts-db": "
|
|
62
|
-
"@gobing-ai/ts-ai-runner": "
|
|
63
|
-
"@gobing-ai/ts-dual-workflow-engine": "
|
|
64
|
-
"@gobing-ai/ts-infra": "
|
|
65
|
-
"@gobing-ai/ts-llm-jsonl-importer": "
|
|
66
|
-
"@gobing-ai/ts-rule-engine": "
|
|
67
|
-
"@gobing-ai/ts-runtime": "
|
|
68
|
-
"@gobing-ai/ts-utils": "
|
|
60
|
+
"@commander-js/extra-typings": "14.0.0",
|
|
61
|
+
"@gobing-ai/ts-db": "0.7.1",
|
|
62
|
+
"@gobing-ai/ts-ai-runner": "0.7.1",
|
|
63
|
+
"@gobing-ai/ts-dual-workflow-engine": "0.7.1",
|
|
64
|
+
"@gobing-ai/ts-infra": "0.7.1",
|
|
65
|
+
"@gobing-ai/ts-llm-jsonl-importer": "0.7.1",
|
|
66
|
+
"@gobing-ai/ts-rule-engine": "0.7.1",
|
|
67
|
+
"@gobing-ai/ts-runtime": "0.7.1",
|
|
68
|
+
"@gobing-ai/ts-utils": "0.7.1",
|
|
69
69
|
"@types/bun": "1.4.3",
|
|
70
70
|
"@types/figlet": "^1.7.0",
|
|
71
71
|
"@types/node-notifier": "8.0.5",
|
|
72
|
-
"commander": "
|
|
72
|
+
"commander": "14.0.3",
|
|
73
73
|
"figlet": "^1.11.0",
|
|
74
74
|
"zod": "4.4.3"
|
|
75
75
|
},
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -234,6 +234,8 @@ findings, unresolved, coverage, cost, remediation, errors`.
|
|
|
234
234
|
| `Bash` | `git`, `rg`, `spur task/feature ... --json`, `spur ... check`, `sp:doc-evolve` audit |
|
|
235
235
|
| `Write` | Only for temp files / owner-routed repair payloads after confirmation (with `--resolve`) |
|
|
236
236
|
|
|
237
|
+
**Search routing** (hybrid search, ADR-147): concept, cross-file, or "how does X work" questions → semantic first — the zg MCP tool `zvec_grep_search` when the host exposes it, else `spur self search "<query>" --mode fuzzy --json`. Literal, symbol, regex, or exhaustive occurrence lists → `rg`. If zg is absent or the search response carries a `skipped` reason → fall back to `rg`.
|
|
238
|
+
|
|
237
239
|
## Platform Notes
|
|
238
240
|
|
|
239
241
|
### Claude Code
|
|
@@ -26,7 +26,44 @@ Pick the role whose work this session can actually do. `--session-id` defaults t
|
|
|
26
26
|
`CLAUDE_CODE_SESSION_ID`, which is what the Stop hook matches against — without it the hook cannot
|
|
27
27
|
find this session, though the `wait --inbox` loop still works.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**Renewal is automatic (G75 R1, task 1279).** `join` records the *agent* process that launched this
|
|
30
|
+
session — never the short-lived CLI pid — and starts one detached renewer that heartbeats the lease
|
|
31
|
+
every third of the TTL. Long work with no `wait --inbox` in between no longer lets the lease expire.
|
|
32
|
+
The record says which happened: `identity: 'verified'` with a `pid`/`processStartedAt` means renewal
|
|
33
|
+
is running; `identity: 'unverified'` with `pid: null` means no agent ancestor could be proved, so
|
|
34
|
+
nothing renews and the session must keep looping `wait --inbox` to stay joined. A rejoin from the
|
|
35
|
+
same session reuses the running renewer instead of starting a second one.
|
|
36
|
+
|
|
37
|
+
## Binding a declared member (opt-in, fenced)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
spur agent join --role coder --member <declared-member-id> --json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`--member` binds this session to one **declared** member instead of joining as a plain guest: the
|
|
44
|
+
record id becomes the member id, so `wait --inbox <member-id>` addresses the declared member's inbox,
|
|
45
|
+
and a supervised spawn or fleet dispatch sees the member busy through its own occupant row. It exits 2
|
|
46
|
+
with a named reason for an unknown/disabled member, a role mismatch, an executor that cannot attest
|
|
47
|
+
the stage capabilities, a live occupant, or a concurrent binder that lost the race. Guests without
|
|
48
|
+
`--member` are unchanged — and still excluded from role selection.
|
|
49
|
+
|
|
50
|
+
### Attached lifecycle reports carry the binding pin (task 1282)
|
|
51
|
+
|
|
52
|
+
A bound occupant's lifecycle reports must present the host binding pin or they are refused (exit 2):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
spur agent report --state working --seq <ns> --pin <ownerEpoch>:<occupancyGeneration> --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The first pin-matched report completes the handshake (the host's strategy then treats this member as
|
|
59
|
+
stage-visible); later reports never move it. A pin mismatch means the occupant generation moved —
|
|
60
|
+
re-read `spur agent list --specs --json` instead of retrying. Plain guests keep reporting without a pin.
|
|
61
|
+
|
|
62
|
+
## Pull loop (the default path — hooks are acceleration only)
|
|
63
|
+
|
|
64
|
+
The durable inbox loop below is what makes a guest work on **every** host, hooks installed or not.
|
|
65
|
+
Never substitute it with repeated model turns or terminal polling while the session is busy: each
|
|
66
|
+
`wait --inbox` call is one bounded pull, and the session does the work between pulls.
|
|
30
67
|
|
|
31
68
|
`spur agent wait --inbox <id> --timeout 540000 --json` returns **0** with up to five claimed messages
|
|
32
69
|
in `{ id, pending, messages }`, settling their delivery after the output handoff. It returns **1**
|
|
@@ -39,7 +76,13 @@ the work is done.
|
|
|
39
76
|
2. Read the returned messages, including their IDs. `spur message show <id> --json` can reread one;
|
|
40
77
|
`spur message inbox --agent <id> --json` is a non-consuming historical view.
|
|
41
78
|
3. Do the work the message asks for.
|
|
42
|
-
4. `spur message reply <msgId> "<result>"` → reply to each one.
|
|
79
|
+
4. `spur message reply <msgId> "<result>"` → reply to each one. A bound occupant answering a **stage
|
|
80
|
+
request** (a `fleet:task:<requestId>:<attempt>` keyed message) MUST make the reply body the JSON
|
|
81
|
+
correlation payload — `{ "requestId": …, "attempt": …, "ownerEpoch": …, "occupancyGeneration": …,
|
|
82
|
+
"artifact": "<path or summary>" }` — with the values from the request and its own binding. The
|
|
83
|
+
host certifies the turn on that payload alone; a plain-text reply never completes a stage and the
|
|
84
|
+
request is retried to someone else. Do not answer stage requests for a binding you no longer hold:
|
|
85
|
+
a stale epoch/generation in the payload is fenced off, not promoted.
|
|
43
86
|
5. Re-arm: go back to step 1 while the operator wants this session in the fleet.
|
|
44
87
|
|
|
45
88
|
## Leave
|
|
@@ -49,8 +92,29 @@ spur agent leave --json # the guest joined by this session
|
|
|
49
92
|
spur agent leave my-session --json # an explicit id
|
|
50
93
|
```
|
|
51
94
|
|
|
52
|
-
Leaving releases the lease immediately.
|
|
53
|
-
|
|
95
|
+
Leaving releases the lease immediately. A **bound** occupant's leave drains first: it stops new
|
|
96
|
+
assignment, waits up to the drain grace (default 30s, `--drain-timeout <ms>` to bound it) for the
|
|
97
|
+
in-flight turn to settle, then retires the record. A turn that does not settle in time is never
|
|
98
|
+
failed by the leave — it stays outcome-unknown and resumable; nothing is killed. If the session dies
|
|
99
|
+
without leaving, the lease expires and the reconciler pass retires the guest — pending work is never
|
|
100
|
+
lost, it returns to `queued`.
|
|
101
|
+
|
|
102
|
+
## Host capabilities (probed, not assumed)
|
|
103
|
+
|
|
104
|
+
`bun run fleet-e2e --host-probe` writes `docs/reports/fleet-host-capabilities.json`: one row per
|
|
105
|
+
host×mode with the installed binary path/version, the wake channel and the exact `--help` line that
|
|
106
|
+
proves it. Anything unproven is `pull-only` with a reason.
|
|
107
|
+
|
|
108
|
+
| Host | Interactive wake | Headless |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| Codex | `app-server` (a reachable App Server connection) | `pull-only` |
|
|
111
|
+
| Claude Code | `hook` (the Stop callback below) | `pull-only` |
|
|
112
|
+
| Pi | `rpc` | `pull-only` |
|
|
113
|
+
|
|
114
|
+
These values are **installed-host evidence**, so re-read the report instead of trusting this table
|
|
115
|
+
after an upgrade. A `pull-only` row is not a defect: the loop above is the portable contract, and the
|
|
116
|
+
hook/RPC/App Server channels only shorten the wait. `--real-hosts --agents <csv>` is the opt-in lane
|
|
117
|
+
that drives a real host end to end; the default lane never launches one.
|
|
54
118
|
|
|
55
119
|
## Stop-hook delivery (opportunistic)
|
|
56
120
|
|
|
@@ -66,3 +130,5 @@ so the pull loop above — not the hook — is what makes a guest work anywhere.
|
|
|
66
130
|
- Guests are **not** supervised: do not expect restart, pid ownership, or `--drain` injection.
|
|
67
131
|
- Never dispatch a stage to a guest id: `spur agent run --spec <guest-id>` is refused on purpose.
|
|
68
132
|
- Never hold the write slot through a guest: the guest lease is the only heartbeat (R5).
|
|
133
|
+
- Renewal stops itself on agent-process death, a reused pid, a lost fence or `leave`. There is no
|
|
134
|
+
command to stop it and no daemon behind it: it lives no longer than the agent that joined.
|
|
@@ -367,6 +367,8 @@ With `--create-task`, include `"task": { "wbs": "…", "file": "…", "status":
|
|
|
367
367
|
| `Bash` | `spur history` + `spur task` CLI |
|
|
368
368
|
| `Write` | Temp files for section bodies |
|
|
369
369
|
|
|
370
|
+
**Search routing** (hybrid search, ADR-147): concept, cross-file, or "how does X work" questions → semantic first — the zg MCP tool `zvec_grep_search` when the host exposes it, else `spur self search "<query>" --mode fuzzy --json`. Literal, symbol, regex, or exhaustive occurrence lists → `rg`. If zg is absent or the search response carries a `skipped` reason → fall back to `rg`.
|
|
371
|
+
|
|
370
372
|
## Platform Notes
|
|
371
373
|
|
|
372
374
|
- **Claude Code** — invoke via `/sp:dev-find-issue …` or `Skill(skill="sp:issue-finding",
|
|
@@ -141,6 +141,8 @@ Execute phases in order. Stop at the phase boundary required by the selected mod
|
|
|
141
141
|
3. Exclude or de-prioritize generated, vendored, build output, dependency cache, lockfile-only, binary-heavy, and snapshot-heavy paths unless they are directly relevant.
|
|
142
142
|
4. For monorepos, identify packages/apps and either ask for scope or analyze each package at the requested depth if feasible.
|
|
143
143
|
|
|
144
|
+
**Search routing** (hybrid search, ADR-147): concept, cross-file, or "how does X work" questions → semantic first — the zg MCP tool `zvec_grep_search` when the host exposes it, else `spur self search "<query>" --mode fuzzy --json`. Literal, symbol, regex, or exhaustive occurrence lists → `rg`. If zg is absent or the search response carries a `skipped` reason → fall back to `rg`.
|
|
145
|
+
|
|
144
146
|
### Phase 3: Classify
|
|
145
147
|
|
|
146
148
|
Classify the codebase as one or more archetypes:
|
|
@@ -26,7 +26,7 @@ that before using `run` for fan-out dispatch.
|
|
|
26
26
|
| `trace <runId>` | Print one execution record's lineage — the run, its dispatch parents, agent session ids and streams (1076 R4, ADR-132) | `--follow` `--timeout <ms>` `--json` |
|
|
27
27
|
| `list` | List detected coding agents, or agent specs with `--specs` (live run status + member session merged from `spur self serve`) | `--specs` `--server <url>` `--json` |
|
|
28
28
|
| `report` | Report a fleet member lifecycle state (`working`/`idle`/`blocked`) from a host hook (G73 R1/R2, task 1080) | `--state <state>` `--seq <ns>` `--spec <id>` `--json` |
|
|
29
|
-
| `join` | Join the fleet as a guest occupant — a live session that pulls its own work (G73 R2, task 1081) | `--role <name>` `--id <id>` `--session-id <sid>` `--pid <n>` `--executor <name>` `--json` |
|
|
29
|
+
| `join` | Join the fleet as a guest occupant — a live session that pulls its own work (G73 R2, task 1081); `--member` binds a declared member instead (G75 R3, task 1281) | `--role <name>` `--id <id>` `--member <id>` `--session-id <sid>` `--pid <n>` `--executor <name>` `--json` |
|
|
30
30
|
| `leave` | Leave the fleet: release the guest lease, retire the occupant, return claimed messages to `queued` | `[id]` `--session-id <sid>` `--json` |
|
|
31
31
|
| `status` | Agent specs with live process status and member session (requires `spur self serve`) | `--server <url>` `--json` |
|
|
32
32
|
| `doctor [agent]` | Check agent readiness | `--json` `--probe-health` `--force-refresh` |
|
|
@@ -228,11 +228,19 @@ returns its claimed messages to `queued` and removes the record.
|
|
|
228
228
|
| `--session-id <sid>` | Host session id (defaults to `CLAUDE_CODE_SESSION_ID`) |
|
|
229
229
|
| `--pid <n>` | Process id to record |
|
|
230
230
|
| `--executor <name>` | Executor name to record (informational — a guest is never dispatched to) |
|
|
231
|
+
| `--member <id>` | Bind a **declared member** instead of joining as a guest (G75 R3, task 1281): resolves the enabled member, checks role/executor, requires a capability proof, and takes the fenced occupant of `guest:<member-id>`. The record id becomes the member id, so `wait --inbox <member-id>` addresses the declared member's inbox. Exits 2 with `unknown-member`, `disabled-member`, `role-mismatch`, `capability-unattested`, `live-occupant` or `collision`. Without it, `join` is unchanged |
|
|
231
232
|
| `--json` | Machine-readable result |
|
|
232
233
|
|
|
233
234
|
A guest carrying no executor attestation is never a stage target: `spur agent run --spec <guest-id>`
|
|
234
235
|
is refused (R3), and `requiresCapabilities` stages therefore can never reach one.
|
|
235
236
|
|
|
237
|
+
`--member <id>` inverts that for exactly one declared id: the binding takes the member's occupant row
|
|
238
|
+
at generation `max+1` and the `guest:<member-id>` claim, so a supervised spawn or strategy dispatch
|
|
239
|
+
sees the member busy through the same `hasRunning` check it already uses — no dual writers. Every
|
|
240
|
+
renew re-checks both the claim epoch and that generation, so a taken-over member refuses the stale
|
|
241
|
+
binder's claim/accept. `memberBinding.stageEligible` is `false` when the binder's host has only the
|
|
242
|
+
`pull-only` wake channel (`bun run fleet-e2e --host-probe`), i.e. it may receive messages but no stage.
|
|
243
|
+
|
|
236
244
|
## `wait --inbox <id>` - the guest pull primitive (G73 R4)
|
|
237
245
|
|
|
238
246
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spur-cli-self
|
|
3
|
-
description: "spur-cli noun reference for `spur self`: self-management verbs — SDLC action runner (`exec`), scaffold (`init`), database maintenance (`maintain`), schema migrations (`migrate`), local web server (`serve`), and status overview (`status`). The five legacy verbs (`init`, `maintain`, `migrate`, `serve`, `status`) each mount the same command builder as their legacy top-level noun, which remains a hidden alias; `exec`
|
|
3
|
+
description: "spur-cli noun reference for `spur self`: self-management verbs — SDLC action runner (`exec`), scaffold (`init`), database maintenance (`maintain`), schema migrations (`migrate`), hybrid rg/zg search (`search`), local web server (`serve`), and status overview (`status`). The five legacy verbs (`init`, `maintain`, `migrate`, `serve`, `status`) each mount the same command builder as their legacy top-level noun, which remains a hidden alias; `exec` and `search` have no top-level alias."
|
|
4
4
|
see_also:
|
|
5
5
|
- spur-cli
|
|
6
6
|
---
|
|
@@ -14,7 +14,8 @@ Both paths share the same command builder: identical flags, output, and exit cod
|
|
|
14
14
|
top-level forms are omitted from `spur --help`, leaving `self` as the visible surface.
|
|
15
15
|
|
|
16
16
|
`exec` is the exception: it exists only as `spur self exec` — there is no `spur exec` top-level
|
|
17
|
-
alias (`spur exec <action>` is an unknown command), so nothing depends on a legacy path.
|
|
17
|
+
alias (`spur exec <action>` is an unknown command), so nothing depends on a legacy path. `search`
|
|
18
|
+
is the second such verb: `spur self search` only.
|
|
18
19
|
|
|
19
20
|
## Verb map
|
|
20
21
|
|
|
@@ -24,6 +25,7 @@ alias (`spur exec <action>` is an unknown command), so nothing depends on a lega
|
|
|
24
25
|
| `init` | Scaffold a new Spur project in the current directory | `--name <name>` `--force` `--minimal` `--adopt-global-config` `--json` |
|
|
25
26
|
| `maintain` | Run database maintenance: PRAGMA optimize, WAL truncation, optional VACUUM | `--vacuum` `--json` |
|
|
26
27
|
| `migrate` | Apply CLI-owned schema migrations (or `--check` the importer schema) | `--check` `--json` |
|
|
28
|
+
| `search` | Hybrid exact (`rg`) and semantic (`zg`) search over project docs and code | `--mode` `--scope` `--glob` `--limit` `--regex` `--status` `--json` |
|
|
27
29
|
| `serve` | Start the Spur web server (local fallback) | `--port <n>` `--host <addr>` `--no-open` `--cwd <path>` `--json` |
|
|
28
30
|
| `status [path]` | Show project and git status for a Spur project | `--json` |
|
|
29
31
|
|
|
@@ -63,6 +65,39 @@ first non-zero exit.
|
|
|
63
65
|
`--json` without `--list` or `--dry-run` prints a final `{ action, steps: [{ name, exitCode, durationMs }], exitCode }`
|
|
64
66
|
after the streaming output. Full surface: `docs/design/sdlc-actions.md` §3.3.
|
|
65
67
|
|
|
68
|
+
## `self search` - hybrid exact and semantic search
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
spur self search "how is a paused workflow resumed" # auto: exact + fuzzy where available
|
|
72
|
+
spur self search Bun.which --mode exact # ripgrep only
|
|
73
|
+
spur self search 'runCost' --mode fuzzy --limit 5 # zg semantic only
|
|
74
|
+
spur self search resum --mode exact --scope docs --glob '*.md'
|
|
75
|
+
spur self search --status # backend readiness, no query
|
|
76
|
+
spur self search Bun.which --mode exact --json # raw SearchResponse payload
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
One verb over the hybrid search service (`docs/design/hybrid-search.md` §4, ADR-147). `--mode` is
|
|
80
|
+
`exact` | `fuzzy` | `auto` (default `auto`), `--scope` is `docs` | `code` | `all` (default `all`),
|
|
81
|
+
`--limit` is 1–100 (default 20), `--glob` adds a backend glob (repeatable; prefix `!` to negate),
|
|
82
|
+
and `--regex` switches the exact route from fixed string to pattern. `--status` prints the `rg`/`zg`
|
|
83
|
+
readiness payload and takes no query.
|
|
84
|
+
|
|
85
|
+
The groups are `exact` (ripgrep `--json` events) and `fuzzy` (zg `--hybrid`); a group is `null` when
|
|
86
|
+
that route did not run, and `skipped[]` names the degraded route with its reason
|
|
87
|
+
(`zg-not-installed`, `zg-index-missing`, `zg-timeout`, `zg-failed`, `zg-output-error`) plus an exact
|
|
88
|
+
hint string. Hints are printed, never executed — Spur installs and indexes nothing. Human output
|
|
89
|
+
prints `exact (n)` / `fuzzy (n)` headers with `path:start[-end] [matchedBy]` rows, the first three
|
|
90
|
+
snippet lines indented, then the skip lines; zero hits print `no matches`. `--json` emits the
|
|
91
|
+
`SearchResponse` verbatim (`--json-envelope` for the ADR-091 envelope).
|
|
92
|
+
|
|
93
|
+
| Exit | When |
|
|
94
|
+
| ---- | ---- |
|
|
95
|
+
| `0` | results, empty results, or a degraded fuzzy route |
|
|
96
|
+
| `1` | invalid request (empty query, bad mode/scope/limit), rg missing or rg failed |
|
|
97
|
+
| `2` | no query and no `--status` (usage) |
|
|
98
|
+
|
|
99
|
+
Raw zg/rg passthrough flags are deliberately absent: they would leak the adapter.
|
|
100
|
+
|
|
66
101
|
## `self init` - scaffold a Spur project
|
|
67
102
|
|
|
68
103
|
```bash
|
|
@@ -142,6 +142,8 @@ Invoked when a map already exists (operator provides the feature ID). A ticket i
|
|
|
142
142
|
| **Prototype** | Cheap, rough, concrete artifact to react to — an outline, stub, or rough implementation via `sp:code-implementation`. | Linked prototype as a task artifact |
|
|
143
143
|
| **Task** | Literal manual work — nothing to prototype or research. Moving data, provisioning access. | Checklist in task body; resolved when done |
|
|
144
144
|
|
|
145
|
+
**Search routing** (hybrid search, ADR-147): concept, cross-file, or "how does X work" questions → semantic first — the zg MCP tool `zvec_grep_search` when the host exposes it, else `spur self search "<query>" --mode fuzzy --json`. Literal, symbol, regex, or exhaustive occurrence lists → `rg`. If zg is absent or the search response carries a `skipped` reason → fall back to `rg`.
|
|
146
|
+
|
|
145
147
|
An open question from the map is **not** resolved this way. It is settled with the operator in
|
|
146
148
|
conversation (`AskUserQuestion` where available) and recorded straight into **## Decisions so far**
|
|
147
149
|
— no task is claimed, and it does not consume the session's one ticket.
|