@luizsantiago/spec-guardrails 3.0.1
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/LICENSE +21 -0
- package/README.md +206 -0
- package/index.js +335 -0
- package/lib/archive.js +208 -0
- package/lib/assets.js +145 -0
- package/lib/brownfield.js +446 -0
- package/lib/config.js +293 -0
- package/lib/constants.js +262 -0
- package/lib/cursorrules.js +92 -0
- package/lib/delta-merge.js +248 -0
- package/lib/doctor.js +343 -0
- package/lib/download.js +133 -0
- package/lib/feature.js +272 -0
- package/lib/fs-utils.js +114 -0
- package/lib/gates.js +138 -0
- package/lib/install.js +140 -0
- package/lib/memory.js +34 -0
- package/lib/next-steps.js +50 -0
- package/lib/presets.js +176 -0
- package/lib/project-rules.js +210 -0
- package/lib/specs-utils.js +117 -0
- package/lib/token-cost.js +124 -0
- package/package.json +46 -0
- package/rules/engineering-baseline.mdc +56 -0
- package/scripts/_common.py +356 -0
- package/scripts/analyze_artifacts.py +187 -0
- package/scripts/check_commit.py +140 -0
- package/scripts/lessons.py +447 -0
- package/scripts/loop_plan.py +217 -0
- package/scripts/validate_spec.py +345 -0
- package/scripts/validate_state.py +385 -0
- package/scripts/validate_tasks.py +379 -0
- package/skills/agent-architecture.md +221 -0
- package/skills/appsec.md +83 -0
- package/skills/code-simplify.md +49 -0
- package/skills/engineering-standards.md +98 -0
- package/skills/git-handoff.md +213 -0
- package/skills/qa-strategy.md +83 -0
- package/skills/references/analyze.md +56 -0
- package/skills/references/archive.md +60 -0
- package/skills/references/constitution.md +66 -0
- package/skills/references/context-limits.md +73 -0
- package/skills/references/converge.md +47 -0
- package/skills/references/design.md +88 -0
- package/skills/references/discuss.md +68 -0
- package/skills/references/explore.md +61 -0
- package/skills/references/implement.md +175 -0
- package/skills/references/lessons.md +71 -0
- package/skills/references/memory.md +98 -0
- package/skills/references/project-init.md +62 -0
- package/skills/references/quick-mode.md +84 -0
- package/skills/references/specify.md +144 -0
- package/skills/references/sub-agents.md +117 -0
- package/skills/references/tasks.md +178 -0
- package/skills/references/validate.md +210 -0
- package/skills/security-review.md +120 -0
- package/skills/ship-ready.md +50 -0
- package/skills/task-graph-engineering.md +180 -0
- package/templates/GETTING_STARTED.md +61 -0
- package/templates/config.yaml.example +28 -0
- package/templates/presets/default.yaml +16 -0
- package/templates/presets/node-ts.yaml +22 -0
- package/templates/presets/python.yaml +22 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Memory
|
|
2
|
+
|
|
3
|
+
Project memory that survives session amnesia: decisions, handoff, and resume.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Session start (resume)
|
|
8
|
+
- Session end (pause / handoff)
|
|
9
|
+
- Any time a project-level decision is made
|
|
10
|
+
- Any time verification produces a grounded lesson
|
|
11
|
+
|
|
12
|
+
## Artifacts
|
|
13
|
+
|
|
14
|
+
| File | Owner | Purpose |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `.specs/STATE.md` | Agent + owner | Decision log (`AD-NNN`) and handoff snapshot |
|
|
17
|
+
| `.specs/lessons.json` | `lessons.py` | Canonical lessons store |
|
|
18
|
+
| `.specs/LESSONS.md` | `lessons.py` | Generated playbook of confirmed lessons |
|
|
19
|
+
| `.specs/project/PROJECT.md` | Owner | Vision, stack, constraints |
|
|
20
|
+
| `.specs/project/ROADMAP.md` | Owner | Milestones and feature status |
|
|
21
|
+
|
|
22
|
+
## Resume Protocol
|
|
23
|
+
|
|
24
|
+
Run at every session start, before writing any code:
|
|
25
|
+
|
|
26
|
+
1. **Read `STATE.md`** — active feature, phase, next step, blockers.
|
|
27
|
+
2. **Reconcile against git.** The snapshot can be stale; evidence wins:
|
|
28
|
+
```bash
|
|
29
|
+
git branch --show-current
|
|
30
|
+
git status --porcelain
|
|
31
|
+
git log --oneline -10
|
|
32
|
+
```
|
|
33
|
+
Compare with `tasks.md` checkboxes. If commits exist for tasks that STATE says are pending, git is right — update STATE.
|
|
34
|
+
3. **Run the project harness** (tests, lint) before adding new code, so you know the starting baseline.
|
|
35
|
+
4. **Load only what this step needs** — the current feature's spec, plus `context.md` or `design.md` when relevant. Never load two feature specs at once. See `context-limits.md`.
|
|
36
|
+
5. **Propose the reconciled next step** and confirm it with the owner when it is ambiguous or stale.
|
|
37
|
+
|
|
38
|
+
## Pause / Handoff Protocol
|
|
39
|
+
|
|
40
|
+
Run at session end or at a phase milestone:
|
|
41
|
+
|
|
42
|
+
1. Refresh every section of `STATE.md` (template below).
|
|
43
|
+
2. Append a grounded lesson with `lessons.py add` if verification failed. Never hand-edit `LESSONS.md`.
|
|
44
|
+
3. Run the relevant gates and tests — never hand off a red tree silently.
|
|
45
|
+
4. Commit `.specs/` per `git-handoff.md`. **Never auto-push.**
|
|
46
|
+
|
|
47
|
+
## STATE.md Template
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
# Project State & Decisions
|
|
51
|
+
|
|
52
|
+
## Active Feature
|
|
53
|
+
- Feature: [name]
|
|
54
|
+
- Phase: [Specify|Discuss|Design|Tasks|Execute|Verify]
|
|
55
|
+
- Branch: [branch-name]
|
|
56
|
+
|
|
57
|
+
## Next Step (single item)
|
|
58
|
+
- [ ] [one concrete action]
|
|
59
|
+
|
|
60
|
+
## Blockers
|
|
61
|
+
- [open questions or dependencies, or "none"]
|
|
62
|
+
|
|
63
|
+
## Deferred Ideas
|
|
64
|
+
- [good ideas found during Execute that were out of scope]
|
|
65
|
+
|
|
66
|
+
## Decisions
|
|
67
|
+
|
|
68
|
+
### AD-001: [Decision title]
|
|
69
|
+
- **Date**: [ISO date]
|
|
70
|
+
- **Context**: [why this came up]
|
|
71
|
+
- **Decision**: [what was decided]
|
|
72
|
+
- **Consequences**: [what this constrains going forward]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Decision Log Rules
|
|
76
|
+
|
|
77
|
+
- `AD-NNN` numbers are sequential and never reused.
|
|
78
|
+
- Record a decision when it constrains **future work beyond this feature**. Feature-local choices belong in `context.md` or `design.md`.
|
|
79
|
+
- Superseding a decision adds a new `AD-NNN` that references the old one — never edit history in place.
|
|
80
|
+
|
|
81
|
+
## Lessons Rules
|
|
82
|
+
|
|
83
|
+
Lessons are owned by `lessons.py`, not by hand. See `lessons.md`.
|
|
84
|
+
|
|
85
|
+
- Record only from a **grounded failure** in `validation.md`: a surviving mutant, an imprecise acceptance criterion, a failed requirement, or a spec deviation.
|
|
86
|
+
- A clean PASS records nothing.
|
|
87
|
+
- `--source` is mandatory. Candidates are not guidance; only `list --status confirmed` is.
|
|
88
|
+
- Do not edit `LESSONS.md`. The engine generates it from `lessons.json`.
|
|
89
|
+
|
|
90
|
+
## Rules
|
|
91
|
+
|
|
92
|
+
- Write every artifact in **English**.
|
|
93
|
+
- Lazy artifacts: never scaffold empty files to look organized.
|
|
94
|
+
- `STATE.md` has exactly one "Next Step" item. A list of five is not a handoff.
|
|
95
|
+
|
|
96
|
+
## Next
|
|
97
|
+
|
|
98
|
+
`git-handoff.md` — what to stage, how to word the commit, and why no auto-push.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Project Init (Brownfield)
|
|
2
|
+
|
|
3
|
+
Map an existing codebase into `.specs/` project memory before the first `/specify`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Adopting Spec Guardrails on a repo that already has code
|
|
8
|
+
- Owner wants domain specs and `PROJECT.md` before feature work
|
|
9
|
+
- Before `/constitution` or the first Medium+ feature on a brownfield repo
|
|
10
|
+
|
|
11
|
+
## When NOT to Use
|
|
12
|
+
|
|
13
|
+
- Greenfield repo with no code yet — use `install` + `feature-init`
|
|
14
|
+
- Quick-tier-only work with no domain map — optional
|
|
15
|
+
|
|
16
|
+
## Inputs
|
|
17
|
+
|
|
18
|
+
- Repository layout (`packages/`, `apps/`, `src/domains/`, etc.)
|
|
19
|
+
- Stack markers (`package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`)
|
|
20
|
+
- Optional `.specs/config.yaml` preset choice
|
|
21
|
+
|
|
22
|
+
## Output
|
|
23
|
+
|
|
24
|
+
- `.specs/project/PROJECT.md` — vision, detected stack, domain map
|
|
25
|
+
- `.specs/project/ROADMAP.md` — planned domain drafting items
|
|
26
|
+
- `.specs/domains/[domain]/spec.md` — brownfield stubs (one per detected/manual domain)
|
|
27
|
+
- `.specs/config.yaml` — from auto-detected or chosen preset (when missing)
|
|
28
|
+
|
|
29
|
+
## Procedure
|
|
30
|
+
|
|
31
|
+
1. **Run the scan (Tier 0):**
|
|
32
|
+
```bash
|
|
33
|
+
npx @luizsantiago/spec-guardrails project-init --dry-run
|
|
34
|
+
npx @luizsantiago/spec-guardrails project-init [--preset node-ts] [--domains auth,billing]
|
|
35
|
+
```
|
|
36
|
+
2. **Review with the owner** — edit `PROJECT.md`, trim false-positive domains, fill Vision/Constraints.
|
|
37
|
+
3. **Draft domain truth** — replace stub requirements in `.specs/domains/*/spec.md` from code review (or leave stubs until features archive in).
|
|
38
|
+
4. **Optional constitution** — `references/constitution.md` when principles are not yet written.
|
|
39
|
+
5. **First feature** — `feature-init` then `specify.md` using **delta specs** when domain truth exists.
|
|
40
|
+
|
|
41
|
+
## Flags
|
|
42
|
+
|
|
43
|
+
| Flag | Effect |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `--dry-run` | Print stack/domains only |
|
|
46
|
+
| `--preset <name>` | Force config preset (`default`, `node-ts`, `python`) |
|
|
47
|
+
| `--domains a,b` | Manual domain list (overrides auto-detect) |
|
|
48
|
+
| `--no-domains` | Skip domain folder scaffolding |
|
|
49
|
+
| `--no-project` | Skip `PROJECT.md` |
|
|
50
|
+
| `--force` | Overwrite generated project/domain/config files |
|
|
51
|
+
|
|
52
|
+
## Rules
|
|
53
|
+
|
|
54
|
+
- Scan results are **hints**, not approved requirements.
|
|
55
|
+
- Never treat stub domain specs as enforced gates — populate or merge via `archive-feature`.
|
|
56
|
+
- Commit `.specs/project/` and `.specs/domains/` locally (Tier 0); push needs owner go-ahead.
|
|
57
|
+
|
|
58
|
+
## Next
|
|
59
|
+
|
|
60
|
+
- Principles missing → `constitution.md`
|
|
61
|
+
- First change → `feature-init` then `specify.md` (delta spec when brownfield)
|
|
62
|
+
- Back → `agent-architecture.md`
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Quick Mode
|
|
2
|
+
|
|
3
|
+
Express lane for small, low-risk changes. Full pipeline ceremony would cost more than the change itself.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
All of these must hold:
|
|
8
|
+
|
|
9
|
+
- 3 files or fewer
|
|
10
|
+
- No architectural decision
|
|
11
|
+
- No new dependency
|
|
12
|
+
- No change to auth, payments, or data migrations
|
|
13
|
+
- The fix is describable in one sentence
|
|
14
|
+
|
|
15
|
+
Typical: a bug fix, a copy change, a config tweak, a version bump.
|
|
16
|
+
|
|
17
|
+
## When NOT to Use
|
|
18
|
+
|
|
19
|
+
If any guardrail is exceeded, stop and route to `specify.md`. Explicitly:
|
|
20
|
+
|
|
21
|
+
| Signal | Route to |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| More than 3 files | `specify.md` → Simple tier |
|
|
24
|
+
| A design decision appears | `design.md` |
|
|
25
|
+
| More than 5 steps emerge | `tasks.md` |
|
|
26
|
+
| Auth, payments, or data safety touched | Full pipeline + `security-review.md` |
|
|
27
|
+
|
|
28
|
+
Announce the switch — do not silently expand a quick task into a feature.
|
|
29
|
+
|
|
30
|
+
## Output
|
|
31
|
+
|
|
32
|
+
`.specs/quick/NNN-slug/`
|
|
33
|
+
|
|
34
|
+
| File | Content |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `TASK.md` | What, where, approach, verification |
|
|
37
|
+
| `SUMMARY.md` | What changed, commit hash, evidence |
|
|
38
|
+
|
|
39
|
+
`NNN` is sequential across the project (`001`, `002`, …).
|
|
40
|
+
|
|
41
|
+
## Procedure
|
|
42
|
+
|
|
43
|
+
1. **Restate the change in one sentence**, name the files, and state how you will verify it.
|
|
44
|
+
2. **Write `TASK.md`** before touching code. Two minutes of writing prevents the wrong fix.
|
|
45
|
+
3. **Write or extend a test** that fails for the current defect. A quick fix with no test is only allowed for changes with no behavior — copy, formatting, comments.
|
|
46
|
+
4. **Implement the smallest change.**
|
|
47
|
+
5. **Run the project harness** — tests and linter.
|
|
48
|
+
6. **Commit atomically**, Conventional Commits format:
|
|
49
|
+
```bash
|
|
50
|
+
python3 .specs/guardrails/scripts/check_commit.py --message "fix(theme): persist dark mode preference"
|
|
51
|
+
```
|
|
52
|
+
7. **Write `SUMMARY.md`** with the commit hash and the evidence line.
|
|
53
|
+
8. **Record a lesson** with `lessons.py add --source` if the defect revealed a gap that will recur and a `validation.md` exists. Quick-mode copy fixes usually record nothing.
|
|
54
|
+
|
|
55
|
+
## Verification Standard
|
|
56
|
+
|
|
57
|
+
Quick mode compresses ceremony, not carelessness — but it is **not** the full Verify gate:
|
|
58
|
+
|
|
59
|
+
- Prove the change with a test or an explicit, documented manual check.
|
|
60
|
+
- Record evidence in `SUMMARY.md` (`file:line` or the exact manual steps). That is a **process** requirement; `validate_state.py` does not run on Quick artifacts.
|
|
61
|
+
- Blast radius still applies — local commit only; `git push` and deploy need an explicit go-ahead.
|
|
62
|
+
- If any Quick guardrail is exceeded, stop and route to `specify.md` (see When NOT to Use).
|
|
63
|
+
|
|
64
|
+
## Templates
|
|
65
|
+
|
|
66
|
+
```markdown
|
|
67
|
+
# Quick Task: [one-line title]
|
|
68
|
+
|
|
69
|
+
- **Files**: src/hooks/useTheme.ts
|
|
70
|
+
- **Approach**: persist the preference to localStorage on toggle
|
|
71
|
+
- **Verify**: toggle dark mode, reload, preference persists
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
# Summary
|
|
76
|
+
|
|
77
|
+
- **Changed**: persisted theme preference on toggle
|
|
78
|
+
- **Commit**: fix(theme): persist dark mode preference (a1b2c3d)
|
|
79
|
+
- **Evidence**: test/hooks/useTheme.test.ts:18
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Next
|
|
83
|
+
|
|
84
|
+
Back to normal work. If the same class of defect appears again, promote it to a real feature with `specify.md`.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Specify
|
|
2
|
+
|
|
3
|
+
Capture WHAT to build as testable, traceable requirements. Always required (except Quick tier).
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Any change beyond the Quick tier (see `quick-mode.md`)
|
|
8
|
+
- Before writing production code or tests
|
|
9
|
+
|
|
10
|
+
## When NOT to Use
|
|
11
|
+
|
|
12
|
+
- Quick-tier changes (≤3 files, no design decisions) — use `quick-mode.md`
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- Owner's request, in their own words
|
|
17
|
+
- `.specs/STATE.md` decisions (`AD-NNN`) relevant to this area
|
|
18
|
+
- `.specs/project/CONSTITUTION.md` when present
|
|
19
|
+
- `.specs/LESSONS.md` entries that apply — load them with `python3 .specs/guardrails/scripts/lessons.py list --status confirmed`
|
|
20
|
+
- Existing codebase conventions
|
|
21
|
+
- `context-limits.md` — this feature only; do not load sibling specs
|
|
22
|
+
|
|
23
|
+
## Output
|
|
24
|
+
|
|
25
|
+
`.specs/features/[NNN-slug]/spec.md` (created by `feature-init`)
|
|
26
|
+
|
|
27
|
+
## Procedure
|
|
28
|
+
|
|
29
|
+
0. **Allocate feature identity (Tier 0).** Before drafting:
|
|
30
|
+
```bash
|
|
31
|
+
npx @luizsantiago/spec-guardrails feature-init "owner description here"
|
|
32
|
+
```
|
|
33
|
+
Creates `.specs/features/003-slug/`, updates `STATE.md`, and `git checkout -b feat/003-slug`. Skip on Quick tier.
|
|
34
|
+
Optional project context: `npx @luizsantiago/spec-guardrails phase-context specify` when `.specs/config.yaml` exists.
|
|
35
|
+
1. **Act as a thinking partner, not an interviewer.** Challenge vagueness; restate the goal in one sentence and confirm it.
|
|
36
|
+
2. **Surface assumptions before drafting criteria.** State stack/auth/data guesses and ask for corrections; lasting ones go under `## Assumptions` only after that (or after `discuss.md`).
|
|
37
|
+
3. **Mark unknowns explicitly.** Use `[NEEDS CLARIFICATION: specific question]` — never guess. Resolve or remove before owner approval.
|
|
38
|
+
4. **Load confirmed lessons.** Run `python3 .specs/guardrails/scripts/lessons.py list --status confirmed` and apply every rule that matches this work. Candidates are not guidance.
|
|
39
|
+
5. **Detect gray areas.** If the feature touches persistence, external calls, auth, payments, concurrency, or state transitions — or if intent is ambiguous — run `discuss.md` before finalizing.
|
|
40
|
+
6. **Choose spec shape:**
|
|
41
|
+
- **Greenfield** — full spec (`## Requirements`, `## Assumptions`, `## Out of Scope`)
|
|
42
|
+
- **Brownfield** — delta spec (`## ADDED Requirements`, `## MODIFIED Requirements`, `## REMOVED Requirements`)
|
|
43
|
+
7. **Write requirements with stable IDs.** `REQ-001`, `AUTH-002` — prefix plus a zero-padded number. IDs never change once approved; retire them instead.
|
|
44
|
+
8. **Write binary acceptance criteria.** Every criterion is objectively pass or fail. The gate **blocks** a criterion that does not state a required outcome with `SHALL` or `MUST`. Soft verbs (`should`, `will`, `can`, `may`) are not testable — rewrite them before confirming.
|
|
45
|
+
Prefer **EARS** (one pattern per criterion). The gate **warns** when a `SHALL`/`MUST` line has no `WHEN`/`IF` … `THEN` trigger; missing EARS is not a hard fail.
|
|
46
|
+
|
|
47
|
+
| Pattern | Shape | Use when |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| Ubiquitous | The system SHALL [invariant] | Always-on constraints |
|
|
50
|
+
| Event-driven | WHEN [trigger] THEN the system SHALL [outcome] | A discrete action or event |
|
|
51
|
+
| State-driven | WHILE [state] the system SHALL [outcome] | Behavior that holds during a state |
|
|
52
|
+
| Optional-feature | WHERE [capability] the system SHALL [outcome] | Flag- or plan-gated behavior |
|
|
53
|
+
| Unwanted-behavior | IF [undesired] THEN the system SHALL [outcome] | Errors, invalid input, timeouts |
|
|
54
|
+
| Complex | WHILE [state], WHEN [trigger] the system SHALL [outcome] | Combined state + event |
|
|
55
|
+
|
|
56
|
+
One criterion = one behavior. Use concrete values (status, code, bound), not “gracefully” or “quickly”.
|
|
57
|
+
9. **State out of scope explicitly.** This is what prevents scope creep during Execute.
|
|
58
|
+
10. **Record assumptions.** Anything inferred rather than confirmed goes under `## Assumptions`. The section is required; write `- none` only when nothing was inferred.
|
|
59
|
+
11. **Run the gate.** Fix every blocking issue before showing the spec to the owner.
|
|
60
|
+
12. **Get approval.** Do not write implementation code until the spec and derived tests are approved.
|
|
61
|
+
13. **Commit spec (Tier 0).** `docs(spec): add requirements for 003-slug`
|
|
62
|
+
|
|
63
|
+
## Gate
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python3 .specs/guardrails/scripts/validate_spec.py .specs/features/[feature]/spec.md
|
|
67
|
+
python3 .specs/guardrails/scripts/validate_spec.py [feature]
|
|
68
|
+
python3 .specs/guardrails/scripts/validate_spec.py # single-feature projects
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Checks required sections (`Requirements`, `Assumptions`, `Out of Scope`), well-formed IDs, a `SHALL`/`MUST` outcome per criterion, and unresolved placeholders. Sections, IDs, criteria, and placeholders are read from visible markdown — fenced samples and HTML comments do not count. A criterion with `SHALL` but no `WHEN`/`IF` … `THEN` trigger is a warning. Non-zero exit means STOP.
|
|
72
|
+
|
|
73
|
+
## Template
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
# Spec: [Feature]
|
|
77
|
+
|
|
78
|
+
## Goal
|
|
79
|
+
[One sentence: what the owner gets when this ships.]
|
|
80
|
+
|
|
81
|
+
## Requirements
|
|
82
|
+
|
|
83
|
+
### REQ-001: [Short title]
|
|
84
|
+
- **Acceptance Criteria**: WHEN [valid credentials are submitted] THEN the system SHALL [create a session] <!-- event-driven -->
|
|
85
|
+
- IF [the token is expired] THEN the system SHALL [return 401 with code TOKEN_EXPIRED] <!-- unwanted-behavior -->
|
|
86
|
+
|
|
87
|
+
### REQ-002: [Short title]
|
|
88
|
+
- **Acceptance Criteria**: WHILE [a session is active] the system SHALL [reject reuse of a rotated refresh token] <!-- state-driven -->
|
|
89
|
+
- The system SHALL [store passwords only as argon2 hashes] <!-- ubiquitous -->
|
|
90
|
+
|
|
91
|
+
## Assumptions
|
|
92
|
+
- [Anything inferred rather than confirmed]
|
|
93
|
+
|
|
94
|
+
## Out of Scope
|
|
95
|
+
- [Explicitly excluded work]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Delta spec (brownfield)
|
|
99
|
+
|
|
100
|
+
```markdown
|
|
101
|
+
# Spec: 004-dark-mode (delta)
|
|
102
|
+
|
|
103
|
+
## Goal
|
|
104
|
+
Add theme switching without new dependencies.
|
|
105
|
+
|
|
106
|
+
## ADDED Requirements
|
|
107
|
+
|
|
108
|
+
### UI-001: Theme toggle
|
|
109
|
+
- **Acceptance Criteria**: WHEN the user clicks the theme toggle THEN the system SHALL persist the choice in localStorage
|
|
110
|
+
|
|
111
|
+
## MODIFIED Requirements
|
|
112
|
+
|
|
113
|
+
### AUTH-001: Session banner
|
|
114
|
+
- **Acceptance Criteria**: WHILE dark mode is active the system SHALL render the session banner with contrast ratio ≥ 4.5:1
|
|
115
|
+
|
|
116
|
+
## REMOVED Requirements
|
|
117
|
+
- none
|
|
118
|
+
|
|
119
|
+
## Assumptions
|
|
120
|
+
- CSS variables already exist for primary colors
|
|
121
|
+
|
|
122
|
+
## Out of Scope
|
|
123
|
+
- Server-side theme preference sync
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Anti-Patterns
|
|
127
|
+
|
|
128
|
+
| Avoid | Prefer |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| "Login should work well" | "WHEN valid credentials are submitted THEN the system SHALL create a session" |
|
|
131
|
+
| "The system will return 401" | "WHEN the token is expired THEN the system SHALL return 401 with code `TOKEN_EXPIRED`" |
|
|
132
|
+
| Omitting `## Assumptions` | Record inferences, or write `- none` |
|
|
133
|
+
| Guessing when unsure | `[NEEDS CLARIFICATION: auth method not specified]` |
|
|
134
|
+
| Manual slug folders without numbering | `feature-init` before drafting |
|
|
135
|
+
| Renaming `REQ-001` mid-flight | Retire the ID and add a new one |
|
|
136
|
+
| Implementation detail in the spec | Keep HOW in `design.md` |
|
|
137
|
+
|
|
138
|
+
## Next
|
|
139
|
+
|
|
140
|
+
- Gray areas remain → `discuss.md`
|
|
141
|
+
- Tasks drafted → `analyze.md` before approval
|
|
142
|
+
- Architectural decisions needed → `design.md`
|
|
143
|
+
- ≤3 obvious steps → `implement.md`
|
|
144
|
+
- Otherwise → `tasks.md`
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Sub-Agents
|
|
2
|
+
|
|
3
|
+
Operational protocol for multi-agent Execute. Sister material to `task-graph-engineering.md`
|
|
4
|
+
(topology) — this file is the **payload, summary, failure, and merge** contract.
|
|
5
|
+
|
|
6
|
+
## When to Use
|
|
7
|
+
|
|
8
|
+
- `loop-plan` shows a parallel group with 2+ ready tasks (disjoint `Files`)
|
|
9
|
+
- `task-graph.md` marks a parallel group and the owner accepted the split
|
|
10
|
+
- `tasks.md` packs into more than one ~7-task batch (roughly more than 8 tasks total)
|
|
11
|
+
- Diamond verify needs a fresh context that never wrote the code
|
|
12
|
+
|
|
13
|
+
## When NOT to Use
|
|
14
|
+
|
|
15
|
+
- ≤8 tasks that fit one batch — execute inline
|
|
16
|
+
- Sequential work where each step needs the previous step's full picture
|
|
17
|
+
- The owner declined the sub-agent offer
|
|
18
|
+
|
|
19
|
+
**Never auto-spawn.** Offer the split, wait for an explicit yes.
|
|
20
|
+
|
|
21
|
+
## Batch packing
|
|
22
|
+
|
|
23
|
+
1. Walk `### Phase N` groups in order (or document order when phases are unused).
|
|
24
|
+
2. Pack consecutive **whole** phases into a batch until the batch would exceed ~7 tasks.
|
|
25
|
+
3. Never split a phase across workers.
|
|
26
|
+
4. Batches run **sequentially**. Parallelism lives *inside* a batch only when `task-graph.md` marks a parallel group and Files are disjoint.
|
|
27
|
+
|
|
28
|
+
## Worker payload
|
|
29
|
+
|
|
30
|
+
Hand each worker exactly this and nothing else from sibling features:
|
|
31
|
+
|
|
32
|
+
```markdown
|
|
33
|
+
# Worker brief
|
|
34
|
+
|
|
35
|
+
- Feature: [feature]
|
|
36
|
+
- Batch: B[n] of [total]
|
|
37
|
+
- Tasks: T[a] … T[b] (in order)
|
|
38
|
+
- Spec excerpt: only the REQ IDs those tasks name
|
|
39
|
+
- Files ownership: the union of those tasks' Files fields (exclusive)
|
|
40
|
+
- Constraints: AD-NNN that apply; confirmed lessons that apply
|
|
41
|
+
- Forbidden: git push, deploy, editing files outside ownership, spawning further sub-agents
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Load per `context-limits.md`. Do not paste the author's chat.
|
|
45
|
+
|
|
46
|
+
## Worker loop
|
|
47
|
+
|
|
48
|
+
For each task in order:
|
|
49
|
+
|
|
50
|
+
1. Read the task fields. Implement test-first from the named criteria.
|
|
51
|
+
2. Run the task `Gate`. Non-zero → fix (max 3 loops) or stop and report failure.
|
|
52
|
+
3. Run `check_commit.py` on the message, mark the task `[x]`, commit atomically.
|
|
53
|
+
4. Do not start the next task until the commit exists.
|
|
54
|
+
|
|
55
|
+
## Compact summary (required return)
|
|
56
|
+
|
|
57
|
+
Every worker returns this shape — no narrative dump:
|
|
58
|
+
|
|
59
|
+
```markdown
|
|
60
|
+
## Batch B[n] summary
|
|
61
|
+
- Status: PASS | FAIL
|
|
62
|
+
- Tasks done: T1, T2
|
|
63
|
+
- Commits: abc1234, def5678
|
|
64
|
+
- Tests: 12 passed / 0 failed
|
|
65
|
+
- Deviations: none | [what changed vs tasks.md]
|
|
66
|
+
- Blockers: none | [gate output excerpt]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Failure handling
|
|
70
|
+
|
|
71
|
+
| Event | Action |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| Gate fails 3 times on one task | Stop the batch. Return FAIL summary. Do not continue later tasks in the batch. |
|
|
74
|
+
| Worker edits a file outside ownership | Treat as FAIL. Merge owner reverts or reassigns. |
|
|
75
|
+
| Batch FAIL | Orchestrator does not start the next batch. Escalate or rewrite tasks. |
|
|
76
|
+
| Verify FAIL | Gaps become fix tasks; fix → re-verify loop bounded to 3, then escalate. |
|
|
77
|
+
|
|
78
|
+
## Merge owner
|
|
79
|
+
|
|
80
|
+
One agent (usually the orchestrator) owns merge after each batch and after Verify:
|
|
81
|
+
|
|
82
|
+
1. Confirm every task checkbox in the batch is `[x]` and commits are present.
|
|
83
|
+
2. Run the project harness once on the integrated tree.
|
|
84
|
+
3. Resolve conflicts; never ask two workers to touch the same file in the same round.
|
|
85
|
+
4. Only after the final batch: dispatch the **Verifier** (fresh context). See `validate.md`.
|
|
86
|
+
5. Hand off via `git-handoff.md` — push only with an explicit go-ahead.
|
|
87
|
+
|
|
88
|
+
## Verifier dispatch
|
|
89
|
+
|
|
90
|
+
Always-on after the last task commit. Payload:
|
|
91
|
+
|
|
92
|
+
- `spec.md` (+ `context.md` when present)
|
|
93
|
+
- Diff range for the feature
|
|
94
|
+
- Tests named by the spec / tasks
|
|
95
|
+
- `security-review.md` checklist
|
|
96
|
+
- **Not** the author chat, worker summaries as proof, or `STATE.md` Next Step as evidence
|
|
97
|
+
|
|
98
|
+
The verifier writes `validation.md` and runs `validate_state.py`. A PASS WITH GAPS is FAIL.
|
|
99
|
+
|
|
100
|
+
## Model tier (optional)
|
|
101
|
+
|
|
102
|
+
When Spec Guardrails can pick a model per sub-agent:
|
|
103
|
+
|
|
104
|
+
| Role | Tier |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| Mechanical batch | Fast |
|
|
107
|
+
| Ambiguous / core-domain batch | High reasoning |
|
|
108
|
+
| Verifier | Mid-to-high |
|
|
109
|
+
|
|
110
|
+
Otherwise ignore and invest more care on heavy steps.
|
|
111
|
+
|
|
112
|
+
## Related
|
|
113
|
+
|
|
114
|
+
- `task-graph-engineering.md` — DAG, stop rule, diamond, one writer per file
|
|
115
|
+
- `references/implement.md` — when to offer delegation
|
|
116
|
+
- `references/validate.md` — verifier procedure
|
|
117
|
+
- `references/context-limits.md` — what a worker may load
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Tasks
|
|
2
|
+
|
|
3
|
+
Break the work into atomic tasks with real dependencies and binary done criteria. Optional phase.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- More than 3 obvious steps
|
|
8
|
+
- Multiple files, modules, or people involved
|
|
9
|
+
- Any work that could be split across parallel agents
|
|
10
|
+
|
|
11
|
+
## When NOT to Use
|
|
12
|
+
|
|
13
|
+
- ≤3 obvious steps — list them inline at the start of Execute instead
|
|
14
|
+
|
|
15
|
+
**Safety valve:** if the inline listing in Execute reveals more than 5 steps or real dependencies, STOP and create a formal `tasks.md`. The Tasks phase was skipped in error.
|
|
16
|
+
|
|
17
|
+
## Inputs
|
|
18
|
+
|
|
19
|
+
- Approved `spec.md` (and `design.md` when it exists)
|
|
20
|
+
- `task-graph-engineering.md` for topology rules
|
|
21
|
+
- `context-limits.md` if the breakdown is large — keep each task's file list short enough to load
|
|
22
|
+
|
|
23
|
+
## Output
|
|
24
|
+
|
|
25
|
+
`.specs/features/[feature]/tasks.md`, plus `task-graph.md` when the feature has 3+ tasks or parallel work.
|
|
26
|
+
|
|
27
|
+
## Procedure
|
|
28
|
+
|
|
29
|
+
1. **Write one task per deliverable.** A task is something you would hand to a single agent and check in one commit.
|
|
30
|
+
2. **Prefer vertical slices.** One thin verifiable path per **feature** (e.g. register), not “all schema then all APIs then all UI” as *phases*. If `.cursor/rules/fullstack-layer.mdc` is present (`@luizsantiago/fullstack-floor-map`), keep each task `Files` list on **one Lane** (path layer; 0.4.x docs may still say “Floor”). Split UI vs API into T1/T2 with `Depends on`. Vertical still means a thin *feature*, not one task mixing `apps/web` + `apps/api`. See [Companion: Full Stack Floor Map](https://github.com/luizssantiago92/spec-guardrails/blob/main/docs/guide/Companion-fullstack-floor-map.md).
|
|
31
|
+
3. **Give every task the full field set.** Authoring and the gate require all six:
|
|
32
|
+
- `Requirement` — the spec ID it serves (gated)
|
|
33
|
+
- `Files` — where the change lands (gated; required; `none` / `—` rejected; overlap across independent tasks blocks)
|
|
34
|
+
- `Depends on` — real dependencies only, or `—` (gated; `—` means none)
|
|
35
|
+
- `Tests` — the test file that proves it (gated; `none` / `—` rejected)
|
|
36
|
+
- `Gate` — the command that must pass (gated; `none` / `—` rejected)
|
|
37
|
+
- `Done when` — binary criterion (gated; `none` / `—` rejected)
|
|
38
|
+
4. **Delete fake edges.** For every "and then", ask whether the next task actually reads the previous task's output. If not, the edge is fake — remove it and the tasks can run in parallel. See `task-graph-engineering.md`.
|
|
39
|
+
5. **Order tasks so dependencies come first.** Forward dependencies fail the gate. When grouping under `### Phase N`, a task must not depend on a task in a later phase.
|
|
40
|
+
6. **Apply the stop rule.** Only split work that never reads its siblings' results; sequential work stays with one agent.
|
|
41
|
+
7. **Cover every acceptance criterion.** Fill `## Test Coverage Matrix` and `## Gate Check Commands` **before** presenting the list. An unmapped requirement is a missing task. Align each task `Tests` / `Gate` field with those sections.
|
|
42
|
+
8. **Draw the graph** in `task-graph.md` when there are 3+ tasks or any parallel group.
|
|
43
|
+
9. **Run analyze, then the tasks gate**, then present the breakdown for approval.
|
|
44
|
+
```bash
|
|
45
|
+
python3 .specs/guardrails/scripts/analyze_artifacts.py [feature]
|
|
46
|
+
python3 .specs/guardrails/scripts/validate_tasks.py [feature]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Authoring vs gate.** `validate_tasks.py` already enforces REQ coverage and `Tests`/`Gate` fields. The matrix and Gate Check Commands sections are an owner/verifier checklist (judgment) until a future form gate — do not skip them when Tasks ran.
|
|
50
|
+
|
|
51
|
+
## Gate
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python3 .specs/guardrails/scripts/validate_tasks.py .specs/features/[feature]/tasks.md
|
|
55
|
+
python3 .specs/guardrails/scripts/validate_tasks.py [feature]
|
|
56
|
+
python3 .specs/guardrails/scripts/validate_tasks.py # single-feature projects
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Checks task IDs, required fields (including `Files` and `Done when`), dependency direction, later-phase dependencies, cycles, granularity smells, **spec requirement coverage**, and **Files overlap** across independent tasks. `Files`/`Tests`/`Gate`/`Done when` set to `none` or `—` fail. Non-zero exit means STOP.
|
|
60
|
+
|
|
61
|
+
Task headings, fields, and spec requirement IDs are read from visible markdown — fenced samples and HTML comments do not count. When a sibling `spec.md` exists, every requirement heading ID under `## Requirements` must appear in at least one task `Requirement` field. Independent tasks (no dependency path either way) must not share a path in `Files` (`./path`, `/path`, `../path`, quotes, markdown links, case variants, and `path` count as one).
|
|
62
|
+
|
|
63
|
+
The gate does not check that `Done when` is philosophically binary — you do. A passing gate is necessary, not sufficient. Path overlap uses the shared `normalize_file_path` helper (quotes, markdown links, `./`, `/`, `../`, drive letters, casefold).
|
|
64
|
+
|
|
65
|
+
## Execution Plan (phases)
|
|
66
|
+
|
|
67
|
+
Use `### Phase N` when the work has a real staging constraint (schema before handlers, handlers before UI). Phases are ordered groups, not a second ID scheme.
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
# Tasks: Authentication
|
|
71
|
+
|
|
72
|
+
### Phase 1
|
|
73
|
+
|
|
74
|
+
### T1: Create session token module
|
|
75
|
+
- **Requirement**: REQ-001
|
|
76
|
+
- **Files**: src/auth/token.ts
|
|
77
|
+
- **Depends on**: —
|
|
78
|
+
- **Tests**: test/auth/token.test.ts
|
|
79
|
+
- **Gate**: npm test
|
|
80
|
+
- **Done when**: module signs and verifies tokens
|
|
81
|
+
- [ ] complete
|
|
82
|
+
|
|
83
|
+
### Phase 2
|
|
84
|
+
|
|
85
|
+
### T2: Add login endpoint handler
|
|
86
|
+
- **Requirement**: REQ-001
|
|
87
|
+
- **Files**: src/routes/login.ts
|
|
88
|
+
- **Depends on**: T1
|
|
89
|
+
- **Tests**: test/routes/login.test.ts
|
|
90
|
+
- **Gate**: npm test
|
|
91
|
+
- **Done when**: endpoint returns 200 for valid credentials
|
|
92
|
+
- [ ] complete
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Rules the gate enforces:
|
|
96
|
+
|
|
97
|
+
- A task in Phase 1 must not depend on a task in Phase 2 or later
|
|
98
|
+
- Document order still matters: dependencies must appear before dependents
|
|
99
|
+
- Tasks with no phase heading are treated as phase 0 (ungrouped) and may depend only on other ungrouped or earlier-phase tasks
|
|
100
|
+
|
|
101
|
+
Do not invent phases to make the list look organized. Two tasks that can run in the same round belong in the same phase, or in no phase at all.
|
|
102
|
+
|
|
103
|
+
## Template
|
|
104
|
+
|
|
105
|
+
```markdown
|
|
106
|
+
# Tasks: [Feature]
|
|
107
|
+
|
|
108
|
+
### T1: [Imperative, specific title]
|
|
109
|
+
- **Requirement**: REQ-001
|
|
110
|
+
- **Files**: src/auth/token.ts
|
|
111
|
+
- **Depends on**: —
|
|
112
|
+
- **Tests**: test/auth/token.test.ts
|
|
113
|
+
- **Gate**: npm test
|
|
114
|
+
- **Done when**: token module signs and verifies tokens
|
|
115
|
+
- [ ] complete
|
|
116
|
+
|
|
117
|
+
### T2: [Imperative, specific title]
|
|
118
|
+
- **Requirement**: REQ-001
|
|
119
|
+
- **Files**: src/routes/login.ts
|
|
120
|
+
- **Depends on**: T1
|
|
121
|
+
- **Tests**: test/routes/login.test.ts
|
|
122
|
+
- **Gate**: npm test
|
|
123
|
+
- **Done when**: endpoint returns 200 for valid credentials
|
|
124
|
+
- [ ] complete
|
|
125
|
+
|
|
126
|
+
## Test Coverage Matrix
|
|
127
|
+
| Requirement | Task | Tests | Notes |
|
|
128
|
+
| --- | --- | --- | --- |
|
|
129
|
+
| REQ-001 | T1, T2 | test/auth/token.test.ts, test/routes/login.test.ts | |
|
|
130
|
+
|
|
131
|
+
## Gate Check Commands
|
|
132
|
+
| Level | Command |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| Task | the per-task `Gate` field |
|
|
135
|
+
| Feature | npm test |
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Granularity
|
|
139
|
+
|
|
140
|
+
| Too coarse | Atomic |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| "Create form" | T1: add email input component · T2: add email validation · T3: add submit handler |
|
|
143
|
+
| "Implement feature" | One task per file or per contract |
|
|
144
|
+
| "Fix bugs" | One task per reproducible defect |
|
|
145
|
+
| "Add auth" | T1: token module · T2: login handler · T3: refresh handler |
|
|
146
|
+
| "Write tests" | The tests belong on the task that produces the behavior, not as a follow-up |
|
|
147
|
+
|
|
148
|
+
A task that cannot be verified by a single named test is not atomic yet. A title under three words is a smell the gate warns about (`"Add endpoint"` → `"Add login endpoint handler"`).
|
|
149
|
+
|
|
150
|
+
## Good and bad dependencies
|
|
151
|
+
|
|
152
|
+
| Edge | Real or fake | Why |
|
|
153
|
+
| --- | --- | --- |
|
|
154
|
+
| Login handler depends on token module | Real | The handler imports and calls the module |
|
|
155
|
+
| README update depends on login tests | Fake | README does not read test output |
|
|
156
|
+
| Refresh handler depends on login handler | Fake, unless it shares a type the login task creates | Same auth package can land in parallel if files differ |
|
|
157
|
+
| UI form depends on API contract | Real if the form types are generated from the handler | Otherwise the form can mock the contract and run in parallel |
|
|
158
|
+
|
|
159
|
+
Delete fake edges before drawing `task-graph.md`. Most first drafts hide two or three.
|
|
160
|
+
|
|
161
|
+
## Coverage matrix
|
|
162
|
+
|
|
163
|
+
Before approval, map every spec requirement heading under `## Requirements` to at least one task. Every task `Tests` path should appear in the matrix. Fill `## Test Coverage Matrix` and `## Gate Check Commands` in `tasks.md` (see Template).
|
|
164
|
+
|
|
165
|
+
| Requirement | Task | Tests | Notes |
|
|
166
|
+
| --- | --- | --- | --- |
|
|
167
|
+
| REQ-001 | T2 | test/routes/login.test.ts | valid credentials → session |
|
|
168
|
+
| REQ-001 | T2 | test/routes/login.test.ts | invalid → 401 `AUTH_INVALID` |
|
|
169
|
+
| REQ-002 | T3 | test/routes/refresh.test.ts | refresh rotates the token |
|
|
170
|
+
|
|
171
|
+
A requirement with no row is unimplemented by construction. Do not present the breakdown until the matrix is complete. The Python gate already fails uncovered REQ IDs; the table is for humans and Execute.
|
|
172
|
+
|
|
173
|
+
`Files` lists on parallel tasks must be disjoint. If two tasks name the same file, they are one task, or they are sequential.
|
|
174
|
+
|
|
175
|
+
## Next
|
|
176
|
+
|
|
177
|
+
- 3+ tasks or parallel groups → `/task-graph` per `task-graph-engineering.md`
|
|
178
|
+
- Otherwise → `implement.md`
|