spexcode 0.2.8 → 0.3.0
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/README.md +56 -44
- package/package.json +3 -3
- package/spec-cli/bin/spex.mjs +2 -2
- package/spec-cli/hooks/dispatch.sh +1 -1
- package/spec-cli/hooks/harness.sh +26 -6
- package/spec-cli/src/attach.ts +2 -2
- package/spec-cli/src/cli.ts +695 -536
- package/spec-cli/src/client.ts +31 -30
- package/spec-cli/src/contract-filter.ts +1 -1
- package/spec-cli/src/doctor.ts +40 -13
- package/spec-cli/src/gateway.ts +11 -7
- package/spec-cli/src/git.ts +2 -2
- package/spec-cli/src/{board.ts → graph.ts} +44 -14
- package/spec-cli/src/{boardCache.ts → graphCache.ts} +41 -21
- package/spec-cli/src/{boardDelta.ts → graphDelta.ts} +1 -1
- package/spec-cli/src/graphStream.ts +288 -0
- package/spec-cli/src/guide.ts +123 -96
- package/spec-cli/src/harness-select.ts +2 -2
- package/spec-cli/src/harness.ts +30 -14
- package/spec-cli/src/help.ts +289 -384
- package/spec-cli/src/hooks.ts +1 -1
- package/spec-cli/src/index.ts +130 -103
- package/spec-cli/src/init.ts +9 -9
- package/spec-cli/src/issues.ts +89 -33
- package/spec-cli/src/layout.ts +5 -5
- package/spec-cli/src/lint.ts +73 -8
- package/spec-cli/src/localIssues.ts +42 -60
- package/spec-cli/src/materialize.ts +1 -1
- package/spec-cli/src/mentions.ts +15 -15
- package/spec-cli/src/migrate-table.ts +397 -0
- package/spec-cli/src/migrate.ts +386 -0
- package/spec-cli/src/ranker.ts +30 -4
- package/spec-cli/src/reaper.ts +117 -0
- package/spec-cli/src/search.bench.mjs +10 -10
- package/spec-cli/src/search.ts +1 -1
- package/spec-cli/src/sessions.ts +244 -138
- package/spec-cli/src/specs.ts +25 -15
- package/spec-cli/src/supervise.ts +2 -2
- package/spec-cli/src/tree.ts +5 -5
- package/spec-cli/src/uninstall.ts +4 -4
- package/spec-cli/templates/hooks/post-checkout +1 -1
- package/spec-cli/templates/hooks/post-merge +3 -3
- package/spec-cli/templates/hooks/pre-commit +9 -9
- package/spec-cli/templates/hooks/prepare-commit-msg +1 -1
- package/spec-cli/templates/spec/project/{.config → .plugins}/core/idle/idle.sh +2 -2
- package/spec-cli/templates/spec/project/{.config → .plugins}/core/mark-active/mark-active.sh +7 -0
- package/spec-cli/templates/spec/project/{.config → .plugins}/core/mark-active/spec.md +2 -0
- package/spec-cli/templates/spec/project/{.config → .plugins}/core/session-fail/fail.sh +1 -1
- package/spec-cli/templates/spec/project/{.config → .plugins}/core/spec-first/spec-first.sh +1 -1
- package/spec-cli/templates/spec/project/{.config → .plugins}/core/spec-of-file/spec-of-file.sh +2 -2
- package/spec-cli/templates/spec/project/.plugins/core/spec.md +21 -0
- package/spec-cli/templates/spec/project/{.config → .plugins}/core/stop-gate/stop-gate.sh +21 -21
- package/spec-cli/templates/spec/project/{.config → .plugins}/distill/spec.md +2 -2
- package/spec-cli/templates/spec/project/{.config → .plugins}/extract/spec.md +4 -4
- package/spec-cli/templates/spec/project/{.config → .plugins}/forge-link/spec.md +1 -1
- package/spec-cli/templates/spec/project/{.config → .plugins}/regroup/spec.md +2 -2
- package/spec-cli/templates/spec/project/{.config → .plugins}/reproduce-before-fix/spec.md +3 -3
- package/spec-cli/templates/spec/project/{.config → .plugins}/spec.md +4 -4
- package/spec-cli/templates/spec/project/.plugins/supervisor/spec.md +8 -0
- package/spec-cli/templates/spec/project/{.config → .plugins}/tidy/spec.md +1 -1
- package/spec-cli/templates/spec/project/spec.md +1 -1
- package/spec-dashboard/dist/assets/{Dashboard-P0B9ukSG.js → Dashboard-C7Bzsv86.js} +9 -9
- package/spec-dashboard/dist/assets/EvalsPage-DKZZIdHq.js +2 -0
- package/spec-dashboard/dist/assets/{FoldToggle-BuQ0lokE.js → FoldToggle-D5iB4Ac2.js} +1 -1
- package/spec-dashboard/dist/assets/{IssuesPage-H-D8aHEl.js → IssuesPage-CMFTsQhg.js} +1 -1
- package/spec-dashboard/dist/assets/{MobileApp-oZXIeCPb.js → MobileApp-DwuTKgdP.js} +1 -1
- package/spec-dashboard/dist/assets/{SessionInterface-Blr_MEdU.js → SessionInterface-CBS5_cmK.js} +3 -3
- package/spec-dashboard/dist/assets/{SessionWindow-LcCzBMU7.js → SessionWindow-CqAnjWfI.js} +2 -2
- package/spec-dashboard/dist/assets/{Settings-_yOye-In.js → Settings-BW5f0OaW.js} +1 -1
- package/spec-dashboard/dist/assets/{index-uGs9v_9o.css → index-Cc26X4ce.css} +1 -1
- package/spec-dashboard/dist/assets/{index-BhIslAau.js → index-Ce0wDyQS.js} +8 -8
- package/spec-dashboard/dist/index.html +2 -2
- package/{spec-yatsu → spec-eval}/src/cache.ts +8 -5
- package/{spec-yatsu → spec-eval}/src/cli.ts +164 -95
- package/{spec-yatsu → spec-eval}/src/evaltab.ts +24 -24
- package/{spec-yatsu → spec-eval}/src/filing.ts +7 -5
- package/{spec-yatsu → spec-eval}/src/freshness.ts +44 -22
- package/{spec-yatsu → spec-eval}/src/scenariofresh.ts +22 -17
- package/{spec-yatsu/src/yatsu.ts → spec-eval/src/scenarios.ts} +41 -26
- package/{spec-yatsu/src/proof.ts → spec-eval/src/sessioneval.ts} +59 -59
- package/{spec-yatsu → spec-eval}/src/sidecar.ts +7 -1
- package/{spec-yatsu → spec-eval}/src/timeline.ts +1 -1
- package/spec-forge/src/__fixtures__/github-forge.json +9 -9
- package/spec-forge/src/cli.ts +14 -13
- package/spec-forge/src/{needs-yatsu-eval.ts → needs-eval.ts} +6 -6
- package/spec-cli/src/boardStream.ts +0 -179
- package/spec-cli/templates/spec/project/.config/core/spec.md +0 -17
- package/spec-cli/templates/spec/project/.config/supervisor/spec.md +0 -8
- package/spec-dashboard/dist/assets/EvalsPage-BrvAGyc4.js +0 -2
- /package/spec-cli/templates/presets/careful/{.config → .plugins}/clarify-before-code/spec.md +0 -0
- /package/spec-cli/templates/spec/project/{.config → .plugins}/core/idle/spec.md +0 -0
- /package/spec-cli/templates/spec/project/{.config → .plugins}/core/session-fail/spec.md +0 -0
- /package/spec-cli/templates/spec/project/{.config → .plugins}/core/spec-first/spec.md +0 -0
- /package/spec-cli/templates/spec/project/{.config → .plugins}/core/spec-of-file/spec.md +0 -0
- /package/spec-cli/templates/spec/project/{.config → .plugins}/core/stop-gate/spec.md +0 -0
- /package/spec-cli/templates/spec/project/{.config → .plugins}/distill/digest.mjs +0 -0
- /package/spec-cli/templates/spec/project/{.config → .plugins}/memory-hygiene/spec.md +0 -0
package/spec-cli/src/help.ts
CHANGED
|
@@ -1,345 +1,64 @@
|
|
|
1
1
|
// @@@ help journey - the CLI's three help layers, each pointing at the next so no probe dead-ends:
|
|
2
|
-
// 1. `spex help` → the MAP:
|
|
3
|
-
// 2. `spex help <cmd>` → ONE command's usage (also `spex <cmd> --help`, intercepted pre-verb).
|
|
2
|
+
// 1. `spex help` → the MAP: the whole noun-first surface, one line per drawer/verb.
|
|
3
|
+
// 2. `spex help <cmd>` → ONE drawer/command's usage (also `spex <cmd> --help`, intercepted pre-verb).
|
|
4
4
|
// 3. `spex guide [topic]` → the SKILL layer: workflows, file formats, best practice (guide.ts).
|
|
5
5
|
// help answers "what do I type"; guide answers "how do I work". Machine plumbing (hook/launch-script
|
|
6
6
|
// callees) lives under `spex internal` and is deliberately absent from the map — an agent scanning
|
|
7
7
|
// `spex help` sees only verbs meant for it. Governed by the cli-surface spec node.
|
|
8
|
+
//
|
|
9
|
+
// The grammar the map teaches: `spex <noun> <verb> [object] [flags]` — the verb is always the second
|
|
10
|
+
// token after its noun; a bare noun prints its drawer's help; a bare verb exists only where the object is
|
|
11
|
+
// invariably THIS PROJECT. One verb, one spelling: there are no aliases and no promoted twins.
|
|
8
12
|
|
|
9
13
|
// One command's help entry. `see` renders as a trailing "see also:" journey pointer.
|
|
10
14
|
type Entry = { line: string; body: string; see?: string }
|
|
11
15
|
|
|
12
16
|
const SEL_NOTE = `SEL = session id (or unique id-prefix) | node id | branch — every session read/control verb
|
|
13
|
-
accepts any of the three; none (or @all) means every session.`
|
|
14
|
-
|
|
15
|
-
const ROUTING_NOTE = `Backend routing: every session verb accepts --api <url> (--port <n> = localhost sugar) to name its
|
|
16
|
-
backend explicitly — the flag always wins. Bare, it resolves: worker env / the cwd project's live
|
|
17
|
-
recorded backend / fallback / :8787 (spex guide config → BACKEND ROUTING).`
|
|
18
|
-
|
|
19
|
-
// aliases resolve to a canonical entry so `spex help session` and `spex session new --help` meet the same text.
|
|
20
|
-
// The session-sub tokens mirror the CLI's verb-mirror rule: each typeable sub also answers bare at the top
|
|
21
|
-
// level, so its help probe (`spex send --help`, `spex help send`) must land on the session entry, not dead-end.
|
|
22
|
-
const SESSION_SUB_TOKENS = ['reopen', 'done', 'park', 'ask', 'exit', 'close', 'send', 'capture', 'attach', 'rename', 'rawkey', 'prompt']
|
|
23
|
-
const ALIAS: Record<string, string> = {
|
|
24
|
-
'review-proof': 'eval',
|
|
25
|
-
help: 'help',
|
|
26
|
-
...Object.fromEntries(SESSION_SUB_TOKENS.map((t) => [t, 'session'])),
|
|
27
|
-
}
|
|
17
|
+
accepts any of the three; on the list verbs (ls/watch), none (or @all) means every session.`
|
|
28
18
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
line: 'search <query> which spec node GOVERNS a topic — ranked by user-story, not grep',
|
|
33
|
-
body: `Usage: spex search <query…> [--limit N=10] [--json]
|
|
34
|
-
|
|
35
|
-
Finds the spec node(s) whose INTENT matches your topic — ranked by user-story relevance, which
|
|
36
|
-
surfaces user-facing behaviour a code-grep misses. Run it BEFORE touching code: the returned node's
|
|
37
|
-
spec.md body is the current contract for that area. Prints title, id, path, snippet per hit.
|
|
38
|
-
The corpus is English — query in English (translate first if your question isn't).`,
|
|
39
|
-
see: 'spex owner (file → node, the reverse edge) · spex guide spec (what a node is)',
|
|
40
|
-
},
|
|
41
|
-
owner: {
|
|
42
|
-
line: 'owner <path> the reverse edge: which spec node(s) govern or reference a file',
|
|
43
|
-
body: `Usage: spex owner <path> [--actionable]
|
|
44
|
-
|
|
45
|
-
Maps a source file to BOTH spec relations: its GOVERNORS (code: — the source of truth; drives
|
|
46
|
-
drift/yatsu) and its REFERENCERS (related: — coverage only), with the verdict spelled out:
|
|
47
|
-
uncovered ("give it a home"), related-only (covered, but nothing tracks its drift), sanely
|
|
48
|
-
governed (read/honor that spec), or over-owned (> maxOwners — split the file). --actionable
|
|
49
|
-
prints NOTHING unless action is needed (hook use): only uncovered / over-owned fire.`,
|
|
50
|
-
see: 'spex search (topic → node) · spex lint (coverage over the whole tree)',
|
|
51
|
-
},
|
|
52
|
-
tree: {
|
|
53
|
-
line: 'tree the graph as a human-readable tree (status-coloured, badges)',
|
|
54
|
-
body: `Usage: spex tree [--node <id>] [--depth N] [--json]
|
|
55
|
-
|
|
56
|
-
Prints the assembled spec graph as an indented tree — the CLI twin of the dashboard's tidy-tree,
|
|
57
|
-
built from the same board (merged tree + worktree overlay). One line per node: id, derived status
|
|
58
|
-
(coloured when stdout is a tty; NO_COLOR respected — the status word always prints), title, and
|
|
59
|
-
attention badges: drift:N (drifted files), stale:N (yatsu scenarios whose latest reading aged),
|
|
60
|
-
issues:N (open issues), ghost (being added by a worktree).
|
|
61
|
-
--node <id> render just that subtree (unknown id fails loud)
|
|
62
|
-
--depth N limit levels below the shown root; prunes are counted, never silent
|
|
63
|
-
--json the same filtered subtree as nested objects, badge counts precomputed`,
|
|
64
|
-
see: 'spex board (the full flat JSON payload) · spex search (find one node by intent)',
|
|
65
|
-
},
|
|
66
|
-
board: {
|
|
67
|
-
line: 'board dump the assembled board as JSON (tree · overlay · sessions)',
|
|
68
|
-
body: `Usage: spex board
|
|
19
|
+
const ROUTING_NOTE = `Backend routing: every backend-touching verb accepts --api <url> (--port <n> = localhost sugar) to name
|
|
20
|
+
its backend explicitly — the flag always wins. Bare, it resolves: worker env / the cwd project's live
|
|
21
|
+
recorded backend / fallback / :8787 (spex guide settings → BACKEND ROUTING).`
|
|
69
22
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
74
|
-
guide: {
|
|
75
|
-
line: 'guide [topic] the manuals: setup workflow · spec/yatsu file formats · spexcode.json · footprint',
|
|
76
|
-
body: `Usage: spex guide the human setup workflow (install once, adopt a repo, serve)
|
|
77
|
-
spex guide spec the spec.md file format + every lint rule
|
|
78
|
-
spex guide yatsu the yatsu.md scenario format + how loss is measured and filed
|
|
79
|
-
spex guide config every spexcode.json / spexcode.local.json field, and which file it belongs in
|
|
80
|
-
spex guide footprint the footprint model: never-tracked artifacts, exclude + content filter, anchors
|
|
23
|
+
const DOT_NOTE = `\`.\` as a node argument means the node THIS worktree works on (the session's bound node, else the
|
|
24
|
+
node/<id> branch). One-shot payload reads (graph · spec search · session ls/show/review · eval ls ·
|
|
25
|
+
scenario ls · issue ls/show/links) take --json.`
|
|
81
26
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// ── author & verify (worker loop) ─────────────────────────────────────────
|
|
87
|
-
lint: {
|
|
88
|
-
line: 'lint check the spec↔code graph (integrity·living·altitude·coverage·drift·owners)',
|
|
89
|
-
body: `Usage: spex lint
|
|
90
|
-
|
|
91
|
-
Checks the whole graph and exits non-zero on errors (or a blocked commit-local drift gate):
|
|
92
|
-
integrity (error) a code:/related: path doesn't exist
|
|
93
|
-
living (error) a body accretes a "## vN" changelog instead of staying current-state
|
|
94
|
-
altitude (warn) a body slid below contract altitude into a mechanics dump
|
|
95
|
-
coverage (warn) a governed source file no node claims yet
|
|
96
|
-
drift (warn) a governed file changed after its spec's last version
|
|
97
|
-
owners (warn) a file governed by more than maxOwners nodes — split it
|
|
98
|
-
When run from the pre-commit hook, a staged commit touching a heavily-drifted node BLOCKS
|
|
99
|
-
(bypass: SPEXCODE_SKIP_LINT=1); CI/manual runs are advisory beyond errors.`,
|
|
100
|
-
see: 'spex guide spec (each rule explained) · spex ack (drift that is mechanics-only)',
|
|
101
|
-
},
|
|
102
|
-
ack: {
|
|
103
|
-
line: 'ack <node>… --reason stamp Spec-OK on HEAD: this change keeps those specs valid',
|
|
104
|
-
body: `Usage: spex ack <node-id>… --reason "<why the contract still holds>"
|
|
105
|
-
|
|
106
|
-
Amends HEAD with a Spec-OK trailer per node — the drift remedy when only MECHANICS changed and the
|
|
107
|
-
spec's contract still holds. --reason is required (it forces the check) but NOT stored; git keeps
|
|
108
|
-
only the trailer. If the intent DID change, edit the spec instead — same commit as the code.`,
|
|
109
|
-
see: 'spex lint (where drift is reported) · spex guide spec (drift remedies)',
|
|
110
|
-
},
|
|
111
|
-
yatsu: {
|
|
112
|
-
line: 'yatsu <sub> measure a node’s scenarios & file the loss signal: scan | eval | retract | show | clean',
|
|
113
|
-
body: `Usage: spex yatsu scan [--changed] list nodes/scenarios missing readings
|
|
114
|
-
spex yatsu eval [.|<node>] [--scenario <name>] (--pass|--fail) [--note <text>]
|
|
115
|
-
[--image <png> …] [--result <path|->] [--video <webm|mp4>] [--timeline <json>]
|
|
116
|
-
spex yatsu retract [.|<node>] [--scenario <name>] [--last | --ts <iso>] [--note <why>]
|
|
117
|
-
spex yatsu show [.|<node>] [--json] readings history for a node
|
|
118
|
-
spex yatsu clean [--keep-latest | --all] prune stored readings
|
|
119
|
-
|
|
120
|
-
Files a reading of a scenario against its expected — the loss signal the optimizer reads. Measure
|
|
121
|
-
through the REAL product surface (run it, drive a browser, capture), never by reasoning about
|
|
122
|
-
the code. Evidence kind follows the behaviour: MOVING/timed behaviour (scroll, animation,
|
|
123
|
-
playback, a multi-step flow) records a \`--video\`; a STATIC end state screenshots \`--image\`;
|
|
124
|
-
backend/CLI files a \`--result\` transcript. A fix's proof is a fail→pass pair on the SAME
|
|
125
|
-
scenario. \`retract\` is the sanctioned undo for a botched filing: it APPENDS a retraction
|
|
126
|
-
event (traceable, never deletes a line).`,
|
|
127
|
-
see: 'spex guide yatsu (yatsu.md format + evidence rules) · spex blob (stash evidence bytes)',
|
|
128
|
-
},
|
|
129
|
-
blob: {
|
|
130
|
-
line: 'blob put|get evidence bytes ⇄ content hash: put stashes & prints the hash, get reads back',
|
|
131
|
-
body: `Usage: spex blob put <file|->
|
|
132
|
-
spex blob get <hash> [-o <file>]
|
|
133
|
-
|
|
134
|
-
put writes bytes into the shared content-addressed evidence cache and prints the hash — transport
|
|
135
|
-
only, no reading filed. Use the hash with --evidence on issues/remarks; re-putting the same content
|
|
136
|
-
restores a pruned or cloned-away blob.
|
|
137
|
-
|
|
138
|
-
get is the symmetric read: hash in, bytes out. Local cache first (no backend needed — the evidence
|
|
139
|
-
is usually on this disk), then the backend's /api/yatsu/blob/:hash on a local miss; both missing
|
|
140
|
-
fails loud naming each path. Bytes go to stdout by default (pipe-friendly); -o writes a file.`,
|
|
141
|
-
see: 'spex yatsu eval (file a reading with evidence) · spex issues open --evidence <hash>',
|
|
142
|
-
},
|
|
143
|
-
issues: {
|
|
144
|
-
line: 'issues … THE issue surface: one merged local+forge list, plus all write verbs',
|
|
145
|
-
body: `Usage: spex issues the merged read (local + forge, store-tagged)
|
|
146
|
-
[--node <id>] [--store local|github] [--all] [--json]
|
|
147
|
-
spex issues open "<concern>" [--store local|<host>] [--node <id>…] [--evidence <hash>…] [--body -|<text>]
|
|
148
|
-
spex issues reply <id> --body -|<text> [--evidence <hash>…] (routes by the issue's store)
|
|
149
|
-
spex issues close <id> close by the issue's store: local lands, forge closes remote
|
|
150
|
-
spex issues promote <id> move an OPEN local issue to the forge (one recorded action)
|
|
151
|
-
spex issues on|off|status toggle/inspect the local-issue workflow
|
|
152
|
-
|
|
153
|
-
Bare \`spex issues\` is the drain view a supervisor reads. \`open\` welcomes taste, annotations, and
|
|
154
|
-
off-mainline smells — not only bugs; \`--store <host>\` opens straight on the forge (the same port the
|
|
155
|
-
dashboard's New form uses). \`close\` and \`reply\` route by the issue's store — one verb, local or forge,
|
|
156
|
-
the same routing as the dashboard. (\`nudge\` exists but is fired by the post-merge hook, not typed.)
|
|
157
|
-
Mentions: @session · [[node]] work in any concern/body — CLI args included. [[node]] links the topic
|
|
158
|
-
node (it also tags the issue, like --node); @session hands the text to that live agent; @new spawns
|
|
159
|
-
a fresh worker on the thread's node.`,
|
|
160
|
-
see: 'spex remark (pin a resolvable concern to an issue or scenario) · spex forge (trace forge → nodes)',
|
|
161
|
-
},
|
|
162
|
-
remark: {
|
|
163
|
-
line: 'remark / resolve / retract pin a resolvable concern to a host; a peer resolves, the author retracts',
|
|
164
|
-
body: `Usage: spex remark <issue-id | <node> --scenario <name>> --body -|<text> [--code-sha <sha>] [--evidence <hash>…]
|
|
165
|
-
spex resolve <remark-ref> (the <thread-id>#<rid> that \`spex remark\` printed)
|
|
166
|
-
spex retract <remark-ref>
|
|
167
|
-
|
|
168
|
-
The resolvable interaction primitive: pin a concern to a HOST — a local issue or a yatsu scenario —
|
|
169
|
-
that a second agent can \`resolve\` and the author can \`retract\`. The whole loop is CLI-first; the
|
|
170
|
-
dashboard adds no capability.`,
|
|
171
|
-
see: 'spex issues (the hosts) · spex yatsu show (scenario hosts)',
|
|
172
|
-
},
|
|
173
|
-
forge: {
|
|
174
|
-
line: 'forge <sub> read-only trace of forge issues/PRs onto spec nodes: links | eval-pending',
|
|
175
|
-
body: `Usage: spex forge links [--host github] [--node <id>] [--json]
|
|
176
|
-
spex forge eval-pending [--host github] [--node <id>] [--json]
|
|
177
|
-
|
|
178
|
-
Resolves a forge's open issues/PRs to the spec nodes they serve (the Spec: marker in an issue body;
|
|
179
|
-
a node/<id> branch links its PR for free). Read-only — git/.spec stays the single source of truth.`,
|
|
180
|
-
see: 'spex issues (the merged read that includes forge threads)',
|
|
181
|
-
},
|
|
182
|
-
// ── dispatch & manage sessions (manager loop) ─────────────────────────────
|
|
183
|
-
new: {
|
|
184
|
-
line: 'new "<prompt>" launch a worker session in its own node worktree [--prompt-file <path>|-] [--node <id>] [--launcher <name>]',
|
|
185
|
-
body: `Usage: spex new "<task prompt>" [--node <id>] [--launcher <name>]
|
|
186
|
-
spex new --prompt-file <path>|- [--node <id>] [--launcher <name>]
|
|
187
|
-
|
|
188
|
-
Creates a session: node branch + worktree + a launched agent carrying your prompt (= session new).
|
|
189
|
-
Give it ONLY its task — the dev-flow contract reaches it through the materialized system prompt.
|
|
190
|
-
--node <id> (or the prompt's first [[id]] mention, same effect) binds the session to that node:
|
|
191
|
-
branch name node/<id>-<shortid>, board attribution, and one appended line with the node's spec.md
|
|
192
|
-
path when the node exists. With neither, the session is bound to no node.
|
|
193
|
-
--prompt-file <path> reads the prompt from a file (- = stdin), so a long multi-paragraph prompt never
|
|
194
|
-
fights shell quoting; it is exclusive with the inline prompt (both given = error), and an unreadable
|
|
195
|
-
or empty file refuses the launch.
|
|
196
|
-
The launcher name selects both the agent harness and the command/auth profile (built-ins: claude, codex);
|
|
197
|
-
omitting it requires sessions.defaultLauncher in spexcode.json or spexcode.local.json.
|
|
198
|
-
Routes through the running backend (auth env + concurrency cap); prints the created session JSON.
|
|
199
|
-
Then MONITOR it: background \`spex wait <id>\`, or \`spex watch\` for the whole stream.
|
|
200
|
-
Talk to it with \`spex send <id> "<msg>"\` — never raw tmux keystrokes.`,
|
|
201
|
-
see: 'spex wait / spex watch (monitor) · spex send (talk to it) · spex review (when it proposes) · ' + SEL_NOTE.split('\n')[0],
|
|
202
|
-
},
|
|
203
|
-
ls: {
|
|
204
|
-
line: 'ls [SEL…] living-sessions table [--status a,b] [--json] [--api URL]',
|
|
205
|
-
body: `Usage: spex ls [SEL…] [--status a,b] [--json] [--api <url> | --port <n>]
|
|
206
|
-
|
|
207
|
-
One-shot table of living sessions and their states, from the resolved backend — bare \`spex ls\` in a
|
|
208
|
-
project's tree hits THAT project's live backend; --api <url> (or --port <n>) points it anywhere,
|
|
209
|
-
including a remote machine's. ${SEL_NOTE}
|
|
210
|
-
${ROUTING_NOTE}`,
|
|
211
|
-
see: 'spex watch (the live stream) · spex wait (block on one session)',
|
|
212
|
-
},
|
|
213
|
-
watch: {
|
|
214
|
-
line: 'watch [SEL…] stream actionable transitions — NEVER EXITS; background it, never block on it',
|
|
215
|
-
body: `Usage: spex watch [SEL…] [--as NAME] [--status a,b] [--idle] [--interval N=5]
|
|
216
|
-
|
|
217
|
-
Streams session lifecycle transitions (launched → review/done/offline/error/needs-input → closed)
|
|
218
|
-
until killed. It NEVER EXITS — it is the human's forever stream. An agent must background it or use
|
|
219
|
-
\`spex wait <SEL>\` (one-shot) instead; blocking a turn on watch freezes you. Watching draws a
|
|
220
|
-
supervision edge on the session graph and greets the watched sessions once.
|
|
221
|
-
${SEL_NOTE}`,
|
|
222
|
-
see: 'spex wait (the one-shot, guaranteed-to-exit counterpart)',
|
|
223
|
-
},
|
|
224
|
-
wait: {
|
|
225
|
-
line: 'wait <SEL> block until <SEL> is actionable, print the status, exit',
|
|
226
|
-
body: `Usage: spex wait <SEL> [--timeout S=1200] [--interval S=2] [--idle]
|
|
227
|
-
|
|
228
|
-
Blocks until the session reaches an actionable status, prints it, and EXITS — the supervisor's
|
|
229
|
-
per-worker monitor (background one wait per worker; the exit is your wake-up). Guaranteed to
|
|
230
|
-
terminate: --timeout is the hard wall (exit 1); a vanished session exits 2; a down backend fails
|
|
231
|
-
loud (exit 1), never a false timeout. Draws the watcher→worker edge for the whole wait.
|
|
232
|
-
${SEL_NOTE}`,
|
|
233
|
-
see: 'spex watch (the forever stream) · spex review (what to run when it prints review/done)',
|
|
234
|
-
},
|
|
235
|
-
review: {
|
|
236
|
-
line: 'review <SEL> manager cockpit: ahead · merge-base diff · gates · proposal [--json]',
|
|
237
|
-
body: `Usage: spex review <SEL> [--json]
|
|
238
|
-
|
|
239
|
-
The ONE review payload for a session: commits ahead of the trunk, uncommitted files, its proposal,
|
|
240
|
-
the gates (conflicts with the trunk, lint), and the merge-base diff — decide from this, don't
|
|
241
|
-
hand-run git. The MEASURED side of the decision is \`spex eval <SEL>\`: the changed nodes' eval
|
|
242
|
-
readings, and (--export) the self-contained HTML export.
|
|
243
|
-
${SEL_NOTE}`,
|
|
244
|
-
see: 'spex eval (the session’s measured loss) · spex merge (act on an approved review)',
|
|
245
|
-
},
|
|
246
|
-
eval: {
|
|
247
|
-
line: 'eval <SEL> the session’s eval readings: its changed nodes’ measured loss [--export]',
|
|
248
|
-
body: `Usage: spex eval <SEL> [--json]
|
|
249
|
-
spex eval <SEL> --export [--open | --out <path> | --json]
|
|
250
|
-
|
|
251
|
-
The session's evaluation, read from the backend (the dashboard Eval tab's CLI twin): every spec node
|
|
252
|
-
the session's diff touches, each DECLARED scenario at its CURRENT score (latest reading, rooted at
|
|
253
|
-
the session's worktree). Blind spots lead (declared, never measured — the outstanding loss), then
|
|
254
|
-
the session's OWN measurements ✦-marked, then the inherited baseline (other sessions' latest
|
|
255
|
-
readings) under an explicit divider. A frontend change with no yatsu.md is flagged, never hidden.
|
|
256
|
-
--export writes the evaluation as ONE self-contained HTML artifact instead (diff · evidence
|
|
257
|
-
inlined · gates; --json = the model) for CI/sharing. (\`spex review proof\` is its deprecated alias.)
|
|
258
|
-
This is the READ; filing a reading stays \`spex yatsu eval\`.
|
|
259
|
-
${SEL_NOTE}`,
|
|
260
|
-
see: 'spex review (gates + diff — the merge decision) · spex yatsu eval (FILE a reading, the write verb)',
|
|
261
|
-
},
|
|
262
|
-
merge: {
|
|
263
|
-
line: 'merge <SEL> gated merge into the trunk — dispatched to the session’s own agent',
|
|
264
|
-
body: `Usage: spex merge <SEL>
|
|
265
|
-
|
|
266
|
-
Dispatches the merge to the session's OWN agent (it knows the work's intent and resolves conflicts);
|
|
267
|
-
the server never touches the trunk's tree. Gates re-check first. After it lands, confirm HEAD
|
|
268
|
-
advanced before closing the session — closing an unmerged branch discards the work.
|
|
269
|
-
Mutating verbs are PROJECT-BOUND: a backend serving another project's repo refuses the write loudly
|
|
270
|
-
(name the target with --api <url> to write cross-project on purpose).
|
|
271
|
-
${SEL_NOTE}`,
|
|
272
|
-
see: 'spex review (before) · spex session close (after the merge is confirmed)',
|
|
273
|
-
},
|
|
274
|
-
session: {
|
|
275
|
-
line: 'session <sub> every session verb answers here: new·ls·watch·wait·review·merge·reopen·done·park·ask·exit·close·send·capture·attach·rename·rawkey·prompt',
|
|
276
|
-
body: `Worker verbs (declare YOUR OWN state — a claim the board and your supervisor act on):
|
|
277
|
-
spex session done --propose merge|nothing|close [--note T] committed and stopping; merge = ready for review
|
|
278
|
-
spex session park --note <what-you-await> a real background task will wake you
|
|
279
|
-
spex session ask --note <your-question> stopped on the human; resumes when they reply
|
|
280
|
-
|
|
281
|
-
Manager verbs (control another session; all take SEL):
|
|
282
|
-
spex session send <SEL> "<msg>" deliver a message (fail-loud: a dead dispatch exits non-zero)
|
|
283
|
-
spex session capture <SEL> the live pane as text
|
|
284
|
-
spex session rename <SEL> "<name>" set the display name ("" clears; the right-click rename, as a verb)
|
|
285
|
-
spex session rawkey <SEL> "<keys>" raw nav keys to a TUI dialog, in strike order (e.g. "Up Up Enter";
|
|
286
|
-
named keys · single chars · C-/M-/S- combos; fail-loud)
|
|
287
|
-
spex session prompt <SEL> the session's originating prompt
|
|
288
|
-
spex session reopen <SEL> [--force] relaunch ONLY if confirmed offline (--force for a wedged live one)
|
|
289
|
-
spex session exit <SEL> soft stop: kill the agent, KEEP the worktree (resumable)
|
|
290
|
-
spex session close <SEL> retire the session and its worktree
|
|
291
|
-
|
|
292
|
-
Promoted verbs — they answer in this drawer too (same verb, either drawer):
|
|
293
|
-
spex session new|ls|watch|wait|review|merge … ≡ spex new|ls|watch|wait|review|merge …
|
|
294
|
-
And the reverse holds for every sub above: it also answers bare at the top level
|
|
295
|
-
(spex send <SEL> "…" ≡ spex session send <SEL> "…"). One implementation, two spellings —
|
|
296
|
-
you never have to guess which drawer a session verb lives in.
|
|
27
|
+
const MENTION_NOTE = `Mentions: @session · [[node]] · @new work in ANY prompt, issue, or remark body — text passed as a CLI
|
|
28
|
+
arg included. [[node]] names the topic node; @session hands the text to that live agent; @new spawns a
|
|
29
|
+
fresh worker on the thread's node.`
|
|
297
30
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
another project's repo refuses loudly — name the target with --api <url> to drive it on purpose.
|
|
313
|
-
${ROUTING_NOTE}`,
|
|
314
|
-
see: 'spex new (launch) · spex wait/watch (monitor) · spex review/merge (land)',
|
|
31
|
+
const ENTRIES: Record<string, Entry> = {
|
|
32
|
+
// ── project verbs (implicit object = this project) ────────────────────────
|
|
33
|
+
graph: {
|
|
34
|
+
line: 'graph the assembled view: bare = readable tree · --json = the full payload',
|
|
35
|
+
body: `Usage: spex graph [--focus <id>] [--depth N] [--json]
|
|
36
|
+
|
|
37
|
+
The ONE assembled view — merged spec tree + worktree overlay + sessions. Bare it renders the
|
|
38
|
+
status-coloured tree (coloured when stdout is a tty; NO_COLOR respected), one line per node: id,
|
|
39
|
+
derived status, title, and attention badges (drift:N · stale:N · issues:N · ghost).
|
|
40
|
+
--focus <id> render just that subtree (unknown id fails loud)
|
|
41
|
+
--depth N limit levels below the shown root; prunes are counted, never silent
|
|
42
|
+
--json the full payload (tree · overlay · sessions), identical to GET /api/graph — machine
|
|
43
|
+
food; with --focus/--depth it is that filtered subtree as nested objects instead`,
|
|
44
|
+
see: 'spex spec search (find one node by intent) · spex session ls (just the sessions, as a table)',
|
|
315
45
|
},
|
|
316
|
-
|
|
317
|
-
// ── install & serve (operator) ────────────────────────────────────────────
|
|
318
46
|
init: {
|
|
319
47
|
line: 'init [dir] adopt SpexCode on a repo: seed .spec + hooks + materialize [--preset name]',
|
|
320
48
|
body: `Usage: spex init [dir=cwd] [--preset default|careful]
|
|
321
49
|
|
|
322
|
-
Scaffolds adoption in one shot: seeds a starter .spec tree (project root + .
|
|
50
|
+
Scaffolds adoption in one shot: seeds a starter .spec tree (project root + .plugins plugins), plants
|
|
323
51
|
spexcode.json, installs the git hooks, and materializes the harness artifacts (contract block +
|
|
324
|
-
shims). Additive — never overwrites your files. --preset picks the .
|
|
52
|
+
shims). Additive — never overwrites your files. --preset picks the .plugins plugin tier (cumulative).
|
|
325
53
|
Footprint is fixed: materialized artifacts are never tracked — hidden via the per-clone .git/info/exclude, with
|
|
326
54
|
a tracked/mixed CLAUDE.md/AGENTS.md covered by the clean/smudge filter (see spex guide footprint).`,
|
|
327
|
-
see: 'spex guide (the full setup workflow) · spex uninstall (the inverse) · spex lint (adoption TODO)',
|
|
328
|
-
},
|
|
329
|
-
uninstall: {
|
|
330
|
-
line: 'uninstall [dir] surgical inverse of init — removes generated artifacts, keeps your .spec [--hooks]',
|
|
331
|
-
body: `Usage: spex uninstall [dir=cwd] [--hooks]
|
|
332
|
-
|
|
333
|
-
Removes every SpexCode-GENERATED artifact (harness shims · contract blocks · trust entries ·
|
|
334
|
-
exclude/ignore blocks · global store · plugin bundle) and never your .spec/.config data or your own
|
|
335
|
-
prose. Git hooks are preserved unless --hooks.`,
|
|
336
|
-
see: 'spex init (re-adopt later — your .spec survives)',
|
|
55
|
+
see: 'spex guide (the full setup workflow) · spex uninstall (the inverse) · spex spec lint (adoption TODO)',
|
|
337
56
|
},
|
|
338
57
|
materialize: {
|
|
339
58
|
line: 'materialize re-materialize the harness artifacts (contract block · shims) for cwd’s project',
|
|
340
59
|
body: `Usage: spex materialize
|
|
341
60
|
|
|
342
|
-
Materializes the surface:system
|
|
61
|
+
Materializes the surface:system plugin nodes into the managed <!-- spexcode --> block of
|
|
343
62
|
CLAUDE.md/AGENTS.md plus the .claude/.codex shims, and prints the content hash. The materialize anchors on
|
|
344
63
|
git-native events only (init · this verb · session-worktree creation · the pre-commit/post-checkout/
|
|
345
64
|
post-merge hooks) — run it by hand after a toolchain update, or in the setup step of any clone that
|
|
@@ -348,118 +67,304 @@ never arrive via git.`,
|
|
|
348
67
|
see: 'spex doctor (verify the materialized artifacts actually reach an agent)',
|
|
349
68
|
},
|
|
350
69
|
doctor: {
|
|
351
|
-
line: 'doctor diagnose whether the workflow actually reaches this agent
|
|
352
|
-
body: `Usage: spex doctor
|
|
353
|
-
|
|
354
|
-
spex doctor contract
|
|
355
|
-
spex doctor conflicts
|
|
70
|
+
line: 'doctor diagnose whether the workflow actually reaches this agent [--contract|--conflicts]',
|
|
71
|
+
body: `Usage: spex doctor per-layer coverage report: preconditions · git-hook floor · contract ·
|
|
72
|
+
hooks + handler existence · backend — for every harness materialize delivers to
|
|
73
|
+
spex doctor --contract print the composed surface:system text any agent here reads
|
|
74
|
+
spex doctor --conflicts detect double-delivery (loose artifacts beside the managed ones)
|
|
356
75
|
|
|
357
76
|
Run it when a worker seems to be missing its contract or hooks — it names the broken layer and the
|
|
358
77
|
repair, instead of you diffing materialized files by hand.`,
|
|
359
78
|
see: 'spex materialize (re-materialize the artifacts doctor checks)',
|
|
360
79
|
},
|
|
80
|
+
uninstall: {
|
|
81
|
+
line: 'uninstall [dir] surgical inverse of init — removes generated artifacts, keeps your .spec [--hooks]',
|
|
82
|
+
body: `Usage: spex uninstall [dir=cwd] [--hooks]
|
|
83
|
+
|
|
84
|
+
Removes every SpexCode-GENERATED artifact (harness shims · contract blocks · trust entries ·
|
|
85
|
+
exclude/ignore blocks · global store · plugin bundle) and never your .spec/.plugins data or your own
|
|
86
|
+
prose. Git hooks are preserved unless --hooks.`,
|
|
87
|
+
see: 'spex init (re-adopt later — your .spec survives)',
|
|
88
|
+
},
|
|
361
89
|
serve: {
|
|
362
|
-
line: 'serve
|
|
363
|
-
body: `Usage: spex serve [--port N=8787]
|
|
364
|
-
spex serve --public --password <pw> [--tls-cert F --tls-key F] [--http]
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
runtime tier — that's how a bare \`spex\` run from this project's tree
|
|
370
|
-
spex guide
|
|
371
|
-
self-signed TLS (own cert via --tls-cert/--tls-key; --http drops TLS)
|
|
372
|
-
|
|
90
|
+
line: 'serve [api|ui] api (default) = the backend :8787 · ui = the dashboard :5173 on top of it',
|
|
91
|
+
body: `Usage: spex serve [api] [--port N=8787]
|
|
92
|
+
spex serve [api] --public --password <pw> [--tls-cert F --tls-key F] [--http]
|
|
93
|
+
spex serve ui [--port N=5173] [--api-port N=8787] [--host H=127.0.0.1]
|
|
94
|
+
|
|
95
|
+
\`serve\` (or \`serve api\`) runs the backend for the repo at cwd behind a zero-downtime supervisor
|
|
96
|
+
(hot-reloads on source change; the public port never gaps). On a successful bind it RECORDS its
|
|
97
|
+
endpoint in the per-project runtime tier — that's how a bare \`spex\` run from this project's tree
|
|
98
|
+
finds this backend (spex guide settings → BACKEND ROUTING). --public exposes it on a public IP behind
|
|
99
|
+
a password + self-signed TLS (own cert via --tls-cert/--tls-key; --http drops TLS).
|
|
100
|
+
|
|
101
|
+
\`serve ui\` is a SEPARATE process: it serves the bundled dashboard on its own port and proxies /api +
|
|
102
|
+
the terminal socket to a running backend (--api-port pairs with the backend's --port, so many
|
|
103
|
+
projects coexist on one host). Loopback-only by default; --host 0.0.0.0 opens it to a LAN/tailnet —
|
|
104
|
+
still plain HTTP with no gate, so bind wide only on a network you trust.`,
|
|
105
|
+
see: 'GET /health (backend liveness probe)',
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
// ── the noun drawers ──────────────────────────────────────────────────────
|
|
109
|
+
spec: {
|
|
110
|
+
line: 'spec <verb> the governance graph: search · owner · lint · ack',
|
|
111
|
+
body: `Usage: spex spec search <query…> [--limit N=10] [--json]
|
|
112
|
+
spex spec owner <path> [--actionable]
|
|
113
|
+
spex spec lint
|
|
114
|
+
spex spec ack <node-id>… --reason "<why the contract still holds>"
|
|
115
|
+
|
|
116
|
+
search — which spec node GOVERNS a topic, ranked by user-story relevance (which surfaces user-facing
|
|
117
|
+
behaviour a code-grep misses). Run it BEFORE touching code: the node's spec.md body is the current
|
|
118
|
+
contract. The corpus is English — query in English.
|
|
119
|
+
|
|
120
|
+
owner — the reverse edge: a file's GOVERNORS (code: — drives drift + eval freshness) and REFERENCERS (related:
|
|
121
|
+
— coverage only), with the verdict spelled out (uncovered / related-only / sanely governed /
|
|
122
|
+
over-owned → split the file). --actionable prints NOTHING unless action is needed (hook use).
|
|
123
|
+
|
|
124
|
+
lint — checks the whole spec↔code graph and exits non-zero on errors (or a blocked commit-local
|
|
125
|
+
drift gate). Errors: integrity (a code:/related: file does not exist) · one-govern (a node governs >1
|
|
126
|
+
file) · living (a "## vN" changelog heading) · id-format (an id char outside the whitelist — ascii
|
|
127
|
+
[a-z0-9-] or a non-ascii unicode letter/number, CJK ok — or a leaf id
|
|
128
|
+
reused) · mention (a [[id]] naming no node). Warns: altitude · breadth · coverage · drift ·
|
|
129
|
+
related-drift · owners · confusable-id (two leaf ids one edit apart). spec lint's errors BLOCK commits (the pre-commit shim; bypass SPEXCODE_SKIP_LINT=1);
|
|
130
|
+
contrast \`spex eval lint\`, which is pure advisory and never blocks anyone.
|
|
131
|
+
|
|
132
|
+
ack — stamp Spec-OK on HEAD (an empty stamp commit): the drift remedy when only MECHANICS changed
|
|
133
|
+
and the spec's contract still holds. --reason is required but NOT stored. If the intent DID change,
|
|
134
|
+
edit the spec instead — same commit as the code.`,
|
|
135
|
+
see: 'spex guide spec (the file format + every lint rule) · spex graph (browse the whole tree)',
|
|
136
|
+
},
|
|
137
|
+
session: {
|
|
138
|
+
line: 'session <verb> the worktree state machine: new · ls · watch · wait · review · merge · send · …',
|
|
139
|
+
body: `Manager verbs (dispatch, monitor, land):
|
|
140
|
+
spex session new "<prompt>" [--prompt-file <path>|-] [--node <id>] [--launcher <name>]
|
|
141
|
+
Launch a worker in its own node worktree. Give it ONLY its task — the dev-flow contract
|
|
142
|
+
reaches it through the materialized system prompt. --node (or the prompt's first [[id]],
|
|
143
|
+
same effect) binds the session to that node. --prompt-file <path>|- carries a long prompt
|
|
144
|
+
without shell quoting (exclusive with the inline prompt). Then MONITOR it (wait/watch below).
|
|
145
|
+
spex session ls [SEL…] [--status a,b] [--json] one-shot table of living sessions
|
|
146
|
+
spex session watch [SEL…] [--as NAME] [--idle] [--interval N=5]
|
|
147
|
+
Streams lifecycle transitions until killed — it NEVER EXITS; the human's forever stream. An
|
|
148
|
+
agent must background it or use wait; blocking a turn on watch freezes you.
|
|
149
|
+
spex session wait <SEL> [--timeout S=1200] [--interval S=2] [--idle]
|
|
150
|
+
EDGE-TRIGGERED sleep on one session — ALWAYS run it in the BACKGROUND; its exit is your wake-up.
|
|
151
|
+
Prints the session's current status immediately (stderr), then exits 0 only when it OBSERVES
|
|
152
|
+
the session TRANSITION from a non-actionable status into an actionable one, printing the
|
|
153
|
+
observed path on stdout (e.g. working→review — read the LAST token as the status reached).
|
|
154
|
+
USE IT to sleep until a dispatched worker next needs you — including a dispatched MERGE
|
|
155
|
+
actually landing (review→working while the merge runs, then the edge back is your wake-up).
|
|
156
|
+
It NEVER returns just because the session is actionable ALREADY — for "what is it right NOW"
|
|
157
|
+
use \`session ls\` / \`session review\` instead. --timeout is the guaranteed exit (code 1,
|
|
158
|
+
observed path on stderr). Background one wait per worker.
|
|
159
|
+
spex session review <SEL> [--json] the merge cockpit: ahead · uncommitted · proposal · gates ·
|
|
160
|
+
merge-base diff — decide from this, don't hand-run git
|
|
161
|
+
spex session merge <SEL> gated merge, dispatched to the session's OWN agent; confirm
|
|
162
|
+
HEAD advanced before closing — closing unmerged discards work
|
|
163
|
+
|
|
164
|
+
Control another session (all take SEL):
|
|
165
|
+
spex session send <SEL> "<msg>" deliver a message (fail-loud: a dead dispatch exits non-zero)
|
|
166
|
+
spex session send <SEL> --keys "<keys>"
|
|
167
|
+
LAST RESORT: raw nav-mode keystrokes to a TUI dialog ("Up Up Enter", C-/M-/S- combos). The raw
|
|
168
|
+
key surface is UNSTABLE and can confirm dangerous dialogs — don't reach for it unless a plain
|
|
169
|
+
\`session send\` text provably cannot land.
|
|
170
|
+
spex session rename <SEL> "<name>" set the display name ("" clears)
|
|
171
|
+
spex session show <SEL> [--capture] [--json]
|
|
172
|
+
The session record: status · node · branch · launcher · the full originating prompt.
|
|
173
|
+
--capture prints the LIVE PANE as text instead (empty pane = exit 0; unknown session = exit 2).
|
|
174
|
+
spex session resume <SEL> [--force] relaunch ONLY if confirmed offline (--force for a wedged one)
|
|
175
|
+
spex session stop <SEL> soft stop: kill the agent, KEEP the worktree (resumable)
|
|
176
|
+
spex session close <SEL> retire the session and its worktree
|
|
177
|
+
|
|
178
|
+
Worker verbs (declare YOUR OWN state — a claim the graph and your supervisor act on):
|
|
179
|
+
spex session done --propose merge|nothing|close [--note T] committed and stopping
|
|
180
|
+
spex session park --note <what-you-await> a real background task will wake you
|
|
181
|
+
spex session ask --note <your-question> stopped on the human; resumes on reply
|
|
182
|
+
|
|
183
|
+
Human escape hatch:
|
|
184
|
+
spex session attach <SEL> sit in the worker's REAL tmux (detach: C-b d). INTERACTIVE
|
|
185
|
+
AND BLOCKING — an agent must NEVER run it in a turn: use
|
|
186
|
+
show --capture / send. LOCAL-only (fails loud on a remote backend).
|
|
187
|
+
|
|
188
|
+
${SEL_NOTE}
|
|
189
|
+
Manager verbs that WRITE (send/rename/resume/stop/close/merge) are PROJECT-BOUND: a backend serving
|
|
190
|
+
another project's repo refuses loudly — name the target with --api <url> to drive it on purpose.
|
|
191
|
+
${MENTION_NOTE}`,
|
|
192
|
+
see: 'spex eval ls --session <SEL> (the session’s measured loss) · spex help eval',
|
|
193
|
+
},
|
|
194
|
+
eval: {
|
|
195
|
+
line: 'eval <verb> the measurement system: add · ls · scenario ls · lint · retract · clean',
|
|
196
|
+
body: `Usage: spex eval add [<node>|.] [--scenario <name>] (--pass|--fail) [--note <text>]
|
|
197
|
+
[--image <png> …repeatable] [--result <path|->] [--video <webm|mp4>] [--timeline <json>]
|
|
198
|
+
spex eval ls [<node>|.] [--json] a node's eval timeline, newest first
|
|
199
|
+
spex eval ls --session <SEL> [--json] a session's aggregate: its changed nodes' scores
|
|
200
|
+
spex eval ls --session <SEL> --export [--open | --out <path>]
|
|
201
|
+
spex eval scenario ls [<node>|.] [--unmeasured] [--json] declared scenarios; bare = every node
|
|
202
|
+
spex eval lint [--changed] measurement-layer findings (advisory, always exit 0)
|
|
203
|
+
spex eval retract [<node>|.] [--scenario <name>] [--last | --ts <iso>] [--note <why>]
|
|
204
|
+
spex eval clean [--keep-latest | --all] GC the content-addressed evidence cache
|
|
205
|
+
|
|
206
|
+
add — file an eval of a scenario against its expected: the loss signal the optimizer reads.
|
|
207
|
+
Measure through the REAL product surface, never by reasoning about the code. Evidence kind follows
|
|
208
|
+
the behaviour: MOVING/timed behaviour records a --video; a STATIC end state screenshots --image;
|
|
209
|
+
backend/CLI files a --result transcript. A fix's evidence is a fail→pass pair on the SAME scenario.
|
|
210
|
+
|
|
211
|
+
ls — node-scoped bare (its per-scenario eval history); session-scoped with an EXPLICIT --session
|
|
212
|
+
(never type-sniffed): every node the session's diff touches, blind spots first, its OWN measurements
|
|
213
|
+
✦-marked ahead of the inherited baseline. --export writes that evaluation as ONE self-contained
|
|
214
|
+
HTML artifact (diff · evidence inlined · gates) for CI/sharing.
|
|
215
|
+
|
|
216
|
+
scenario ls — the DECLARED contracts (name · tags · latest verdict), no evals: bare lists every
|
|
217
|
+
measurable node's scenarios; --unmeasured keeps only the never-measured — the blind-spot worklist.
|
|
218
|
+
|
|
219
|
+
lint — the measurement layer's findings: malformed eval.md (eval-schema) · unmeasured (eval-missing) ·
|
|
220
|
+
stale (eval-drift) · orphaned remark tracks (eval-dangling) · governed source with no eval.md
|
|
221
|
+
(eval-coverage — the same name and shape as spec lint's coverage, one rule per layer) · over-owned
|
|
222
|
+
files (eval-owners). --changed scopes to the nodes THIS branch touched. spec lint's errors block
|
|
223
|
+
commits; eval lint is PURE ADVISORY, always exit 0 — a measurement gap never blocks anyone.
|
|
224
|
+
|
|
225
|
+
retract — the sanctioned undo for a botched filing: APPENDS a retraction event (traceable, never
|
|
226
|
+
deletes a line); the previous eval becomes latest again, or the scenario honestly returns to
|
|
227
|
+
unmeasured.
|
|
228
|
+
|
|
229
|
+
${DOT_NOTE}`,
|
|
230
|
+
see: 'spex guide eval (the eval.md scenario format + evidence rules) · spex evidence (bare byte transport)',
|
|
231
|
+
},
|
|
232
|
+
issue: {
|
|
233
|
+
line: 'issue <verb> concern threads, local + forge merged: ls · show · open · reply · close · promote · links',
|
|
234
|
+
body: `Usage: spex issue ls [--node <id>] [--store local|<host>] [--all] [--json]
|
|
235
|
+
spex issue show <id> [--json]
|
|
236
|
+
spex issue open "<concern>" [--store local|<host>] [--node <id>…] [--evidence <hash>…] [--body -|<text>]
|
|
237
|
+
spex issue reply <id> --body -|<text> [--evidence <hash>…]
|
|
238
|
+
spex issue close <id>
|
|
239
|
+
spex issue promote <id>
|
|
240
|
+
spex issue links [--pending] [--store <host>] [--node <id>] [--json]
|
|
241
|
+
|
|
242
|
+
ls is the drain view a supervisor reads: ONE store-tagged list, local + forge interleaved by
|
|
243
|
+
creation time. \`show <id>\` is the single-thread detail — the whole thread with its replies (a local
|
|
244
|
+
id, or a forge id like github#12). \`open\` welcomes taste, annotations, and off-mainline smells —
|
|
245
|
+
not only bugs; --store <host> opens straight on the forge. \`reply\` and \`close\` route by the
|
|
246
|
+
issue's store — one verb, local or forge. \`promote\` moves an OPEN local issue to the forge as one
|
|
247
|
+
recorded action. \`links\` is the read-only forge trace: which open forge issues/PRs serve which
|
|
248
|
+
spec node (--pending narrows to threads still awaiting an eval). The issues workflow's
|
|
249
|
+
on/off switch is the \`issues.enabled\` key in spexcode.json (no CLI toggle verb — edit the JSON;
|
|
250
|
+
\`spex doctor\` reports its state).
|
|
251
|
+
${MENTION_NOTE}`,
|
|
252
|
+
see: 'spex remark (pin a resolvable concern to an issue or scenario) · spex evidence put (stash evidence bytes)',
|
|
253
|
+
},
|
|
254
|
+
remark: {
|
|
255
|
+
line: 'remark <verb> resolvable pins on a host: add · resolve · retract',
|
|
256
|
+
body: `Usage: spex remark add <issue-id | <node> --scenario <name>> --body -|<text> [--code-sha <sha>] [--evidence <hash>…]
|
|
257
|
+
spex remark resolve <ref> (the <thread-id>#<rid> that \`spex remark add\` printed)
|
|
258
|
+
spex remark retract <ref>
|
|
259
|
+
|
|
260
|
+
The resolvable interaction primitive: \`add\` pins a concern to a HOST — a local issue, or a scenario
|
|
261
|
+
(\`--scenario\` present ⇒ the positional is a node; otherwise it is an issue id — the flag decides,
|
|
262
|
+
never type-sniffing). A SECOND agent \`resolve\`s it (never the author); the AUTHOR \`retract\`s their
|
|
263
|
+
own. The whole loop is CLI-first; the dashboard adds no capability.`,
|
|
264
|
+
see: 'spex issue (the thread hosts) · spex eval ls (scenario hosts)',
|
|
265
|
+
},
|
|
266
|
+
evidence: {
|
|
267
|
+
line: 'evidence put|get content-addressed bytes: put stashes & prints the hash, get reads back',
|
|
268
|
+
body: `Usage: spex evidence put <file|->
|
|
269
|
+
spex evidence get <hash> [-o <file>]
|
|
270
|
+
|
|
271
|
+
put writes bytes into the shared content-addressed evidence cache and prints the hash — transport
|
|
272
|
+
only, no eval filed. Use the hash with --evidence on issues/remarks; re-putting the same content
|
|
273
|
+
restores pruned or cloned-away evidence.
|
|
274
|
+
|
|
275
|
+
get is the symmetric read: hash in, bytes out. Local cache first (no backend needed — the evidence
|
|
276
|
+
is usually on this disk), then the backend on a local miss; both missing fails loud naming each
|
|
277
|
+
path. Bytes go to stdout by default (pipe-friendly); -o writes a file.`,
|
|
278
|
+
see: 'spex eval add (file an eval WITH evidence) · spex issue open --evidence <hash>',
|
|
373
279
|
},
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
280
|
+
|
|
281
|
+
// ── help & guide ──────────────────────────────────────────────────────────
|
|
282
|
+
guide: {
|
|
283
|
+
line: 'guide [topic] the manuals: setup workflow · spec/eval file formats · spexcode.json · footprint',
|
|
284
|
+
body: `Usage: spex guide the human setup workflow (install once, adopt a repo, serve)
|
|
285
|
+
spex guide spec the spec.md file format + every lint rule
|
|
286
|
+
spex guide eval the eval.md scenario format + how loss is measured and filed
|
|
287
|
+
spex guide settings every spexcode.json / spexcode.local.json field, and which file it belongs in
|
|
288
|
+
spex guide footprint the footprint model: never-tracked artifacts, exclude + content filter, anchors
|
|
289
|
+
|
|
290
|
+
guide is the SKILL layer — workflows and formats. Command usage lives here in help
|
|
291
|
+
(\`spex help <cmd>\`); guide carries what the commands assume you know.`,
|
|
383
292
|
},
|
|
384
293
|
|
|
385
294
|
// ── plumbing ──────────────────────────────────────────────────────────────
|
|
386
295
|
internal: {
|
|
387
296
|
line: '', // deliberately not on the map
|
|
388
|
-
body: `Usage: spex internal <
|
|
297
|
+
body: `Usage: spex internal <sub>
|
|
389
298
|
|
|
390
299
|
Machine plumbing — called by generated hooks and launch scripts, never typed by a human or agent:
|
|
391
300
|
trunk print the resolved source-of-truth branch (the pre-commit main-guard captures it)
|
|
392
301
|
commit-surgery pre-commit footprint anchor: unconditional materialize + staged-index repair
|
|
393
302
|
refresh-footprint quiet materialize — the post-checkout/post-merge freshness anchor
|
|
394
|
-
|
|
395
|
-
|
|
303
|
+
check-staged pre-commit eval backstop: reject staged stray evidence files / malformed eval.md
|
|
304
|
+
session-state <st> --session <id> a lifecycle hook authors the session's state
|
|
305
|
+
session-fail --session <id> the StopFailure hook marks the session errored
|
|
306
|
+
session-idle --session <id> the idle-prompt hook marks an active session idle
|
|
307
|
+
commit-gate the Stop gate's deterministic commit check (exit 0 = ready to declare done)
|
|
308
|
+
nudge <node> the post-merge hook prints the issue nudge for a merged node
|
|
309
|
+
codex-launch <sock> <cwd> [prompt…] backend-owned codex thread/start + first turn (launch script)
|
|
310
|
+
codex-turn <sock> <threadId> <text…> fire a follow-up turn on an owned thread (tests/scripts)
|
|
396
311
|
|
|
397
312
|
If you reached for one of these by hand, the porcelain you want is probably elsewhere: the trunk
|
|
398
|
-
name also lives at GET /api/layout; sessions are driven with spex new / session send
|
|
313
|
+
name also lives at GET /api/settings (.layout); sessions are driven with spex session new / session send;
|
|
314
|
+
your own state is declared with spex session done|park|ask.`,
|
|
399
315
|
see: 'spex help (the porcelain map)',
|
|
400
316
|
},
|
|
401
317
|
help: {
|
|
402
318
|
line: '',
|
|
403
|
-
body: `Usage: spex help the command map
|
|
404
|
-
spex help <command> one command's usage (same as spex <command> --help)
|
|
319
|
+
body: `Usage: spex help the command map
|
|
320
|
+
spex help <command> one command/drawer's usage (same as spex <command> --help)
|
|
405
321
|
spex guide [topic] the skill layer: workflows, file formats, best practice`,
|
|
406
322
|
},
|
|
407
323
|
}
|
|
408
324
|
|
|
409
|
-
// `spex <cmd> --help` must meet the user wherever they typed it:
|
|
410
|
-
//
|
|
325
|
+
// `spex <cmd> --help` must meet the user wherever they typed it: cli.ts intercepts the probe pre-verb and
|
|
326
|
+
// asks for the FIRST token's entry, so `spex session send --help` answers with the session drawer's entry.
|
|
411
327
|
export function commandHelp(name: string): string | null {
|
|
412
|
-
const
|
|
413
|
-
const e = ENTRIES[key]
|
|
328
|
+
const e = ENTRIES[name]
|
|
414
329
|
if (!e) return null
|
|
415
330
|
const oneLiner = e.line.replace(/^\S+(\s+\S+)*?\s{2,}/, '') // the map line minus its "cmd args" column
|
|
416
|
-
const header = oneLiner ? `spex ${
|
|
331
|
+
const header = oneLiner ? `spex ${name} — ${oneLiner}\n\n` : '' // unlisted entries (internal, help) lead with their own Usage
|
|
417
332
|
return `${header}${e.body}${e.see ? `\n\nsee also: ${e.see}` : ''}\n\nmap: spex help · skills: spex guide`
|
|
418
333
|
}
|
|
419
334
|
|
|
420
335
|
export function overviewHelp(): string {
|
|
421
336
|
return `spex — SpexCode CLI (spec↔code graph + worktree session state machine)
|
|
422
337
|
|
|
423
|
-
Usage: spex <
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
${ENTRIES.owner.line}
|
|
428
|
-
${ENTRIES.tree.line}
|
|
429
|
-
${ENTRIES.board.line}
|
|
430
|
-
${ENTRIES.guide.line}
|
|
338
|
+
Usage: spex <noun> <verb> [object] [flags] the verb is always the token after its noun;
|
|
339
|
+
a bare noun prints that drawer's help
|
|
340
|
+
spex help <command> one command's usage (or spex <command> --help — always
|
|
341
|
+
safe: a help probe never runs the verb)
|
|
431
342
|
|
|
432
|
-
|
|
433
|
-
${ENTRIES.
|
|
434
|
-
${ENTRIES.ack.line}
|
|
435
|
-
${ENTRIES.yatsu.line}
|
|
436
|
-
${ENTRIES.blob.line}
|
|
437
|
-
${ENTRIES.issues.line}
|
|
438
|
-
${ENTRIES.remark.line}
|
|
439
|
-
${ENTRIES.forge.line}
|
|
440
|
-
|
|
441
|
-
Dispatch & manage sessions (the manager loop)
|
|
442
|
-
${ENTRIES.new.line}
|
|
443
|
-
${ENTRIES.ls.line}
|
|
444
|
-
${ENTRIES.watch.line}
|
|
445
|
-
${ENTRIES.wait.line}
|
|
446
|
-
${ENTRIES.review.line}
|
|
447
|
-
${ENTRIES.eval.line}
|
|
448
|
-
${ENTRIES.merge.line}
|
|
449
|
-
${ENTRIES.session.line}
|
|
450
|
-
|
|
451
|
-
Install & serve (the operator loop)
|
|
343
|
+
Project verbs (implicit object = this project)
|
|
344
|
+
${ENTRIES.graph.line}
|
|
452
345
|
${ENTRIES.init.line}
|
|
453
|
-
${ENTRIES.uninstall.line}
|
|
454
346
|
${ENTRIES.materialize.line}
|
|
455
347
|
${ENTRIES.doctor.line}
|
|
348
|
+
${ENTRIES.uninstall.line}
|
|
456
349
|
${ENTRIES.serve.line}
|
|
457
|
-
${ENTRIES.dashboard.line}
|
|
458
350
|
|
|
459
|
-
|
|
351
|
+
Noun drawers
|
|
352
|
+
${ENTRIES.spec.line}
|
|
353
|
+
${ENTRIES.session.line}
|
|
354
|
+
${ENTRIES.eval.line}
|
|
355
|
+
${ENTRIES.issue.line}
|
|
356
|
+
${ENTRIES.remark.line}
|
|
357
|
+
${ENTRIES.evidence.line}
|
|
358
|
+
|
|
359
|
+
Manuals
|
|
360
|
+
${ENTRIES.guide.line}
|
|
460
361
|
|
|
461
|
-
|
|
362
|
+
Conventions (stated once, hold everywhere)
|
|
363
|
+
${SEL_NOTE.split('\n').join('\n ')}
|
|
364
|
+
${DOT_NOTE.split('\n').join('\n ')}
|
|
365
|
+
${ROUTING_NOTE.split('\n').join('\n ')}
|
|
366
|
+
${MENTION_NOTE.split('\n').join('\n ')}
|
|
462
367
|
|
|
463
|
-
Concepts & best practice live in the guide: spex guide (setup) · guide spec · guide
|
|
368
|
+
Concepts & best practice live in the guide: spex guide (setup) · guide spec · guide eval · guide settings · guide footprint.
|
|
464
369
|
Machine plumbing (hook/launch-script callees) lives under \`spex internal\` — not part of your vocabulary.`
|
|
465
370
|
}
|