@luizsantiago/spec-guardrails 4.1.0 → 4.2.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 +195 -78
- package/index.js +6 -0
- package/lib/cursor-hooks.js +115 -0
- package/lib/install.js +10 -2
- package/package.json +2 -2
- package/skills/agent-architecture.md +13 -2
- package/skills/references/elicitation.md +12 -0
- package/templates/GETTING_STARTED.md +5 -3
- package/templates/config.yaml.example +7 -1
package/README.md
CHANGED
|
@@ -5,100 +5,218 @@
|
|
|
5
5
|
|
|
6
6
|
**Governed spec-driven development for AI coding agents.**
|
|
7
7
|
|
|
8
|
-
Spec Guardrails
|
|
8
|
+
Spec Guardrails installs a working method into your repository: the agent writes down what it is going to build, gets your approval, implements in small waves, and proves the result before calling it done. Nothing about your stack changes — you get written requirements, a task plan, and verification evidence stored as files in the project.
|
|
9
9
|
|
|
10
|
-
npm: [`@luizsantiago/spec-guardrails`](https://www.npmjs.com/package/@luizsantiago/spec-guardrails) **4.
|
|
10
|
+
npm: [`@luizsantiago/spec-guardrails`](https://www.npmjs.com/package/@luizsantiago/spec-guardrails) **4.2.x**
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
## What
|
|
14
|
+
## What changes in practice
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| Layer | Role |
|
|
16
|
+
| Without it | With Spec Guardrails |
|
|
19
17
|
| --- | --- |
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
18
|
+
| The agent jumps straight to code and says "done" | Requirements are written and approved first, and "done" needs evidence |
|
|
19
|
+
| Each new chat starts from zero | Specs, decisions, and state live in `.specs/` and survive the session |
|
|
20
|
+
| Small fixes and risky features get the same treatment | The agent measures complexity and applies only the depth the change needs |
|
|
21
|
+
| The whole playbook is pasted into every message | One phase guide is loaded per turn, which keeps cost and focus under control |
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
You stay in charge of scope: the agent proposes, you approve specs, task plans, and anything that touches git beyond local commits.
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
Read more: [Overview](docs/guide/Overview.md) · [How it works](docs/guide/How-it-works.md) · [Concepts](docs/guide/concepts.md)
|
|
27
26
|
|
|
28
27
|
---
|
|
29
28
|
|
|
30
|
-
##
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
Run once in your project root:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @luizsantiago/spec-guardrails install
|
|
35
|
+
npx @luizsantiago/spec-guardrails doctor
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`install` writes the phase guides for your agent and creates the `.specs/` folder. Re-run it after upgrading the package — your existing `.specs/` notes are preserved. After that, you work in **agent chat**, not in the terminal; the agent calls the CLI and checks when needed.
|
|
31
39
|
|
|
32
|
-
|
|
|
40
|
+
| Requirement | Role |
|
|
33
41
|
| --- | --- |
|
|
34
|
-
| **
|
|
35
|
-
| **
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
| **Node.js 18+** | Required — the CLI and the install step |
|
|
43
|
+
| **Python 3.10+** | Optional — turns on automatic proof at each step |
|
|
44
|
+
|
|
45
|
+
### Do you need Python?
|
|
46
|
+
|
|
47
|
+
**Node alone is enough to use everything** — every phase, every document, every approval point. The full process runs the same way.
|
|
48
|
+
|
|
49
|
+
The difference is who decides whether a step is really finished:
|
|
50
|
+
|
|
51
|
+
- **Without Python** — the agent checks its own work by reading the phase checklist. It works, but you are trusting the agent to be honest when it is eager to move on.
|
|
52
|
+
- **With Python** — the same checks run automatically, and the agent **cannot advance** with half-done work: saying "done" without test evidence, writing a task that matches no requirement, or closing a step with an open question all stop the process until fixed.
|
|
40
53
|
|
|
41
|
-
|
|
54
|
+
In short: Python turns "trust the agent" into "the agent has to prove it."
|
|
55
|
+
|
|
56
|
+
Which checks exist and what each one requires: [Gates](docs/guide/gates.md) · [Guarantees matrix](docs/guide/Guarantees-matrix.md)
|
|
57
|
+
|
|
58
|
+
Read more: [Quick start](docs/guide/Quick-start.md) · [Platform parity](docs/guide/Platform-parity.md) · [CHANGELOG](docs/CHANGELOG.md)
|
|
42
59
|
|
|
43
60
|
---
|
|
44
61
|
|
|
45
|
-
##
|
|
62
|
+
## How you use it day to day
|
|
46
63
|
|
|
47
|
-
|
|
64
|
+
You describe your project or the feature you want — in chat, or by pointing the agent at a file such as `prd.md` or `docs/brief.md`. With Spec Guardrails already installed, the agent reads that material plus what is already in the repo and picks up from there if work is in progress (`STATE.md` tells it where you left off).
|
|
48
65
|
|
|
49
|
-
```
|
|
50
|
-
|
|
66
|
+
```
|
|
67
|
+
YOU describe the project or feature
|
|
68
|
+
(chat, prd.md, docs/brief.md, kickoff paste)
|
|
69
|
+
│
|
|
70
|
+
▼
|
|
71
|
+
┌──────────────────────┐
|
|
72
|
+
│ READ & CLASSIFY │ Agent reads your inputs and the repo,
|
|
73
|
+
│ │ then sizes the change (see table below).
|
|
74
|
+
└──────────┬───────────┘
|
|
75
|
+
│
|
|
76
|
+
Still vague? ──► Requirements analysis (optional)
|
|
77
|
+
│ Up to 5 questions per round, one topic at a time,
|
|
78
|
+
│ with suggested options — never repeats what your
|
|
79
|
+
│ document already answered.
|
|
80
|
+
▼
|
|
81
|
+
┌──────────────────────┐
|
|
82
|
+
│ REQUIREMENTS BRIEF │ Captured gaps and decisions in writing.
|
|
83
|
+
└──────────┬───────────┘
|
|
84
|
+
│
|
|
85
|
+
◆ YOU APPROVE ◆ (1 of 3 — when elicitation ran)
|
|
86
|
+
│
|
|
87
|
+
▼
|
|
88
|
+
┌──────────────────────┐
|
|
89
|
+
│ SPECIFY │ What must happen, what "done" means,
|
|
90
|
+
│ │ what is out of scope → spec.md
|
|
91
|
+
└──────────┬───────────┘
|
|
92
|
+
│
|
|
93
|
+
◆ YOU APPROVE ◆ (2 of 3)
|
|
94
|
+
│
|
|
95
|
+
▼
|
|
96
|
+
┌──────────────────────┐
|
|
97
|
+
│ TASKS │ Small checkable jobs → tasks.md
|
|
98
|
+
│ │ (+ task-graph.md when work can split)
|
|
99
|
+
└──────────┬───────────┘
|
|
100
|
+
│
|
|
101
|
+
◆ YOU APPROVE ◆ (3 of 3)
|
|
102
|
+
│
|
|
103
|
+
▼
|
|
104
|
+
┌──────────────────────┐
|
|
105
|
+
│ BUILD (loop) │ One wave at a time: test, implement,
|
|
106
|
+
│ ↺ │ check, commit — repeat until done.
|
|
107
|
+
└──────────┬───────────┘
|
|
108
|
+
▼
|
|
109
|
+
┌──────────────────────┐
|
|
110
|
+
│ VERIFY │ Independent review with proof → validation.md
|
|
111
|
+
└──────────┬───────────┘
|
|
112
|
+
▼
|
|
113
|
+
┌──────────────────────┐
|
|
114
|
+
│ ARCHIVE │ Fold outcome into project memory.
|
|
115
|
+
└──────────────────────┘
|
|
116
|
+
|
|
117
|
+
Tiny fix (≤3 files, no new dependency)?
|
|
118
|
+
Express lane: build → verify → commit (no spec/tasks ceremony).
|
|
51
119
|
```
|
|
52
120
|
|
|
53
|
-
|
|
121
|
+
The agent never skips your approvals on the full path. Requirements analysis is **suggested**, not forced — if the request is already clear, it goes straight to Specify.
|
|
54
122
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
123
|
+
Read more: [How it works](docs/guide/How-it-works.md) · [Agent commands](docs/guide/agent-commands.md)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## How it sizes the work
|
|
128
|
+
|
|
129
|
+
Before starting, the agent classifies the change and loads only what that change needs. A typo does not get a task graph; a payments integration does not skip review.
|
|
130
|
+
|
|
131
|
+
| Complexity | Typical scope | What gets created | Your approvals |
|
|
132
|
+
| --- | --- | --- | --- |
|
|
133
|
+
| **Quick** | ≤3 files, no new dependency, no auth/payments | Code + quick evidence | None (express lane) |
|
|
134
|
+
| **Simple** | Small localized change, 2–5 files | `spec.md` → code → `validation.md` | Spec |
|
|
135
|
+
| **Medium** | Real feature, under ~10 jobs | `spec.md`, `tasks.md` → code → `validation.md` → archive | Spec + tasks |
|
|
136
|
+
| **Complex** | New APIs, architecture, infrastructure | Above + `design.md`, option discussion | Spec + tasks (+ design when used) |
|
|
137
|
+
| **Parallel** | Work safely splittable across agents | Above + `task-graph.md` | Spec + tasks |
|
|
59
138
|
|
|
60
|
-
|
|
139
|
+
This is also why sessions stay affordable: the agent loads one short guide per step instead of the entire playbook.
|
|
140
|
+
|
|
141
|
+
Read more: [Complexity tiers](docs/guide/concepts.md#complexity-tiers--how-the-agent-chooses-depth) · [Token efficiency](docs/guide/Token-efficiency.md)
|
|
61
142
|
|
|
62
143
|
---
|
|
63
144
|
|
|
64
|
-
##
|
|
145
|
+
## What is inside the kit
|
|
146
|
+
|
|
147
|
+
Each block names what ships in the package, how many pieces there are, and what you get from it. Technical detail lives in the linked guides.
|
|
65
148
|
|
|
66
|
-
|
|
149
|
+
### Artifacts (12)
|
|
67
150
|
|
|
68
|
-
|
|
151
|
+
Plain markdown in `.specs/` — the paper trail that survives the chat and reviews like code in git.
|
|
69
152
|
|
|
70
|
-
|
|
|
153
|
+
| File | What it holds |
|
|
71
154
|
| --- | --- |
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
155
|
+
| `STATE.md` | Active feature, current phase, next step |
|
|
156
|
+
| `requirements-brief.md` | Answers from requirements analysis, signed off by you |
|
|
157
|
+
| `spec.md` | Requirements, acceptance criteria, out of scope |
|
|
158
|
+
| `exploration.md` | Compared solution options (when used) |
|
|
159
|
+
| `design.md` | Technical approach and decisions (when used) |
|
|
160
|
+
| `tasks.md` | Checkable jobs with file ownership |
|
|
161
|
+
| `task-graph.md` | Which jobs can run in parallel (when used) |
|
|
162
|
+
| `validation.md` | Independent verify verdict and proof |
|
|
163
|
+
| `project/PROJECT.md` | Long-lived repo map |
|
|
164
|
+
| `project/ROADMAP.md` | Planned and delivered features |
|
|
165
|
+
| `domains/<slug>/spec.md` | Consolidated domain knowledge after archive |
|
|
166
|
+
| `lessons.json` | Rules learned from past failures |
|
|
79
167
|
|
|
80
|
-
|
|
168
|
+
→ [Architecture](docs/guide/Architecture.md)
|
|
81
169
|
|
|
82
|
-
|
|
170
|
+
### Skills (1 hub + 19 phase guides + 8 specialists)
|
|
83
171
|
|
|
84
|
-
|
|
172
|
+
Instructions the agent loads **one at a time** — hub `agent-architecture.md` (router + contract), phase guides such as `specify.md`, `tasks.md`, `implement.md`, `validate.md`, and specialists such as `appsec.md`, `qa-strategy.md`, `security-review.md` when the work needs them.
|
|
85
173
|
|
|
86
|
-
|
|
174
|
+
→ [Skills and hub](docs/guide/skills-and-hub.md)
|
|
87
175
|
|
|
88
|
-
|
|
176
|
+
### Gates (9)
|
|
89
177
|
|
|
90
|
-
|
|
178
|
+
Automatic checks at step boundaries — each one blocks a specific kind of shortcut:
|
|
179
|
+
|
|
180
|
+
| Gate | Stops the agent when… |
|
|
91
181
|
| --- | --- |
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
182
|
+
| `validate-req-analysis` | Requirements brief has open questions or no owner approval |
|
|
183
|
+
| `validate-spec` | Spec has no testable acceptance criteria |
|
|
184
|
+
| `analyze-artifacts` | A requirement has no matching task |
|
|
185
|
+
| `validate-tasks` | Tasks are vague or file ownership conflicts |
|
|
186
|
+
| `validate-traceability` | REQ → task → proof chain is broken |
|
|
187
|
+
| `validate-state` | Feature is declared done without evidence |
|
|
188
|
+
| `validate-quick` | Quick-mode fix broke its size or shape rules |
|
|
189
|
+
| `check-commit` | Commit message does not follow the agreed format |
|
|
190
|
+
| `lessons` | A failed verify tries to skip the lesson step |
|
|
191
|
+
|
|
192
|
+
→ [Gates](docs/guide/gates.md) · [Garantees matrix](docs/guide/Guarantees-matrix.md)
|
|
193
|
+
|
|
194
|
+
### Requirements analysis
|
|
195
|
+
|
|
196
|
+
When the request is still fuzzy, the agent asks a **few targeted questions** — at most five per round, one topic at a time, always with suggested options — and never re-asks what your document already answered. You approve the brief before Specify starts.
|
|
197
|
+
|
|
198
|
+
→ [Requirements analysis](docs/guide/requirements-analysis.md)
|
|
100
199
|
|
|
101
|
-
|
|
200
|
+
### Loops
|
|
201
|
+
|
|
202
|
+
Implementation happens in **small waves**: pick the next runnable jobs, test, implement, check, commit, repeat. Parallel work only when two jobs touch different files; if tests fail, the agent retries a bounded number of times before escalating to you.
|
|
203
|
+
|
|
204
|
+
→ [Loop patterns](docs/guide/loop-patterns.md)
|
|
205
|
+
|
|
206
|
+
### Memory (6 commands)
|
|
207
|
+
|
|
208
|
+
`memory-index`, `memory-search`, `memory-query`, `memory-retrieve`, `episodes`, and `code-index` — so a new session or teammate can ask "what did we decide about session timeout?" without you re-explaining. Lessons from verify failures feed back into future runs.
|
|
209
|
+
|
|
210
|
+
→ [Memory](docs/guide/Memory.md) · [Brownfield context](docs/guide/brownfield-context.md)
|
|
211
|
+
|
|
212
|
+
### Optional — off by default
|
|
213
|
+
|
|
214
|
+
| Capability | What it adds |
|
|
215
|
+
| --- | --- |
|
|
216
|
+
| **Cursor IDE hooks** | Scope check before file edits and shell-command policy on Cursor — disabled by default; requirements analysis can ask if you want them; you can also enable or disable anytime in chat |
|
|
217
|
+
| **Semantic memory search** | Find past specs and decisions by meaning, not just keywords |
|
|
218
|
+
|
|
219
|
+
→ [Cursor hooks and sandbox](docs/guide/Cursor-hooks-and-sandbox.md) · [Memory](docs/guide/Memory.md)
|
|
102
220
|
|
|
103
221
|
---
|
|
104
222
|
|
|
@@ -109,25 +227,22 @@ Guides: [Memory](docs/guide/Memory.md) · [Cursor hooks and sandbox](docs/guide/
|
|
|
109
227
|
| `.cursor/skills/` (+ Claude, Copilot, Codex trees) | Phase instructions for the agent |
|
|
110
228
|
| `.specs/STATE.md` | Active feature and next step |
|
|
111
229
|
| `.specs/features/NNN-slug/` | Spec, tasks, and validation per feature |
|
|
112
|
-
| `.specs/guardrails/scripts/` | Python
|
|
230
|
+
| `.specs/guardrails/scripts/` | Python checks (when Brakes mode is on) |
|
|
113
231
|
| `.specs/config.yaml` | Optional project rules and execution policy |
|
|
114
232
|
|
|
115
|
-
Architecture: [Skills and hub](docs/guide/skills-and-hub.md) · [Architecture](docs/guide/Architecture.md)
|
|
116
|
-
|
|
117
233
|
---
|
|
118
234
|
|
|
119
235
|
## Documentation
|
|
120
236
|
|
|
121
|
-
Start with the guide that matches your question; each page links deeper where needed.
|
|
122
|
-
|
|
123
237
|
| Topic | Start here | Go deeper |
|
|
124
238
|
| --- | --- | --- |
|
|
125
239
|
| Orientation | [Overview](docs/guide/Overview.md) | [Concepts](docs/guide/concepts.md) |
|
|
126
240
|
| First session | [Quick start](docs/guide/Quick-start.md) | [Agent commands](docs/guide/agent-commands.md) |
|
|
127
|
-
| Cursor IDE protection | [Cursor hooks and sandbox](docs/guide/Cursor-hooks-and-sandbox.md) | [Guarantees matrix](docs/guide/Guarantees-matrix.md) |
|
|
128
241
|
| Process model | [How it works](docs/guide/How-it-works.md) | [Loop patterns](docs/guide/loop-patterns.md) |
|
|
129
242
|
| Enforcement | [Gates](docs/guide/gates.md) | [Gates and guarantees](docs/guide/Gates-and-guarantees.md) |
|
|
243
|
+
| Requirements | [Requirements analysis](docs/guide/requirements-analysis.md) | [Agent commands → /elicit](docs/guide/agent-commands.md) |
|
|
130
244
|
| Long-running projects | [Memory](docs/guide/Memory.md) | [Brownfield context](docs/guide/brownfield-context.md) |
|
|
245
|
+
| Cursor IDE (optional) | [Cursor hooks and sandbox](docs/guide/Cursor-hooks-and-sandbox.md) | [Guarantees matrix](docs/guide/Guarantees-matrix.md) |
|
|
131
246
|
| Questions | [FAQ](docs/guide/FAQ.md) | [Stability policy](docs/guide/Stability-policy.md) |
|
|
132
247
|
|
|
133
248
|
Full index: [docs/guide/README.md](docs/guide/README.md)
|
|
@@ -136,22 +251,18 @@ Full index: [docs/guide/README.md](docs/guide/README.md)
|
|
|
136
251
|
|
|
137
252
|
## Contributing
|
|
138
253
|
|
|
139
|
-
|
|
254
|
+
Focused improvements to skills, gates, CLI, docs, and tests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for repository layout, gate stability rules, and local checks.
|
|
140
255
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
The recommended workflow is to **dogfood the product**: install Spec Guardrails, describe your change through the agent phases, implement against approved artifacts, and verify before opening a PR.
|
|
144
|
-
|
|
145
|
-
**In your own project or fork** — use the latest stable release from npm:
|
|
256
|
+
**Build your contribution with Spec Guardrails.** In your own project or fork, install the latest stable release and let the phases guide the change:
|
|
146
257
|
|
|
147
258
|
```bash
|
|
148
259
|
npx @luizsantiago/spec-guardrails@latest install
|
|
149
260
|
npx @luizsantiago/spec-guardrails doctor
|
|
150
261
|
```
|
|
151
262
|
|
|
152
|
-
|
|
263
|
+
Describe the change in chat, approve the spec and the task plan, implement, and verify before opening the pull request — the resulting `.specs/` folder is the evidence that supports your PR.
|
|
153
264
|
|
|
154
|
-
**In this source repository
|
|
265
|
+
**In this source repository**, work against your branch instead of the published package:
|
|
155
266
|
|
|
156
267
|
```bash
|
|
157
268
|
git clone https://github.com/luizssantiago92/spec-guardrails.git
|
|
@@ -161,16 +272,22 @@ npm run guardrails -- install
|
|
|
161
272
|
npm run guardrails -- doctor
|
|
162
273
|
```
|
|
163
274
|
|
|
164
|
-
Edit
|
|
275
|
+
Edit sources under `skills/`, `lib/`, `scripts/`, and `rules/`; re-run `npm run guardrails -- install` after changing shipped assets, and run `npm test` before every PR.
|
|
165
276
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Credits
|
|
280
|
+
|
|
281
|
+
Spec Guardrails adapts patterns from open-source work. These are the projects whose ideas are actually shipped in the package:
|
|
282
|
+
|
|
283
|
+
| Project | License | Used for |
|
|
284
|
+
| --- | --- | --- |
|
|
285
|
+
| [tlc-spec-driven](https://github.com/tech-leads-club/agent-skills/tree/main/packages/skills-catalog/skills/(development)/tlc-spec-driven) | CC-BY-4.0 | Spec → tasks → execute → verify model, `.specs/` layout, gate philosophy |
|
|
286
|
+
| [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) | MIT | Design-discussion patterns and definition-of-done framing |
|
|
287
|
+
| [graph-engineering](https://github.com/codejunkie99/graph-engineering) | MIT | Task-graph rules behind safe parallel waves |
|
|
288
|
+
| [loop-engineering](https://github.com/cobusgreyling/loop-engineering) | MIT | Wave-based execution model |
|
|
172
289
|
|
|
173
|
-
|
|
290
|
+
Everything else — the CLI, the Python checks, the platform adapters, and the requirements-analysis phase — is original work in this repository. Full lineage, including references we cite but do not bundle: [Credits and lineage](docs/guide/credits.md).
|
|
174
291
|
|
|
175
292
|
---
|
|
176
293
|
|
package/index.js
CHANGED
|
@@ -67,6 +67,8 @@ Commands:
|
|
|
67
67
|
install Install skills, references, gates and .specs/ memory
|
|
68
68
|
[--preset <name>] Seed .specs/config.yaml from a built-in preset
|
|
69
69
|
[--force-config] Replace existing config.yaml when using --preset
|
|
70
|
+
[--with-cursor-hooks] Register Cursor IDE hooks (off by default)
|
|
71
|
+
[--without-cursor-hooks] Remove shipped Cursor hooks and set cursor.hooks: false
|
|
70
72
|
init-config [--preset <name>] Create .specs/config.yaml (default preset: default)
|
|
71
73
|
[--force] Replace existing config.yaml
|
|
72
74
|
preset list List built-in config presets
|
|
@@ -202,6 +204,10 @@ if (command === "--version" || command === "-v" || command === "version") {
|
|
|
202
204
|
}
|
|
203
205
|
} else if (arg === "--force-config") {
|
|
204
206
|
installOptions.forceConfig = true;
|
|
207
|
+
} else if (arg === "--with-cursor-hooks") {
|
|
208
|
+
installOptions.withCursorHooks = true;
|
|
209
|
+
} else if (arg === "--without-cursor-hooks") {
|
|
210
|
+
installOptions.withoutCursorHooks = true;
|
|
205
211
|
} else {
|
|
206
212
|
throw new Error(`Unknown install flag: ${arg}`);
|
|
207
213
|
}
|
package/lib/cursor-hooks.js
CHANGED
|
@@ -107,3 +107,118 @@ export async function installCursorHooks(cwd, options = {}) {
|
|
|
107
107
|
await fs.writeFile(hooksJsonPath, `${JSON.stringify(merged, null, 2)}\n`, "utf8");
|
|
108
108
|
log(`✅ Cursor hooks → ${CURSOR_HOOKS_JSON} (context-guard + sandbox shell checks)`);
|
|
109
109
|
}
|
|
110
|
+
|
|
111
|
+
/** @type {Set<string>} */
|
|
112
|
+
const SHIPPED_HOOK_COMMANDS = new Set(CURSOR_HOOK_SCRIPTS.map((script) => script.dest));
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Read `cursor.hooks` from `.specs/config.yaml` (default false).
|
|
116
|
+
*
|
|
117
|
+
* @param {string} text
|
|
118
|
+
* @returns {boolean}
|
|
119
|
+
*/
|
|
120
|
+
export function parseCursorHooksFromConfigText(text) {
|
|
121
|
+
const cursorBlock = text.match(/^cursor:\s*\n(?:[ \t#].*\n)*/m);
|
|
122
|
+
if (!cursorBlock) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const hooksLine = cursorBlock[0].match(/^\s+hooks:\s*(true|false)\s*(?:#.*)?$/m);
|
|
126
|
+
return hooksLine?.[1] === "true";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @param {string} cwd
|
|
131
|
+
* @returns {Promise<boolean>}
|
|
132
|
+
*/
|
|
133
|
+
export async function readCursorHooksEnabled(cwd) {
|
|
134
|
+
try {
|
|
135
|
+
const text = await readFileSafe(path.join(cwd, ".specs/config.yaml"));
|
|
136
|
+
return parseCursorHooksFromConfigText(text);
|
|
137
|
+
} catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Persist `cursor.hooks` in `.specs/config.yaml` when the file exists.
|
|
144
|
+
*
|
|
145
|
+
* @param {string} cwd
|
|
146
|
+
* @param {boolean} enabled
|
|
147
|
+
* @returns {Promise<boolean>}
|
|
148
|
+
*/
|
|
149
|
+
export async function writeCursorHooksInConfig(cwd, enabled) {
|
|
150
|
+
const configPath = path.join(cwd, ".specs/config.yaml");
|
|
151
|
+
let text;
|
|
152
|
+
try {
|
|
153
|
+
text = await readFileSafe(configPath);
|
|
154
|
+
} catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const cursorBlock = `cursor:\n hooks: ${enabled ? "true" : "false"}\n`;
|
|
159
|
+
|
|
160
|
+
if (/^cursor:/m.test(text)) {
|
|
161
|
+
text = text.replace(/^cursor:\s*\n(?:[ \t#].*\n)*/m, cursorBlock);
|
|
162
|
+
} else {
|
|
163
|
+
text = `${text.replace(/\s+$/, "")}\n\n${cursorBlock}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
await fs.writeFile(configPath, text, "utf8");
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Resolve whether install should register Cursor hooks.
|
|
172
|
+
*
|
|
173
|
+
* @param {string} cwd
|
|
174
|
+
* @param {{ withCursorHooks?: boolean, withoutCursorHooks?: boolean }} [options]
|
|
175
|
+
* @returns {Promise<boolean>}
|
|
176
|
+
*/
|
|
177
|
+
export async function resolveCursorHooksInstall(cwd, options = {}) {
|
|
178
|
+
if (options.withCursorHooks === true) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
if (options.withoutCursorHooks === true || options.withCursorHooks === false) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
return readCursorHooksEnabled(cwd);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Remove shipped hook entries and scripts; persist `cursor.hooks: false`.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} cwd
|
|
191
|
+
* @param {{ log?: (message: string) => void }} [options]
|
|
192
|
+
*/
|
|
193
|
+
export async function removeCursorHooks(cwd, options = {}) {
|
|
194
|
+
const log = options.log ?? (() => {});
|
|
195
|
+
const hooksJsonPath = path.join(cwd, CURSOR_HOOKS_JSON);
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const existing = JSON.parse(await readFileSafe(hooksJsonPath));
|
|
199
|
+
if (existing.hooks && typeof existing.hooks === "object") {
|
|
200
|
+
for (const [event, entries] of Object.entries(existing.hooks)) {
|
|
201
|
+
if (!Array.isArray(entries)) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
existing.hooks[event] = entries.filter(
|
|
205
|
+
(entry) => !SHIPPED_HOOK_COMMANDS.has(/** @type {{ command?: string }} */ (entry).command),
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
await fs.writeFile(hooksJsonPath, `${JSON.stringify(existing, null, 2)}\n`, "utf8");
|
|
209
|
+
}
|
|
210
|
+
} catch {
|
|
211
|
+
// hooks.json missing or invalid — still remove scripts below
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
for (const script of CURSOR_HOOK_SCRIPTS) {
|
|
215
|
+
try {
|
|
216
|
+
await fs.unlink(path.join(cwd, script.dest));
|
|
217
|
+
} catch {
|
|
218
|
+
// already absent
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await writeCursorHooksInConfig(cwd, false);
|
|
223
|
+
log(`✅ Cursor hooks disabled → removed shipped entries from ${CURSOR_HOOKS_JSON}`);
|
|
224
|
+
}
|
package/lib/install.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
resolveAssetOverride,
|
|
14
14
|
} from "./constants.js";
|
|
15
15
|
import { installPlatformAdapters } from "./adapters.js";
|
|
16
|
-
import { installCursorHooks } from "./cursor-hooks.js";
|
|
16
|
+
import { installCursorHooks, removeCursorHooks, resolveCursorHooksInstall, writeCursorHooksInConfig } from "./cursor-hooks.js";
|
|
17
17
|
import { ensureDir, readFileSafe, writeFileIfMissing } from "./fs-utils.js";
|
|
18
18
|
import { hasPython } from "./gates.js";
|
|
19
19
|
import { initGuardrailsMemory } from "./memory.js";
|
|
@@ -119,7 +119,15 @@ export async function install(options = {}) {
|
|
|
119
119
|
await installPlatformAdapters(cwd);
|
|
120
120
|
log("✅ Adapters → .cursorrules, CLAUDE.md, copilot-instructions.md, AGENTS.md, .codex/AGENTS.md");
|
|
121
121
|
|
|
122
|
-
await
|
|
122
|
+
const hooksEnabled = await resolveCursorHooksInstall(cwd, options);
|
|
123
|
+
if (hooksEnabled) {
|
|
124
|
+
await installCursorHooks(cwd, { log });
|
|
125
|
+
await writeCursorHooksInConfig(cwd, true);
|
|
126
|
+
} else if (options.withoutCursorHooks || options.withCursorHooks === false) {
|
|
127
|
+
await removeCursorHooks(cwd, { log });
|
|
128
|
+
} else {
|
|
129
|
+
log("ℹ️ Cursor hooks skipped (off by default). Enable: install --with-cursor-hooks or cursor.hooks: true in .specs/config.yaml");
|
|
130
|
+
}
|
|
123
131
|
|
|
124
132
|
const gettingStartedCreated = await writeFileIfMissing(
|
|
125
133
|
path.join(cwd, ".specs/GETTING_STARTED.md"),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luizsantiago/spec-guardrails",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.2.0",
|
|
4
|
+
"description": "Governed spec-driven process kit for AI agents: phase guides, .specs/ memory, optional Python gates. Loop: specify, tasks, execute, verify. Cursor hooks opt-in (off by default). Node 18+; Python 3.10+ for Brakes. Cursor, Claude, Copilot, Codex.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"spec-guardrails": "./index.js"
|
|
@@ -49,11 +49,11 @@ Structural gates run **before** owner review, so they cannot drift when the mode
|
|
|
49
49
|
| Before Execute waves (3+ tasks) | `npx @luizsantiago/spec-guardrails loop-plan [feature]` |
|
|
50
50
|
| Parallel wave (2+ tasks, disjoint Files) | `npx @luizsantiago/spec-guardrails workspace-prepare [feature] --tasks T1,T2` |
|
|
51
51
|
| After parallel wave merge | `npx @luizsantiago/spec-guardrails workspace-cleanup [feature] --force` |
|
|
52
|
-
| Before editing paths outside task Files | `npx @luizsantiago/spec-guardrails context-guard check-edit <path> [--op write]` — **Cursor:**
|
|
52
|
+
| Before editing paths outside task Files | `npx @luizsantiago/spec-guardrails context-guard check-edit <path> [--op write]` — **Cursor:** optional auto-run via hooks when `cursor.hooks: true` (see below) |
|
|
53
53
|
| Before claiming feature complete | `npx @luizsantiago/spec-guardrails context-guard check-complete [feature]` |
|
|
54
54
|
| Session episodic note | `npx @luizsantiago/spec-guardrails episodes record --summary "…"` |
|
|
55
55
|
| Brownfield code lookup | `npx @luizsantiago/spec-guardrails code-index rebuild` · `code-index search "…"` |
|
|
56
|
-
| Shell safety check | `npx @luizsantiago/spec-guardrails sandbox check-command "<cmd>"` |
|
|
56
|
+
| Shell safety check | `npx @luizsantiago/spec-guardrails sandbox check-command "<cmd>"` — **Cursor:** optional auto-run via hooks when enabled |
|
|
57
57
|
| Solution exploration (explicit) | `npx @luizsantiago/spec-guardrails solution-explore init <feature> --candidates A,B` |
|
|
58
58
|
| Before exploration decision | `npx @luizsantiago/spec-guardrails solution-explore validate [feature]` |
|
|
59
59
|
| Retrieve related context | `npx @luizsantiago/spec-guardrails memory-retrieve "<query>"` |
|
|
@@ -73,6 +73,17 @@ A **non-zero exit means STOP** — fix the artifact, then re-run the gate. Never
|
|
|
73
73
|
|
|
74
74
|
**Process mode (Brakes off).** If Python 3.10+ or shell execution is unavailable, say so once, then perform the same checks by reading the artifact against the reference checklist. Process mode never lowers the standard; it only changes who runs the check. Run `doctor` to see separate **Process** and **Brakes** scores.
|
|
75
75
|
|
|
76
|
+
## Cursor IDE hooks (optional — off by default)
|
|
77
|
+
|
|
78
|
+
Shipped hooks auto-run `context-guard check-edit` and `sandbox check-command` on Cursor. **They are not installed unless the owner opts in** — the core loop and CLI checks work the same without them.
|
|
79
|
+
|
|
80
|
+
| Owner says | Action |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| Enable Cursor hooks | `npx @luizsantiago/spec-guardrails install --with-cursor-hooks` |
|
|
83
|
+
| Disable Cursor hooks | `npx @luizsantiago/spec-guardrails install --without-cursor-hooks` |
|
|
84
|
+
|
|
85
|
+
`/elicit` may ask once on Cursor during the first requirements round. Recommend **off** on low-RAM machines (each edit/shell spawns Node). Details: repository doc [Cursor hooks and sandbox](https://github.com/luizssantiago92/spec-guardrails/blob/main/docs/guide/Cursor-hooks-and-sandbox.md).
|
|
86
|
+
|
|
76
87
|
## Phase Map
|
|
77
88
|
|
|
78
89
|
```
|
|
@@ -108,6 +108,18 @@ Mark covered items: `covered by kickoff.md §…` — **do not ask again**.
|
|
|
108
108
|
| One area per round | UI **or** API **or** data — not all at once |
|
|
109
109
|
| Stop when | Gaps closed, owner says "enough", or Open questions is `- none` |
|
|
110
110
|
|
|
111
|
+
**Cursor IDE hooks (optional, once per project — first elicitation round only):**
|
|
112
|
+
|
|
113
|
+
If the platform is **Cursor** and `.cursor/hooks.json` has no shipped Spec Guardrails entries yet, ask **once**:
|
|
114
|
+
|
|
115
|
+
> "Cursor can run automatic scope checks before file edits and screen shell commands. This is **off by default** (lighter on modest machines). Enable Cursor hooks for this project? A) Yes — run `install --with-cursor-hooks` B) No — keep off (recommended on low-RAM machines) C) Decide later"
|
|
116
|
+
|
|
117
|
+
- **Yes** → `npx @luizsantiago/spec-guardrails install --with-cursor-hooks` (sets `cursor.hooks: true` in config when present).
|
|
118
|
+
- **No** → note in brief or STATE; do not install hooks.
|
|
119
|
+
- **Later** → skip; owner can say "enable Cursor hooks" or "disable Cursor hooks" in chat anytime.
|
|
120
|
+
|
|
121
|
+
Never block Elicitation or Specify on this question.
|
|
122
|
+
|
|
111
123
|
Templates by detected type (ask only relevant dimensions):
|
|
112
124
|
|
|
113
125
|
- **UI** — layout, primary actions, navigation, states
|
|
@@ -16,17 +16,18 @@ You installed the **Spec Guardrails**. You do **not** need to memorize CLI comma
|
|
|
16
16
|
|
|
17
17
|
3. Review `.specs/features/…/spec.md` and **approve** before implementation.
|
|
18
18
|
|
|
19
|
-
**Plain-language guide:** [Overview](https://github.com/luizssantiago92/spec-guardrails/blob/main/docs/guide/Overview.md) · [Memory](https://github.com/luizssantiago92/spec-guardrails/blob/main/docs/guide/Memory.md)
|
|
19
|
+
**Plain-language guide:** [Overview](https://github.com/luizssantiago92/spec-guardrails/blob/main/docs/guide/Overview.md) · [Requirements analysis](https://github.com/luizssantiago92/spec-guardrails/blob/main/docs/guide/requirements-analysis.md) · [Memory](https://github.com/luizssantiago92/spec-guardrails/blob/main/docs/guide/Memory.md)
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
## Agent commands (chat — not terminal)
|
|
24
24
|
|
|
25
|
-
Type these in **chat** in your agent environment. They load phase procedures from the installed skills tree (e.g. `.cursor/skills/references/`, `.github/skills/references/`, `.codex/skills/references/` — use the tree your agent loads).
|
|
25
|
+
Type these in **chat** in your agent environment. They load phase procedures from the installed skills tree (e.g. `.cursor/skills/references/`, `.github/skills/references/`, `.codex/skills/references/` — use the tree your agent loads). With **Python 3.10+**, the agent runs automatic gates at each step; without Python, the same checks are done manually (Process mode).
|
|
26
26
|
|
|
27
27
|
| Command | When |
|
|
28
28
|
| --- | --- |
|
|
29
|
-
| `/
|
|
29
|
+
| `/elicit` | Request is vague — structured Q&A before Specify (optional) |
|
|
30
|
+
| `/specify` | **Start here** when the goal is clear — written requirements |
|
|
30
31
|
| `/tasks` | Break into jobs after spec approval |
|
|
31
32
|
| `/loop` | Implement — agent runs `loop-plan` each wave |
|
|
32
33
|
| `/verify` | Fresh-context proof after last task |
|
|
@@ -43,6 +44,7 @@ Type these in **chat** in your agent environment. They load phase procedures fro
|
|
|
43
44
|
| Command | When |
|
|
44
45
|
| --- | --- |
|
|
45
46
|
| `install` | First time or upgrade |
|
|
47
|
+
| `install --with-cursor-hooks` | Optional — enable Cursor IDE hooks (off by default on 4.2+) |
|
|
46
48
|
| `project-init` | Brownfield repo (optional) |
|
|
47
49
|
| `doctor` | Install looks broken |
|
|
48
50
|
| `classify-change` / `feature-status` | Pick a tier or see next step |
|
|
@@ -72,7 +72,13 @@ elicitation:
|
|
|
72
72
|
- docs/prd.md
|
|
73
73
|
- .specs/project/kickoff.md
|
|
74
74
|
|
|
75
|
-
#
|
|
75
|
+
# Cursor IDE hooks (optional — off by default; Cursor only)
|
|
76
|
+
# Enable: install --with-cursor-hooks or hooks: true then re-run install
|
|
77
|
+
# Disable: install --without-cursor-hooks
|
|
78
|
+
cursor:
|
|
79
|
+
hooks: false
|
|
80
|
+
|
|
81
|
+
# Soft OS sandbox (optional — policy, not containers; used when hooks are enabled)
|
|
76
82
|
sandbox:
|
|
77
83
|
mode: warn
|
|
78
84
|
deny_patterns:
|