prizmkit 1.0.103 → 1.0.105
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/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/run.sh +12 -0
- package/bundled/dev-pipeline/scripts/utils.py +333 -31
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +26 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +26 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +26 -0
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +10 -1
- package/bundled/dev-pipeline/templates/feature-list-schema.json +10 -1
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +8 -1
- package/bundled/skills/bug-planner/SKILL.md +2 -2
- package/bundled/skills/prizmkit-init/SKILL.md +125 -5
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +1 -1
- package/bundled/skills/prizmkit-prizm-docs/assets/PRIZM-SPEC.md +56 -7
- package/bundled/skills/prizmkit-retrospective/SKILL.md +28 -1
- package/package.json +1 -1
package/bundled/VERSION.json
CHANGED
|
@@ -288,6 +288,18 @@ sys.exit(1)
|
|
|
288
288
|
fi
|
|
289
289
|
fi
|
|
290
290
|
|
|
291
|
+
# Check if session produced a failure-log for future retries
|
|
292
|
+
if [[ "$session_status" != "success" && -n "$feature_slug" ]]; then
|
|
293
|
+
local project_root_for_failure
|
|
294
|
+
project_root_for_failure="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
295
|
+
local failure_log="$project_root_for_failure/.prizmkit/specs/${feature_slug}/failure-log.md"
|
|
296
|
+
if [[ -f "$failure_log" ]]; then
|
|
297
|
+
log_info "FAILURE_LOG: Session wrote failure-log.md — will be available to next retry"
|
|
298
|
+
else
|
|
299
|
+
log_info "FAILURE_LOG: No failure-log.md written by session"
|
|
300
|
+
fi
|
|
301
|
+
fi
|
|
302
|
+
|
|
291
303
|
# Update feature status
|
|
292
304
|
local update_output
|
|
293
305
|
update_output=$(python3 "$SCRIPTS_DIR/update-feature-status.py" \
|
|
@@ -8,6 +8,7 @@ to avoid duplication across pipeline scripts.
|
|
|
8
8
|
import json
|
|
9
9
|
import logging
|
|
10
10
|
import os
|
|
11
|
+
import re
|
|
11
12
|
import sys
|
|
12
13
|
|
|
13
14
|
|
|
@@ -107,26 +108,95 @@ def _build_progress_bar(percent, width=20):
|
|
|
107
108
|
return "{} {:>3}%".format(bar, int(percent))
|
|
108
109
|
|
|
109
110
|
|
|
111
|
+
def _read_file_safe(filepath):
|
|
112
|
+
"""Read a file and return its content, or empty string on error."""
|
|
113
|
+
try:
|
|
114
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
115
|
+
return f.read()
|
|
116
|
+
except (IOError, OSError):
|
|
117
|
+
return ""
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _detect_node_runtime(project_root, pkg):
|
|
121
|
+
"""Detect Node.js runtime version from engines, .nvmrc, or .node-version."""
|
|
122
|
+
engines = pkg.get("engines", {})
|
|
123
|
+
node_ver = engines.get("node", "")
|
|
124
|
+
if node_ver:
|
|
125
|
+
return "Node.js {}".format(node_ver)
|
|
126
|
+
|
|
127
|
+
for version_file in [".nvmrc", ".node-version"]:
|
|
128
|
+
vpath = os.path.join(project_root, version_file)
|
|
129
|
+
if os.path.isfile(vpath):
|
|
130
|
+
content = _read_file_safe(vpath).strip()
|
|
131
|
+
if content:
|
|
132
|
+
return "Node.js {}".format(content)
|
|
133
|
+
|
|
134
|
+
return "Node.js"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _parse_python_deps(py_content, req_content):
|
|
138
|
+
"""Extract Python package names from pyproject.toml and requirements.txt.
|
|
139
|
+
|
|
140
|
+
Returns a set of lowercased package names (without version specifiers).
|
|
141
|
+
"""
|
|
142
|
+
deps = set()
|
|
143
|
+
|
|
144
|
+
# Parse requirements.txt lines: "package==1.0", "package>=2.0", "package"
|
|
145
|
+
for line in req_content.splitlines():
|
|
146
|
+
line = line.strip()
|
|
147
|
+
if not line or line.startswith("#") or line.startswith("-"):
|
|
148
|
+
continue
|
|
149
|
+
# Split on version specifiers and extras
|
|
150
|
+
name = re.split(r"[>=<!~;\[\s]", line, 1)[0].strip()
|
|
151
|
+
if name:
|
|
152
|
+
deps.add(name.lower())
|
|
153
|
+
|
|
154
|
+
# Parse pyproject.toml dependencies (simplified: look for quoted strings
|
|
155
|
+
# in [project.dependencies] and [project.optional-dependencies.*] sections)
|
|
156
|
+
in_deps_section = False
|
|
157
|
+
for line in py_content.splitlines():
|
|
158
|
+
stripped = line.strip()
|
|
159
|
+
if stripped.startswith("["):
|
|
160
|
+
in_deps_section = (
|
|
161
|
+
"dependencies" in stripped.lower()
|
|
162
|
+
and "optional" not in stripped.lower()
|
|
163
|
+
) or "dependencies" in stripped.lower()
|
|
164
|
+
continue
|
|
165
|
+
if in_deps_section:
|
|
166
|
+
# Match quoted dependency: "flask>=2.0" or 'django~=4.0'
|
|
167
|
+
match = re.match(r"""^[\s"']*([a-zA-Z0-9_-]+)""", stripped)
|
|
168
|
+
if match:
|
|
169
|
+
deps.add(match.group(1).lower())
|
|
170
|
+
|
|
171
|
+
return deps
|
|
172
|
+
|
|
173
|
+
|
|
110
174
|
def detect_project_context(project_root):
|
|
111
175
|
"""Auto-detect project tech stack from project files.
|
|
112
176
|
|
|
113
|
-
Reads package.json, pyproject.toml,
|
|
114
|
-
to infer language,
|
|
115
|
-
|
|
177
|
+
Reads package.json, pyproject.toml, requirements.txt, docker-compose,
|
|
178
|
+
and common config files to infer language, frameworks, styling,
|
|
179
|
+
database, ORM, bundler, testing, and project type.
|
|
180
|
+
|
|
181
|
+
Returns a dict of detected key-value pairs. Only detected fields are
|
|
182
|
+
included — no empty or null values. Adapts to any project type
|
|
183
|
+
(frontend-only, backend-only, fullstack, library, CLI, monorepo).
|
|
116
184
|
"""
|
|
117
185
|
detected = {}
|
|
118
186
|
|
|
119
|
-
# 1. Node.js / JavaScript / TypeScript project
|
|
187
|
+
# ── 1. Node.js / JavaScript / TypeScript project ──
|
|
120
188
|
pkg_path = os.path.join(project_root, "package.json")
|
|
121
189
|
if os.path.isfile(pkg_path):
|
|
122
190
|
try:
|
|
123
191
|
with open(pkg_path, "r", encoding="utf-8") as f:
|
|
124
192
|
pkg = json.load(f)
|
|
125
193
|
|
|
126
|
-
#
|
|
194
|
+
# All dependencies combined for detection
|
|
127
195
|
deps = {}
|
|
128
196
|
deps.update(pkg.get("dependencies", {}))
|
|
129
197
|
deps.update(pkg.get("devDependencies", {}))
|
|
198
|
+
|
|
199
|
+
# Language
|
|
130
200
|
if "typescript" in deps or os.path.isfile(
|
|
131
201
|
os.path.join(project_root, "tsconfig.json")
|
|
132
202
|
):
|
|
@@ -134,7 +204,10 @@ def detect_project_context(project_root):
|
|
|
134
204
|
else:
|
|
135
205
|
detected["language"] = "JavaScript"
|
|
136
206
|
|
|
137
|
-
#
|
|
207
|
+
# Runtime
|
|
208
|
+
detected["runtime"] = _detect_node_runtime(project_root, pkg)
|
|
209
|
+
|
|
210
|
+
# Test framework (more specific first)
|
|
138
211
|
scripts = pkg.get("scripts", {})
|
|
139
212
|
test_script = (
|
|
140
213
|
scripts.get("test", "")
|
|
@@ -150,35 +223,256 @@ def detect_project_context(project_root):
|
|
|
150
223
|
elif "--test" in test_script or "node:test" in test_script:
|
|
151
224
|
detected["testing_framework"] = "Node.js built-in test runner"
|
|
152
225
|
|
|
153
|
-
#
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
226
|
+
# ── Frontend framework ──
|
|
227
|
+
frontend_frameworks = [
|
|
228
|
+
("next", "Next.js"),
|
|
229
|
+
("nuxt", "Nuxt"),
|
|
230
|
+
("@angular/core", "Angular"),
|
|
231
|
+
("svelte", "Svelte"),
|
|
232
|
+
("solid-js", "Solid.js"),
|
|
233
|
+
("react", "React"),
|
|
234
|
+
("vue", "Vue.js"),
|
|
235
|
+
]
|
|
236
|
+
for dep_name, fw_name in frontend_frameworks:
|
|
237
|
+
if dep_name in deps:
|
|
238
|
+
detected["frontend_framework"] = fw_name
|
|
239
|
+
break
|
|
240
|
+
|
|
241
|
+
# ── Backend framework ──
|
|
242
|
+
backend_frameworks = [
|
|
243
|
+
("@nestjs/core", "NestJS"),
|
|
244
|
+
("express", "Express.js"),
|
|
245
|
+
("fastify", "Fastify"),
|
|
246
|
+
("koa", "Koa"),
|
|
247
|
+
("hapi", "Hapi"),
|
|
248
|
+
("hono", "Hono"),
|
|
249
|
+
]
|
|
250
|
+
for dep_name, fw_name in backend_frameworks:
|
|
251
|
+
if dep_name in deps:
|
|
252
|
+
detected["backend_framework"] = fw_name
|
|
253
|
+
break
|
|
254
|
+
|
|
255
|
+
# Legacy "framework" field for backward compatibility
|
|
256
|
+
if "frontend_framework" in detected:
|
|
257
|
+
detected["framework"] = detected["frontend_framework"]
|
|
258
|
+
elif "backend_framework" in detected:
|
|
259
|
+
detected["framework"] = detected["backend_framework"]
|
|
260
|
+
|
|
261
|
+
# ── Frontend styling ──
|
|
262
|
+
styling_libs = [
|
|
263
|
+
("tailwindcss", "Tailwind CSS"),
|
|
264
|
+
("@tailwindcss/vite", "Tailwind CSS"),
|
|
265
|
+
("styled-components", "Styled Components"),
|
|
266
|
+
("@emotion/react", "Emotion"),
|
|
267
|
+
("@emotion/styled", "Emotion"),
|
|
268
|
+
("@mui/material", "Material UI"),
|
|
269
|
+
("@chakra-ui/react", "Chakra UI"),
|
|
270
|
+
("antd", "Ant Design"),
|
|
271
|
+
("sass", "SCSS/Sass"),
|
|
272
|
+
("node-sass", "SCSS/Sass"),
|
|
273
|
+
("less", "Less"),
|
|
274
|
+
]
|
|
275
|
+
for dep_name, style_name in styling_libs:
|
|
276
|
+
if dep_name in deps:
|
|
277
|
+
detected["frontend_styling"] = style_name
|
|
278
|
+
break
|
|
279
|
+
|
|
280
|
+
# ── Database ──
|
|
281
|
+
db_libs = [
|
|
282
|
+
("pg", "PostgreSQL"),
|
|
283
|
+
("postgres", "PostgreSQL"),
|
|
284
|
+
("mysql2", "MySQL"),
|
|
285
|
+
("mysql", "MySQL"),
|
|
286
|
+
("better-sqlite3", "SQLite"),
|
|
287
|
+
("mongodb", "MongoDB"),
|
|
288
|
+
("mongoose", "MongoDB"),
|
|
289
|
+
("redis", "Redis"),
|
|
290
|
+
("ioredis", "Redis"),
|
|
291
|
+
]
|
|
292
|
+
for dep_name, db_name in db_libs:
|
|
293
|
+
if dep_name in deps:
|
|
294
|
+
detected["database"] = db_name
|
|
295
|
+
break
|
|
296
|
+
|
|
297
|
+
# ── ORM ──
|
|
298
|
+
orm_libs = [
|
|
299
|
+
("@prisma/client", "Prisma"),
|
|
300
|
+
("prisma", "Prisma"),
|
|
301
|
+
("drizzle-orm", "Drizzle"),
|
|
302
|
+
("typeorm", "TypeORM"),
|
|
303
|
+
("sequelize", "Sequelize"),
|
|
304
|
+
("mongoose", "Mongoose"),
|
|
305
|
+
("knex", "Knex.js"),
|
|
306
|
+
("@mikro-orm/core", "MikroORM"),
|
|
307
|
+
]
|
|
308
|
+
for dep_name, orm_name in orm_libs:
|
|
309
|
+
if dep_name in deps:
|
|
310
|
+
detected["orm"] = orm_name
|
|
311
|
+
break
|
|
312
|
+
|
|
313
|
+
# ── Bundler ──
|
|
314
|
+
bundler_libs = [
|
|
315
|
+
("vite", "Vite"),
|
|
316
|
+
("webpack", "Webpack"),
|
|
317
|
+
("esbuild", "esbuild"),
|
|
318
|
+
("rollup", "Rollup"),
|
|
319
|
+
("parcel", "Parcel"),
|
|
320
|
+
("turbo", "Turborepo"),
|
|
321
|
+
("@rspack/core", "Rspack"),
|
|
322
|
+
]
|
|
323
|
+
for dep_name, bundler_name in bundler_libs:
|
|
324
|
+
if dep_name in deps:
|
|
325
|
+
detected["bundler"] = bundler_name
|
|
326
|
+
break
|
|
327
|
+
|
|
328
|
+
# ── Project type inference ──
|
|
329
|
+
has_frontend = "frontend_framework" in detected
|
|
330
|
+
has_backend = "backend_framework" in detected
|
|
331
|
+
has_workspaces = "workspaces" in pkg
|
|
332
|
+
has_bin = "bin" in pkg
|
|
333
|
+
|
|
334
|
+
if has_workspaces:
|
|
335
|
+
detected["project_type"] = "monorepo"
|
|
336
|
+
elif has_frontend and has_backend:
|
|
337
|
+
detected["project_type"] = "fullstack"
|
|
338
|
+
elif has_frontend:
|
|
339
|
+
detected["project_type"] = "frontend"
|
|
340
|
+
elif has_backend:
|
|
341
|
+
detected["project_type"] = "backend"
|
|
342
|
+
elif has_bin:
|
|
343
|
+
detected["project_type"] = "cli"
|
|
344
|
+
elif "main" in pkg or "exports" in pkg:
|
|
345
|
+
detected["project_type"] = "library"
|
|
346
|
+
|
|
164
347
|
except (json.JSONDecodeError, IOError):
|
|
165
348
|
pass
|
|
166
349
|
|
|
167
|
-
# 2. Python project detection
|
|
168
|
-
if not detected:
|
|
350
|
+
# ── 2. Python project detection ──
|
|
351
|
+
if "language" not in detected:
|
|
352
|
+
py_content = ""
|
|
169
353
|
for marker in ["pyproject.toml", "setup.py", "requirements.txt"]:
|
|
170
|
-
|
|
354
|
+
marker_path = os.path.join(project_root, marker)
|
|
355
|
+
if os.path.isfile(marker_path):
|
|
171
356
|
detected["language"] = "Python"
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
357
|
+
if marker == "pyproject.toml":
|
|
358
|
+
py_content = _read_file_safe(marker_path)
|
|
359
|
+
break
|
|
360
|
+
|
|
361
|
+
if detected.get("language") == "Python":
|
|
362
|
+
req_path = os.path.join(project_root, "requirements.txt")
|
|
363
|
+
req_content = _read_file_safe(req_path) if os.path.isfile(req_path) else ""
|
|
364
|
+
py_deps = _parse_python_deps(py_content, req_content)
|
|
365
|
+
|
|
366
|
+
# Runtime version (regex for requires-python = ">=3.11")
|
|
367
|
+
if py_content:
|
|
368
|
+
ver_match = re.search(
|
|
369
|
+
r'requires-python\s*=\s*["\']([^"\']+)["\']', py_content
|
|
370
|
+
)
|
|
371
|
+
if ver_match:
|
|
372
|
+
detected["runtime"] = "Python {}".format(ver_match.group(1))
|
|
373
|
+
|
|
374
|
+
# Testing
|
|
375
|
+
if "pytest" in py_deps:
|
|
376
|
+
detected["testing_framework"] = "pytest"
|
|
377
|
+
|
|
378
|
+
# Backend framework
|
|
379
|
+
py_backend = [
|
|
380
|
+
("django", "Django"),
|
|
381
|
+
("fastapi", "FastAPI"),
|
|
382
|
+
("flask", "Flask"),
|
|
383
|
+
("starlette", "Starlette"),
|
|
384
|
+
("tornado", "Tornado"),
|
|
385
|
+
("aiohttp", "aiohttp"),
|
|
386
|
+
]
|
|
387
|
+
for dep_name, fw_name in py_backend:
|
|
388
|
+
if dep_name in py_deps:
|
|
389
|
+
detected["backend_framework"] = fw_name
|
|
390
|
+
detected["framework"] = fw_name
|
|
391
|
+
break
|
|
392
|
+
|
|
393
|
+
# Database / ORM
|
|
394
|
+
py_db = [
|
|
395
|
+
("psycopg2", "PostgreSQL"),
|
|
396
|
+
("psycopg", "PostgreSQL"),
|
|
397
|
+
("asyncpg", "PostgreSQL"),
|
|
398
|
+
("pymysql", "MySQL"),
|
|
399
|
+
("pymongo", "MongoDB"),
|
|
400
|
+
("motor", "MongoDB"),
|
|
401
|
+
]
|
|
402
|
+
for dep_name, db_name in py_db:
|
|
403
|
+
if dep_name in py_deps:
|
|
404
|
+
detected["database"] = db_name
|
|
405
|
+
break
|
|
406
|
+
|
|
407
|
+
py_orm = [
|
|
408
|
+
("sqlalchemy", "SQLAlchemy"),
|
|
409
|
+
("tortoise-orm", "Tortoise ORM"),
|
|
410
|
+
("peewee", "Peewee"),
|
|
411
|
+
]
|
|
412
|
+
for dep_name, orm_name in py_orm:
|
|
413
|
+
if dep_name in py_deps:
|
|
414
|
+
detected["orm"] = orm_name
|
|
415
|
+
break
|
|
416
|
+
# Django ORM: if django is a dep and no other ORM detected
|
|
417
|
+
if "django" in py_deps and "orm" not in detected:
|
|
418
|
+
detected["orm"] = "Django ORM"
|
|
419
|
+
|
|
420
|
+
# Project type
|
|
421
|
+
if "backend_framework" in detected:
|
|
422
|
+
detected["project_type"] = "backend"
|
|
423
|
+
|
|
424
|
+
# ── 3. Go project detection ──
|
|
425
|
+
if "language" not in detected:
|
|
426
|
+
go_mod_path = os.path.join(project_root, "go.mod")
|
|
427
|
+
if os.path.isfile(go_mod_path):
|
|
428
|
+
detected["language"] = "Go"
|
|
429
|
+
detected["runtime"] = "Go"
|
|
430
|
+
go_content = _read_file_safe(go_mod_path)
|
|
431
|
+
if "gin-gonic" in go_content:
|
|
432
|
+
detected["backend_framework"] = "Gin"
|
|
433
|
+
elif "labstack/echo" in go_content:
|
|
434
|
+
detected["backend_framework"] = "Echo"
|
|
435
|
+
elif "go-chi/chi" in go_content:
|
|
436
|
+
detected["backend_framework"] = "Chi"
|
|
437
|
+
if "backend_framework" in detected:
|
|
438
|
+
detected["framework"] = detected["backend_framework"]
|
|
439
|
+
detected["project_type"] = "backend"
|
|
440
|
+
|
|
441
|
+
# ── 4. Rust / Java / other languages (basic detection) ──
|
|
442
|
+
if "language" not in detected:
|
|
443
|
+
if os.path.isfile(os.path.join(project_root, "Cargo.toml")):
|
|
444
|
+
detected["language"] = "Rust"
|
|
445
|
+
detected["runtime"] = "Rust"
|
|
446
|
+
elif os.path.isfile(os.path.join(project_root, "pom.xml")):
|
|
447
|
+
detected["language"] = "Java"
|
|
448
|
+
detected["runtime"] = "Java (Maven)"
|
|
449
|
+
elif os.path.isfile(os.path.join(project_root, "build.gradle")):
|
|
450
|
+
detected["language"] = "Java/Kotlin"
|
|
451
|
+
detected["runtime"] = "Java (Gradle)"
|
|
452
|
+
|
|
453
|
+
# ── 5. Database from docker-compose (cross-language) ──
|
|
454
|
+
if "database" not in detected:
|
|
455
|
+
for dc_name in [
|
|
456
|
+
"docker-compose.yml",
|
|
457
|
+
"docker-compose.yaml",
|
|
458
|
+
"compose.yml",
|
|
459
|
+
"compose.yaml",
|
|
460
|
+
]:
|
|
461
|
+
dc_path = os.path.join(project_root, dc_name)
|
|
462
|
+
if os.path.isfile(dc_path):
|
|
463
|
+
dc_content = _read_file_safe(dc_path).lower()
|
|
464
|
+
dc_db = [
|
|
465
|
+
("postgres", "PostgreSQL"),
|
|
466
|
+
("mysql", "MySQL"),
|
|
467
|
+
("mariadb", "MariaDB"),
|
|
468
|
+
("mongo", "MongoDB"),
|
|
469
|
+
("redis", "Redis"),
|
|
470
|
+
("sqlite", "SQLite"),
|
|
471
|
+
]
|
|
472
|
+
for pattern, db_name in dc_db:
|
|
473
|
+
if pattern in dc_content:
|
|
474
|
+
detected["database"] = db_name
|
|
475
|
+
break
|
|
182
476
|
break
|
|
183
477
|
|
|
184
478
|
return detected
|
|
@@ -199,10 +493,18 @@ def enrich_global_context(global_context, project_root):
|
|
|
199
493
|
"language": "language",
|
|
200
494
|
"testing_framework": "testing_strategy",
|
|
201
495
|
"framework": "framework",
|
|
496
|
+
"frontend_framework": "frontend_framework",
|
|
497
|
+
"frontend_styling": "frontend_styling",
|
|
498
|
+
"backend_framework": "backend_framework",
|
|
499
|
+
"database": "database",
|
|
500
|
+
"orm": "orm",
|
|
501
|
+
"bundler": "bundler",
|
|
502
|
+
"project_type": "project_type",
|
|
503
|
+
"runtime": "runtime",
|
|
202
504
|
}
|
|
203
505
|
# Alternate key names that should block auto-detection
|
|
204
506
|
alt_keys = {
|
|
205
|
-
"testing_strategy": ["testing_framework", "test_framework"],
|
|
507
|
+
"testing_strategy": ["testing_framework", "test_framework", "testing"],
|
|
206
508
|
}
|
|
207
509
|
for det_key, ctx_key in key_mapping.items():
|
|
208
510
|
if det_key not in detected:
|
|
@@ -73,6 +73,15 @@ Check `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` — if it exists, s
|
|
|
73
73
|
|
|
74
74
|
### Phase 1: Build Context Snapshot
|
|
75
75
|
|
|
76
|
+
**Check for previous failure log:**
|
|
77
|
+
```bash
|
|
78
|
+
cat .prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md 2>/dev/null || echo "NO_PREVIOUS_FAILURE"
|
|
79
|
+
```
|
|
80
|
+
If failure-log.md exists:
|
|
81
|
+
- Read ROOT_CAUSE and SUGGESTION — adjust your approach accordingly
|
|
82
|
+
- Read DISCOVERED_TRAPS — if any are genuine, inject into .prizm-docs/ during Phase 4 retrospective
|
|
83
|
+
- Do NOT delete failure-log.md until this session succeeds
|
|
84
|
+
|
|
76
85
|
```bash
|
|
77
86
|
ls .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md 2>/dev/null && echo "EXISTS" || echo "MISSING"
|
|
78
87
|
```
|
|
@@ -167,6 +176,23 @@ git commit -m "chore({{FEATURE_ID}}): include session artifacts"
|
|
|
167
176
|
| Context Snapshot | `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` |
|
|
168
177
|
| Project Root | {{PROJECT_ROOT}} |
|
|
169
178
|
|
|
179
|
+
## Failure Capture Protocol
|
|
180
|
+
|
|
181
|
+
If you encounter an unrecoverable error, context overflow, or are about to exit without completing all phases:
|
|
182
|
+
|
|
183
|
+
1. Write `.prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md` BEFORE exiting:
|
|
184
|
+
```
|
|
185
|
+
FAILURE_TYPE: timeout | test_failure | review_rejected | context_overflow | unknown
|
|
186
|
+
PHASE: <which phase failed>
|
|
187
|
+
ROOT_CAUSE: <1-2 sentence explanation>
|
|
188
|
+
ATTEMPTED: <approaches already tried>
|
|
189
|
+
SUGGESTION: <what the next session should try differently>
|
|
190
|
+
DISCOVERED_TRAPS:
|
|
191
|
+
- [CRITICAL|HIGH|LOW] <gotcha discovered during this failed session> | FIX: <approach>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
2. This file is intentionally lightweight — write it BEFORE context runs out.
|
|
195
|
+
|
|
170
196
|
## Reminders
|
|
171
197
|
|
|
172
198
|
- Tier 1: you handle everything directly — no subagents needed
|
|
@@ -84,6 +84,15 @@ Check `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` — if exists, skip
|
|
|
84
84
|
|
|
85
85
|
### Phase 1: Build Context Snapshot (you, the orchestrator)
|
|
86
86
|
|
|
87
|
+
**Check for previous failure log:**
|
|
88
|
+
```bash
|
|
89
|
+
cat .prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md 2>/dev/null || echo "NO_PREVIOUS_FAILURE"
|
|
90
|
+
```
|
|
91
|
+
If failure-log.md exists:
|
|
92
|
+
- Read ROOT_CAUSE and SUGGESTION — adjust your approach accordingly
|
|
93
|
+
- Read DISCOVERED_TRAPS — if any are genuine, inject into .prizm-docs/ during Phase 5 retrospective
|
|
94
|
+
- Do NOT delete failure-log.md until this session succeeds
|
|
95
|
+
|
|
87
96
|
```bash
|
|
88
97
|
ls .prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md 2>/dev/null && echo "EXISTS" || echo "MISSING"
|
|
89
98
|
```
|
|
@@ -216,6 +225,23 @@ git commit -m "chore({{FEATURE_ID}}): include session artifacts"
|
|
|
216
225
|
| Reviewer Agent Def | {{REVIEWER_SUBAGENT_PATH}} |
|
|
217
226
|
| Project Root | {{PROJECT_ROOT}} |
|
|
218
227
|
|
|
228
|
+
## Failure Capture Protocol
|
|
229
|
+
|
|
230
|
+
If you encounter an unrecoverable error, context overflow, or are about to exit without completing all phases:
|
|
231
|
+
|
|
232
|
+
1. Write `.prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md` BEFORE exiting:
|
|
233
|
+
```
|
|
234
|
+
FAILURE_TYPE: timeout | test_failure | review_rejected | context_overflow | unknown
|
|
235
|
+
PHASE: <which phase failed>
|
|
236
|
+
ROOT_CAUSE: <1-2 sentence explanation>
|
|
237
|
+
ATTEMPTED: <approaches already tried>
|
|
238
|
+
SUGGESTION: <what the next session should try differently>
|
|
239
|
+
DISCOVERED_TRAPS:
|
|
240
|
+
- [CRITICAL|HIGH|LOW] <gotcha discovered during this failed session> | FIX: <approach>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
2. This file is intentionally lightweight — write it BEFORE context runs out.
|
|
244
|
+
|
|
219
245
|
## Reminders
|
|
220
246
|
|
|
221
247
|
- Tier 2: orchestrator builds context+plan, Dev implements, Reviewer reviews+tests — use direct Agent spawn for agents
|
|
@@ -147,6 +147,15 @@ After team setup: check `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md`
|
|
|
147
147
|
|
|
148
148
|
### Phase 1-2: Specify + Plan — Orchestrator (you)
|
|
149
149
|
|
|
150
|
+
**Check for previous failure log:**
|
|
151
|
+
```bash
|
|
152
|
+
cat .prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md 2>/dev/null || echo "NO_PREVIOUS_FAILURE"
|
|
153
|
+
```
|
|
154
|
+
If failure-log.md exists:
|
|
155
|
+
- Read ROOT_CAUSE and SUGGESTION — adjust your approach accordingly
|
|
156
|
+
- Read DISCOVERED_TRAPS — if any are genuine, inject into .prizm-docs/ during Phase 6 retrospective
|
|
157
|
+
- Do NOT delete failure-log.md until this session succeeds
|
|
158
|
+
|
|
150
159
|
Check existing artifacts first:
|
|
151
160
|
```bash
|
|
152
161
|
ls .prizmkit/specs/{{FEATURE_SLUG}}/ 2>/dev/null
|
|
@@ -396,6 +405,23 @@ git commit -m "chore({{FEATURE_ID}}): include session artifacts"
|
|
|
396
405
|
| Project Root | {{PROJECT_ROOT}} |
|
|
397
406
|
| Feature List Path | {{FEATURE_LIST_PATH}} |
|
|
398
407
|
|
|
408
|
+
## Failure Capture Protocol
|
|
409
|
+
|
|
410
|
+
If you encounter an unrecoverable error, context overflow, or are about to exit without completing all phases:
|
|
411
|
+
|
|
412
|
+
1. Write `.prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md` BEFORE exiting:
|
|
413
|
+
```
|
|
414
|
+
FAILURE_TYPE: timeout | test_failure | review_rejected | context_overflow | unknown
|
|
415
|
+
PHASE: <which phase failed>
|
|
416
|
+
ROOT_CAUSE: <1-2 sentence explanation>
|
|
417
|
+
ATTEMPTED: <approaches already tried>
|
|
418
|
+
SUGGESTION: <what the next session should try differently>
|
|
419
|
+
DISCOVERED_TRAPS:
|
|
420
|
+
- [CRITICAL|HIGH|LOW] <gotcha discovered during this failed session> | FIX: <approach>
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
2. This file is intentionally lightweight — write it BEFORE context runs out.
|
|
424
|
+
|
|
399
425
|
## Reminders
|
|
400
426
|
|
|
401
427
|
- Tier 3: full team — Dev (implementation) → Reviewer (review + test) — spawn agents directly via Agent tool
|
|
@@ -151,7 +151,16 @@
|
|
|
151
151
|
"description": "Global context for all bug fixes in this batch",
|
|
152
152
|
"properties": {
|
|
153
153
|
"tech_stack": { "type": "string" },
|
|
154
|
-
"
|
|
154
|
+
"language": { "type": "string" },
|
|
155
|
+
"runtime": { "type": "string" },
|
|
156
|
+
"frontend_framework": { "type": "string" },
|
|
157
|
+
"frontend_styling": { "type": "string" },
|
|
158
|
+
"backend_framework": { "type": "string" },
|
|
159
|
+
"database": { "type": "string" },
|
|
160
|
+
"orm": { "type": "string" },
|
|
161
|
+
"testing_strategy": { "type": "string" },
|
|
162
|
+
"bundler": { "type": "string" },
|
|
163
|
+
"project_type": { "type": "string" },
|
|
155
164
|
"ci_pipeline": { "type": "string" }
|
|
156
165
|
}
|
|
157
166
|
}
|
|
@@ -108,8 +108,17 @@
|
|
|
108
108
|
"type": "object",
|
|
109
109
|
"properties": {
|
|
110
110
|
"tech_stack": { "type": "string" },
|
|
111
|
+
"language": { "type": "string" },
|
|
112
|
+
"runtime": { "type": "string" },
|
|
113
|
+
"frontend_framework": { "type": "string" },
|
|
114
|
+
"frontend_styling": { "type": "string" },
|
|
115
|
+
"backend_framework": { "type": "string" },
|
|
116
|
+
"database": { "type": "string" },
|
|
117
|
+
"orm": { "type": "string" },
|
|
111
118
|
"design_system": { "type": "string" },
|
|
112
|
-
"testing_strategy": { "type": "string" }
|
|
119
|
+
"testing_strategy": { "type": "string" },
|
|
120
|
+
"bundler": { "type": "string" },
|
|
121
|
+
"project_type": { "type": "string" }
|
|
113
122
|
}
|
|
114
123
|
}
|
|
115
124
|
}
|
|
@@ -47,8 +47,15 @@ Do NOT use this skill when:
|
|
|
47
47
|
|
|
48
48
|
Before questions, check optional context files (never block if absent):
|
|
49
49
|
- `.prizm-docs/root.prizm` (architecture/project context)
|
|
50
|
-
- `.prizmkit/config.json` (existing stack preferences)
|
|
50
|
+
- `.prizmkit/config.json` (existing stack preferences and detected tech stack)
|
|
51
51
|
- existing `feature-list.json` (required for incremental mode)
|
|
52
|
+
|
|
53
|
+
**Tech stack auto-population from config.json:**
|
|
54
|
+
- If `.prizmkit/config.json` contains a `tech_stack` object, use it to pre-fill `global_context` fields in the generated `feature-list.json`.
|
|
55
|
+
- Map config fields to global_context: `language`, `runtime`, `frontend_framework`, `frontend_styling`, `backend_framework`, `database`, `orm`, `testing` → `testing_strategy`, `bundler`, `project_type`.
|
|
56
|
+
- Do NOT re-ask the user for tech stack info that is already present in config.json. Instead, show the detected stack and ask: "Is this correct? Any changes?"
|
|
57
|
+
- If config.json has no `tech_stack`, fall back to asking during Phase 2 (constraints and tech assumptions).
|
|
58
|
+
|
|
52
59
|
Note:
|
|
53
60
|
- This skill **reads** `.prizmkit/config.json` if present.
|
|
54
61
|
- This skill does **not** create `.prizmkit/config.json` directly.
|
|
@@ -43,8 +43,8 @@ Launch the interactive bug planning process through 4 phases.
|
|
|
43
43
|
### Phase 1: Project Context
|
|
44
44
|
|
|
45
45
|
1. **Identify project**: Read project name and description from existing `feature-list.json` or ask user
|
|
46
|
-
2. **Identify tech stack**: Read from `feature-list.json` global_context
|
|
47
|
-
3. **Identify testing framework**:
|
|
46
|
+
2. **Identify tech stack**: Read from `.prizmkit/config.json` `tech_stack` (preferred), then `feature-list.json` global_context, then `.prizm-docs/root.prizm`. Only ask user if none of these sources provide tech stack info.
|
|
47
|
+
3. **Identify testing framework**: Read from `.prizmkit/config.json` `tech_stack.testing`, or auto-detect from package.json/requirements.txt/etc., or ask user
|
|
48
48
|
|
|
49
49
|
Output: `project_name`, `project_description`, `global_context` fields populated.
|
|
50
50
|
|
|
@@ -35,6 +35,8 @@ Project takeover and bootstrap skill. Scans any project (brownfield or greenfiel
|
|
|
35
35
|
|
|
36
36
|
MODE DETECTION:
|
|
37
37
|
- If `.prizm-docs/` exists: Ask user if they want to reinitialize or update
|
|
38
|
+
- **Reinitialize**: overwrites `.prizm-docs/` and `config.json` tech_stack (fresh start)
|
|
39
|
+
- **Update**: re-scans tech stack and merges changes into existing `config.json` (see Step 3b merge strategy); updates `root.prizm` TECH_STACK if changed; preserves existing `.prizm-docs/` L1/L2 docs
|
|
38
40
|
- If project has source code: brownfield mode
|
|
39
41
|
- If project is nearly empty: greenfield mode
|
|
40
42
|
|
|
@@ -50,6 +52,18 @@ BROWNFIELD WORKFLOW (existing project):
|
|
|
50
52
|
3. Identify entry points by language convention
|
|
51
53
|
4. Catalog dependencies (external packages)
|
|
52
54
|
5. Count source files per directory
|
|
55
|
+
6. Detect detailed tech stack (adaptive — only include fields that apply to this project):
|
|
56
|
+
- **Language & Runtime**: e.g. TypeScript + Node.js 20, Python 3.11, Go 1.22
|
|
57
|
+
- **Frontend framework** (if applicable): React, Vue.js, Angular, Next.js, Svelte, etc.
|
|
58
|
+
- **Frontend styling** (if applicable): Tailwind CSS, SCSS, Styled Components, Material UI, etc.
|
|
59
|
+
- **Backend framework** (if applicable): Express.js, FastAPI, Django, NestJS, Gin, etc.
|
|
60
|
+
- **Database** (if applicable): PostgreSQL, MySQL, MongoDB, Redis, SQLite — detected from deps or `docker-compose.yml`
|
|
61
|
+
- **ORM** (if applicable): Prisma, Drizzle, TypeORM, SQLAlchemy, Mongoose, etc.
|
|
62
|
+
- **Bundler** (if applicable): Vite, Webpack, esbuild, Rollup, Turborepo
|
|
63
|
+
- **Testing**: Vitest, Jest, pytest, Go test, etc.
|
|
64
|
+
- **Project type** (inferred): `frontend` | `backend` | `fullstack` | `library` | `cli` | `monorepo`
|
|
65
|
+
|
|
66
|
+
**IMPORTANT**: Not all projects have all fields. A pure backend API will have no `frontend_framework` or `frontend_styling`. A library may have no database. Only record what is actually detected — never generate empty or placeholder values.
|
|
53
67
|
|
|
54
68
|
**Step 2: Prizm Documentation Generation**
|
|
55
69
|
Invoke prizmkit-prizm-docs (Init operation), passing the two-tier module structure from Step 1:
|
|
@@ -64,6 +78,57 @@ Invoke prizmkit-prizm-docs (Init operation), passing the two-tier module structu
|
|
|
64
78
|
- `.prizmkit/config.json` (adoption_mode, speckit_hooks_enabled, platform)
|
|
65
79
|
- `.prizmkit/specs/` (empty)
|
|
66
80
|
|
|
81
|
+
3b. Write detected tech stack to `.prizmkit/config.json`:
|
|
82
|
+
|
|
83
|
+
**Merge strategy** (handles re-init without losing user edits):
|
|
84
|
+
- Read existing `config.json` if present
|
|
85
|
+
- If `tech_stack` field exists AND `_auto_detected` is `false` or absent:
|
|
86
|
+
→ **SKIP** — user has manually configured tech stack, preserve their settings
|
|
87
|
+
- If `tech_stack` field exists AND `_auto_detected` is `true`:
|
|
88
|
+
→ **MERGE** — overwrite auto-detected values with new detection results, but preserve any keys the user added manually (keys not in the new detection result)
|
|
89
|
+
- If `tech_stack` field does NOT exist:
|
|
90
|
+
→ **WRITE** full detected tech stack with `"_auto_detected": true`
|
|
91
|
+
- Only include fields that were actually detected (no empty/null values)
|
|
92
|
+
|
|
93
|
+
Example config.json after init (fullstack project):
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"adoption_mode": "passive",
|
|
97
|
+
"platform": "claude",
|
|
98
|
+
"tech_stack": {
|
|
99
|
+
"language": "TypeScript",
|
|
100
|
+
"runtime": "Node.js 20",
|
|
101
|
+
"frontend_framework": "React",
|
|
102
|
+
"frontend_styling": "Tailwind CSS",
|
|
103
|
+
"backend_framework": "Express.js",
|
|
104
|
+
"database": "PostgreSQL",
|
|
105
|
+
"orm": "Prisma",
|
|
106
|
+
"testing": "Vitest",
|
|
107
|
+
"bundler": "Vite",
|
|
108
|
+
"project_type": "fullstack",
|
|
109
|
+
"_auto_detected": true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Example config.json after init (pure Python backend):
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"adoption_mode": "passive",
|
|
118
|
+
"platform": "claude",
|
|
119
|
+
"tech_stack": {
|
|
120
|
+
"language": "Python",
|
|
121
|
+
"runtime": "Python >=3.11",
|
|
122
|
+
"backend_framework": "FastAPI",
|
|
123
|
+
"database": "PostgreSQL",
|
|
124
|
+
"orm": "SQLAlchemy",
|
|
125
|
+
"testing": "pytest",
|
|
126
|
+
"project_type": "backend",
|
|
127
|
+
"_auto_detected": true
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
67
132
|
**Step 4: Hook & Settings Configuration**
|
|
68
133
|
|
|
69
134
|
4a. Read or create platform settings file (`.codebuddy/settings.json` or `.claude/settings.json`)
|
|
@@ -74,15 +139,44 @@ Invoke prizmkit-prizm-docs (Init operation), passing the two-tier module structu
|
|
|
74
139
|
4d. Preserve any existing hooks and settings — never overwrite user's custom configuration
|
|
75
140
|
|
|
76
141
|
**Step 5: Report**
|
|
77
|
-
Output summary: platform detected, tech stack detected, modules discovered, L1 docs generated, platform-specific configuration applied, next recommended steps.
|
|
142
|
+
Output summary: platform detected, tech stack detected (with detail), modules discovered, L1 docs generated, platform-specific configuration applied, next recommended steps.
|
|
143
|
+
|
|
144
|
+
Tech stack report format (only show detected fields, adapt to project type):
|
|
145
|
+
```
|
|
146
|
+
Tech stack detected:
|
|
147
|
+
Language: TypeScript
|
|
148
|
+
Runtime: Node.js 20
|
|
149
|
+
Frontend: React + Tailwind CSS
|
|
150
|
+
Backend: Express.js
|
|
151
|
+
Database: PostgreSQL (Prisma)
|
|
152
|
+
Testing: Vitest
|
|
153
|
+
Bundler: Vite
|
|
154
|
+
Project type: fullstack
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
For a pure backend Python project, the report would show:
|
|
158
|
+
```
|
|
159
|
+
Tech stack detected:
|
|
160
|
+
Language: Python
|
|
161
|
+
Runtime: Python >=3.11
|
|
162
|
+
Backend: FastAPI
|
|
163
|
+
Database: PostgreSQL (SQLAlchemy)
|
|
164
|
+
Testing: pytest
|
|
165
|
+
Project type: backend
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Saved to: `.prizmkit/config.json` → `tech_stack` field
|
|
78
169
|
|
|
79
170
|
Include platform-specific guidance:
|
|
80
171
|
- CodeBuddy: "Use `/prizmkit-specify` to start your first feature"
|
|
81
172
|
- Claude Code: "Use `/prizmkit-specify` to start your first feature"
|
|
82
173
|
|
|
83
174
|
GREENFIELD WORKFLOW (new project):
|
|
84
|
-
- Skip Step 1 (no code to scan)
|
|
85
|
-
-
|
|
175
|
+
- Skip Step 1 (no code to scan) — but ask the user about their intended tech stack:
|
|
176
|
+
- "What language/framework will you use?" (e.g. React + Node.js, Python + FastAPI, etc.)
|
|
177
|
+
- Record answers in `config.json` `tech_stack` with `"_auto_detected": false` (user-provided, not auto-detected)
|
|
178
|
+
- If user is unsure, skip tech_stack — it can be populated later on re-init after code exists
|
|
179
|
+
- Step 2: Create minimal `.prizm-docs/` with just `root.prizm` skeleton (populate TECH_STACK from user answers if provided)
|
|
86
180
|
- Steps 3-5: Same as brownfield (Step 5 Report recommends starting with specify for first feature)
|
|
87
181
|
|
|
88
182
|
### Gradual Adoption Path
|
|
@@ -107,14 +201,23 @@ User can change mode in `.prizmkit/config.json`: `"adoption_mode": "passive" | "
|
|
|
107
201
|
|
|
108
202
|
## Example
|
|
109
203
|
|
|
110
|
-
**Brownfield init on a Node.js project:**
|
|
204
|
+
**Brownfield init on a fullstack Node.js project:**
|
|
111
205
|
```
|
|
112
206
|
$ /prizmkit-init
|
|
113
207
|
|
|
114
208
|
Platform detected: Claude Code
|
|
115
|
-
Tech stack: TypeScript, Node.js, Express
|
|
116
209
|
Mode: Brownfield (154 source files found)
|
|
117
210
|
|
|
211
|
+
Tech stack detected:
|
|
212
|
+
Language: TypeScript
|
|
213
|
+
Runtime: Node.js 20
|
|
214
|
+
Frontend: React + Tailwind CSS
|
|
215
|
+
Backend: Express.js
|
|
216
|
+
Database: PostgreSQL (Prisma)
|
|
217
|
+
Testing: Vitest
|
|
218
|
+
Bundler: Vite
|
|
219
|
+
Project type: fullstack
|
|
220
|
+
|
|
118
221
|
Modules discovered:
|
|
119
222
|
src/routes/ → .prizm-docs/routes.prizm (12 files)
|
|
120
223
|
src/models/ → .prizm-docs/models.prizm (8 files)
|
|
@@ -123,8 +226,25 @@ Modules discovered:
|
|
|
123
226
|
|
|
124
227
|
Generated: root.prizm + 4 L1 docs + changelog.prizm
|
|
125
228
|
Configured: .claude/rules/ (2 files), hooks in settings.json
|
|
229
|
+
Saved: .prizmkit/config.json (tech_stack recorded)
|
|
126
230
|
|
|
127
231
|
Next: Use /prizmkit-specify to start your first feature
|
|
128
232
|
```
|
|
129
233
|
|
|
234
|
+
**Re-init after PrizmKit upgrade (existing config preserved):**
|
|
235
|
+
```
|
|
236
|
+
$ /prizmkit-init
|
|
237
|
+
|
|
238
|
+
.prizm-docs/ already exists. Reinitialize or update?
|
|
239
|
+
> Update (preserve existing docs)
|
|
240
|
+
|
|
241
|
+
Tech stack changes detected:
|
|
242
|
+
+ bundler: Vite (newly detected)
|
|
243
|
+
~ testing: Jest → Vitest (updated)
|
|
244
|
+
= language: TypeScript (unchanged)
|
|
245
|
+
= frontend: React (unchanged)
|
|
246
|
+
|
|
247
|
+
Merged into .prizmkit/config.json (2 fields updated, user overrides preserved)
|
|
248
|
+
```
|
|
249
|
+
|
|
130
250
|
IMPORTANT: Use `${SKILL_DIR}` placeholder for all path references. Never hardcode absolute paths.
|
|
@@ -121,7 +121,7 @@ Check format compliance and consistency of all .prizm docs.
|
|
|
121
121
|
PRECONDITION: .prizm-docs/ exists.
|
|
122
122
|
|
|
123
123
|
STEPS:
|
|
124
|
-
1. FORMAT CHECK: Verify all .prizm files use KEY: value format. Flag any prose paragraphs, code blocks (```), markdown headers (##), emoji, ASCII art, or horizontal rules.
|
|
124
|
+
1. FORMAT CHECK: Verify all .prizm files use KEY: value format. Flag any prose paragraphs, code blocks (```), markdown headers (##), emoji, ASCII art, or horizontal rules. Flag TRAPS entries missing severity prefix ([CRITICAL], [HIGH], or [LOW]). Note: [REVIEW] preceding severity (e.g., `[REVIEW][HIGH]`) is a valid temporary staleness marker, not a format violation.
|
|
125
125
|
2. SIZE CHECK: Verify size limits: L0 <= 4KB, L1 <= 3KB, L2 <= 5KB. Report files exceeding limits with current size.
|
|
126
126
|
3. POINTER CHECK: Verify all arrow (->) references resolve to existing .prizm files. Report broken pointers.
|
|
127
127
|
4. TIMESTAMP CHECK: Verify all docs have UPDATED field. Flag docs with UPDATED older than 30 days as potentially stale.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
PRIZM_SPEC_VERSION:
|
|
1
|
+
PRIZM_SPEC_VERSION: 3
|
|
2
2
|
PURPOSE: AI-only documentation framework for vibe coding projects
|
|
3
3
|
AUDIENCE: AI agents (not humans)
|
|
4
4
|
FORMAT: KEY: value pairs, ALL CAPS section headers, arrow pointers
|
|
@@ -180,7 +180,7 @@ TEMPLATE:
|
|
|
180
180
|
- PREFER: <module-specific preference>
|
|
181
181
|
|
|
182
182
|
TRAPS:
|
|
183
|
-
- <what looks safe but is dangerous> | FIX: <correct approach>
|
|
183
|
+
- [CRITICAL|HIGH|LOW] <what looks safe but is dangerous> | FIX: <correct approach>
|
|
184
184
|
|
|
185
185
|
DECISIONS:
|
|
186
186
|
- <what was decided> — <rationale>
|
|
@@ -195,6 +195,16 @@ CONSTRAINTS:
|
|
|
195
195
|
- SUBDIRS entries must have arrow pointer (->) if L2 doc exists
|
|
196
196
|
- KEY_FILES lists only the most important files (max 10-15)
|
|
197
197
|
- RULES may only SUPPLEMENT root.prizm RULES with module-specific exceptions, never contradict them
|
|
198
|
+
- TRAPS entries MUST have severity prefix ([CRITICAL], [HIGH], or [LOW]). [REVIEW] may precede severity as a temporary staleness marker.
|
|
199
|
+
- TRAPS optional fields: append `| REF: <7-char-hash>` for traceability, `| STALE_IF: <glob>` for auto-expiry detection
|
|
200
|
+
|
|
201
|
+
TRAPS_FORMAT_REFERENCE (spec-only — do NOT include this block in generated .prizm files):
|
|
202
|
+
- Severity levels: CRITICAL = data loss/security/financial/crash, HIGH = functional failure/silent error, LOW = naming/minor quality
|
|
203
|
+
- Temporary prefix: [REVIEW] may precede severity (e.g., `[REVIEW][HIGH]`) — signals the TRAP needs re-validation. Consumed by the next retrospective: verify and either remove [REVIEW] or delete the TRAP.
|
|
204
|
+
- REF: first 7 chars of the commit where the trap was discovered (optional, for traceability)
|
|
205
|
+
- STALE_IF: glob pattern — when matched files are deleted or heavily rewritten, this trap needs re-validation (optional)
|
|
206
|
+
- Minimal valid format: `- [SEVERITY] <description> | FIX: <approach>`
|
|
207
|
+
- Full format: `- [SEVERITY] <description> | FIX: <approach> | REF: <hash> | STALE_IF: <glob>`
|
|
198
208
|
|
|
199
209
|
## 3.3 L2: detail.prizm
|
|
200
210
|
|
|
@@ -220,8 +230,8 @@ TEMPLATE:
|
|
|
220
230
|
- REJECTED: <approach that was tried/considered and abandoned + why>
|
|
221
231
|
|
|
222
232
|
TRAPS:
|
|
223
|
-
- <gotcha: something that looks correct but is wrong or dangerous>
|
|
224
|
-
- <non-obvious coupling, race condition, or side effect>
|
|
233
|
+
- [CRITICAL|HIGH|LOW] <gotcha: something that looks correct but is wrong or dangerous> | FIX: <correct approach>
|
|
234
|
+
- [CRITICAL|HIGH|LOW] <non-obvious coupling, race condition, or side effect> | FIX: <approach>
|
|
225
235
|
|
|
226
236
|
CHANGELOG:
|
|
227
237
|
- YYYY-MM-DD | <verb>: <description of recent change to this module>
|
|
@@ -238,6 +248,9 @@ CONSTRAINTS:
|
|
|
238
248
|
- DOMAIN-SPECIFIC SECTIONS are flexible, not prescribed
|
|
239
249
|
- DECISIONS is append-only (never delete, archive if >20 entries)
|
|
240
250
|
- TRAPS section is CRITICAL for preventing AI from making known mistakes
|
|
251
|
+
- TRAPS entries MUST have severity prefix ([CRITICAL], [HIGH], or [LOW]). [REVIEW] may precede severity as a temporary staleness marker.
|
|
252
|
+
- TRAPS optional fields: append `| REF: <7-char-hash>` for traceability, `| STALE_IF: <glob>` for auto-expiry detection
|
|
253
|
+
- TRAPS severity guide: CRITICAL = data loss/security/financial/crash, HIGH = functional failure/silent error, LOW = naming/minor quality
|
|
241
254
|
- REJECTED entries prevent AI from re-proposing failed approaches
|
|
242
255
|
- FILES lists all files, not just key ones
|
|
243
256
|
- RULES may only SUPPLEMENT root.prizm RULES with module-specific exceptions, never contradict them
|
|
@@ -440,6 +453,7 @@ NEVER: Session-specific context or conversation history (docs are session-indepe
|
|
|
440
453
|
NEVER: Flowcharts, diagrams, mermaid blocks, or ASCII art (wastes tokens, AI cannot parse visually)
|
|
441
454
|
NEVER: Markdown headers (## / ###) inside .prizm files (use ALL CAPS KEY: format instead)
|
|
442
455
|
NEVER: Rewrite entire .prizm files on update (modify only affected sections)
|
|
456
|
+
NEVER: TRAPS entries without severity prefix ([CRITICAL], [HIGH], or [LOW])
|
|
443
457
|
|
|
444
458
|
---
|
|
445
459
|
|
|
@@ -821,6 +835,16 @@ V2 (2026-03-02): Enhanced specification
|
|
|
821
835
|
- Enhanced Section 9.1 with ON_DEEP_READ trigger alongside ON_MODIFY
|
|
822
836
|
- Updated PRIZM_SPEC_VERSION to 2
|
|
823
837
|
|
|
838
|
+
V3 (2026-03-25): Knowledge quality and resilience
|
|
839
|
+
- TRAPS entries now MUST have severity prefix: [CRITICAL], [HIGH], or [LOW]
|
|
840
|
+
- TRAPS optional fields: REF (commit hash for traceability), STALE_IF (glob for auto-expiry detection)
|
|
841
|
+
- Added TRAPS staleness check in retrospective (step 1g): auto-archive stale TRAPS when count > 10
|
|
842
|
+
- Added Failure Capture Protocol: bootstrap templates write failure-log.md on session failure for cross-session learning
|
|
843
|
+
- Added retrospective data source: failure-log.md DISCOVERED_TRAPS are prioritized for .prizm-docs/ injection
|
|
844
|
+
- Added TRAPS_FORMAT_REFERENCE as spec-only block (must NOT appear in generated .prizm files)
|
|
845
|
+
- Added V2→V3 migration: auto-tag legacy TRAPS with [LOW] default severity
|
|
846
|
+
- Updated PRIZM_SPEC_VERSION to 3
|
|
847
|
+
|
|
824
848
|
---
|
|
825
849
|
|
|
826
850
|
# SECTION 15: CONFLICT RESOLUTION
|
|
@@ -884,8 +908,8 @@ BEST_PRACTICE: Coordinate on MODULE_INDEX changes (adding/removing modules) to a
|
|
|
884
908
|
|
|
885
909
|
## 16.1 Migration Principles
|
|
886
910
|
|
|
887
|
-
BACKWARD_COMPATIBLE:
|
|
888
|
-
FORWARD_COMPATIBLE:
|
|
911
|
+
BACKWARD_COMPATIBLE: V3 can parse V2 docs without errors, but Validate will flag TRAPS entries missing severity prefixes and auto-migration (Section 16.3) will add [LOW] defaults
|
|
912
|
+
FORWARD_COMPATIBLE: V2 tools will ignore V3-only fields they do not recognize
|
|
889
913
|
MIGRATION_TRIGGER: AI detects PRIZM_VERSION in root.prizm and applies migration if needed
|
|
890
914
|
|
|
891
915
|
## 16.2 V1 to V2 Migration
|
|
@@ -911,7 +935,32 @@ ALGORITHM: prizm_migrate_v1_to_v2
|
|
|
911
935
|
4. UPDATE_CHANGELOG:
|
|
912
936
|
APPEND: - YYYY-MM-DD | root | update: migrated from PRIZM_VERSION 1 to 2
|
|
913
937
|
|
|
914
|
-
## 16.3
|
|
938
|
+
## 16.3 V2 to V3 Migration
|
|
939
|
+
|
|
940
|
+
TRIGGER: Automatic on first prizmkit-prizm-docs Update or Validate operation after spec upgrade
|
|
941
|
+
|
|
942
|
+
ALGORITHM: prizm_migrate_v2_to_v3
|
|
943
|
+
|
|
944
|
+
1. UPDATE_VERSION:
|
|
945
|
+
Change: PRIZM_VERSION: 2 -> PRIZM_VERSION: 3
|
|
946
|
+
In: root.prizm
|
|
947
|
+
|
|
948
|
+
2. MIGRATE_TRAPS_FORMAT:
|
|
949
|
+
SCAN: All L1 and L2 .prizm files for TRAPS entries
|
|
950
|
+
FOR EACH TRAPS entry without severity prefix ([CRITICAL], [HIGH], or [LOW]):
|
|
951
|
+
PREPEND: [LOW] as conservative default severity
|
|
952
|
+
EXAMPLE: `- foo is dangerous | FIX: use bar` becomes `- [LOW] foo is dangerous | FIX: bar`
|
|
953
|
+
RATIONALE: [LOW] is the safest default — it preserves the trap without over-alarming.
|
|
954
|
+
AI or user can manually upgrade severity to [HIGH] or [CRITICAL] during next retrospective.
|
|
955
|
+
|
|
956
|
+
3. VALIDATE:
|
|
957
|
+
Run full Validate operation
|
|
958
|
+
REPORT: Migration results — number of TRAPS entries migrated, files updated
|
|
959
|
+
|
|
960
|
+
4. UPDATE_CHANGELOG:
|
|
961
|
+
APPEND: - YYYY-MM-DD | root | update: migrated from PRIZM_VERSION 2 to 3 (TRAPS severity prefixes added)
|
|
962
|
+
|
|
963
|
+
## 16.4 Future Version Migration Pattern
|
|
915
964
|
|
|
916
965
|
FOR any future version N to N+1:
|
|
917
966
|
|
|
@@ -63,6 +63,9 @@ git diff --name-status
|
|
|
63
63
|
- **L1**: Update FILES count, KEY_FILES (if major files added/removed), INTERFACES (if public API changed), UPDATED timestamp
|
|
64
64
|
- **L0 root.prizm**: Update MODULE_INDEX file counts only if counts changed. Update UPDATED only if structural change (module added/removed).
|
|
65
65
|
|
|
66
|
+
**1d-migrate.** Legacy TRAPS format migration (opportunistic):
|
|
67
|
+
While updating an affected L1/L2 doc, if you encounter TRAPS entries **without** a severity prefix (e.g., `- foo | FIX: bar` instead of `- [LOW] foo | FIX: bar`), prepend `[LOW]` as a conservative default. This clears legacy format debt incrementally — only in files already being touched, never as a bulk operation.
|
|
68
|
+
|
|
66
69
|
**1e.** If new directory with 3+ source files matches no existing module: create L1 doc immediately, add to MODULE_INDEX, defer L2.
|
|
67
70
|
|
|
68
71
|
**1f.** Enforce size limits:
|
|
@@ -72,6 +75,15 @@ git diff --name-status
|
|
|
72
75
|
|
|
73
76
|
**SKIP structural sync if**: only internal implementation changed (no interface/dependency impact), only comments/whitespace, only test files, only .prizm files, bug fixes with no interface change.
|
|
74
77
|
|
|
78
|
+
**1g. TRAPS staleness check** (only when an L2 doc's TRAPS section has > 10 entries):
|
|
79
|
+
|
|
80
|
+
Perform a quick staleness scan on existing TRAPS to prevent unbounded accumulation:
|
|
81
|
+
1. If a TRAP has `STALE_IF:` and the glob-matched files no longer exist (verified via `ls` or `git status`) → delete the TRAP entry, append CHANGELOG: `remove: archived stale TRAP - <summary>`
|
|
82
|
+
2. If a TRAP has `REF:` and the referenced code has been substantially rewritten (>80% of the original diff is gone, checked via `git log --follow`) → prepend `[REVIEW]` to the severity, signaling it needs manual verification
|
|
83
|
+
3. Process at most 5 of the oldest TRAPS per L2 doc per session (to bound context cost)
|
|
84
|
+
|
|
85
|
+
This step is lightweight — it only triggers when TRAPS exceed 10 entries, and processes at most 5 per run.
|
|
86
|
+
|
|
75
87
|
---
|
|
76
88
|
|
|
77
89
|
## Job 2: Architecture Knowledge Injection → `.prizm-docs/`
|
|
@@ -95,14 +107,29 @@ Extract TRAPS, RULES, and DECISIONS from development work and inject into `.priz
|
|
|
95
107
|
- `.prizmkit/specs/###-feature-name/context-snapshot.md` — read the '## Implementation Log' section (Dev's changes, decisions, discoveries) and '## Review Notes' section (Reviewer's findings). These are the **preferred source** for pre-categorized decisions and findings. If these sections exist, prefer them over re-extracting from git diff.
|
|
96
108
|
- `.prizmkit/specs/###-feature-name/plan.md` — if feature work, read planned vs actual
|
|
97
109
|
- `.prizmkit/bugfix/<id>/fix-report.md` — if bugfix, read what was discovered
|
|
110
|
+
- `.prizmkit/specs/###-feature-name/failure-log.md` — if a previous session failed, read DISCOVERED_TRAPS. These are high-value TRAPS because they come from actual failures — prioritize injecting them into `.prizm-docs/`
|
|
98
111
|
- The relevant `.prizm-docs/` L1/L2 docs for affected modules
|
|
99
112
|
|
|
100
113
|
**2b.** Extract knowledge from what was **observed in code**, not invented:
|
|
101
114
|
|
|
102
115
|
**TRAPS** (highest priority) — things that look safe but break:
|
|
103
|
-
-
|
|
116
|
+
- Minimal format: `- [SEVERITY] <description> | FIX: <approach>`
|
|
117
|
+
- Full format: `- [SEVERITY] <description> | FIX: <approach> | REF: <hash> | STALE_IF: <glob>`
|
|
104
118
|
- Source: actual bugs hit, surprising behavior discovered in code, non-obvious coupling
|
|
105
119
|
|
|
120
|
+
**TRAPS severity classification guide**:
|
|
121
|
+
- `[CRITICAL]`: data loss, security vulnerability, financial error, system crash
|
|
122
|
+
- `[HIGH]`: functional failure, silent error, interface incompatibility
|
|
123
|
+
- `[LOW]`: misleading naming, non-intuitive API usage, minor performance issue
|
|
124
|
+
|
|
125
|
+
When writing TRAPS:
|
|
126
|
+
- Severity prefix is MANDATORY (e.g., `[CRITICAL]`, `[HIGH]`, `[LOW]`)
|
|
127
|
+
- OPTIONAL: append `| REF: <7-char-hash>` when you know the relevant commit (for traceability)
|
|
128
|
+
- OPTIONAL: append `| STALE_IF: <glob>` when the TRAP is tightly coupled to specific files (for auto-expiry detection)
|
|
129
|
+
|
|
130
|
+
**Consuming [REVIEW] markers** (from staleness check 1g):
|
|
131
|
+
- If you encounter a TRAP prefixed with `[REVIEW]` (e.g., `[REVIEW][HIGH] ...`), verify whether the trap is still valid by checking the current code. If still valid: remove the `[REVIEW]` prefix, keeping the severity. If no longer relevant: delete the TRAP entry and append CHANGELOG.
|
|
132
|
+
|
|
106
133
|
**RULES** — conventions established or constraints discovered:
|
|
107
134
|
- Format: `- MUST/NEVER/PREFER: <rule>`
|
|
108
135
|
- Source: patterns that proved necessary during implementation
|