devrites 3.0.4 → 3.0.5

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +55 -43
  3. package/SECURITY.md +72 -58
  4. package/docs/agents/issue-driven-rites.md +5 -5
  5. package/docs/architecture.md +61 -45
  6. package/docs/capability-surface-selection.md +3 -1
  7. package/docs/cli.md +9 -2
  8. package/docs/command-map.md +6 -2
  9. package/docs/engine/agent-contract.md +5 -3
  10. package/docs/engine/commands.md +27 -14
  11. package/docs/engine/state-schema.md +8 -4
  12. package/docs/engine/workspace-schema.md +5 -4
  13. package/docs/flow.md +18 -7
  14. package/docs/porting-to-a-new-harness.md +6 -2
  15. package/docs/release.md +10 -9
  16. package/docs/skills.md +1 -1
  17. package/docs/templates/CRITIC_REVIEW_PACKET_TEMPLATE.md +35 -0
  18. package/docs/usage.md +26 -16
  19. package/engine/internal/lib/packageexistence.go +729 -52
  20. package/engine/internal/lib/packageexistence_test.go +343 -0
  21. package/engine/internal/lib/util.go +1 -1
  22. package/pack/.claude/skills/devrites-lib/SKILL.md +7 -9
  23. package/pack/.claude/skills/devrites-lib/reference/reply-contract.md +11 -3
  24. package/pack/.claude/skills/devrites-lib/reference/standards/development-workflow.md +2 -3
  25. package/pack/.claude/skills/rite/SKILL.md +6 -7
  26. package/pack/.claude/skills/rite/reference/menu.md +5 -5
  27. package/pack/.claude/skills/rite-adopt/SKILL.md +2 -3
  28. package/pack/generated/claude/skills/devrites-lib/SKILL.md +7 -9
  29. package/pack/generated/claude/skills/devrites-lib/reference/reply-contract.md +11 -3
  30. package/pack/generated/claude/skills/devrites-lib/reference/standards/development-workflow.md +2 -3
  31. package/pack/generated/claude/skills/rite/SKILL.md +6 -7
  32. package/pack/generated/claude/skills/rite/reference/menu.md +5 -5
  33. package/pack/generated/claude/skills/rite-adopt/SKILL.md +2 -3
  34. package/pack/generated/codex/skills/devrites-lib/SKILL.md +7 -9
  35. package/pack/generated/codex/skills/devrites-lib/reference/reply-contract.md +11 -3
  36. package/pack/generated/codex/skills/devrites-lib/reference/standards/development-workflow.md +2 -3
  37. package/pack/generated/codex/skills/rite/SKILL.md +6 -7
  38. package/pack/generated/codex/skills/rite/reference/menu.md +5 -5
  39. package/pack/generated/codex/skills/rite-adopt/SKILL.md +2 -3
  40. package/package.json +1 -1
  41. package/scripts/skills-inventory.mjs +18 -0
@@ -0,0 +1,343 @@
1
+ package lib
2
+
3
+ import (
4
+ "bytes"
5
+ "os"
6
+ "os/exec"
7
+ "path/filepath"
8
+ "strings"
9
+ "testing"
10
+ )
11
+
12
+ func TestPackageExistenceJavaScriptWorkspaces(t *testing.T) {
13
+ tests := []struct {
14
+ name string
15
+ sourcePath string
16
+ workingDir string
17
+ importLine string
18
+ files map[string]string
19
+ wantCode int
20
+ wantFinding string
21
+ }{
22
+ {
23
+ name: "nested workspace",
24
+ sourcePath: "frontend/src/example.ts",
25
+ workingDir: "frontend",
26
+ importLine: `import { Dialog } from "@ark-ui/svelte/dialog";`,
27
+ files: map[string]string{
28
+ "frontend/package.json": `{"dependencies":{"@ark-ui/svelte":"^5.22.1"}}`,
29
+ },
30
+ },
31
+ {
32
+ name: "scoped package subpath",
33
+ sourcePath: "app/src/example.ts",
34
+ importLine: `import value from "@scope/package/subpath";`,
35
+ files: map[string]string{
36
+ "app/package.json": `{"devDependencies":{"@scope/package":"1.0.0"}}`,
37
+ },
38
+ },
39
+ {
40
+ name: "wildcard alias",
41
+ sourcePath: "frontend/src/example.ts",
42
+ importLine: `import Button from "$lib/components/button";`,
43
+ files: map[string]string{
44
+ "frontend/package.json": `{}`,
45
+ "frontend/tsconfig.json": "{\n // SvelteKit generates the inherited aliases.\n \"extends\": \"./.svelte-kit/tsconfig.json\"\n}",
46
+ "frontend/.svelte-kit/tsconfig.json": `{"compilerOptions":{"paths":{"$lib/*":["../src/lib/*"]}}}`,
47
+ },
48
+ },
49
+ {
50
+ name: "exact alias",
51
+ sourcePath: "frontend/src/example.ts",
52
+ importLine: `import library from "$lib";`,
53
+ files: map[string]string{
54
+ "frontend/package.json": `{}`,
55
+ "frontend/tsconfig.json": `{"compilerOptions":{"paths":{"$lib":["./src/lib"]}}}`,
56
+ },
57
+ },
58
+ {
59
+ name: "package shaped alias",
60
+ sourcePath: "frontend/src/example.svelte",
61
+ importLine: `import { css } from "styled-system/css";`,
62
+ files: map[string]string{
63
+ "frontend/package.json": `{}`,
64
+ "frontend/jsconfig.json": `{"compilerOptions":{"paths":{"styled-system/*":["./styled-system/*"]}}}`,
65
+ },
66
+ },
67
+ {
68
+ name: "undeclared dependency",
69
+ sourcePath: "frontend/src/example.ts",
70
+ importLine: `import missing from "definitely-missing-package";`,
71
+ files: map[string]string{"frontend/package.json": `{}`},
72
+ wantCode: 3,
73
+ wantFinding: "definitely-missing-package",
74
+ },
75
+ {
76
+ name: "sibling isolation",
77
+ sourcePath: "workspace-a/src/example.ts",
78
+ importLine: `import sibling from "sibling-only-package";`,
79
+ files: map[string]string{
80
+ "workspace-a/package.json": `{}`,
81
+ "workspace-b/package.json": `{"dependencies":{"sibling-only-package":"1.0.0"}}`,
82
+ },
83
+ wantCode: 3,
84
+ wantFinding: "sibling-only-package",
85
+ },
86
+ {
87
+ name: "malformed config does not allow alias",
88
+ sourcePath: "frontend/src/example.ts",
89
+ importLine: `import { css } from "styled-system/css";`,
90
+ files: map[string]string{
91
+ "frontend/package.json": `{}`,
92
+ "frontend/tsconfig.json": `{"compilerOptions":{"paths":{"styled-system/*":["./styled-system/*"]}}`,
93
+ },
94
+ wantCode: 3,
95
+ wantFinding: "styled-system",
96
+ },
97
+ }
98
+
99
+ for _, test := range tests {
100
+ t.Run(test.name, func(t *testing.T) {
101
+ repo := t.TempDir()
102
+ writePackageExistenceFile(t, repo, "Cargo.toml", "[package]\nname = \"fixture\"\nversion = \"0.1.0\"\n")
103
+ writePackageExistenceFile(t, repo, test.sourcePath, "// baseline\n")
104
+ for path, content := range test.files {
105
+ writePackageExistenceFile(t, repo, path, content+"\n")
106
+ }
107
+ gitPackageExistence(t, repo, "init", "-q")
108
+ gitPackageExistence(t, repo, "config", "user.email", "test@example.com")
109
+ gitPackageExistence(t, repo, "config", "user.name", "Test")
110
+ gitPackageExistence(t, repo, "add", ".")
111
+ gitPackageExistence(t, repo, "commit", "-qm", "baseline")
112
+ if err := os.MkdirAll(featureDir(repo, "feat"), 0o755); err != nil {
113
+ t.Fatal(err)
114
+ }
115
+ writePackageExistenceFile(t, repo, test.sourcePath, "// baseline\n"+test.importLine+"\n")
116
+ t.Chdir(filepath.Join(repo, test.workingDir))
117
+
118
+ var stdout, stderr bytes.Buffer
119
+ gotCode := PackageExistence(repo, []string{"feat"}, &stdout, &stderr)
120
+ if gotCode != test.wantCode {
121
+ t.Fatalf("code = %d, want %d\nstdout: %s\nstderr: %s", gotCode, test.wantCode, stdout.String(), stderr.String())
122
+ }
123
+ if test.wantFinding != "" && !strings.Contains(stderr.String(), test.wantFinding) {
124
+ t.Fatalf("stderr does not name %q: %s", test.wantFinding, stderr.String())
125
+ }
126
+ })
127
+ }
128
+ }
129
+
130
+ func TestPackageExistenceNonJavaScriptWorkspaces(t *testing.T) {
131
+ tests := []struct {
132
+ name string
133
+ sourcePath string
134
+ addedSource string
135
+ files map[string]string
136
+ wantCode int
137
+ wantFinding string
138
+ }{
139
+ {
140
+ name: "go import block rejects undeclared module",
141
+ sourcePath: "main.go",
142
+ addedSource: "package main\n\nimport (\n\t\"definitely.invalid/missing\"\n)\n",
143
+ files: map[string]string{"go.mod": "module example.com/app\n\ngo 1.26\n"},
144
+ wantCode: 3,
145
+ wantFinding: "definitely.invalid/missing",
146
+ },
147
+ {
148
+ name: "go modules do not collide by hostname",
149
+ sourcePath: "main.go",
150
+ addedSource: "package main\n\nimport \"github.com/evil/missing\"\n",
151
+ files: map[string]string{"go.mod": "module example.com/app\n\ngo 1.26\n\nrequire github.com/good/pkg v1.0.0\n"},
152
+ wantCode: 3,
153
+ wantFinding: "github.com/evil/missing",
154
+ },
155
+ {
156
+ name: "nested go module declaration",
157
+ sourcePath: "backend/main.go",
158
+ addedSource: "package main\n\nimport \"github.com/good/pkg/sub\"\n",
159
+ files: map[string]string{
160
+ "Cargo.toml": "[package]\nname = \"root\"\nversion = \"0.1.0\"\n",
161
+ "backend/go.mod": "module example.com/backend\n\ngo 1.26\n\nrequire github.com/good/pkg v1.0.0\n",
162
+ },
163
+ },
164
+ {
165
+ name: "go standard library subpackage",
166
+ sourcePath: "main.go",
167
+ addedSource: "package main\n\nimport \"encoding/json\"\n",
168
+ files: map[string]string{"go.mod": "module example.com/app\n\ngo 1.26\n"},
169
+ },
170
+ {
171
+ name: "go standard library typo remains undeclared",
172
+ sourcePath: "main.go",
173
+ addedSource: "package main\n\nimport \"encoding/josn\"\n",
174
+ files: map[string]string{"go.mod": "module example.com/app\n\ngo 1.26\n"},
175
+ wantCode: 3,
176
+ wantFinding: "encoding/josn",
177
+ },
178
+ {
179
+ name: "malformed go manifest does not declare import",
180
+ sourcePath: "main.go",
181
+ addedSource: "package main\n\nimport \"github.com/missing/pkg\"\n",
182
+ files: map[string]string{"go.mod": "module example.com/app\n\ngo 1.26\n\nrequire (\n github.com/missing/pkg v1.0.0\n"},
183
+ wantCode: 3,
184
+ wantFinding: "github.com/missing/pkg",
185
+ },
186
+ {
187
+ name: "rust rejects undeclared crate",
188
+ sourcePath: "src/main.rs",
189
+ addedSource: "use definitely_missing_crate::Thing;\n",
190
+ files: map[string]string{"Cargo.toml": "[package]\nname = \"fixture\"\nversion = \"0.1.0\"\n\n[dependencies]\n"},
191
+ wantCode: 3,
192
+ wantFinding: "definitely_missing_crate",
193
+ },
194
+ {
195
+ name: "nested rust dependency and hyphen normalization",
196
+ sourcePath: "crates/app/src/main.rs",
197
+ addedSource: "use serde_json::Value;\n",
198
+ files: map[string]string{
199
+ "Cargo.toml": "[workspace]\nmembers = [\"crates/app\"]\n",
200
+ "crates/app/Cargo.toml": "[package]\nname = \"app\"\nversion = \"0.1.0\"\n\n[dependencies.serde-json]\nversion = \"1\"\n",
201
+ },
202
+ },
203
+ {
204
+ name: "python dotted import uses top-level module",
205
+ sourcePath: "app.py",
206
+ addedSource: "from requests.sessions import Session\n",
207
+ files: map[string]string{"requirements.txt": "requests==2.32.0\n"},
208
+ },
209
+ {
210
+ name: "python standard library module",
211
+ sourcePath: "app.py",
212
+ addedSource: "import asyncio\n",
213
+ files: map[string]string{"requirements.txt": "requests==2.32.0\n"},
214
+ },
215
+ {
216
+ name: "nested python manifest declaration",
217
+ sourcePath: "backend/app.py",
218
+ addedSource: "import requests\n",
219
+ files: map[string]string{
220
+ "Cargo.toml": "[package]\nname = \"root\"\nversion = \"0.1.0\"\n",
221
+ "backend/requirements.txt": "requests==2.32.0\n",
222
+ },
223
+ },
224
+ {
225
+ name: "pyproject dependency declaration",
226
+ sourcePath: "service/app.py",
227
+ addedSource: "import requests\n",
228
+ files: map[string]string{
229
+ "service/pyproject.toml": "[project]\ndependencies = [\n \"requests[socks]>=2.32\",\n]\n",
230
+ },
231
+ },
232
+ {
233
+ name: "pipfile dependency declaration",
234
+ sourcePath: "service/app.py",
235
+ addedSource: "import requests\n",
236
+ files: map[string]string{
237
+ "service/Pipfile": "[packages]\nrequests = \"*\"\n",
238
+ },
239
+ },
240
+ {
241
+ name: "malformed pyproject does not declare import",
242
+ sourcePath: "service/app.py",
243
+ addedSource: "import definitely_missing\n",
244
+ files: map[string]string{
245
+ "service/pyproject.toml": "[project]\ndependencies = [\n \"definitely_missing\"\n",
246
+ },
247
+ wantCode: 3,
248
+ wantFinding: "definitely_missing",
249
+ },
250
+ {
251
+ name: "python multiple imports reject undeclared module",
252
+ sourcePath: "app.py",
253
+ addedSource: "import requests, definitely_missing\n",
254
+ files: map[string]string{"requirements.txt": "requests==2.32.0\n"},
255
+ wantCode: 3,
256
+ wantFinding: "definitely_missing",
257
+ },
258
+ {
259
+ name: "comments and other ecosystems do not declare python imports",
260
+ sourcePath: "app.py",
261
+ addedSource: "import definitely_missing\n",
262
+ files: map[string]string{
263
+ "Cargo.toml": "[package]\nname = \"definitely_missing\"\nversion = \"0.1.0\"\n",
264
+ "requirements.txt": "# definitely_missing is intentionally absent\n",
265
+ },
266
+ wantCode: 3,
267
+ wantFinding: "definitely_missing",
268
+ },
269
+ }
270
+
271
+ for _, test := range tests {
272
+ t.Run(test.name, func(t *testing.T) {
273
+ repo := t.TempDir()
274
+ for path, content := range test.files {
275
+ writePackageExistenceFile(t, repo, path, content)
276
+ }
277
+ writePackageExistenceFile(t, repo, test.sourcePath, "// baseline\n")
278
+ gitPackageExistence(t, repo, "init", "-q")
279
+ gitPackageExistence(t, repo, "config", "user.email", "test@example.com")
280
+ gitPackageExistence(t, repo, "config", "user.name", "Test")
281
+ gitPackageExistence(t, repo, "add", ".")
282
+ gitPackageExistence(t, repo, "commit", "-qm", "baseline")
283
+ if err := os.MkdirAll(featureDir(repo, "feat"), 0o755); err != nil {
284
+ t.Fatal(err)
285
+ }
286
+ writePackageExistenceFile(t, repo, test.sourcePath, test.addedSource)
287
+ t.Chdir(repo)
288
+
289
+ var stdout, stderr bytes.Buffer
290
+ gotCode := PackageExistence(repo, []string{"feat"}, &stdout, &stderr)
291
+ if gotCode != test.wantCode {
292
+ t.Fatalf("code = %d, want %d\nstdout: %s\nstderr: %s", gotCode, test.wantCode, stdout.String(), stderr.String())
293
+ }
294
+ if test.wantFinding != "" && !strings.Contains(stderr.String(), test.wantFinding) {
295
+ t.Fatalf("stderr does not name %q: %s", test.wantFinding, stderr.String())
296
+ }
297
+ })
298
+ }
299
+ }
300
+
301
+ func TestPackageExistenceGenericResolverFailsClosed(t *testing.T) {
302
+ repo := t.TempDir()
303
+ writePackageExistenceFile(t, repo, "package.json", `{"dependencies":{"definitely-missing-package":"1.0.0"}}`)
304
+ writePackageExistenceFile(t, repo, "src/example.custom", "// baseline\n")
305
+ gitPackageExistence(t, repo, "init", "-q")
306
+ gitPackageExistence(t, repo, "config", "user.email", "test@example.com")
307
+ gitPackageExistence(t, repo, "config", "user.name", "Test")
308
+ gitPackageExistence(t, repo, "add", ".")
309
+ gitPackageExistence(t, repo, "commit", "-qm", "baseline")
310
+ if err := os.MkdirAll(featureDir(repo, "feat"), 0o755); err != nil {
311
+ t.Fatal(err)
312
+ }
313
+ writePackageExistenceFile(t, repo, "src/example.custom", "import \"definitely-missing-package\"\n")
314
+ t.Chdir(repo)
315
+
316
+ var stdout, stderr bytes.Buffer
317
+ gotCode := PackageExistence(repo, []string{"feat"}, &stdout, &stderr)
318
+ if gotCode != 3 {
319
+ t.Fatalf("code = %d, want 3\nstdout: %s\nstderr: %s", gotCode, stdout.String(), stderr.String())
320
+ }
321
+ if !strings.Contains(stderr.String(), "definitely-missing-package") {
322
+ t.Fatalf("stderr does not name unresolved import: %s", stderr.String())
323
+ }
324
+ }
325
+
326
+ func writePackageExistenceFile(t *testing.T, root, path, content string) {
327
+ t.Helper()
328
+ fullPath := filepath.Join(root, filepath.FromSlash(path))
329
+ if err := os.MkdirAll(filepath.Dir(fullPath), 0o755); err != nil {
330
+ t.Fatal(err)
331
+ }
332
+ if err := os.WriteFile(fullPath, []byte(content), 0o644); err != nil {
333
+ t.Fatal(err)
334
+ }
335
+ }
336
+
337
+ func gitPackageExistence(t *testing.T, root string, args ...string) {
338
+ t.Helper()
339
+ cmd := exec.Command("git", append([]string{"-C", root}, args...)...)
340
+ if out, err := cmd.CombinedOutput(); err != nil {
341
+ t.Fatalf("git %s: %v\n%s", strings.Join(args, " "), err, out)
342
+ }
343
+ }
@@ -14,7 +14,7 @@ func gitToplevel(dir string) string {
14
14
  if err != nil {
15
15
  return ""
16
16
  }
17
- return strings.TrimSpace(string(out))
17
+ return filepath.Clean(strings.TrimSpace(string(out)))
18
18
  }
19
19
 
20
20
  // gitDiffNames lists the paths that differ, relative to gitRoot. With one ref it
@@ -7,14 +7,13 @@ disable-model-invocation: true
7
7
 
8
8
  # devrites-lib — internal shared helpers (not a command)
9
9
 
10
- This is **not** a skill you run. It is the manifest for DevRites'
11
- cross-cutting helper operations, each exposed as a subcommand of the global
12
- `devrites` binary. A skill invokes one as `devrites <op>` — the same call from
13
- any workspace, with no install layout or script path to resolve.
10
+ This is **not** a skill you run. It is DevRites' manifest for shared references
11
+ and control-plane operations. Skills call `devrites-engine <command>` from any
12
+ workspace; no pack script path is required.
14
13
 
15
14
  ## Operations
16
15
 
17
- Each is a subcommand of the global `devrites` binary, run as `devrites <op>`.
16
+ These are selected `devrites-engine` contracts; `devrites-engine help` is exhaustive.
18
17
 
19
18
  **Read-only — orient / gate (never mutate the workspace):**
20
19
 
@@ -76,7 +75,6 @@ devrites-engine progress
76
75
 
77
76
  **Unified entrypoint (tool-agnostic):**
78
77
 
79
- - The `devrites` binary is that unified CLI, dispatching to all of the above (`orient` / `ready` /
80
- `evidence-fresh` / `acceptance` / `spec-validate` / `tick-afk` / `resolve` / `close` /
81
- `active` / `list` / `use`), so any agent or human can drive `.devrites/` without the skill
82
- prose. See [`docs/cli.md`](../../../../docs/cli.md).
78
+ - `devrites-engine` is the shared CLI for agents, CI, and humans. The npm
79
+ `devrites` shim acquires it, owns install/update/uninstall bootstrap, and
80
+ proxies other commands.
@@ -59,9 +59,17 @@ Rules:
59
59
 
60
60
  ```text
61
61
  Awaiting human: <qid> · <gate> · <slice/phase>
62
- Question: <one-line question>
63
- Recommended: <option 1 + short reason>
64
- Options: <2-4 compact choices, if already generated>
62
+
63
+ Question
64
+ <question>
65
+
66
+ Recommended
67
+ 1. <option 1 + short reason>
68
+
69
+ Other options
70
+ 2. <option 2>
71
+ 3. <option 3 if any>
72
+
65
73
  Resume: /rite-resolve <qid> "<answer>"
66
74
  Record: .devrites/work/<slug>/questions.md
67
75
  ↻ Hygiene: no /clear until the answer is persisted
@@ -1,8 +1,7 @@
1
1
  # Development workflow
2
2
 
3
- Ship small, integrate often, keep the main branch releasable. This is the general
4
- engineering loop the DevRites feature lifecycle (spec → define → build → prove → polish →
5
- review → seal → ship) runs on top of.
3
+ Ship small, integrate often, keep the main branch releasable. DevRites runs this
4
+ lifecycle atop that loop: spec → define → vet → build → prove → polish → review → seal → ship.
6
5
 
7
6
  ## Work in small batches
8
7
  - Break work into thin, independently shippable slices and integrate them frequently —
@@ -70,12 +70,10 @@ Both forms hit the same skill — the menu form for discovery, the `/rite-<verb>
70
70
  the now-active feature. It is cheap context-switching only — no re-spec, no phase run. If
71
71
  the workspace is missing, list the slugs under `.devrites/work/` and stop.
72
72
 
73
- `guide` is also inline — a first-feature walkthrough that teaches the lifecycle by running
74
- it. Agree on one **real, genuinely small** change, then dispatch the normal phases in order
75
- (spec define build prove seal ship). Per phase, exactly two narration beats:
76
- before, what it will decide; after, what it wrote in `.devrites/work/<slug>/` and why. Walk
77
- every phase — the small change is what makes the full ceremony affordable to watch. Pause
78
- at each boundary for the user's go-ahead. Teach without lecturing.
73
+ `guide` is an inline first-feature walkthrough. Agree on one **real, genuinely small**
74
+ change, then run spec temper define vet build prove → polish → review → seal →
75
+ ship. Before each phase, say what it decides; after, name what it wrote and why. Pause at
76
+ every boundary. Teach without lecturing.
79
77
 
80
78
  Specialist triggers (model-invoked inside the above):
81
79
  `devrites-frontend-craft` (UI) · `devrites-browser-proof` (UI verify) ·
@@ -106,9 +104,10 @@ SPEC /rite spec ≡ /rite-spec investigate deep
106
104
  ADOPT /rite adopt ≡ /rite-adopt onboard existing code → reverse-derive spec.md + seed conventions
107
105
  TEMPER /rite temper ≡ /rite-temper optional — strategic review: scope mode + pre-mortem, harden the spec
108
106
  PLAN /rite define ≡ /rite-define turn the spec into plan + task slices + state
109
- VET /rite vet ≡ /rite-vet optional engineering plan review: scope · architecture · tests · perf, harden the plan
107
+ VET /rite vet ≡ /rite-vet mandatory every plan light/full engineering review by stakes
110
108
  REPLAN /rite plan ≡ /rite-plan decompose / reslice / repair an active plan
111
109
  BUILD /rite build ≡ /rite-build implement exactly one verified vertical slice, then stop
110
+ CONVERGE /rite converge ≡ /rite-converge recovery — append work needed to meet intent
112
111
  PROVE /rite prove ≡ /rite-prove tests + build + runtime + browser evidence
113
112
  POLISH /rite polish ≡ /rite-polish code polish always; UI normalize + polish if UI
114
113
  REVIEW /rite review ≡ /rite-review feature-scoped multi-axis review
@@ -7,11 +7,11 @@ what each command does or how phases connect.
7
7
 
8
8
  | Phase | Command | Use when |
9
9
  |---|---|---|
10
- | Spec | `/rite-spec <feature>` | **Start here.** Investigate deeply → write spec.md. Asks you with options; gathers any design references you attach (optional). |
10
+ | Spec | `/rite-spec <feature>` | **New feature.** Investigate deeply → write spec.md. Asks with options; gathers attached design references (optional). |
11
11
  | Adopt | `/rite-adopt` | Onboard an existing codebase instead of starting fresh — reverse-derive spec.md + seed the conventions ledger. |
12
12
  | Temper | `/rite-temper` | _Optional, before define._ Strategic review of the spec — scope mode (expand/selective/hold-rigor/reduce) + pre-mortem; hardens the spec. Best on big/risky features; mandatory in `/rite-autocomplete`. |
13
13
  | Plan | `/rite-define` | Turn the approved spec into plan + vertical task slices + state. |
14
- | Vet | `/rite-vet` | _Optional, before build._ Engineering review of the plan — scope · architecture · tests · perf; hardens the plan. Best on big/risky features; mandatory in `/rite-autocomplete`. |
14
+ | Vet | `/rite-vet` | _Required before build._ Review every plan — scope · architecture · tests · perf; light for simple/reversible, full for high stakes. |
15
15
  | Re-plan | `/rite-plan` | The active plan is too big, wrong, stale, ambiguous, or blocked. |
16
16
  | Build | `/rite-build` | Implement the next single vertical slice. Stops after one slice. |
17
17
  | Converge | `/rite-converge` | _Recovery._ Code drifted from / falls short of intent (resumed cold, adopted, stalled build) — assess live code vs spec/plan/tasks and append the remaining work as new slices for `/rite-build`. |
@@ -27,10 +27,10 @@ what each command does or how phases connect.
27
27
  ## Typical orderings
28
28
 
29
29
  - **Every feature**: `/rite-spec` (spec) → *(big feature? `/rite-temper` — strategic review)* →
30
- `/rite-define` (plan) → *(big feature? `/rite-vet` engineering review)*
30
+ `/rite-define` (plan) → `/rite-vet` (engineering review; light or full) →
31
31
  `/rite-build` ×N (all slices) → `/rite-prove` (once all built) →
32
32
  `/rite-polish` (always: code + UI if UI) → `/rite-review` → `/rite-seal` → `/rite-ship`.
33
- - **Existing codebase**: `/rite-adopt` (onboard spec.md + conventions) continue at `/rite-define`.
33
+ - **Existing codebase**: `/rite-adopt` → `/rite-define` → `/rite-vet` → build.
34
34
  - **Drift mid-build**: stop → drift question → `/rite-plan` (repair) → resume build.
35
35
  - **Resumed / adopted / stalled**: `/rite-converge` (assess live code vs intent → append the
36
36
  remaining slices) → `/rite-build` ×N → continue at `/rite-prove`.
@@ -38,5 +38,5 @@ what each command does or how phases connect.
38
38
  ## Rules this menu obeys
39
39
 
40
40
  - `/rite` never edits code or runs a phase workflow.
41
- - It reads `.devrites/ACTIVE` and `state.md` for status only.
41
+ - Menu mode runs `devrites-engine first-task`; `/rite-status` owns workspace status.
42
42
  - It suggests; the user (or Claude, when appropriate) invokes the real skill.
@@ -79,9 +79,8 @@ upholds invariants worth proposing as project principles (step 4a).
79
79
  ([`principles.md`](../devrites-lib/reference/standards/principles.md)). Propose, don't impose — an unratified candidate
80
80
  stays a convention, not a gate. Skip cleanly when nothing rises to an invariant (common — a
81
81
  fresh adopt may declare zero principles, and that's valid).
82
- 5. **Hand off.** The project is now in the lifecycle with a spec and a head-start ledger.
83
- Point the user at `/rite-temper` (big/risky) or `/rite-define` (straightforward) do not
84
- plan or build here.
82
+ 5. **Hand off.** Spec and ledger are ready. Next: `/rite-temper` if big/risky,
83
+ else `/rite-define`; every plan then runs `/rite-vet` before build. Do not plan/build here.
85
84
  **Completion:** one next rite is reported and no plan or application code was written.
86
85
 
87
86
  > **Mid-flight discipline.** Don't invent conventions the code doesn't actually follow, don't
@@ -7,14 +7,13 @@ disable-model-invocation: true
7
7
 
8
8
  # devrites-lib — internal shared helpers (not a command)
9
9
 
10
- This is **not** a skill you run. It is the manifest for DevRites'
11
- cross-cutting helper operations, each exposed as a subcommand of the global
12
- `devrites` binary. A skill invokes one as `devrites <op>` — the same call from
13
- any workspace, with no install layout or script path to resolve.
10
+ This is **not** a skill you run. It is DevRites' manifest for shared references
11
+ and control-plane operations. Skills call `devrites-engine <command>` from any
12
+ workspace; no pack script path is required.
14
13
 
15
14
  ## Operations
16
15
 
17
- Each is a subcommand of the global `devrites` binary, run as `devrites <op>`.
16
+ These are selected `devrites-engine` contracts; `devrites-engine help` is exhaustive.
18
17
 
19
18
  **Read-only — orient / gate (never mutate the workspace):**
20
19
 
@@ -76,7 +75,6 @@ devrites-engine progress
76
75
 
77
76
  **Unified entrypoint (tool-agnostic):**
78
77
 
79
- - The `devrites` binary is that unified CLI, dispatching to all of the above (`orient` / `ready` /
80
- `evidence-fresh` / `acceptance` / `spec-validate` / `tick-afk` / `resolve` / `close` /
81
- `active` / `list` / `use`), so any agent or human can drive `.devrites/` without the skill
82
- prose. See [`docs/cli.md`](../../../../docs/cli.md).
78
+ - `devrites-engine` is the shared CLI for agents, CI, and humans. The npm
79
+ `devrites` shim acquires it, owns install/update/uninstall bootstrap, and
80
+ proxies other commands.
@@ -59,9 +59,17 @@ Rules:
59
59
 
60
60
  ```text
61
61
  Awaiting human: <qid> · <gate> · <slice/phase>
62
- Question: <one-line question>
63
- Recommended: <option 1 + short reason>
64
- Options: <2-4 compact choices, if already generated>
62
+
63
+ Question
64
+ <question>
65
+
66
+ Recommended
67
+ 1. <option 1 + short reason>
68
+
69
+ Other options
70
+ 2. <option 2>
71
+ 3. <option 3 if any>
72
+
65
73
  Resume: /rite-resolve <qid> "<answer>"
66
74
  Record: .devrites/work/<slug>/questions.md
67
75
  ↻ Hygiene: no /clear until the answer is persisted
@@ -1,8 +1,7 @@
1
1
  # Development workflow
2
2
 
3
- Ship small, integrate often, keep the main branch releasable. This is the general
4
- engineering loop the DevRites feature lifecycle (spec → define → build → prove → polish →
5
- review → seal → ship) runs on top of.
3
+ Ship small, integrate often, keep the main branch releasable. DevRites runs this
4
+ lifecycle atop that loop: spec → define → vet → build → prove → polish → review → seal → ship.
6
5
 
7
6
  ## Work in small batches
8
7
  - Break work into thin, independently shippable slices and integrate them frequently —
@@ -70,12 +70,10 @@ Both forms hit the same skill — the menu form for discovery, the `/rite-<verb>
70
70
  the now-active feature. It is cheap context-switching only — no re-spec, no phase run. If
71
71
  the workspace is missing, list the slugs under `.devrites/work/` and stop.
72
72
 
73
- `guide` is also inline — a first-feature walkthrough that teaches the lifecycle by running
74
- it. Agree on one **real, genuinely small** change, then dispatch the normal phases in order
75
- (spec define build prove seal ship). Per phase, exactly two narration beats:
76
- before, what it will decide; after, what it wrote in `.devrites/work/<slug>/` and why. Walk
77
- every phase — the small change is what makes the full ceremony affordable to watch. Pause
78
- at each boundary for the user's go-ahead. Teach without lecturing.
73
+ `guide` is an inline first-feature walkthrough. Agree on one **real, genuinely small**
74
+ change, then run spec temper define vet build prove → polish → review → seal →
75
+ ship. Before each phase, say what it decides; after, name what it wrote and why. Pause at
76
+ every boundary. Teach without lecturing.
79
77
 
80
78
  Specialist triggers (model-invoked inside the above):
81
79
  `devrites-frontend-craft` (UI) · `devrites-browser-proof` (UI verify) ·
@@ -106,9 +104,10 @@ SPEC /rite spec ≡ /rite-spec investigate deep
106
104
  ADOPT /rite adopt ≡ /rite-adopt onboard existing code → reverse-derive spec.md + seed conventions
107
105
  TEMPER /rite temper ≡ /rite-temper optional — strategic review: scope mode + pre-mortem, harden the spec
108
106
  PLAN /rite define ≡ /rite-define turn the spec into plan + task slices + state
109
- VET /rite vet ≡ /rite-vet optional engineering plan review: scope · architecture · tests · perf, harden the plan
107
+ VET /rite vet ≡ /rite-vet mandatory every plan light/full engineering review by stakes
110
108
  REPLAN /rite plan ≡ /rite-plan decompose / reslice / repair an active plan
111
109
  BUILD /rite build ≡ /rite-build implement exactly one verified vertical slice, then stop
110
+ CONVERGE /rite converge ≡ /rite-converge recovery — append work needed to meet intent
112
111
  PROVE /rite prove ≡ /rite-prove tests + build + runtime + browser evidence
113
112
  POLISH /rite polish ≡ /rite-polish code polish always; UI normalize + polish if UI
114
113
  REVIEW /rite review ≡ /rite-review feature-scoped multi-axis review
@@ -7,11 +7,11 @@ what each command does or how phases connect.
7
7
 
8
8
  | Phase | Command | Use when |
9
9
  |---|---|---|
10
- | Spec | `/rite-spec <feature>` | **Start here.** Investigate deeply → write spec.md. Asks you with options; gathers any design references you attach (optional). |
10
+ | Spec | `/rite-spec <feature>` | **New feature.** Investigate deeply → write spec.md. Asks with options; gathers attached design references (optional). |
11
11
  | Adopt | `/rite-adopt` | Onboard an existing codebase instead of starting fresh — reverse-derive spec.md + seed the conventions ledger. |
12
12
  | Temper | `/rite-temper` | _Optional, before define._ Strategic review of the spec — scope mode (expand/selective/hold-rigor/reduce) + pre-mortem; hardens the spec. Best on big/risky features; mandatory in `/rite-autocomplete`. |
13
13
  | Plan | `/rite-define` | Turn the approved spec into plan + vertical task slices + state. |
14
- | Vet | `/rite-vet` | _Optional, before build._ Engineering review of the plan — scope · architecture · tests · perf; hardens the plan. Best on big/risky features; mandatory in `/rite-autocomplete`. |
14
+ | Vet | `/rite-vet` | _Required before build._ Review every plan — scope · architecture · tests · perf; light for simple/reversible, full for high stakes. |
15
15
  | Re-plan | `/rite-plan` | The active plan is too big, wrong, stale, ambiguous, or blocked. |
16
16
  | Build | `/rite-build` | Implement the next single vertical slice. Stops after one slice. |
17
17
  | Converge | `/rite-converge` | _Recovery._ Code drifted from / falls short of intent (resumed cold, adopted, stalled build) — assess live code vs spec/plan/tasks and append the remaining work as new slices for `/rite-build`. |
@@ -27,10 +27,10 @@ what each command does or how phases connect.
27
27
  ## Typical orderings
28
28
 
29
29
  - **Every feature**: `/rite-spec` (spec) → *(big feature? `/rite-temper` — strategic review)* →
30
- `/rite-define` (plan) → *(big feature? `/rite-vet` engineering review)*
30
+ `/rite-define` (plan) → `/rite-vet` (engineering review; light or full) →
31
31
  `/rite-build` ×N (all slices) → `/rite-prove` (once all built) →
32
32
  `/rite-polish` (always: code + UI if UI) → `/rite-review` → `/rite-seal` → `/rite-ship`.
33
- - **Existing codebase**: `/rite-adopt` (onboard spec.md + conventions) continue at `/rite-define`.
33
+ - **Existing codebase**: `/rite-adopt` → `/rite-define` → `/rite-vet` → build.
34
34
  - **Drift mid-build**: stop → drift question → `/rite-plan` (repair) → resume build.
35
35
  - **Resumed / adopted / stalled**: `/rite-converge` (assess live code vs intent → append the
36
36
  remaining slices) → `/rite-build` ×N → continue at `/rite-prove`.
@@ -38,5 +38,5 @@ what each command does or how phases connect.
38
38
  ## Rules this menu obeys
39
39
 
40
40
  - `/rite` never edits code or runs a phase workflow.
41
- - It reads `.devrites/ACTIVE` and `state.md` for status only.
41
+ - Menu mode runs `devrites-engine first-task`; `/rite-status` owns workspace status.
42
42
  - It suggests; the user (or Claude, when appropriate) invokes the real skill.
@@ -79,9 +79,8 @@ upholds invariants worth proposing as project principles (step 4a).
79
79
  ([`principles.md`](../devrites-lib/reference/standards/principles.md)). Propose, don't impose — an unratified candidate
80
80
  stays a convention, not a gate. Skip cleanly when nothing rises to an invariant (common — a
81
81
  fresh adopt may declare zero principles, and that's valid).
82
- 5. **Hand off.** The project is now in the lifecycle with a spec and a head-start ledger.
83
- Point the user at `/rite-temper` (big/risky) or `/rite-define` (straightforward) do not
84
- plan or build here.
82
+ 5. **Hand off.** Spec and ledger are ready. Next: `/rite-temper` if big/risky,
83
+ else `/rite-define`; every plan then runs `/rite-vet` before build. Do not plan/build here.
85
84
  **Completion:** one next rite is reported and no plan or application code was written.
86
85
 
87
86
  > **Mid-flight discipline.** Don't invent conventions the code doesn't actually follow, don't