@mohammadhprp/system-prompt 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/framework/agents/backend-architect.md +1 -1
  2. package/framework/commands/commit.md +0 -3
  3. package/framework/mcps/figma-mcp-go/README.md +0 -1
  4. package/framework/mcps/gitlab-mcp/README.md +0 -1
  5. package/framework/mcps/jira-mcp/README.md +0 -1
  6. package/framework/mcps/laravel-boost/README.md +0 -1
  7. package/framework/mcps/notion-mcp/README.md +0 -1
  8. package/framework/mcps/supabase-mcp/README.md +0 -1
  9. package/framework/plugins/opencode-goal-plugin/README.md +0 -1
  10. package/framework/references/standards/api.md +0 -1
  11. package/framework/references/standards/architecture.md +0 -1
  12. package/framework/references/standards/database.md +0 -1
  13. package/framework/references/standards/debugging.md +0 -1
  14. package/framework/references/standards/documentation.md +0 -2
  15. package/framework/references/standards/logging.md +0 -1
  16. package/framework/references/standards/naming.md +0 -1
  17. package/framework/references/standards/observability.md +0 -1
  18. package/framework/references/standards/performance.md +0 -1
  19. package/framework/references/standards/pull-requests.md +0 -1
  20. package/framework/references/standards/security.md +0 -1
  21. package/framework/references/standards/testing.md +0 -1
  22. package/framework/skills/README.md +15 -3
  23. package/framework/skills/codenavi/SKILL.md +306 -0
  24. package/framework/skills/codenavi/examples.md +33 -0
  25. package/framework/skills/codenavi/references/coding-principles.md +143 -0
  26. package/framework/skills/codenavi/references/notebook-spec.md +171 -0
  27. package/framework/skills/create-adr/SKILL.md +429 -0
  28. package/framework/skills/create-adr/examples.md +35 -0
  29. package/framework/skills/docs-writer/SKILL.md +39 -0
  30. package/framework/skills/docs-writer/examples.md +34 -0
  31. package/framework/skills/docs-writer/references/style-guide.md +72 -0
  32. package/framework/skills/frontend-design/SKILL.md +55 -0
  33. package/framework/skills/frontend-design/examples.md +45 -0
  34. package/framework/skills/humanizer/SKILL.md +412 -0
  35. package/framework/skills/humanizer/examples.md +46 -0
  36. package/framework/skills/learning-opportunities/SKILL.md +140 -0
  37. package/framework/skills/learning-opportunities/examples.md +34 -0
  38. package/framework/skills/learning-opportunities/references/PRINCIPLES.md +42 -0
  39. package/framework/skills/perf-web-optimization/SKILL.md +163 -0
  40. package/framework/skills/perf-web-optimization/examples.md +35 -0
  41. package/framework/skills/perf-web-optimization/references/bundle-optimization.md +180 -0
  42. package/framework/skills/perf-web-optimization/references/core-web-vitals.md +154 -0
  43. package/framework/skills/perf-web-optimization/references/image-optimization.md +170 -0
  44. package/framework/skills/security-best-practices/LICENSE.txt +201 -0
  45. package/framework/skills/security-best-practices/SKILL.md +89 -0
  46. package/framework/skills/security-best-practices/examples.md +35 -0
  47. package/framework/skills/security-best-practices/references/golang-general-backend-security.md +988 -0
  48. package/framework/skills/security-best-practices/references/javascript-express-web-server-security.md +1151 -0
  49. package/framework/skills/security-best-practices/references/javascript-general-web-frontend-security.md +725 -0
  50. package/framework/skills/security-best-practices/references/javascript-jquery-web-frontend-security.md +672 -0
  51. package/framework/skills/security-best-practices/references/javascript-typescript-nextjs-web-server-security.md +1138 -0
  52. package/framework/skills/security-best-practices/references/javascript-typescript-react-web-frontend-security.md +975 -0
  53. package/framework/skills/security-best-practices/references/javascript-typescript-vue-web-frontend-security.md +789 -0
  54. package/framework/skills/security-best-practices/references/python-django-web-server-security.md +880 -0
  55. package/framework/skills/security-best-practices/references/python-fastapi-web-server-security.md +1030 -0
  56. package/framework/skills/security-best-practices/references/python-flask-web-server-security.md +835 -0
  57. package/framework/skills/sentry/SKILL.md +127 -0
  58. package/framework/skills/sentry/examples.md +34 -0
  59. package/framework/skills/sentry/scripts/sentry_api.py +238 -0
  60. package/framework/skills/show-me/SKILL.md +127 -0
  61. package/framework/skills/show-me/examples.md +78 -0
  62. package/framework/skills/spec-driven-eval/SKILL.md +341 -0
  63. package/framework/skills/spec-driven-eval/examples.md +35 -0
  64. package/framework/skills/spec-driven-eval/references/quickstart.md +118 -0
  65. package/framework/skills/spec-driven-eval/references/reference.md +295 -0
  66. package/framework/skills/technical-design-doc-creator/README.md +411 -0
  67. package/framework/skills/technical-design-doc-creator/SKILL.md +1484 -0
  68. package/framework/skills/technical-design-doc-creator/examples.md +35 -0
  69. package/framework/skills/tlc-spec-driven/SKILL.md +184 -0
  70. package/framework/skills/tlc-spec-driven/examples.md +34 -0
  71. package/framework/skills/tlc-spec-driven/references/code-analysis.md +98 -0
  72. package/framework/skills/tlc-spec-driven/references/coding-principles.md +72 -0
  73. package/framework/skills/tlc-spec-driven/references/context-limits.md +31 -0
  74. package/framework/skills/tlc-spec-driven/references/design.md +199 -0
  75. package/framework/skills/tlc-spec-driven/references/discuss.md +159 -0
  76. package/framework/skills/tlc-spec-driven/references/implement.md +436 -0
  77. package/framework/skills/tlc-spec-driven/references/lessons.md +115 -0
  78. package/framework/skills/tlc-spec-driven/references/memory.md +144 -0
  79. package/framework/skills/tlc-spec-driven/references/specify.md +228 -0
  80. package/framework/skills/tlc-spec-driven/references/sub-agents.md +147 -0
  81. package/framework/skills/tlc-spec-driven/references/tasks.md +451 -0
  82. package/framework/skills/tlc-spec-driven/references/validate.md +355 -0
  83. package/framework/skills/tlc-spec-driven/scripts/check_commit.py +115 -0
  84. package/framework/skills/tlc-spec-driven/scripts/lessons.py +412 -0
  85. package/framework/skills/tlc-spec-driven/scripts/validate_spec.py +260 -0
  86. package/framework/skills/tlc-spec-driven/scripts/validate_state.py +162 -0
  87. package/framework/skills/tlc-spec-driven/scripts/validate_tasks.py +251 -0
  88. package/framework/skills/web-design-guidelines/SKILL.md +65 -0
  89. package/framework/skills/web-design-guidelines/examples.md +32 -0
  90. package/framework/skills/web-design-guidelines/references/guideline.md +174 -0
  91. package/package.json +1 -1
  92. package/src/catalog.js +15 -3
  93. package/src/installer.js +66 -1
  94. package/framework/skills/backend-engineer/SKILL.md +0 -76
  95. package/framework/skills/backend-engineer/examples.md +0 -31
  96. package/framework/skills/documentation/SKILL.md +0 -74
  97. package/framework/skills/documentation/examples.md +0 -31
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ validate_state.py - deterministic completion gate for a feature.
4
+
5
+ The skill's strongest invariant is "the Verifier is always-on, never prompted;
6
+ Execute is not done until validation.md reports PASS." That is prose the model
7
+ must remember. This turns it into a checkable pass/fail the closing step runs
8
+ automatically, so declaring a feature done without a real Verifier report fails
9
+ loudly instead of slipping through.
10
+
11
+ It does NOT merely check that validation.md exists - a report that exists but is
12
+ empty, still holds the template placeholder, or has no evidence would pass a
13
+ shallow existence check while proving nothing. This gate requires a real,
14
+ filled verdict plus at least one file:line evidence citation.
15
+
16
+ Operates only on the .specs/ markdown artifacts (stack- and tool-agnostic). No
17
+ dependencies. Run from the project root (the dir that contains .specs), or pass
18
+ --root. Meant to be invoked by the skill as the closing gate of Execute, the
19
+ same way lessons.py is invoked at distillation - not a manual step.
20
+
21
+ Usage:
22
+ python3 <skill-dir>/scripts/validate_state.py [feature]
23
+ python3 <skill-dir>/scripts/validate_state.py
24
+
25
+ Invoke from the skill directory that ships this script (not the project root).
26
+ Pass --root when cwd is not the project that contains .specs/.
27
+
28
+ Exit codes: 0 ok, 1 a completed feature is missing a real PASS report,
29
+ 2 usage error.
30
+ """
31
+
32
+ import argparse
33
+ import os
34
+ import re
35
+ import sys
36
+
37
+ # A file:line citation: a path with an extension, then :<line>. e.g. src/a.ts:42
38
+ EVIDENCE_RE = re.compile(r"[\w./-]+\.[A-Za-z0-9]+:\d+")
39
+
40
+
41
+ def _feature_dirs(root):
42
+ base = os.path.join(root, ".specs", "features")
43
+ if not os.path.isdir(base):
44
+ return base, []
45
+ dirs = [
46
+ d for d in sorted(os.listdir(base))
47
+ if os.path.isdir(os.path.join(base, d))
48
+ ]
49
+ return base, dirs
50
+
51
+
52
+ def _verdict(text):
53
+ """Return 'pass', 'fail', 'unfilled', or None from a validation report."""
54
+ # Look at the '## Validation' heading first, then a '**Result**' line.
55
+ lines = text.splitlines()
56
+ candidates = [
57
+ ln for ln in lines
58
+ if re.search(r"^#{1,4}\s*validation\b", ln.strip(), re.IGNORECASE)
59
+ or re.search(r"\*{0,2}result\*{0,2}\s*:", ln.strip(), re.IGNORECASE)
60
+ ]
61
+ hay = " ".join(candidates) if candidates else text
62
+ has_pass = re.search(r"\bPASS\b", hay) is not None
63
+ has_fail = re.search(r"\bFAIL\b", hay) is not None
64
+ if has_pass and has_fail:
65
+ # Both present on the verdict line = unfilled template "[PASS | FAIL]".
66
+ return "unfilled"
67
+ if has_pass:
68
+ return "pass"
69
+ if has_fail:
70
+ return "fail"
71
+ return None
72
+
73
+
74
+ def _appears_complete(fdir):
75
+ """Conservative completeness heuristic for the cross-check mode.
76
+
77
+ A feature 'appears complete' if it already has a validation.md, or if it has
78
+ a tasks.md with at least one task and no unchecked '- [ ]' boxes left. When
79
+ the signal is ambiguous (no tasks.md, Tasks phase skipped), returns False so
80
+ an in-flight feature is never falsely flagged.
81
+ """
82
+ if os.path.exists(os.path.join(fdir, "validation.md")):
83
+ return True
84
+ tasks = os.path.join(fdir, "tasks.md")
85
+ if not os.path.exists(tasks):
86
+ return False
87
+ body = open(tasks, encoding="utf-8", errors="replace").read()
88
+ if not re.search(r"^#{2,4}\s+T\d+\s*:", body, re.MULTILINE):
89
+ return False
90
+ if re.search(r"^\s*-\s*\[\s\]", body, re.MULTILINE):
91
+ return False # unchecked box remains -> still in progress
92
+ return True
93
+
94
+
95
+ def _check_feature(fdir, name):
96
+ """Return list of error strings for one feature (empty = pass)."""
97
+ errors = []
98
+ vpath = os.path.join(fdir, "validation.md")
99
+ if not os.path.exists(vpath):
100
+ errors.append(
101
+ f"{name}: no validation.md - Execute is not done until the Verifier "
102
+ f"writes it (author != verifier). Dispatch validation before marking done."
103
+ )
104
+ return errors
105
+ text = open(vpath, encoding="utf-8", errors="replace").read()
106
+ verdict = _verdict(text)
107
+ if verdict is None:
108
+ errors.append(f"{name}: validation.md has no PASS/FAIL verdict (a prose-only report does not count)")
109
+ elif verdict == "unfilled":
110
+ errors.append(f"{name}: validation.md verdict is still the template placeholder '[PASS | FAIL]' - not filled")
111
+ elif verdict == "fail":
112
+ errors.append(f"{name}: validation.md verdict is FAIL - route the ranked gaps to fix tasks, then re-verify (feature is not done)")
113
+ if verdict == "pass" and not EVIDENCE_RE.search(text):
114
+ errors.append(f"{name}: validation.md is PASS but cites no file:line evidence - evidence-or-zero not satisfied")
115
+ return errors
116
+
117
+
118
+ def _resolve(root, feature):
119
+ base, dirs = _feature_dirs(root)
120
+ if not os.path.isdir(base):
121
+ print(f"validate_state: no {base} directory - nothing to check.")
122
+ return []
123
+ if feature:
124
+ fdir = feature if os.path.isdir(feature) else os.path.join(base, feature)
125
+ if not os.path.isdir(fdir):
126
+ print(f"validate_state: feature not found: {feature}", file=sys.stderr)
127
+ raise SystemExit(2)
128
+ return [(fdir, os.path.basename(fdir.rstrip("/")))]
129
+ if len(dirs) == 1:
130
+ return [(os.path.join(base, dirs[0]), dirs[0])]
131
+ if not dirs:
132
+ print("validate_state: no features under .specs/features/ - nothing to check.")
133
+ return []
134
+ # Cross-check mode: only features that appear complete.
135
+ picked = [(os.path.join(base, d), d) for d in dirs if _appears_complete(os.path.join(base, d))]
136
+ if not picked:
137
+ print("validate_state: no completed feature detected (all in progress) - nothing to gate.")
138
+ return picked
139
+
140
+
141
+ def main(argv=None):
142
+ p = argparse.ArgumentParser(prog="validate_state.py", description="Deterministic completion gate: a done feature must have a real PASS validation report.")
143
+ p.add_argument("feature", nargs="?", default=None, help="Feature dir or name (default: sole feature, else cross-check all completed)")
144
+ p.add_argument("--root", default=".", help="Project root containing .specs/ (default: current dir)")
145
+ args = p.parse_args(argv)
146
+ root = os.path.abspath(args.root)
147
+
148
+ targets = _resolve(root, args.feature)
149
+ all_errors = []
150
+ for fdir, name in targets:
151
+ all_errors += _check_feature(fdir, name)
152
+
153
+ for e in all_errors:
154
+ print(f" ERROR {e}")
155
+ n = len(all_errors)
156
+ checked = ", ".join(name for _, name in targets) or "(none)"
157
+ print(f"\nvalidate_state: {n} error(s) across [{checked}]")
158
+ return 1 if n else 0
159
+
160
+
161
+ if __name__ == "__main__":
162
+ raise SystemExit(main())
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ validate_tasks.py - deterministic pre-approval checks for a feature tasks.md.
4
+
5
+ Turns the three pre-approval checks (task granularity, diagram-vs-definition
6
+ cross-check, test co-location) into a checkable pass/fail run BEFORE tasks are
7
+ presented for approval, instead of trusting the model to build the tables by
8
+ hand. Pure standard library, zero dependencies. Operates only on the tasks.md
9
+ markdown artifact, so it is stack-agnostic and tool-agnostic.
10
+
11
+ What it checks (heuristic markdown inspection, not a full parser):
12
+ ERROR - a required section is missing
13
+ ERROR - a task is missing its `Tests` or `Gate` field
14
+ ERROR - a task depends on a task in a LATER phase (dependencies point back only)
15
+ ERROR - a dependency edge shown in the diagram has no matching `Depends on`
16
+ (and vice-versa) when both sides are parseable
17
+ WARN - a task's `Where` names multiple files (granularity smell -> split it)
18
+ WARN - a task says `Tests: none` (confirm the coverage matrix agrees)
19
+ WARN - the diagram could not be parsed confidently (cross-check skipped)
20
+
21
+ Usage:
22
+ python3 <skill-dir>/scripts/validate_tasks.py [target] [--root DIR] [--strict]
23
+
24
+ Invoke from the skill directory that ships this script (not the project root).
25
+ target Path to a tasks.md, a feature directory, or a project root.
26
+ Omitted -> auto-detect the single feature under <root>/.specs/features/.
27
+ --root Project root that contains .specs/ (default: current dir).
28
+ --strict Treat warnings as errors.
29
+
30
+ Exit codes: 0 pass, 1 errors found (or warnings under --strict), 2 usage error.
31
+ """
32
+
33
+ import argparse
34
+ import os
35
+ import re
36
+ import sys
37
+
38
+ REQUIRED_SECTIONS = ["Test Coverage Matrix", "Gate Check Commands", "Execution Plan", "Task Breakdown"]
39
+ TASK_RE = re.compile(r"^#{2,4}\s+(T\d+)\s*:", re.IGNORECASE)
40
+ EDGE_RE = re.compile(r"\bT\d+\b")
41
+ FILE_HINT_RE = re.compile(r"[\w./-]+\.\w{1,6}\b")
42
+
43
+
44
+ def resolve_tasks(target, root):
45
+ if target:
46
+ if os.path.isfile(target):
47
+ return target
48
+ if os.path.isdir(target):
49
+ cand = os.path.join(target, "tasks.md")
50
+ if os.path.isfile(cand):
51
+ return cand
52
+ return _autodetect(target)
53
+ # Not a path: treat as a feature name under <root>/.specs/features/<name>/
54
+ cand = os.path.join(root, ".specs", "features", target, "tasks.md")
55
+ if os.path.isfile(cand):
56
+ return cand
57
+ return None
58
+ return _autodetect(root)
59
+
60
+
61
+ def _autodetect(root):
62
+ base = os.path.join(root, ".specs", "features")
63
+ if not os.path.isdir(base):
64
+ return None
65
+ features = [d for d in sorted(os.listdir(base)) if os.path.isfile(os.path.join(base, d, "tasks.md"))]
66
+ if len(features) == 1:
67
+ return os.path.join(base, features[0], "tasks.md")
68
+ if len(features) == 0:
69
+ return None
70
+ raise SystemExit(
71
+ "validate_tasks: multiple features found; pass one explicitly:\n "
72
+ + "\n ".join(os.path.join(base, f, "tasks.md") for f in features)
73
+ )
74
+
75
+
76
+ def section_present(lines, name):
77
+ return any(re.match(r"^#{1,4}\s+" + re.escape(name) + r"\b", ln.strip()) for ln in lines)
78
+
79
+
80
+ def parse_tasks(lines):
81
+ """Return a dict: task_id -> {'deps': set, 'tests': str|None, 'gate': str|None, 'where': str}."""
82
+ tasks = {}
83
+ current = None
84
+ for ln in lines:
85
+ m = TASK_RE.match(ln.strip())
86
+ if m:
87
+ current = m.group(1).upper()
88
+ tasks[current] = {"deps": set(), "tests": None, "gate": None, "where": ""}
89
+ continue
90
+ if current is None:
91
+ continue
92
+ stripped = ln.strip()
93
+ dm = re.match(r"^\*{0,2}Depends on\*{0,2}\s*:\s*(.*)$", stripped, re.IGNORECASE)
94
+ if dm:
95
+ body = dm.group(1)
96
+ if "none" not in body.lower():
97
+ for e in EDGE_RE.findall(body.upper()):
98
+ tasks[current]["deps"].add(e)
99
+ wm = re.match(r"^\*{0,2}Where\*{0,2}\s*:\s*(.*)$", stripped, re.IGNORECASE)
100
+ if wm:
101
+ tasks[current]["where"] = wm.group(1)
102
+ tm = re.match(r"^\*{0,2}Tests\*{0,2}\s*:\s*(.*)$", stripped, re.IGNORECASE)
103
+ if tm:
104
+ tasks[current]["tests"] = tm.group(1).strip()
105
+ gm = re.match(r"^\*{0,2}Gate\*{0,2}\s*:\s*(.*)$", stripped, re.IGNORECASE)
106
+ if gm:
107
+ tasks[current]["gate"] = gm.group(1).strip()
108
+ return tasks
109
+
110
+
111
+ def parse_phase_membership(lines):
112
+ """Map task_id -> phase index, read from '### Phase N' headers in the Execution Plan."""
113
+ membership = {}
114
+ phase_idx = 0
115
+ in_phase = False
116
+ for ln in lines:
117
+ pm = re.match(r"^#{2,4}\s+Phase\s+(\d+)", ln.strip(), re.IGNORECASE)
118
+ if pm:
119
+ phase_idx = int(pm.group(1))
120
+ in_phase = True
121
+ continue
122
+ if in_phase:
123
+ # Map a task to a phase ONLY when it appears as a task header (### Tn:),
124
+ # never when it is merely referenced (e.g. in a `Depends on:` line or a
125
+ # diagram arrow), which would misattribute the referenced task to this phase.
126
+ hm = TASK_RE.match(ln.strip())
127
+ if hm:
128
+ membership[hm.group(1).upper()] = phase_idx
129
+ return membership
130
+
131
+
132
+ def parse_diagram_edges(lines):
133
+ """Best-effort: parse 'Tx -> Ty' / 'Tx → Ty' arrow chains from fenced blocks.
134
+ Returns (edges:set[(src,dst)], parsed:bool)."""
135
+ edges = set()
136
+ in_fence = False
137
+ found_any_arrow = False
138
+ for ln in lines:
139
+ if ln.strip().startswith("```"):
140
+ in_fence = not in_fence
141
+ continue
142
+ if not in_fence:
143
+ continue
144
+ # normalize arrow glyphs
145
+ norm = ln.replace("→", "->").replace("──", "-").replace("-", "-")
146
+ if "->" not in norm:
147
+ continue
148
+ chain = EDGE_RE.findall(norm.upper())
149
+ # only treat as a chain if arrows connect them left-to-right
150
+ segments = [s for s in re.split(r"->", norm)]
151
+ seq = []
152
+ for seg in segments:
153
+ ids = EDGE_RE.findall(seg.upper())
154
+ seq.append(ids[-1] if ids else None)
155
+ for a, b in zip(seq, seq[1:]):
156
+ if a and b:
157
+ edges.add((a, b))
158
+ found_any_arrow = True
159
+ return edges, found_any_arrow
160
+
161
+
162
+ def check(tasks_path):
163
+ with open(tasks_path, "r", encoding="utf-8") as f:
164
+ lines = f.read().splitlines()
165
+ errors, warnings = [], []
166
+
167
+ for name in REQUIRED_SECTIONS:
168
+ if not section_present(lines, name):
169
+ errors.append(f"missing required section: ## {name}")
170
+
171
+ tasks = parse_tasks(lines)
172
+ if not tasks:
173
+ warnings.append("no tasks (### T1: ...) parsed - is this file filled in?")
174
+ return errors, warnings
175
+
176
+ # Field presence + granularity smell.
177
+ for tid, t in tasks.items():
178
+ if t["tests"] is None:
179
+ errors.append(f"{tid}: missing `Tests` field")
180
+ elif t["tests"].lower().startswith("none"):
181
+ warnings.append(f"{tid}: Tests: none - confirm the Test Coverage Matrix says 'none' for this layer")
182
+ if t["gate"] is None:
183
+ errors.append(f"{tid}: missing `Gate` field")
184
+ files = FILE_HINT_RE.findall(t["where"])
185
+ if len(set(files)) > 1:
186
+ warnings.append(f"{tid}: `Where` names multiple files {sorted(set(files))} - granularity smell, consider splitting")
187
+
188
+ # Forward-phase dependency.
189
+ membership = parse_phase_membership(lines)
190
+ for tid, t in tasks.items():
191
+ p_here = membership.get(tid)
192
+ if p_here is None:
193
+ continue
194
+ for dep in t["deps"]:
195
+ p_dep = membership.get(dep)
196
+ if p_dep is not None and p_dep > p_here:
197
+ errors.append(f"{tid} (phase {p_here}) depends on {dep} (phase {p_dep}) - dependencies must point backward or within the same phase")
198
+
199
+ # Diagram vs definition cross-check (best effort).
200
+ edges, parsed = parse_diagram_edges(lines)
201
+ if not parsed:
202
+ warnings.append("diagram arrows not parsed confidently - diagram/definition cross-check skipped (verify by hand)")
203
+ else:
204
+ def intra_phase(a, b):
205
+ # Parity applies only within a phase. A backward cross-phase dependency
206
+ # is validated by the forward-phase check above and needs no diagram arrow;
207
+ # phase diagrams are drawn per phase, so cross-phase edges are out of scope here.
208
+ pa, pb = membership.get(a), membership.get(b)
209
+ if pa is None or pb is None:
210
+ return True # unknown phase -> keep best-effort parity
211
+ return pa == pb
212
+
213
+ dep_edges = set()
214
+ for tid, t in tasks.items():
215
+ for dep in t["deps"]:
216
+ dep_edges.add((dep, tid)) # arrow points dep -> task
217
+ only_in_diagram = {(a, b) for (a, b) in (edges - dep_edges) if intra_phase(a, b)}
218
+ only_in_defs = {(a, b) for (a, b) in (dep_edges - edges) if intra_phase(a, b)}
219
+ for a, b in sorted(only_in_diagram):
220
+ if a in tasks and b in tasks:
221
+ errors.append(f"diagram shows {a} -> {b} but {b} has no matching `Depends on: {a}`")
222
+ for a, b in sorted(only_in_defs):
223
+ errors.append(f"{b} declares `Depends on: {a}` but the diagram has no {a} -> {b} arrow")
224
+
225
+ return errors, warnings
226
+
227
+
228
+ def main(argv=None):
229
+ p = argparse.ArgumentParser(prog="validate_tasks.py", description="Pre-approval checks for a feature tasks.md.")
230
+ p.add_argument("target", nargs="?", default=None)
231
+ p.add_argument("--root", default=".")
232
+ p.add_argument("--strict", action="store_true")
233
+ args = p.parse_args(argv)
234
+
235
+ tasks_path = resolve_tasks(args.target, args.root)
236
+ if not tasks_path:
237
+ print("validate_tasks: could not locate a tasks.md. Pass a path or run from the project root.", file=sys.stderr)
238
+ return 2
239
+
240
+ errors, warnings = check(tasks_path)
241
+ for w in warnings:
242
+ print(f" WARN {w}")
243
+ for e in errors:
244
+ print(f" ERROR {e}")
245
+ fail = errors or (warnings and args.strict)
246
+ print(f"\nvalidate_tasks: {len(errors)} error(s), {len(warnings)} warning(s) in {tasks_path}")
247
+ return 1 if fail else 0
248
+
249
+
250
+ if __name__ == "__main__":
251
+ raise SystemExit(main())
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: web-design-guidelines
3
+ description: Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices". Focuses on visual design and interaction patterns. Do NOT use for performance audits (use core-web-vitals), SEO (use seo), or comprehensive site audits (use web-quality-audit).
4
+ metadata:
5
+ author: vercel
6
+ version: '1.0.0'
7
+ argument-hint: <file-or-pattern>
8
+ ---
9
+
10
+ # Web Interface Guidelines
11
+
12
+ Review files for compliance with Web Interface Guidelines.
13
+
14
+ ## How It Works
15
+
16
+ 1. Read the guidelines from `#[[file:references/guideline.md]]`
17
+ 2. Read the specified files (or prompt user for files/pattern)
18
+ 3. Check against all rules in the guidelines
19
+ 4. Output findings in the terse `file:line` format
20
+
21
+ ## Guidelines Reference
22
+
23
+ All rules and output format instructions are in:
24
+
25
+ ```
26
+ #[[file:references/guideline.md]]
27
+ ```
28
+
29
+ The guidelines cover:
30
+
31
+ - Accessibility (ARIA, semantic HTML, keyboard navigation)
32
+ - Focus states and keyboard interaction
33
+ - Forms (autocomplete, validation, labels)
34
+ - Animation (reduced motion, performance)
35
+ - Typography (proper characters, number formatting)
36
+ - Content handling (overflow, empty states)
37
+ - Images (dimensions, lazy loading)
38
+ - Performance (virtualization, DOM reads)
39
+ - Navigation & state (URL sync, deep linking)
40
+ - Touch & interaction (tap delays, safe areas)
41
+ - Dark mode & theming
42
+ - Locale & i18n
43
+ - Hydration safety
44
+ - Common anti-patterns to flag
45
+
46
+ ## Usage
47
+
48
+ When a user provides a file or pattern argument:
49
+
50
+ 1. Read the guidelines from `references/guideline.md`
51
+ 2. Read the specified files
52
+ 3. Apply all rules from the guidelines
53
+ 4. Output findings using the format specified in the guidelines
54
+
55
+ If no files specified, ask the user which files to review.
56
+
57
+ ## Output Format
58
+
59
+ Follow the format in the guidelines:
60
+
61
+ - Group findings by file
62
+ - Use `file:line` format (VS Code clickable)
63
+ - Terse, high signal-to-noise
64
+ - State issue + location
65
+ - Skip explanation unless fix is non-obvious
@@ -0,0 +1,32 @@
1
+ # Web Design Guidelines Examples
2
+
3
+ ## Review a component for accessibility
4
+
5
+ User: "Review my dropdown component."
6
+
7
+ Good agent behavior:
8
+
9
+ - Read the guidelines from `references/guideline.md` first, then the specified file.
10
+ - Check ARIA usage, keyboard navigation, focus states, and semantic HTML against the rules.
11
+ - Output findings grouped by file in `file:line` format, state the issue and location, and skip explanations unless the fix is non-obvious.
12
+
13
+ ## Audit a page's interaction patterns
14
+
15
+ User: "Check my checkout page against best practices."
16
+
17
+ Good agent behavior:
18
+
19
+ - Apply the rules for forms (labels, validation, autocomplete), touch targets, tap delays, and reduced motion.
20
+ - Flag focus visibility and safe-area issues on mobile.
21
+ - Keep the output terse and high signal-to-noise: issue + `file:line` location.
22
+ - Redirect the user to the right skill when a request is out of scope, such as a performance audit.
23
+
24
+ ## Review without a file specified
25
+
26
+ User: "Audit my site."
27
+
28
+ Good agent behavior:
29
+
30
+ - Ask which files or pattern to review before starting, since the skill needs a target.
31
+ - Once provided, read the files and check them against all rules in the guidelines.
32
+ - Produce the grouped `file:line` findings rather than a prose essay.
@@ -0,0 +1,174 @@
1
+ # Web Interface Guidelines
2
+
3
+ Review these files for compliance: $ARGUMENTS
4
+
5
+ Read files, check against rules below. Output concise but comprehensive—sacrifice grammar for brevity. High signal-to-noise.
6
+
7
+ ## Rules
8
+
9
+ ### Accessibility
10
+
11
+ - Icon-only buttons need `aria-label`
12
+ - Form controls need `<label>` or `aria-label`
13
+ - Interactive elements need keyboard handlers (`onKeyDown`/`onKeyUp`)
14
+ - `<button>` for actions, `<a>`/`<Link>` for navigation (not `<div onClick>`)
15
+ - Images need `alt` (or `alt=""` if decorative)
16
+ - Decorative icons need `aria-hidden="true"`
17
+ - Async updates (toasts, validation) need `aria-live="polite"`
18
+ - Use semantic HTML (`<button>`, `<a>`, `<label>`, `<table>`) before ARIA
19
+ - Headings hierarchical `<h1>`–`<h6>`; include skip link for main content
20
+ - `scroll-margin-top` on heading anchors
21
+
22
+ ### Focus States
23
+
24
+ - Interactive elements need visible focus: `focus-visible:ring-*` or equivalent
25
+ - Never `outline-none` / `outline: none` without focus replacement
26
+ - Use `:focus-visible` over `:focus` (avoid focus ring on click)
27
+ - Group focus with `:focus-within` for compound controls
28
+
29
+ ### Forms
30
+
31
+ - Inputs need `autocomplete` and meaningful `name`
32
+ - Use correct `type` (`email`, `tel`, `url`, `number`) and `inputmode`
33
+ - Never block paste (`onPaste` + `preventDefault`)
34
+ - Labels clickable (`htmlFor` or wrapping control)
35
+ - Disable spellcheck on emails, codes, usernames (`spellCheck={false}`)
36
+ - Checkboxes/radios: label + control share single hit target (no dead zones)
37
+ - Submit button stays enabled until request starts; spinner during request
38
+ - Errors inline next to fields; focus first error on submit
39
+ - Placeholders end with `…` and show example pattern
40
+ - `autocomplete="off"` on non-auth fields to avoid password manager triggers
41
+ - Warn before navigation with unsaved changes (`beforeunload` or router guard)
42
+
43
+ ### Animation
44
+
45
+ - Honor `prefers-reduced-motion` (provide reduced variant or disable)
46
+ - Animate `transform`/`opacity` only (compositor-friendly)
47
+ - Never `transition: all`—list properties explicitly
48
+ - Set correct `transform-origin`
49
+ - SVG: transforms on `<g>` wrapper with `transform-box: fill-box; transform-origin: center`
50
+ - Animations interruptible—respond to user input mid-animation
51
+
52
+ ### Typography
53
+
54
+ - `…` not `...`
55
+ - Curly quotes `"` `"` not straight `"`
56
+ - Non-breaking spaces: `10&nbsp;MB`, `⌘&nbsp;K`, brand names
57
+ - Loading states end with `…`: `"Loading…"`, `"Saving…"`
58
+ - `font-variant-numeric: tabular-nums` for number columns/comparisons
59
+ - Use `text-wrap: balance` or `text-pretty` on headings (prevents widows)
60
+
61
+ ### Content Handling
62
+
63
+ - Text containers handle long content: `truncate`, `line-clamp-*`, or `break-words`
64
+ - Flex children need `min-w-0` to allow text truncation
65
+ - Handle empty states—don't render broken UI for empty strings/arrays
66
+ - User-generated content: anticipate short, average, and very long inputs
67
+
68
+ ### Images
69
+
70
+ - `<img>` needs explicit `width` and `height` (prevents CLS)
71
+ - Below-fold images: `loading="lazy"`
72
+ - Above-fold critical images: `priority` or `fetchpriority="high"`
73
+
74
+ ### Performance
75
+
76
+ - Large lists (>50 items): virtualize (`virtua`, `content-visibility: auto`)
77
+ - No layout reads in render (`getBoundingClientRect`, `offsetHeight`, `offsetWidth`, `scrollTop`)
78
+ - Batch DOM reads/writes; avoid interleaving
79
+ - Prefer uncontrolled inputs; controlled inputs must be cheap per keystroke
80
+ - Add `<link rel="preconnect">` for CDN/asset domains
81
+ - Critical fonts: `<link rel="preload" as="font">` with `font-display: swap`
82
+
83
+ ### Navigation & State
84
+
85
+ - URL reflects state—filters, tabs, pagination, expanded panels in query params
86
+ - Links use `<a>`/`<Link>` (Cmd/Ctrl+click, middle-click support)
87
+ - Deep-link all stateful UI (if uses `useState`, consider URL sync via nuqs or similar)
88
+ - Destructive actions need confirmation modal or undo window—never immediate
89
+
90
+ ### Touch & Interaction
91
+
92
+ - `touch-action: manipulation` (prevents double-tap zoom delay)
93
+ - `-webkit-tap-highlight-color` set intentionally
94
+ - `overscroll-behavior: contain` in modals/drawers/sheets
95
+ - During drag: disable text selection, `inert` on dragged elements
96
+ - `autoFocus` sparingly—desktop only, single primary input; avoid on mobile
97
+
98
+ ### Safe Areas & Layout
99
+
100
+ - Full-bleed layouts need `env(safe-area-inset-*)` for notches
101
+ - Avoid unwanted scrollbars: `overflow-x-hidden` on containers, fix content overflow
102
+ - Flex/grid over JS measurement for layout
103
+
104
+ ### Dark Mode & Theming
105
+
106
+ - `color-scheme: dark` on `<html>` for dark themes (fixes scrollbar, inputs)
107
+ - `<meta name="theme-color">` matches page background
108
+ - Native `<select>`: explicit `background-color` and `color` (Windows dark mode)
109
+
110
+ ### Locale & i18n
111
+
112
+ - Dates/times: use `Intl.DateTimeFormat` not hardcoded formats
113
+ - Numbers/currency: use `Intl.NumberFormat` not hardcoded formats
114
+ - Detect language via `Accept-Language` / `navigator.languages`, not IP
115
+
116
+ ### Hydration Safety
117
+
118
+ - Inputs with `value` need `onChange` (or use `defaultValue` for uncontrolled)
119
+ - Date/time rendering: guard against hydration mismatch (server vs client)
120
+ - `suppressHydrationWarning` only where truly needed
121
+
122
+ ### Hover & Interactive States
123
+
124
+ - Buttons/links need `hover:` state (visual feedback)
125
+ - Interactive states increase contrast: hover/active/focus more prominent than rest
126
+
127
+ ### Content & Copy
128
+
129
+ - Active voice: "Install the CLI" not "The CLI will be installed"
130
+ - Title Case for headings/buttons (Chicago style)
131
+ - Numerals for counts: "8 deployments" not "eight"
132
+ - Specific button labels: "Save API Key" not "Continue"
133
+ - Error messages include fix/next step, not just problem
134
+ - Second person; avoid first person
135
+ - `&` over "and" where space-constrained
136
+
137
+ ### Anti-patterns (flag these)
138
+
139
+ - `user-scalable=no` or `maximum-scale=1` disabling zoom
140
+ - `onPaste` with `preventDefault`
141
+ - `transition: all`
142
+ - `outline-none` without focus-visible replacement
143
+ - Inline `onClick` navigation without `<a>`
144
+ - `<div>` or `<span>` with click handlers (should be `<button>`)
145
+ - Images without dimensions
146
+ - Large arrays `.map()` without virtualization
147
+ - Form inputs without labels
148
+ - Icon buttons without `aria-label`
149
+ - Hardcoded date/number formats (use `Intl.*`)
150
+ - `autoFocus` without clear justification
151
+
152
+ ## Output Format
153
+
154
+ Group by file. Use `file:line` format (VS Code clickable). Terse findings.
155
+
156
+ ```text
157
+ ## src/Button.tsx
158
+
159
+ src/Button.tsx:42 - icon button missing aria-label
160
+ src/Button.tsx:18 - input lacks label
161
+ src/Button.tsx:55 - animation missing prefers-reduced-motion
162
+ src/Button.tsx:67 - transition: all → list properties
163
+
164
+ ## src/Modal.tsx
165
+
166
+ src/Modal.tsx:12 - missing overscroll-behavior: contain
167
+ src/Modal.tsx:34 - "..." → "…"
168
+
169
+ ## src/Card.tsx
170
+
171
+ ✓ pass
172
+ ```
173
+
174
+ State issue + location. Skip explanation unless fix non-obvious. No preamble.