spexcode 0.2.1 → 0.2.2
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 +147 -103
- package/README.zh-CN.md +123 -88
- package/package.json +1 -1
- package/spec-cli/bin/spex.mjs +24 -1
- package/spec-cli/src/attach.ts +50 -0
- package/spec-cli/src/cli.ts +214 -62
- package/spec-cli/src/client.ts +47 -9
- package/spec-cli/src/{self.ts → doctor.ts} +26 -25
- package/spec-cli/src/guide.ts +63 -11
- package/spec-cli/src/harness.ts +48 -19
- package/spec-cli/src/help.ts +137 -49
- package/spec-cli/src/index.ts +31 -11
- package/spec-cli/src/issues.ts +48 -21
- package/spec-cli/src/layout.ts +4 -4
- package/spec-cli/src/localIssues.ts +44 -60
- package/spec-cli/src/materialize.ts +4 -2
- package/spec-cli/src/mentions.ts +22 -1
- package/spec-cli/src/pty-bridge.ts +39 -4
- package/spec-cli/src/ranker.ts +31 -12
- package/spec-cli/src/search.bench.mjs +30 -7
- package/spec-cli/src/search.ts +39 -0
- package/spec-cli/src/sessions.ts +149 -62
- package/spec-cli/src/specs.ts +16 -4
- package/spec-cli/src/supervise.ts +30 -6
- package/spec-cli/src/tree.ts +118 -0
- package/spec-cli/templates/hooks/post-merge +2 -2
- package/spec-cli/templates/hooks/pre-commit +34 -15
- package/spec-cli/templates/hooks/prepare-commit-msg +8 -1
- package/spec-dashboard/dist/assets/Dashboard-BwZ2KzxB.js +27 -0
- package/spec-dashboard/dist/assets/Dashboard-C5ap-Sga.css +1 -0
- package/spec-dashboard/dist/assets/EvalsPage-DV75EdP4.js +3 -0
- package/spec-dashboard/dist/assets/FoldToggle-GwE0-k1d.js +1 -0
- package/spec-dashboard/dist/assets/IssuesPage-B17pnl9I.js +1 -0
- package/spec-dashboard/dist/assets/MobileApp-WEZbR8M1.js +1 -0
- package/spec-dashboard/dist/assets/SessionInterface-DYP7pi_n.css +32 -0
- package/spec-dashboard/dist/assets/SessionInterface-Sh8kHpnj.js +71 -0
- package/spec-dashboard/dist/assets/SessionWindow-EzFq-hLG.js +9 -0
- package/spec-dashboard/dist/assets/Settings-Dgtg-Xb9.js +1 -0
- package/spec-dashboard/dist/assets/index-CCmnCbKS.css +1 -0
- package/spec-dashboard/dist/assets/index-Dd0_U5rk.js +41 -0
- package/spec-dashboard/dist/index.html +2 -2
- package/spec-yatsu/src/cli.ts +89 -15
- package/spec-yatsu/src/scenariofresh.ts +100 -30
- package/spec-dashboard/dist/assets/index-Ct_ubwrd.css +0 -32
- package/spec-dashboard/dist/assets/index-DehTZ-h9.js +0 -145
package/README.md
CHANGED
|
@@ -1,149 +1,193 @@
|
|
|
1
|
-
<img src="docs/sdd-tuxedo-pooh.png" alt="
|
|
1
|
+
<img src="docs/sdd-tuxedo-pooh.png" alt="tuxedo pooh meme" width="420">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# SpexCode
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Spec-driven development with AI agents in the loop. SpexCode keeps a versioned tree of specs inside
|
|
6
|
+
your git repo, links every spec to the code it governs, and runs a session manager that dispatches
|
|
7
|
+
coding agents into isolated worktrees. You review and merge; the tool keeps intent and
|
|
8
|
+
implementation from drifting apart. (All screenshots below are this very repo on its own board.)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
*spec node*: a `.spec/**/spec.md` whose body states the part's present intent. Git is the database:
|
|
11
|
-
a node's version is its count of content commits, and "drift" is governed code that moved ahead of
|
|
12
|
-
its spec. The `spex` CLI and the live dashboard read everything straight from git; there is no
|
|
13
|
-
separate store.
|
|
10
|
+
English | [中文](./README.zh-CN.md) · Docs: [spexcode.net](https://spexcode.net) · License: MIT
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
- **[Working with agents →](https://spexcode.net/working-with-agents/)** — the longer write-up on the docs site.
|
|
12
|
+
Quick links: [the model](#the-model) · [quick start](#quick-start) ·
|
|
13
|
+
[agents](#working-with-agents) · [yatsu](#measuring-behavior-yatsu) · [config](#configuration)
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
## The model
|
|
20
16
|
|
|
21
|
-
|
|
17
|
+
A spec node is a directory under `.spec/` containing a `spec.md`: frontmatter (title, status, a
|
|
18
|
+
`code:` list of the files it governs) plus a prose body stating what that part of the system is
|
|
19
|
+
supposed to do, right now. Nodes nest, so the tree mirrors how you think about the project rather
|
|
20
|
+
than the file layout. The body has two parts. The short **raw source** states the intent; changing it takes explicit
|
|
21
|
+
human approval (an agent can draft it, a human signs off). The **expanded spec** is the agent's
|
|
22
|
+
detailed reading of that intent; it iterates freely but must always match the raw source.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
way to use it is by talking to your coding agent. You describe what you want in plain language
|
|
25
|
-
(*"add a spec node for the auth flow", "extract specs for this package", "dispatch a worker to
|
|
26
|
-
implement Y"*) and the agent runs the `spex` CLI for you while you supervise on the board. The
|
|
27
|
-
manual CLI below is the substrate; your agent is the daily interface.
|
|
24
|
+
<img src="docs/readme-node.png" alt="spec node popup">
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
contract (the spec-node ritual, the commit-before-declare gate, the merge style) into a
|
|
31
|
-
`<!-- spexcode -->` managed block in your repo's `CLAUDE.md`/`AGENTS.md`, which
|
|
32
|
-
**[Claude Code](https://www.anthropic.com/claude-code)** and **Codex** auto-discover as always-on
|
|
33
|
-
context. From there the agent self-serves detail on demand from the built-in manual: `spex guide`
|
|
34
|
-
(the workflow), `spex guide spec` / `spex guide yatsu` (the file formats), and `spex guide config`
|
|
35
|
-
(every `spexcode.json` setting). You can tell it *"run `spex guide config` and set me up a
|
|
36
|
-
launcher"*.
|
|
26
|
+
Two rules make this workable:
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
1. **Git is the database.** There is no separate store. A node's version count is the number of
|
|
29
|
+
commits that touched its `spec.md`, its history view is `git log` on that file, and each version
|
|
30
|
+
is attributed to an agent session through a `Session:` commit trailer. This is also why a spec
|
|
31
|
+
body always describes present intent and gets rewritten in place: changelog headings inside the
|
|
32
|
+
body are banned (the linter enforces it), because git already keeps the history.
|
|
33
|
+
2. **Spec and code land together.** A change is one commit that updates both the `spec.md` and the
|
|
34
|
+
code it justifies. When code moves without its spec, the linter flags it,
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
```
|
|
37
|
+
drift: spec-cli/src/board.ts is 1 commit(s) ahead of spec 'board-lean' (v8) — may be stale
|
|
38
|
+
```
|
|
45
39
|
|
|
46
|
-
|
|
47
|
-
> dispatching workers onto your nodes) also needs **tmux** and an authenticated **Claude Code or
|
|
48
|
-
> Codex** on your PATH. Those agents run commands on your machine, so read
|
|
49
|
-
> [`SECURITY.md`](./docs/SECURITY.md) before exposing the backend.
|
|
40
|
+
and keeps flagging until the spec catches up.
|
|
50
41
|
|
|
51
|
-
|
|
42
|
+
## The optimization loop
|
|
52
43
|
|
|
53
|
-
|
|
44
|
+
Specs, commits, and yatsu readings compose into one loop. The spec is the loss function: it states what you want, and
|
|
45
|
+
it's the half a human signs off on. Commits are the optimizer. **yatsu**, the measurement
|
|
46
|
+
subsystem, is the eval: it scores how far live behavior currently sits from the spec, and the
|
|
47
|
+
score's history lives in git like everything else.
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
<img src="docs/readme-loop.png" alt="the spec/code optimization loop">
|
|
50
|
+
|
|
51
|
+
It also settles where the human stands day to day: nobody reads a neural net by staring at its
|
|
52
|
+
weights, and between merge gates you don't have to stare at agent diffs either. Attention goes to
|
|
53
|
+
the spec and the eval readings; the diff gets read once, at merge time.
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
`.config` plugins that define the dev flow), a starter **`spexcode.json`**, and the per-clone
|
|
63
|
-
**git hooks** (a `pre-commit` hook that runs **spec-lint**, blocking on broken spec↔code links, and
|
|
64
|
-
**main-guard**, which blocks direct commits to `main`, plus a `prepare-commit-msg` hook that stamps
|
|
65
|
-
each commit's session attribution). It also **materializes** the harness artifacts that make the
|
|
66
|
-
agent path work: the `<!-- spexcode -->` contract block in `CLAUDE.md`/`AGENTS.md`, and the
|
|
67
|
-
`.claude/` / `.codex/` shims (the `settings.json` hooks) a self-launched agent discovers. Those
|
|
68
|
-
artifacts are generated and gitignored; they are regenerated on each machine, never committed.
|
|
55
|
+
## Quick start
|
|
69
56
|
|
|
70
|
-
|
|
71
|
-
describe the project, point `spexcode.json`'s `lint.governedRoots` at your real source dir(s), and
|
|
72
|
-
check the graph:
|
|
57
|
+
Requires Node ≥ 22 and git. This part is plain tooling — no AI involved yet.
|
|
73
58
|
|
|
74
59
|
```sh
|
|
75
|
-
|
|
60
|
+
npm i -g spexcode # installs the `spex` command
|
|
61
|
+
cd your-repo
|
|
62
|
+
spex init # seeds .spec/, installs git hooks, renders the agent contract
|
|
63
|
+
spex serve # API backend on :8787
|
|
64
|
+
spex dashboard # board UI on :5173, proxying to the backend
|
|
76
65
|
```
|
|
77
66
|
|
|
78
|
-
|
|
67
|
+
`spex init` is additive. It works on any existing git repo and never overwrites your files: it
|
|
68
|
+
creates a root `.spec/project/spec.md` and a starter `spexcode.json`, installs the pre-commit
|
|
69
|
+
hooks, and writes a managed block into `CLAUDE.md`/`AGENTS.md` so any agent working in the repo
|
|
70
|
+
discovers the workflow on its own.
|
|
71
|
+
|
|
72
|
+
Then grow the tree:
|
|
73
|
+
|
|
74
|
+
1. Edit `.spec/project/spec.md` to describe the project.
|
|
75
|
+
2. Add child nodes for the parts you want governed, each with a `code:` list pointing at existing
|
|
76
|
+
files.
|
|
77
|
+
3. Run `spex lint`. Coverage warnings list the source files no spec claims yet; that list is your
|
|
78
|
+
adoption TODO.
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
You are not expected to hand-author all of this. The intended workflow is to have an agent do most
|
|
81
|
+
of the spec writing; `spex guide spec` prints the exact file format it needs.
|
|
82
|
+
[Getting started](https://spexcode.net/getting-started/) on the docs site walks the setup end to
|
|
83
|
+
end.
|
|
81
84
|
|
|
82
|
-
-
|
|
83
|
-
budgets, and launcher **names**. Facts that are true for the project.
|
|
84
|
-
- **`spexcode.local.json`** — *gitignored, host-specific*: absolute launcher command paths,
|
|
85
|
-
cert/secret paths, and the private-overlay switch (`private: true`, which makes `spex materialize`
|
|
86
|
-
leave zero trace in the tracked tree — ignores go to the local git exclude, not the committed
|
|
87
|
-
`.gitignore` — so you can run SpexCode on a repo you share but don't own). Facts that are true for
|
|
88
|
-
one machine.
|
|
85
|
+
<img src="docs/readme-board.png" alt="dashboard screenshot">
|
|
89
86
|
|
|
90
|
-
|
|
91
|
-
is the authoritative manual for every field and which of the two files it belongs in.
|
|
87
|
+
*SpexCode's own repo on its own board; the sessions top-left are agents building the tool.*
|
|
92
88
|
|
|
93
|
-
|
|
89
|
+
## Working with agents
|
|
94
90
|
|
|
95
|
-
|
|
91
|
+
This part needs tmux and a logged-in [Claude Code](https://www.anthropic.com/claude-code) or Codex
|
|
92
|
+
on the machine.
|
|
96
93
|
|
|
97
94
|
```sh
|
|
98
|
-
spex
|
|
99
|
-
spex dashboard # the board UI on :5173, proxying /api to the backend
|
|
95
|
+
spex new "make the settings page remember the last tab" --node settings
|
|
100
96
|
```
|
|
101
97
|
|
|
102
|
-
|
|
98
|
+
launches a worker session in its own worktree on branch `node/settings`. The worker reads the
|
|
99
|
+
governing spec before touching code, makes the change, rewrites the spec body to match, commits
|
|
100
|
+
both (a hook stamps the `Session:` trailer), then proposes a merge and stops. Workers never merge
|
|
101
|
+
themselves. The merge stays with the manager: when you fire it, the session's own agent runs the
|
|
102
|
+
actual `git merge`, so conflicts land on the one who knows the work. The same dispatch is a
|
|
103
|
+
button on the dashboard (the new-session box on the board); the command form is what agents
|
|
104
|
+
themselves use when they delegate.
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
you can run several projects' boards side by side; the working directory picks which project each
|
|
106
|
-
serves. Give each tab its own identity in that project's `spexcode.json`: `dashboard.title` names it
|
|
107
|
-
and `dashboard.icon` sets the favicon — an emoji (`"🔭"`), an Iconify name (`"mdi:rocket-launch"`),
|
|
108
|
-
or a URL.
|
|
106
|
+
You supervise from outside — on the board, or with the same commands your agent uses:
|
|
109
107
|
|
|
110
|
-
|
|
108
|
+
```sh
|
|
109
|
+
spex watch # stream session transitions: launched / review / done / needs-input ...
|
|
110
|
+
spex review settings # commits ahead of trunk, merge-base diff, typecheck/lint gates
|
|
111
|
+
spex merge settings # gated merge into the trunk
|
|
112
|
+
spex session close settings
|
|
113
|
+
```
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
| `spex watch` | stream session / board transitions as they happen |
|
|
116
|
-
| `spex guide` | print the full workflow, plus the `spec.md` / `yatsu.md` / `config` manuals |
|
|
117
|
-
| `spex board` | dump the current board state as JSON |
|
|
115
|
+
Independent tasks run in parallel. Each worker is isolated in its own worktree, git serializes the
|
|
116
|
+
merges, and a pre-commit guard blocks direct commits on the trunk, so everything flows through
|
|
117
|
+
reviewable node branches.
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
The process is enforced by mechanism, not prompt engineering: the backend creates the branch and a
|
|
120
|
+
hook stamps the attribution; the materialized contract block carries the rest, so your dispatch
|
|
121
|
+
prompt stays task-only. More on this mode of working:
|
|
122
|
+
[working with agents](https://spexcode.net/working-with-agents/).
|
|
120
123
|
|
|
121
|
-
##
|
|
124
|
+
## Measuring behavior: yatsu
|
|
122
125
|
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
yatsu is the measuring half of [the loop](#the-optimization-loop). A spec says what a part should do; a
|
|
127
|
+
`yatsu.md` beside it says how to check. Each scenario is a plain description plus an expected
|
|
128
|
+
result. yatsu itself runs nothing (no DSL, no runner). An agent runs the scenario however it can:
|
|
129
|
+
a test file, a real browser, or just clicking through by hand and screenshotting. It compares
|
|
130
|
+
actual to expected and files the reading with evidence:
|
|
125
131
|
|
|
126
132
|
```sh
|
|
127
|
-
|
|
128
|
-
npm --prefix spec-cli install
|
|
129
|
-
npm --prefix spec-dashboard install
|
|
130
|
-
npm run hooks # install the per-clone git hooks (main-guard + the session-stamp hook)
|
|
133
|
+
spex yatsu eval settings --scenario remembers-tab --pass --image proof.png
|
|
131
134
|
```
|
|
132
135
|
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
Readings live in a git-tracked ndjson next to the spec, so measurements get the same attribution
|
|
137
|
+
and history as spec versions. Bug fixes are expected to bracket: file a failing reading that
|
|
138
|
+
reproduces the bug, fix, then file a passing reading on the same scenario.
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
<img src="docs/readme-eval.png" alt="eval view screenshot">
|
|
141
|
+
|
|
142
|
+
*The eval view: scenario readings on the left; the selected reading's expected result, staleness,
|
|
143
|
+
and recorded video evidence in the middle.*
|
|
144
|
+
|
|
145
|
+
## What's in the repo
|
|
146
|
+
|
|
147
|
+
| Package | Role |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `spec-cli` | The `spex` CLI and the HTTP backend (Hono, runs via tsx, no build step). Reads `.spec` and git live; owns the session state machine and the linter. |
|
|
150
|
+
| `spec-dashboard` | React board: the node graph, per-node spec/history/issues panes, and a real terminal onto each live agent session. |
|
|
151
|
+
| `spec-yatsu` | Scenario definitions, readings, evidence blobs. |
|
|
152
|
+
| `spec-forge` | Read-only tracer that resolves a forge's open issues and PRs to the spec nodes they serve (GitHub today). An issue links itself with a `Spec: <node-id>` line in its body; a PR from a `node/<id>` branch links for free. |
|
|
153
|
+
|
|
154
|
+
## The linter
|
|
155
|
+
|
|
156
|
+
`spex lint` checks the spec↔code graph and is the real gate (the git hook is fast local feedback):
|
|
157
|
+
|
|
158
|
+
- **integrity** (error): a `code:` path that doesn't exist
|
|
159
|
+
- **living** (error): a changelog heading in a spec body
|
|
160
|
+
- **altitude** (warn): a body that slid from contract prose into an implementation dump. The usual
|
|
161
|
+
smell is a numbered step list or a wall of function names; this rule is why spec bodies stay
|
|
162
|
+
short enough to actually read
|
|
163
|
+
- **coverage** (warn): unclaimed source files
|
|
164
|
+
- **drift** (warn): governed code changed after its spec's last version, derived live from git
|
|
165
|
+
|
|
166
|
+
## Configuration
|
|
167
|
+
|
|
168
|
+
`spexcode.json` (committed, portable: layout, lint budgets, dashboard identity, launcher names) and
|
|
169
|
+
`spexcode.local.json` (gitignored, host-specific: absolute launcher paths, plus a `private: true`
|
|
170
|
+
overlay for repos you use but don't own) cover every setting. No `spex config set` yet: you edit the two files by hand (or ask your agent
|
|
171
|
+
to), and `spex guide config` documents every field. The other
|
|
172
|
+
manuals are `spex guide` (the workflow), `spex guide spec`, and `spex guide yatsu`; `spex help`
|
|
173
|
+
maps the commands.
|
|
174
|
+
|
|
175
|
+
## Status
|
|
140
176
|
|
|
141
|
-
|
|
177
|
+
SpexCode develops itself with itself: the `.spec/` tree in this repo is the tool's own spec, and
|
|
178
|
+
every change to the tool lands through the same worker/manager loop it implements. The dashboard
|
|
179
|
+
you install is the one it was built on. Known warts: `spex session new --help`
|
|
180
|
+
doesn't print help, it creates a session named `--help` (dispatch with `spex new`). And the
|
|
181
|
+
altitude lint currently reports forty-odd warnings against this repo's own specs; I haven't had
|
|
182
|
+
time to pay that down.
|
|
183
|
+
The first public write-up was posted on the [LINUX DO](https://linux.do) community — thanks for
|
|
184
|
+
the first round of discussion there.
|
|
142
185
|
|
|
143
|
-
##
|
|
186
|
+
## Contributing
|
|
144
187
|
|
|
145
|
-
|
|
146
|
-
|
|
188
|
+
[`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) gets you from a clone to a first merged change.
|
|
189
|
+
[`docs/AGENT_GUIDE.md`](docs/AGENT_GUIDE.md) has the full mechanics of the node model and the
|
|
190
|
+
reflexive config system.
|
|
147
191
|
|
|
148
192
|
## License
|
|
149
193
|
|
package/README.zh-CN.md
CHANGED
|
@@ -1,134 +1,169 @@
|
|
|
1
|
-
<img src="docs/sdd-tuxedo-pooh.png" alt="
|
|
1
|
+
<img src="docs/sdd-tuxedo-pooh.png" alt="tuxedo pooh 梗图" width="420">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# SpexCode
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
把 AI agent 纳入回路的 spec 驱动开发。SpexCode 在你的 git 仓库里维护一棵带版本的 spec 树,把每个
|
|
6
|
+
spec 和它管辖的代码链接起来,并运行一个会话管理器,把 coding agent 派进相互隔离的 worktree。你负责
|
|
7
|
+
review 和 merge;工具负责让意图和实现不分家。(下面所有截图都是这个仓库自己跑在自己看板上的样子。)
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
*spec 节点*,即一个 `.spec/**/spec.md`,正文描述这个部分当前的意图。git 就是数据库:节点的版本号
|
|
10
|
-
是它的内容 commit 数,"drift" 指被管辖的代码走到了 spec 前面。`spex` CLI 和实时看板直接从 git
|
|
11
|
-
读取这一切,没有第二份存储。
|
|
9
|
+
[English](./README.md) | 中文 · 文档:[spexcode.net](https://spexcode.net) · License: MIT
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- **[Working with agents →](https://spexcode.net/working-with-agents/)**:文档站上更完整的介绍。
|
|
11
|
+
快捷入口:[模型](#模型) · [快速开始](#快速开始) · [agent](#和-agent-一起工作) ·
|
|
12
|
+
[yatsu](#测量行为yatsu) · [配置](#配置)
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
## 模型
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
一个 spec 节点就是 `.spec/` 下的一个目录,里面有一个 `spec.md`:frontmatter(title、status、
|
|
17
|
+
声明管辖文件的 `code:` 清单)加一段正文,描述系统这一部分当前应该做什么。节点可以嵌套,所以这棵树
|
|
18
|
+
对应你对项目的理解方式,而不是文件布局。正文分两个部分。很短的 **raw source** 写意图,改它需要
|
|
19
|
+
人的明确认可,agent 起草、人拍板的也算;**expanded spec** 是 agent 对这个意图的详细展开,自由
|
|
20
|
+
迭代,但必须始终和 raw source 一致。
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
你的 coding agent 对话:用自然语言说你要什么(*"给鉴权流程加一个 spec 节点""把这个包的 spec
|
|
23
|
-
提取出来""派一个 worker 去实现 Y"*),agent 替你执行 `spex` CLI,你在看板上盯进度。下面的手动
|
|
24
|
-
CLI 是底座,agent 才是日常界面。
|
|
22
|
+
<img src="docs/readme-node.png" alt="节点弹窗">
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
先 commit 再声明完成、merge 方式)生成到仓库 `CLAUDE.md`/`AGENTS.md` 里的 `<!-- spexcode -->`
|
|
28
|
-
托管块中,**[Claude Code](https://www.anthropic.com/claude-code)** 和 **Codex** 启动时自动读到。
|
|
29
|
-
更细的内容 agent 自己按需查内置手册:`spex guide`(工作流)、`spex guide spec` /
|
|
30
|
-
`spex guide yatsu`(文件格式)、`spex guide config`(`spexcode.json` 的全部配置项)。你可以直接
|
|
31
|
-
对它说*"跑一下 `spex guide config`,帮我配好 launcher"*。
|
|
24
|
+
两条规则让这套东西成立:
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
1. **git 就是数据库。** 没有第二份存储。节点的版本号是碰过它 `spec.md` 的 commit 数,历史视图就是
|
|
27
|
+
这个文件的 `git log`,每一版通过 `Session:` commit trailer 归属到写它的 agent 会话。也因为这样,
|
|
28
|
+
spec 正文永远只描述当前意图、原地重写:正文里禁止出现 changelog 标题(linter 强制),历史 git
|
|
29
|
+
已经记了。
|
|
30
|
+
2. **spec 和代码一起落地。** 一次改动就是一个 commit,同时更新 `spec.md` 和它所解释的代码。代码
|
|
31
|
+
要是脱开 spec 单独动了,linter 会标出来,
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
```
|
|
34
|
+
drift: spec-cli/src/board.ts is 1 commit(s) ahead of spec 'board-lean' (v8) — may be stale
|
|
35
|
+
```
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
> 还需要 **tmux** 和 PATH 里已登录的 **Claude Code 或 Codex**。这些 agent 会在你的机器上执行
|
|
42
|
-
> 命令,对外暴露后端之前请先读 [`SECURITY.md`](./docs/SECURITY.md)。
|
|
37
|
+
一直标到 spec 跟上为止。
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
## 优化循环
|
|
45
40
|
|
|
46
|
-
|
|
41
|
+
spec、commit、yatsu 读数,这几样合起来是一个循环。spec 是损失函数:定义你要什么,这一半由人拍板。commit 是优化器。
|
|
42
|
+
**yatsu** 是测量子系统,负责评估:量出当前行为离 spec 还有多远,分数的历史照样存在 git 里。
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```
|
|
44
|
+
<img src="docs/readme-loop.zh.png" alt="优化循环示意">
|
|
45
|
+
|
|
46
|
+
它也决定了人平时站在哪:没有人靠盯权重去读神经网络,两次 merge 之间同样不必盯着 agent 的 diff。
|
|
47
|
+
注意力放在 spec 和 eval 读数上;diff 只在 merge 的时候读一次。
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
`.config` 插件)、一份起始 **`spexcode.json`**、每个 clone 各自的 **git hooks**(`pre-commit`
|
|
56
|
-
跑 **spec-lint**,spec↔code 链接坏了会拦下;**main-guard** 拦截直接向 `main` 的提交;
|
|
57
|
-
`prepare-commit-msg` 给每个 commit 盖 session 归属戳)。同时生成 agent 路径需要的产物:
|
|
58
|
-
`CLAUDE.md`/`AGENTS.md` 里的 `<!-- spexcode -->` 契约块,以及 `.claude/`、`.codex/` 的
|
|
59
|
-
settings hooks。这些产物是生成物,已被 gitignore,每台机器各自重新生成,不进版本库。
|
|
49
|
+
## 快速开始
|
|
60
50
|
|
|
61
|
-
|
|
62
|
-
`spexcode.json` 的 `lint.governedRoots` 指向真实源码目录,再检查一遍:
|
|
51
|
+
需要 Node ≥ 22 和 git。这一步是普通工具,还不涉及 AI。
|
|
63
52
|
|
|
64
53
|
```sh
|
|
65
|
-
|
|
54
|
+
npm i -g spexcode # 安装 spex 命令
|
|
55
|
+
cd your-repo
|
|
56
|
+
spex init # 生成 .spec/、安装 git hooks、渲染 agent 契约
|
|
57
|
+
spex serve # API 后端,:8787
|
|
58
|
+
spex dashboard # 看板 UI,:5173,代理到后端
|
|
66
59
|
```
|
|
67
60
|
|
|
68
|
-
|
|
61
|
+
`spex init` 是增量式的,在任何已有 git 仓库上可用,不会覆盖你的文件:生成根节点
|
|
62
|
+
`.spec/project/spec.md`、一份起始 `spexcode.json`、pre-commit hooks,并向 `CLAUDE.md`/`AGENTS.md`
|
|
63
|
+
写入一个托管块,让任何在这个仓库里工作的 agent 自己发现这套工作流。
|
|
64
|
+
|
|
65
|
+
然后把树长起来:
|
|
66
|
+
|
|
67
|
+
1. 编辑 `.spec/project/spec.md`,描述项目。
|
|
68
|
+
2. 给想管辖的部分加子节点,每个带一个指向现有文件的 `code:` 清单。
|
|
69
|
+
3. 跑 `spex lint`。coverage 警告列出还没有 spec 认领的源文件,那就是你的接入 TODO。
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
这些不需要你全部手写。预期的用法是让 agent 完成大部分 spec 写作;`spex guide spec` 会打印它需要的
|
|
72
|
+
确切文件格式。完整的安装过程见文档站的
|
|
73
|
+
[getting started](https://spexcode.net/getting-started/)。
|
|
71
74
|
|
|
72
|
-
-
|
|
73
|
-
launcher 的**名字**。对整个项目成立的事实。
|
|
74
|
-
- **`spexcode.local.json`**:gitignore,单机。launcher 命令的绝对路径、证书和密钥路径、私有覆盖
|
|
75
|
-
开关(`private: true`,让 `spex materialize` 在被跟踪的文件里不留任何痕迹,ignore 写进本地
|
|
76
|
-
git exclude 而不是提交的 `.gitignore`,适合你参与但不拥有的仓库)。只对这台机器成立的事实。
|
|
75
|
+
<img src="docs/readme-board.png" alt="看板截图">
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
**`spex guide config`** 是权威手册。
|
|
77
|
+
*SpexCode 自己的仓库跑在自己的看板上;左上角那些会话就是正在造它的 agent。*
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
## 和 agent 一起工作
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
这一步需要 tmux 和本机已登录的 [Claude Code](https://www.anthropic.com/claude-code) 或 Codex。
|
|
84
82
|
|
|
85
83
|
```sh
|
|
86
|
-
spex
|
|
87
|
-
spex dashboard # 看板 UI,:5173,/api 代理到后端
|
|
84
|
+
spex new "让设置页记住上次打开的标签" --node settings
|
|
88
85
|
```
|
|
89
86
|
|
|
90
|
-
|
|
87
|
+
会在 `node/settings` 分支的独立 worktree 里启动一个 worker 会话。worker 动代码之前先读管辖 spec,
|
|
88
|
+
做出改动,把 spec 正文改写到和实现一致,把两者一起 commit(hook 自动盖 `Session:` 戳),然后提出
|
|
89
|
+
merge 并停下。worker 不自己 merge。合并留在管理者手里:你按下 merge 时,实际的 git merge 由这个
|
|
90
|
+
会话自己的 agent 执行,冲突落在最懂这份活的人手里。同样的派工在看板网页上就是一个按钮(board 的
|
|
91
|
+
new-session 输入框);命令行形态是 agent 之间互相委派时用的。
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
多个项目的看板可以并排跑,工作目录决定各自服务哪个项目。每个标签页的身份在各自项目的
|
|
94
|
-
`spexcode.json` 里配:`dashboard.title` 定名字,`dashboard.icon` 定 favicon,emoji(`"🔭"`)、
|
|
95
|
-
Iconify 名字(`"mdi:rocket-launch"`)或 URL 都行。
|
|
93
|
+
你在外面督工,用看板,或者用 agent 也在用的这几条命令:
|
|
96
94
|
|
|
97
|
-
|
|
95
|
+
```sh
|
|
96
|
+
spex watch # 实时输出会话状态变化:launched / review / done / needs-input ...
|
|
97
|
+
spex review settings # 领先 trunk 的 commit、merge-base diff、typecheck/lint 门
|
|
98
|
+
spex merge settings # 有门禁的 merge 入 trunk
|
|
99
|
+
spex session close settings
|
|
100
|
+
```
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| `spex lint` | 检查 spec↔code 图:coverage、drift、living 规则 |
|
|
102
|
-
| `spex watch` | 实时输出 session / 看板的状态变化 |
|
|
103
|
-
| `spex guide` | 打印完整工作流,以及 `spec.md` / `yatsu.md` / `config` 手册 |
|
|
104
|
-
| `spex board` | 以 JSON 输出当前看板状态 |
|
|
102
|
+
相互独立的任务并行跑。每个 worker 隔离在自己的 worktree 里,merge 由 git 序列化,pre-commit 守卫
|
|
103
|
+
拦截对 trunk 的直接提交,所以一切都从可 review 的 node 分支流过。
|
|
105
104
|
|
|
106
|
-
|
|
105
|
+
流程靠机制强制,不靠提示词工程:后端建分支、hook 盖归属戳,其余规则由 materialize 出的契约块承载,
|
|
106
|
+
所以派工提示词只需要写任务本身。这套工作方式的长版本:
|
|
107
|
+
[working with agents](https://spexcode.net/working-with-agents/)。
|
|
107
108
|
|
|
108
|
-
##
|
|
109
|
+
## 测量行为:yatsu
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
yatsu 就是[优化循环](#优化循环)里负责测量的那一半。spec 说这部分应该做什么;旁边的 `yatsu.md` 说怎么验。每条
|
|
112
|
+
scenario 就是一段普通描述加一个期望结果。yatsu 自己什么都不跑(没有 DSL,也没有 runner)。agent
|
|
113
|
+
用顺手的方式执行场景:测试文件、真实浏览器,或者干脆手点一遍截个图。把实际结果和期望对比,连证据
|
|
114
|
+
一起把读数记档:
|
|
112
115
|
|
|
113
116
|
```sh
|
|
114
|
-
|
|
115
|
-
npm --prefix spec-cli install
|
|
116
|
-
npm --prefix spec-dashboard install
|
|
117
|
-
npm run hooks # 安装每个 clone 各自的 git hooks(main-guard + session 戳)
|
|
117
|
+
spex yatsu eval settings --scenario remembers-tab --pass --image proof.png
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
读数存在 spec 旁边一个 git 跟踪的 ndjson 里,所以测量和 spec 版本享有同样的归属和历史。修 bug 要求
|
|
121
|
+
成对:先记一条复现 bug 的 fail 读数,修掉,再在同一条 scenario 上记一条 pass。
|
|
121
122
|
|
|
122
|
-
|
|
123
|
-
npm run api # 后端 :8787,spec-cli/src 改动即热重载
|
|
124
|
-
npm run web # Vite 起看板(HMR),/api 代理到 :8787
|
|
125
|
-
```
|
|
123
|
+
<img src="docs/readme-eval.png" alt="eval 视图截图">
|
|
126
124
|
|
|
127
|
-
|
|
125
|
+
*eval 视图:左侧是各 scenario 的读数;中间是选中读数的期望结果、过期原因和录屏证据。*
|
|
128
126
|
|
|
129
|
-
##
|
|
127
|
+
## 仓库里有什么
|
|
128
|
+
|
|
129
|
+
| 包 | 职责 |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `spec-cli` | `spex` CLI 和 HTTP 后端(Hono,tsx 直跑,无构建步骤)。实时读 `.spec` 和 git;会话状态机和 linter 都在这里。 |
|
|
132
|
+
| `spec-dashboard` | React 看板:节点图、每个节点的 spec/history/issues 面板,以及连到每个活跃 agent 会话的真终端。 |
|
|
133
|
+
| `spec-yatsu` | scenario 定义、读数、证据文件。 |
|
|
134
|
+
| `spec-forge` | 只读追踪器,把 forge 上的 open issue 和 PR 解析到它们服务的 spec 节点(目前支持 GitHub)。issue 在正文里写一行 `Spec: <node-id>` 即完成链接;从 `node/<id>` 分支开的 PR 自动链接。 |
|
|
135
|
+
|
|
136
|
+
## linter
|
|
137
|
+
|
|
138
|
+
`spex lint` 检查 spec↔code 图,它才是真正的门(git hook 只是快速的本地反馈):
|
|
139
|
+
|
|
140
|
+
- **integrity**(error):`code:` 指向不存在的路径
|
|
141
|
+
- **living**(error):spec 正文里出现 changelog 标题
|
|
142
|
+
- **altitude**(warn):正文从契约层滑落成实现细节堆。常见的味道是一串编号步骤,或者满屏函数名;
|
|
143
|
+
spec 正文还能读得下去,靠的就是这条
|
|
144
|
+
- **coverage**(warn):没被认领的源文件
|
|
145
|
+
- **drift**(warn):被管辖的代码在 spec 最后一版之后又改了,实时从 git 推导
|
|
146
|
+
|
|
147
|
+
## 配置
|
|
148
|
+
|
|
149
|
+
`spexcode.json`(提交进仓库,可移植:布局、lint 预算、看板标识、launcher 名字)和
|
|
150
|
+
`spexcode.local.json`(gitignore,单机:launcher 绝对路径,以及给你参与但不拥有的仓库用的
|
|
151
|
+
`private: true` 覆盖)承载全部设置。暂时没有 `spex config set`:两个文件直接手改(或让 agent 改),每个字段的文档在
|
|
152
|
+
`spex guide config`。其他手册:`spex guide`(工作流)、`spex guide spec`、
|
|
153
|
+
`spex guide yatsu`;`spex help` 列出全部命令。
|
|
154
|
+
|
|
155
|
+
## 现状
|
|
156
|
+
|
|
157
|
+
SpexCode 用它自己开发自己:这个仓库的 `.spec/` 树就是工具自身的 spec,对工具的每个改动都走它
|
|
158
|
+
自己实现的那套 worker/manager 循环落地。你装到的看板就是造它用的那块。已知的坑:`spex session new --help`
|
|
159
|
+
不会打印帮助,而是真的创建一个叫 `--help` 的会话(派工请用 `spex new`)。另外 altitude lint 现在
|
|
160
|
+
对这个仓库自己的 spec 报着四十多条警告,我还没腾出手来清。首次公开介绍发在
|
|
161
|
+
[LINUX DO](https://linux.do) 社区,感谢佬友们的第一轮讨论。
|
|
162
|
+
|
|
163
|
+
## 参与开发
|
|
130
164
|
|
|
131
|
-
|
|
165
|
+
[`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) 带你从 clone 到第一个合入的改动。
|
|
166
|
+
[`docs/AGENT_GUIDE.md`](docs/AGENT_GUIDE.md) 有节点模型和反身配置系统的完整机制。
|
|
132
167
|
|
|
133
168
|
## License
|
|
134
169
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spexcode",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SpexCode — a spec-driven, self-developing dev tool. The `spex` CLI + spec server reads the .spec tree and its git history, and serves the dashboard.",
|
|
6
6
|
"license": "MIT",
|
package/spec-cli/bin/spex.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @@@ spex launcher - this repo has no build step, so the installed `spex` bin shells to tsx to
|
|
3
3
|
// run the TypeScript CLI directly. After `npm link` (or a global install) `spex lint` works anywhere.
|
|
4
4
|
import { spawn } from 'node:child_process'
|
|
5
|
-
import { existsSync } from 'node:fs'
|
|
5
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
6
6
|
import { createRequire } from 'node:module'
|
|
7
7
|
import { fileURLToPath } from 'node:url'
|
|
8
8
|
import { dirname, join } from 'node:path'
|
|
@@ -12,6 +12,29 @@ import { dirname, join } from 'node:path'
|
|
|
12
12
|
// `spex` work from any cwd (agents, git hooks) against this package's code, operating on the cwd.
|
|
13
13
|
const pkg = join(dirname(fileURLToPath(import.meta.url)), '..') // spec-cli/
|
|
14
14
|
const cli = join(pkg, 'src', 'cli.ts')
|
|
15
|
+
|
|
16
|
+
// @@@ mid-merge guard - no build step means every spex call parses this package's live TypeScript, so
|
|
17
|
+
// while a merge conflict is being resolved in the checkout that hosts it, the source holds conflict
|
|
18
|
+
// markers and tsx dies with a raw esbuild stacktrace — on EVERY call, including the Stop hook and an
|
|
19
|
+
// agent's `spex session done`. Catch that one transient state up front: scan the source trees the CLI
|
|
20
|
+
// imports (spec-cli ←→ spec-yatsu ←→ spec-forge), and if any file carries a marker, print one actionable
|
|
21
|
+
// line and exit 75 (EX_TEMPFAIL: transient, retry) instead of spawning tsx into the stacktrace.
|
|
22
|
+
const srcRoots = [join(pkg, 'src'), join(pkg, '..', 'spec-yatsu', 'src'), join(pkg, '..', 'spec-forge', 'src')]
|
|
23
|
+
const conflicted = srcRoots.flatMap((root) => {
|
|
24
|
+
if (!existsSync(root)) return []
|
|
25
|
+
return readdirSync(root, { recursive: true })
|
|
26
|
+
.filter((f) => /\.(ts|tsx|js|mjs)$/.test(String(f)))
|
|
27
|
+
.map((f) => join(root, String(f)))
|
|
28
|
+
.filter((path) => {
|
|
29
|
+
try { return /^<{7} /m.test(readFileSync(path, 'utf8')) } catch { return false }
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
if (conflicted.length) {
|
|
33
|
+
console.error('spex: paused mid-merge — unresolved conflict markers in the source spex runs:')
|
|
34
|
+
for (const f of conflicted) console.error(` ${f}`)
|
|
35
|
+
console.error('spex executes this TypeScript directly (no build step); resolve the merge, then retry. (exit 75)')
|
|
36
|
+
process.exit(75)
|
|
37
|
+
}
|
|
15
38
|
// tsx lives in spec-cli/node_modules in the dev monorepo, but npm may hoist it above the installed
|
|
16
39
|
// `spexcode` package in a real consumer project. Try local candidates first, then let Node resolve upward
|
|
17
40
|
// from spec-cli so project-local and global installs work the same way.
|