@gobing-ai/spur 0.4.18 → 0.4.20
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/config.example.yaml +4 -0
- package/config/workflows/task-pipeline.yaml +6 -1
- package/package.json +9 -9
- package/plugins/sp/README.md +10 -6
- package/plugins/sp/commands/dev-changelog.md +1 -1
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/hooks/fleet-guest-stop.ts +32 -12
- package/plugins/sp/skills/fleet-join/SKILL.md +7 -4
- package/plugins/sp/skills/spur-cli/SKILL.md +2 -2
- package/plugins/sp/skills/spur-cli/references/agent.md +6 -4
- package/plugins/sp/skills/spur-cli/references/message.md +7 -5
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +3 -2
- package/schemas/spur-config.schema.json +5 -0
- package/spur.js +3414 -2760
- package/web/_astro/{BoardApp.CC7Mwswv.js → BoardApp.BDo7Cplz.js} +189 -191
- package/web/_astro/{BoardApp.mWyrWCAR.js → BoardApp.uR1DxOv6.js} +1 -1
- package/web/_astro/{TaskDetail.CtAXuiv8.js → TaskDetail.BiGHeRcp.js} +1 -1
- package/web/_astro/{arc.Duf4u60i.js → arc.BLw5ykEN.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.JoymtqxN.js → architectureDiagram-3BPJPVTR.C2BEgSVb.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.BvmhcioC.js → blockDiagram-GPEHLZMM.D8G9DLH3.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.CfaWkgoQ.js → c4Diagram-AAUBKEIU.dU7HR9k5.js} +1 -1
- package/web/_astro/channel.DSbvfOEf.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.B7uR02cD.js → chunk-2J33WTMH.5BIk-HVp.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.SwiEauYR.js → chunk-4BX2VUAB.BVIKX24s.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.6ZRCK8PO.js → chunk-55IACEB6.Bz2tdkGM.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.Cxra_G3N.js → chunk-727SXJPM.R0d_FlTN.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.Cxd7gZeX.js → chunk-AQP2D5EJ.C2kK8Ok-.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.DCLhFkVc.js → chunk-FMBD7UC4.COAncjFn.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.B9AmKcv6.js → chunk-ND2GUHAM.CeNg5VSN.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.DOjCvl6S.js → chunk-QZHKN3VN.DRGDDzrj.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.BMiT_mNf.js → classDiagram-4FO5ZUOK.DmM59Lgb.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.BMiT_mNf.js → classDiagram-v2-Q7XG4LA2.DmM59Lgb.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.mLBCEGjI.js → cose-bilkent-S5V4N54A.BjKuSb1i.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.CjDAY0qn.js → cynefin-OW5HDTMX.DQevIJEc.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG._G_sP8fP.js → dagre-BM42HDAG.CqOK1C5k.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.39OcfSuz.js → diagram-2AECGRRQ.B7i8Xbcc.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.D7v_eNC4.js → diagram-5GNKFQAL.DXGFk2rU.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.Da1x-lhg.js → diagram-KO2AKTUF.BDC9f2pC.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.C8EnzbEb.js → diagram-LMA3HP47.D-Mrwnmt.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.DPnBj69F.js → diagram-OG6HWLK6.XXGX1BQ_.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.CXMu2TIh.js → erDiagram-TEJ5UH35.DahWkk7M.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.ZklePVtQ.js → flowDiagram-I6XJVG4X.DaG5HfPs.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.BhYOkdqk.js → ganttDiagram-6RSMTGT7.DZe_CQWm.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.CADyX8a1.js → gitGraphDiagram-PVQCEYII.C4zSw3kS.js} +1 -1
- package/web/_astro/index.DVDW9-eD.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.BsdmwjHt.js → infoDiagram-5YYISTIA.CmaEULgT.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CzjZ3Crd.js → ishikawaDiagram-YF4QCWOH.DKKhZJ98.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.Bxj-ZH_t.js → journeyDiagram-JHISSGLW.B6d7TuYQ.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.Cbg3wVvX.js → kanban-definition-UN3LZRKU.xiG_jH03.js} +1 -1
- package/web/_astro/{linear.DJNUrBI9.js → linear.DsbUmqlh.js} +1 -1
- package/web/_astro/{mermaid.core.DVHQV3SF.js → mermaid.core.CihlV6Wy.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.DyomosRU.js → mindmap-definition-RKZ34NQL.Cm2UvqJQ.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.DajtFknN.js → pieDiagram-4H26LBE5.COyvnb_Q.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.Bjq6SjGe.js → quadrantDiagram-W4KKPZXB.BdaJr8EI.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.ubBVqGLP.js → requirementDiagram-4Y6WPE33.aS-qeofA.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.I4q46xd-.js → sankeyDiagram-5OEKKPKP.BxaOWF5N.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DsCgZIa8.js → sequenceDiagram-3UESZ5HK.CfZPPWA1.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DcYjYSqT.js → stateDiagram-AJRCARHV.D6VXy0-M.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Dt8yPqiS.js → stateDiagram-v2-BHNVJYJU.DatbDxXn.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.0YTkoa5F.js → timeline-definition-PNZ67QCA.BxQ7-VRY.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.BNl0l1hs.js → vennDiagram-CIIHVFJN.BJny6MAy.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.BYSX6cfn.js → wardleyDiagram-YWT4CUSO.gzTiYN-4.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DzxxpixK.js → xychartDiagram-2RQKCTM6.DTR_zwDh.js} +1 -1
- package/web/board-runtime.json +0 -6
- package/web/index.html +2 -2
- package/web/_astro/channel.DtEPXXcH.js +0 -1
- package/web/_astro/index.DiC1a6lh.css +0 -1
|
@@ -58,6 +58,10 @@ bootstrap:
|
|
|
58
58
|
command: >-
|
|
59
59
|
spur --no-logo history import --source all &&
|
|
60
60
|
spur --no-logo workflow run config/workflows/history-anatomy.yaml --quiet
|
|
61
|
+
# Without this the chain inherits the 10-minute scheduler default and dies mid-validate.
|
|
62
|
+
# 1h45m: enrich (45-52 min on a slow executor) + validate, still below the server
|
|
63
|
+
# queue's 2h visibility timeout.
|
|
64
|
+
timeoutMs: 6300000
|
|
61
65
|
|
|
62
66
|
# ── Spur app section (validated by spurConfigSchema in
|
|
63
67
|
# @gobing-ai/spur-config) ──
|
|
@@ -701,10 +701,15 @@ states:
|
|
|
701
701
|
# PASS, and a clean review gate (open P1-P3 finding or an uncited claim blocks it).
|
|
702
702
|
# Fail-closed: any missing/corrupt input leaves FAIL, so the transitions can route a
|
|
703
703
|
# non-PASS review into remediation instead of dead-ending the run.
|
|
704
|
+
# Idempotent re-entry: the answer file is consumed as a stage input, so a second visit to
|
|
705
|
+
# this state has no answer to re-judge. An ABSENT answer is not new evidence against a
|
|
706
|
+
# PASS — the durable `<wbs>-verdict.json` and the residual gate still have to pass — so the
|
|
707
|
+
# run-scoped verdict status is consulted only when an answer is actually present (without
|
|
708
|
+
# this, re-entry overwrote a PASS with FAIL and closed the task's run as `failed`).
|
|
704
709
|
- kind: shell
|
|
705
710
|
options:
|
|
706
711
|
command: >-
|
|
707
|
-
mkdir -p .spur/run; S=FAIL; if [ "$(cat ".spur/run/$__runId-review-verdict.status" 2>/dev/null)" = PASS ]
|
|
712
|
+
mkdir -p .spur/run; S=FAIL; if [ ! -f ".spur/run/$__runId-review-answer.txt" -o "$(cat ".spur/run/$__runId-review-verdict.status" 2>/dev/null)" = PASS ]; then [ "$(jq -r '.verdict // empty' ".spur/run/$wbs-verdict.json" 2>/dev/null)" = PASS ] && $spurBin task residual "$wbs" review-gate --no-logo >&2 && S=PASS; fi; printf '%s\n' "$S" > ".spur/run/$wbs-review.status"; exit 0
|
|
708
713
|
# (d) record the review severity as the lane decision's outcome (1263 R3b): the
|
|
709
714
|
# question `task-semantic-risk` answered is "is this risky?", and the Review table's
|
|
710
715
|
# worst finding is the answer as observed. Resolved rows count (a fixed P2 was still
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.20",
|
|
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",
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@commander-js/extra-typings": "^14.0.0",
|
|
61
|
-
"@gobing-ai/ts-db": "^0.5.
|
|
62
|
-
"@gobing-ai/ts-ai-runner": "^0.5.
|
|
63
|
-
"@gobing-ai/ts-dual-workflow-engine": "^0.5.
|
|
64
|
-
"@gobing-ai/ts-infra": "^0.5.
|
|
65
|
-
"@gobing-ai/ts-llm-jsonl-importer": "^0.5.
|
|
66
|
-
"@gobing-ai/ts-rule-engine": "^0.5.
|
|
67
|
-
"@gobing-ai/ts-runtime": "^0.5.
|
|
68
|
-
"@gobing-ai/ts-utils": "^0.5.
|
|
61
|
+
"@gobing-ai/ts-db": "^0.5.33",
|
|
62
|
+
"@gobing-ai/ts-ai-runner": "^0.5.33",
|
|
63
|
+
"@gobing-ai/ts-dual-workflow-engine": "^0.5.33",
|
|
64
|
+
"@gobing-ai/ts-infra": "^0.5.33",
|
|
65
|
+
"@gobing-ai/ts-llm-jsonl-importer": "^0.5.33",
|
|
66
|
+
"@gobing-ai/ts-rule-engine": "^0.5.33",
|
|
67
|
+
"@gobing-ai/ts-runtime": "^0.5.33",
|
|
68
|
+
"@gobing-ai/ts-utils": "^0.5.33",
|
|
69
69
|
"@types/bun": "1.4.3",
|
|
70
70
|
"@types/figlet": "^1.7.0",
|
|
71
71
|
"@types/node-notifier": "8.0.5",
|
package/plugins/sp/README.md
CHANGED
|
@@ -536,14 +536,18 @@ block/ask prints one JSON object that superskill renders per host:
|
|
|
536
536
|
targets:
|
|
537
537
|
|
|
538
538
|
- Codex, OpenCode, Antigravity and Hermes get only `scripts/`, staged as
|
|
539
|
-
`.agents/scripts/sp
|
|
539
|
+
`.agents/scripts/sp/` — together with `lib/`, which lands **inside** the plugin root
|
|
540
|
+
(`.agents/scripts/sp/lib/`). Install drops the `scripts/` level, so it retargets an entry's
|
|
541
|
+
`../../lib/…` to `../lib/…` for the staged tree; older superskill builds stage the same `lib/`
|
|
542
|
+
at the shared `.agents/scripts/lib/` instead and leave the import depth alone. Both resolve.
|
|
540
543
|
- Native targets (Claude Code, omp, Grok) get the whole plugin.
|
|
541
544
|
|
|
542
|
-
So `scripts/hooks/<id>.ts`, importing `../../lib
|
|
543
|
-
every target.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
and
|
|
545
|
+
So `scripts/hooks/<id>.ts`, importing `../../lib/…` relative to `plugins/sp/`, is the only path that
|
|
546
|
+
resolves the same way on every target. Keep that import depth as written — it is correct for the
|
|
547
|
+
plugin tree, and install fixes it up for the collapsed staged tree. `hooks/` keeps the registry
|
|
548
|
+
only; `script-contract-check` rejects a hook entry there, because on native installs it would shadow
|
|
549
|
+
the staged one and staged targets would never receive it. Hook logic stays in the plugin (Revision
|
|
550
|
+
2026-10-15); the files are entries and lib cores, not `spur` commands.
|
|
547
551
|
|
|
548
552
|
**Escape hatch:** `SPUR_WRITE_GUARD=off` short-circuits the write guard before any subprocess.
|
|
549
553
|
|
|
@@ -26,5 +26,5 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
|
|
|
26
26
|
|
|
27
27
|
## Implementation
|
|
28
28
|
|
|
29
|
-
Follow the inline procedure in [dev-operations.md](../skills/spur-dev/references/dev-operations.md#8-changelog) (changelog). This is a docs-only generator: run no quality gates (`spur self exec autofix|check|lint`, typecheck, tests, rules) — a generic "verify before finishing" rule does not apply here. The generator's own claim-verification pass is part of the procedure, not a gate, and carries one required check per claim bullet (dev-operations §8, step 7): a **source citation** — an anchor naming a URL or a repo `path:line` — held in the bullet's `<!-- src: … -->` comment and re-verified by step 8's self-check.
|
|
29
|
+
Follow the inline procedure in [dev-operations.md](../skills/spur-dev/references/dev-operations.md#8-changelog) (changelog). This is a docs-only generator: run no quality gates (`spur self exec autofix|check|lint`, typecheck, tests, rules) — a generic "verify before finishing" rule does not apply here. The generator's own claim-verification pass is part of the procedure, not a gate, and carries one required check per claim bullet (dev-operations §8, step 7): a **source citation** — an anchor naming a URL or a repo `path:line` — held in the bullet's `<!-- src: … -->` comment and re-verified by step 8's self-check. The comment also carries `· confidence: <level>`, derived from the anchors — `HIGH` all `path:line` beyond line 1 and resolving, `MEDIUM` all resolving but not all line-precise, `LOW` otherwise — and cross-checked by `repo-wide-tests/changelog-confidence.test.ts` (ADR-144): it is a function of the anchors, not a self-assessment, and a level the anchors do not support is rejected.
|
|
30
30
|
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -37,7 +37,7 @@ export const GUEST_STOP_PROBE_MS = 2000;
|
|
|
37
37
|
/** How many pending messages the delivered reason names. */
|
|
38
38
|
export const GUEST_STOP_MAX_MESSAGES = 5;
|
|
39
39
|
|
|
40
|
-
/**
|
|
40
|
+
/** Preview length for legacy queued snapshots; an owned handoff carries the full body. */
|
|
41
41
|
export const GUEST_STOP_BODY_CHARS = 140;
|
|
42
42
|
|
|
43
43
|
/** Hard per-invocation timeout for a `spur` child the hook shells out to. */
|
|
@@ -108,20 +108,41 @@ export function stopDecisionFor(
|
|
|
108
108
|
} catch {
|
|
109
109
|
return null;
|
|
110
110
|
}
|
|
111
|
-
const
|
|
111
|
+
const payload = rows !== null && typeof rows === 'object' && 'data' in rows ? rows.data : rows;
|
|
112
|
+
const list = Array.isArray(payload)
|
|
113
|
+
? payload
|
|
114
|
+
: payload !== null && typeof payload === 'object' && 'messages' in payload && Array.isArray(payload.messages)
|
|
115
|
+
? payload.messages
|
|
116
|
+
: undefined;
|
|
112
117
|
if (list === undefined) return null;
|
|
118
|
+
const handedOff = payload !== null && typeof payload === 'object' && 'pending' in payload;
|
|
113
119
|
const pending = list
|
|
114
|
-
.
|
|
115
|
-
.
|
|
116
|
-
.
|
|
120
|
+
.filter((row) => row !== null && typeof row === 'object')
|
|
121
|
+
.map((row) => row as { id?: unknown; from_id?: unknown; fromId?: unknown; body?: unknown; status?: unknown })
|
|
122
|
+
.filter(
|
|
123
|
+
(row) =>
|
|
124
|
+
typeof row.body === 'string' &&
|
|
125
|
+
(row.status === undefined ||
|
|
126
|
+
(handedOff
|
|
127
|
+
? ['queued', 'claimed', 'delivered'].includes(String(row.status))
|
|
128
|
+
: row.status === 'queued')),
|
|
129
|
+
)
|
|
130
|
+
.slice(0, handedOff ? undefined : maxMessages);
|
|
117
131
|
if (pending.length === 0) return null;
|
|
118
132
|
const lines = pending.map((row) => {
|
|
119
133
|
const from =
|
|
120
134
|
typeof row.from_id === 'string' ? row.from_id : typeof row.fromId === 'string' ? row.fromId : 'fleet';
|
|
121
|
-
const body =
|
|
122
|
-
.
|
|
123
|
-
.
|
|
124
|
-
|
|
135
|
+
const body = handedOff
|
|
136
|
+
? String(row.body ?? '')
|
|
137
|
+
: String(row.body ?? '')
|
|
138
|
+
.replace(/\s+/g, ' ')
|
|
139
|
+
.trim();
|
|
140
|
+
const id = typeof row.id === 'string' ? ` [${row.id}]` : '';
|
|
141
|
+
const preview =
|
|
142
|
+
!handedOff && body.length > GUEST_STOP_BODY_CHARS
|
|
143
|
+
? `${body.slice(0, GUEST_STOP_BODY_CHARS)}… (read the full message with spur message show ${String(row.id ?? '<msgId>')} --json)`
|
|
144
|
+
: body;
|
|
145
|
+
return `- ${from}${id}: ${preview}`;
|
|
125
146
|
});
|
|
126
147
|
const reason = `Pending fleet messages for ${guestId}:\n${lines.join('\n')}\n\nHandle them, then \`spur message reply <msgId> …\` and continue.`;
|
|
127
148
|
return JSON.stringify({ decision: 'block', reason });
|
|
@@ -155,11 +176,10 @@ export function runFleetGuestStop(payload: GuestStopPayload, deps: GuestStopDeps
|
|
|
155
176
|
guest.id,
|
|
156
177
|
'--timeout',
|
|
157
178
|
String(deps.probeMs ?? GUEST_STOP_PROBE_MS),
|
|
179
|
+
'--json',
|
|
158
180
|
]);
|
|
159
181
|
if (probe.status !== 0) return null;
|
|
160
|
-
|
|
161
|
-
if (inbox.status !== 0) return null;
|
|
162
|
-
return stopDecisionFor(guest.id, inbox.stdout, deps.maxMessages);
|
|
182
|
+
return stopDecisionFor(guest.id, probe.stdout, deps.maxMessages);
|
|
163
183
|
} catch {
|
|
164
184
|
return null;
|
|
165
185
|
}
|
|
@@ -28,13 +28,16 @@ find this session, though the `wait --inbox` loop still works.
|
|
|
28
28
|
|
|
29
29
|
## Pull loop
|
|
30
30
|
|
|
31
|
-
`spur agent wait --inbox <id> --timeout 540000` returns **0**
|
|
32
|
-
|
|
31
|
+
`spur agent wait --inbox <id> --timeout 540000 --json` returns **0** with up to five claimed messages
|
|
32
|
+
in `{ id, pending, messages }`, settling their delivery after the output handoff. It returns **1**
|
|
33
|
+
on timeout. An output failure releases the exact claims for retry; inbox listing itself never
|
|
34
|
+
consumes messages. Each call heartbeats the lease, so a looping session stays joined. The Bash tool's
|
|
33
35
|
own ~10-minute limit is why the timeout stays under it: one bounded call per turn, re-armed after
|
|
34
36
|
the work is done.
|
|
35
37
|
|
|
36
|
-
1. `spur agent wait --inbox <id> --timeout 540000 --json` → exit 0
|
|
37
|
-
2. `spur message
|
|
38
|
+
1. `spur agent wait --inbox <id> --timeout 540000 --json` → exit 0 hands this session `messages`.
|
|
39
|
+
2. Read the returned messages, including their IDs. `spur message show <id> --json` can reread one;
|
|
40
|
+
`spur message inbox --agent <id> --json` is a non-consuming historical view.
|
|
38
41
|
3. Do the work the message asks for.
|
|
39
42
|
4. `spur message reply <msgId> "<result>"` → reply to each one.
|
|
40
43
|
5. Re-arm: go back to step 1 while the operator wants this session in the fleet.
|
|
@@ -46,7 +46,7 @@ Pick the noun, read its reference. Each Tier A and Tier B reference owns that no
|
|
|
46
46
|
| **Tier A** | **workflow** | Dual-mode workflow runtime: author state-machine / transition-flow workflows, validate, run, read traces | [references/workflows.md](references/workflows.md) |
|
|
47
47
|
| **Tier A** | **builder** | Release/PR plumbing: `bump-ver` (including read-only `--check`), `drop-tags`, `publish`, the four flat PR verbs (`pr-status`, `pr-check`, `pr-open`, `pr-review`), and the read-only `show-branches` topology report | [references/builder.md](references/builder.md) |
|
|
48
48
|
| **Tier B** | **agent** | Coding-agent execution surface: run prompts via detected/named agents, list agent specs (incl. `agent.fleet` members), start/stop supervised processes, fleet `report`/`join`/`leave`/`wait`/`trace`, readiness check | [references/agent.md](references/agent.md) |
|
|
49
|
-
| **Tier B** | **message** | Durable inter-agent messaging: send, inbox, reply, watch | [references/message.md](references/message.md) |
|
|
49
|
+
| **Tier B** | **message** | Durable inter-agent messaging: send, inbox, show, read, reply, watch | [references/message.md](references/message.md) |
|
|
50
50
|
| **Tier B** | **self** | Self-management verbs: scaffold (`init`), project SDLC actions (`exec`), database maintenance (`maintain`), schema migrations (`migrate`), local web server (`serve`), status overview (`status`); `self init` runs post-scaffold validation probes & layout classification | [references/self.md](references/self.md) |
|
|
51
51
|
| **Tier B** | **history** | Import agent histories, aggregate forensic artifacts, render reports, and run the checkpoint-resumed daily pipeline | [references/history.md](references/history.md) |
|
|
52
52
|
| **Tier B** | **projects** | Manage the local multi-project registry and start/stop project servers | [references/projects.md](references/projects.md) |
|
|
@@ -162,7 +162,7 @@ and spreading it; full contract in `docs/04_DESIGN.md` §1.0.1.
|
|
|
162
162
|
`list --specs`, `start`/`stop`). Cross-references the
|
|
163
163
|
[dispatch-surface rule](../parallel-execution/references/dispatch-surface.md).
|
|
164
164
|
- **[references/message.md](references/message.md)** - durable inter-agent messaging (`send`,
|
|
165
|
-
`inbox`, `reply`, `watch`).
|
|
165
|
+
`inbox`, `show`, `read`, `reply`, `watch`).
|
|
166
166
|
- **[references/decision.md](references/decision.md)** - decision catalog (`list`, `show`, `run`,
|
|
167
167
|
`status`); with no reachable backend each decision serves its declared fallback. Authoring and
|
|
168
168
|
tuning: [references/decision/lifecycle.md](references/decision/lifecycle.md).
|
|
@@ -239,10 +239,12 @@ is refused (R3), and `requiresCapabilities` stages therefore can never reach one
|
|
|
239
239
|
spur agent wait --inbox reviewer-g1 --timeout 540000 --json
|
|
240
240
|
```
|
|
241
241
|
|
|
242
|
-
Returns `0`
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
242
|
+
Returns `0` after handing off up to five queued messages, with `{ id, pending, messages }` in JSON;
|
|
243
|
+
`pending` is the handed-off batch count. Exact claims settle as delivered after output succeeds and
|
|
244
|
+
release for retry if output fails; further queued work stays for the next pull. Returns `1` on timeout
|
|
245
|
+
or when the id is not a joined guest. Every call heartbeats the guest's lease, so a session that keeps
|
|
246
|
+
looping stays joined; the timeout stays under the Bash tool's ~10-minute limit. The
|
|
247
|
+
`fleet-join` skill loops it (wait → work from returned messages → `spur message reply`),
|
|
246
248
|
and the `fleet-guest-stop` plugin hook delivers the same messages at a turn boundary on hosts that
|
|
247
249
|
support a blocking Stop hook.
|
|
248
250
|
|
|
@@ -19,8 +19,10 @@ use it well*.
|
|
|
19
19
|
|
|
20
20
|
| Verb | Purpose | Key flags |
|
|
21
21
|
| ---- | ------- | --------- |
|
|
22
|
-
| `send <body>` |
|
|
23
|
-
| `inbox` | List messages addressed to an agent | `--agent <id>` `--unresolved` `--json` |
|
|
22
|
+
| `send <body>` | Send to a member inbox; `--to` defaults to the orchestrator | `--to <id>` `--role <name>` `--from <id>` `--request-key <key>` `--wait` `--until <state>` `--timeout <ms>` `--json` |
|
|
23
|
+
| `inbox` | List messages addressed to an agent (writes nothing) | `--agent <id>` `--unresolved` `--json` |
|
|
24
|
+
| `show <msg-id>` | Print one thread, root plus replies, oldest first, both directions | `--json` |
|
|
25
|
+
| `read <msg-id>` | Mark a message read (`--reader`, default `operator`); idempotent | `--reader <id>` `--json` |
|
|
24
26
|
| `reply <msg-id> <body>` | Thread a reply to a message | `--json` |
|
|
25
27
|
| `watch` | Follow an agent inbox - surface new messages as they arrive | `--agent <id>` `--interval <ms>` `--json` |
|
|
26
28
|
|
|
@@ -49,14 +51,14 @@ wait; enqueue is **not** rolled back if the wait later fails.
|
|
|
49
51
|
|
|
50
52
|
| Flag | Purpose |
|
|
51
53
|
| ------ | --------- |
|
|
52
|
-
| `--to <id>` | Recipient
|
|
54
|
+
| `--to <id>` | Recipient address. Mutually exclusive with `--role`. Omitted = the project's orchestrator member (`FleetService.resolveOrchestrator`); with none bound the verb exits 2 and writes no row. |
|
|
53
55
|
| `--role <name>` | Address by Layer-1 role or executor name. Must resolve to exactly one materialized instance; zero (`count=0`, candidates `none`) or multi (`count=N` + candidates) matches are hard errors (exit 1); unknown name exits 2 naming the accepted vocabulary (`AGENT_ROLE_NAMES` ∪ executor names). Resolution yields the same spec-id path as `--to`; `--wait` snapshots that occupant pin. (0685 R6 / ADR-075 amendment) |
|
|
54
56
|
| `--from <id>` | Sender id (default: `operator`). |
|
|
55
57
|
| `--request-key <key>` | Caller-minted idempotency key. The same key with the same body + recipient replays the original receipt (`replayed: true`, no second row/delivery); the same key with a different payload fails with a request-key-conflict error (0832). |
|
|
56
58
|
| `replayed` receipt field | Present on keyed sends: `true` when this submission was a replay of an earlier accepted send. |
|
|
57
59
|
| `requestKey` receipt field | Present on keyed sends, including replays; echoes the accepted key. Blank keys are rejected. |
|
|
58
60
|
| `--wait` | Block until the recipient reaches `--until` (snapshots occupant before send). |
|
|
59
|
-
| `--until <state>` | Wait target: `injected` \| `invoke-exit` (repeatable OR). Default `invoke-exit`. |
|
|
61
|
+
| `--until <state>` | Wait target: `injected` \| `invoke-exit` (repeatable OR). Default `invoke-exit`. `injected` is satisfied when THIS message leaves `queued` — claimed, delivered or failed — not when the recipient's inbox is empty. |
|
|
60
62
|
| `--timeout <ms>` | Caller deadline in milliseconds. |
|
|
61
63
|
| `--json` | Output machine-readable JSON (`{ msgId, toId, status, wait: { satisfied } }`). |
|
|
62
64
|
|
|
@@ -86,7 +88,7 @@ carry their persisted origin and run status; exhausted attempts keep the same re
|
|
|
86
88
|
| `reason` | Meaning |
|
|
87
89
|
| -------- | --------- |
|
|
88
90
|
| `delivery-failed` | The drain marked the delivery failed (`injectError` carries why), or its run's receipt outcome is `errored`. |
|
|
89
|
-
| `attempts-exhausted` | The message burned its bounded redelivery budget (`
|
|
91
|
+
| `attempts-exhausted` | The message burned its bounded redelivery budget (`MAX_DELIVERY_ATTEMPTS`, 0831; renamed by G11); the claim sweeper marks it `failed`. |
|
|
90
92
|
| `outcome-unknown` | The drain consumed it and no completion receipt ever arrived: the agent may have edited files. **Never requeued, never auto-released** — a human decides. |
|
|
91
93
|
| `run-exit-only` | Its run exited (receipt outcome `run-exit-only`) with no workflow verification result. |
|
|
92
94
|
|
|
@@ -590,10 +590,11 @@ host instructions does not add one. An opt-in gate is explicit: `gitmsg --check
|
|
|
590
590
|
- `keepachangelog` (default): `## [<version>] - <date>` header, then category headings per the keepachangelog convention — `### Added` / `### Fixed` / `### Changed` / `### Removed` / `### Other` — mapped from conventional-commit types.
|
|
591
591
|
- `simple`: flat bulleted list grouped by type heading (`### feat`, `### fix`, …).
|
|
592
592
|
6. Emit: with `<file>`, insert the section into that file above its newest `## [` release heading (or after its title when none exists) and touch nothing else in the file; without `<file>`, print it to stdout.
|
|
593
|
-
7. **Verify claims before emitting — one required check on every claim bullet.** Classify first: an *API/library claim* is a bullet asserting what code, an API, a library, a dependency or a version does — skip merge/bookkeeping bullets that assert no such fact (a status move, a filing, a doc relocation). Then run the check and append one HTML comment line directly under the bullet carrying its anchor: `<!-- src: <citation>
|
|
593
|
+
7. **Verify claims before emitting — one required check on every claim bullet.** Classify first: an *API/library claim* is a bullet asserting what code, an API, a library, a dependency or a version does — skip merge/bookkeeping bullets that assert no such fact (a status move, a filing, a doc relocation). Then run the check and append one HTML comment line directly under the bullet carrying its anchor and the level that anchor supports: `<!-- src: <citation> · confidence: <level> -->`.
|
|
594
594
|
- **Source citation — the anchor.** Internal claims (what a commit or the code does): confirm against the commit diff (`git show --stat <hash>`, reading hunks when the summary asserts behavior) or the artifact's presence in the tree; cite `path[:line]` — bare path for whole-file claims, `path:line` for a specific behavior or symbol. External claims (framework/library/version behavior): confirm against official docs for the installed version; cite the URL. An anchor you cannot produce fails the check — reword the bullet or drop the claim; a citation is not a citation until it names something a reader can open.
|
|
595
|
+
- **Confidence — derived, not judged.** The level is a function of the anchors in the comment (ADR-144), and the repo-wide check recomputes it: `HIGH` when every anchor is a `path:line` beyond line 1 and each resolves (file exists, line within it), `MEDIUM` when every anchor resolves but the set is not all line-precise (an external URL, a bare path, or a `:1` anchor), `LOW` when an anchor does not resolve or the comment lists none. To record `MEDIUM` over in-tree evidence, cite a URL or a whole file rather than asserting it — a `HIGH` the anchors do not support is exactly what `repo-wide-tests/changelog-confidence.test.ts` rejects.
|
|
595
596
|
- **Defect precision decides what must be fixed.** The check is precise once a bullet is classified as a claim: an annotation missing its anchor is unambiguously wrong and blocks emitting. A summary broader than its evidence is reworded to what the anchor shows. Which bullets *are* claims is the heuristic half — resolve it by this step's rule, and for a genuinely borderline bullet say so in the bullet's body rather than annotating or skipping it silently.
|
|
596
|
-
8. Self-check before emitting: every short hash in `<since>..<until>` appears exactly once, and every claim bullet carries exactly one `<!-- src: … -->` comment holding exactly one anchor — no unannotated claim bullets, no duplicate annotations. Fix any miss or duplicate; do not report a verdict.
|
|
597
|
+
8. Self-check before emitting: every short hash in `<since>..<until>` appears exactly once, and every claim bullet carries exactly one `<!-- src: … -->` comment holding exactly one anchor with its `· confidence: <level>` token matching what those anchors support (step 7's derivation: `HIGH` all `path:line` beyond line 1 and resolving, `MEDIUM` all resolving but not all line-precise, `LOW` otherwise) — no unannotated claim bullets, no duplicate annotations. Fix any miss or duplicate; do not report a verdict.
|
|
597
598
|
9. Reply in at most three lines: the range, bullet counts per category plus the verified-claim count, and the output target.
|
|
598
599
|
- **Invariants:** Bullets are derived from `git log` only; the claim-verification pass (step 7) adds evidence from commit diffs, the working tree, and official docs. No quality gates — no `spur self exec autofix|check|lint` and no typecheck, test or rule run, and no edits beyond the one inserted section (its verification comments included). The file is left uncommitted.
|
|
599
600
|
|
|
@@ -120,6 +120,11 @@
|
|
|
120
120
|
"type": "string",
|
|
121
121
|
"minLength": 1,
|
|
122
122
|
"description": "Five-field cron expression (minute hour day-of-month month day-of-week) evaluated in local time. Mutually exclusive with `intervalMinutes`."
|
|
123
|
+
},
|
|
124
|
+
"timeoutMs": {
|
|
125
|
+
"type": ["integer", "null"],
|
|
126
|
+
"minimum": 1,
|
|
127
|
+
"description": "Total child budget for this job in milliseconds. At the deadline the runtime SIGTERMs the owned process group, then SIGKILLs after the scheduler grace. `null` is explicit unlimited; absent falls back to the global scheduler default (10 min). Keep a model-driven chain below the server queue's 2 h visibility timeout so it fails its own attempt instead of being re-delivered."
|
|
123
128
|
}
|
|
124
129
|
},
|
|
125
130
|
"oneOf": [
|