@surlymochan/evalid 0.0.0-stage → 0.3.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.
Files changed (192) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/LICENSE +21 -0
  3. package/README.md +315 -2
  4. package/RELEASE_NOTES.md +102 -0
  5. package/atoms/registry.json +758 -0
  6. package/bin/xflow.js +7208 -0
  7. package/docs/adoption/README.md +128 -0
  8. package/docs/adoption/openflow-release-hardening.md +61 -0
  9. package/docs/benchmark-openflow-vs-gstack-superpowers-openspec-2026-05-25.md +81 -0
  10. package/docs/compatibility.md +52 -0
  11. package/docs/competitive-benchmark.md +108 -0
  12. package/docs/corps-operator-guide.md +75 -0
  13. package/docs/demo-proof.md +126 -0
  14. package/docs/examples-gallery.md +115 -0
  15. package/docs/fixtures/tracker-item.json +7 -0
  16. package/docs/goal-vs-codex.md +129 -0
  17. package/docs/gstack-comparison.md +88 -0
  18. package/docs/install-upgrade.md +133 -0
  19. package/docs/integrations.md +49 -0
  20. package/docs/launch-demo.md +123 -0
  21. package/docs/launch-dossier.md +180 -0
  22. package/docs/methodology.md +149 -0
  23. package/docs/npm-publish-handoff.md +83 -0
  24. package/docs/openspec-migration.md +106 -0
  25. package/docs/public-benchmark.md +68 -0
  26. package/docs/public-release.md +145 -0
  27. package/docs/quality-assessment.md +139 -0
  28. package/docs/quickstart.md +156 -0
  29. package/docs/reviewer-guide.md +43 -0
  30. package/docs/spec-kit-benchmark.md +73 -0
  31. package/docs/super-assistant-comparison.md +106 -0
  32. package/docs/superpowers-comparison.md +82 -0
  33. package/docs/team-adoption.md +123 -0
  34. package/docs/tooling-matrix.md +91 -0
  35. package/docs/walkthrough.md +76 -0
  36. package/docs/workflow-manual.md +1125 -0
  37. package/package.json +83 -4
  38. package/prompts/pencil-draft.md +46 -0
  39. package/prompts/pencil-refine.md +46 -0
  40. package/prompts/phase-artifact.md +24 -0
  41. package/prompts/phase-execution.md +32 -0
  42. package/schemas/competitor-reconstruction-contract.schema.json +91 -0
  43. package/schemas/llm-design-review-aggregate.schema.json +83 -0
  44. package/schemas/visual-benchmark.schema.json +978 -0
  45. package/schemas/workflow.schema.json +100 -0
  46. package/scripts/run-tests.mjs +23 -0
  47. package/scripts/takein_digest.py +139 -0
  48. package/specs/README.md +118 -0
  49. package/specs/architecture.md +36 -0
  50. package/specs/product.md +33 -0
  51. package/specs/workflow.md +349 -0
  52. package/src/agent_team/atoms/codex-app-bridge.js +8 -0
  53. package/src/agent_team/atoms/design/competitor-reconstruction-review.js +44 -0
  54. package/src/agent_team/atoms/design/contract-freeze.js +8 -0
  55. package/src/agent_team/atoms/design/generation-contract.js +442 -0
  56. package/src/agent_team/atoms/design/reconstruction-pack.js +246 -0
  57. package/src/agent_team/atoms/design/reference-surface-lock.js +49 -0
  58. package/src/agent_team/atoms/patch-challenge.js +19 -0
  59. package/src/agent_team/atoms/pencil/accept.js +9 -0
  60. package/src/agent_team/atoms/pencil/draft.js +365 -0
  61. package/src/agent_team/atoms/pencil/refine.js +229 -0
  62. package/src/agent_team/atoms/phase-run-dispatch.js +8 -0
  63. package/src/agent_team/atoms/team-run.js +380 -0
  64. package/src/agent_team/atoms/visual/aesthetic-review.js +231 -0
  65. package/src/agent_team/atoms/visual/benchmark-repair-plan.js +291 -0
  66. package/src/agent_team/atoms/visual/benchmark.js +1652 -0
  67. package/src/agent_team/atoms/visual/design-selection.js +23 -0
  68. package/src/agent_team/atoms/visual/direction-synthesis.js +124 -0
  69. package/src/agent_team/atoms/visual/dom-rect-export.js +129 -0
  70. package/src/agent_team/atoms/visual/image-diff.js +186 -0
  71. package/src/agent_team/atoms/visual/layout-competition.js +8 -0
  72. package/src/agent_team/atoms/visual/page-evidence-capture.js +806 -0
  73. package/src/agent_team/atoms/visual/playwright-runtime.js +8 -0
  74. package/src/agent_team/atoms/visual/review-aggregate.js +87 -0
  75. package/src/agent_team/atoms/visual/review.js +77 -0
  76. package/src/agent_team/atoms/visual/visual-report.js +197 -0
  77. package/src/agent_team/atoms/visual/visual-token-export.js +417 -0
  78. package/src/agent_team/common.js +311 -0
  79. package/src/core/atoms/agent-invoke.js +684 -0
  80. package/src/core/atoms/event/ingest.js +30 -0
  81. package/src/core/atoms/experience/digest.js +55 -0
  82. package/src/core/atoms/gate/artifact-verify.js +83 -0
  83. package/src/core/atoms/gate/competitor-contract-validate.js +119 -0
  84. package/src/core/atoms/gate/evidence-collect.js +64 -0
  85. package/src/core/atoms/gate/payload-from-phase-run.js +78 -0
  86. package/src/core/atoms/gate/visual-benchmark-validate.js +183 -0
  87. package/src/core/atoms/gate/workbench.js +79 -0
  88. package/src/core/atoms/intake/classify.js +15 -0
  89. package/src/core/atoms/intake/design-skill-select.js +16 -0
  90. package/src/core/atoms/intake/preview-or-refine.js +19 -0
  91. package/src/core/atoms/intake/recommend.js +20 -0
  92. package/src/core/atoms/intake/research-same-category.js +19 -0
  93. package/src/core/atoms/intervention/create.js +30 -0
  94. package/src/core/atoms/memory/manage.js +27 -0
  95. package/src/core/atoms/memory/mount.js +13 -0
  96. package/src/core/atoms/mission/create.js +19 -0
  97. package/src/core/atoms/mission/list.js +14 -0
  98. package/src/core/atoms/mission/show.js +26 -0
  99. package/src/core/atoms/notify/checkpoint.js +46 -0
  100. package/src/core/atoms/phase-run/complete.js +42 -0
  101. package/src/core/atoms/phase-run/fail.js +40 -0
  102. package/src/core/atoms/phase-run/persist.js +39 -0
  103. package/src/core/atoms/phase-run/start.js +30 -0
  104. package/src/core/atoms/plugin/run.js +76 -0
  105. package/src/core/atoms/policy/gate.js +90 -0
  106. package/src/core/atoms/policy/resolve.js +11 -0
  107. package/src/core/atoms/storage/sync.js +57 -0
  108. package/src/core/atoms/workflow/advance.js +25 -0
  109. package/src/core/atoms/workflow/guard.js +127 -0
  110. package/src/core/atoms/workflow/state-load.js +37 -0
  111. package/src/core/bindings.js +37 -0
  112. package/src/core/change-artifacts.js +134 -0
  113. package/src/core/competitive-score.js +265 -0
  114. package/src/core/concurrency-policy.js +35 -0
  115. package/src/core/execution-log.js +108 -0
  116. package/src/core/intake-recommendation.js +134 -0
  117. package/src/core/memory-state.js +62 -0
  118. package/src/core/mission-state.js +780 -0
  119. package/src/core/pending-gates.js +66 -0
  120. package/src/core/phase-cost.js +116 -0
  121. package/src/core/phase-run-read.js +27 -0
  122. package/src/core/policy-overlay.js +180 -0
  123. package/src/core/state-store.js +201 -0
  124. package/src/core/workflow-executor.js +998 -0
  125. package/src/core/workflow-integrity.js +111 -0
  126. package/src/core/workflow-loader.js +163 -0
  127. package/src/core/workflow-rerun.js +84 -0
  128. package/src/core/workflow-state.js +119 -0
  129. package/src/server.js +1307 -0
  130. package/workflows/corps.yaml +479 -0
  131. package/workflows/yolo.yaml +233 -0
  132. package/xflow/README.md +76 -0
  133. package/xflow/aha/SKILL.md +82 -0
  134. package/xflow/aha/scripts/append_aha.py +50 -0
  135. package/xflow/archive/scripts/archive_change.py +338 -0
  136. package/xflow/archive/templates/merge-design.md +54 -0
  137. package/xflow/archive/templates/merge-workflow.md +26 -0
  138. package/xflow/atoms/__init__.py +6 -0
  139. package/xflow/atoms/a1_issue_create_or_patch.py +70 -0
  140. package/xflow/atoms/a2_branch_create_and_link.py +42 -0
  141. package/xflow/atoms/a3_repo_doctor.py +11 -0
  142. package/xflow/atoms/a4_project_set_status.py +11 -0
  143. package/xflow/atoms/a5_archive_commit_push_close.py +11 -0
  144. package/xflow/atoms/a6_pr_create.py +72 -0
  145. package/xflow/atoms/b1_change_scaffold.py +11 -0
  146. package/xflow/atoms/b2_status_read.py +16 -0
  147. package/xflow/atoms/b2b_status_write.py +20 -0
  148. package/xflow/atoms/b3_status_transition.py +27 -0
  149. package/xflow/atoms/b4_handoff_scaffold_or_refresh.py +11 -0
  150. package/xflow/atoms/b5_aha_append.py +11 -0
  151. package/xflow/atoms/b6_takein_digest.py +11 -0
  152. package/xflow/atoms/b6b_lookback_digest.py +11 -0
  153. package/xflow/atoms/b7_change_mission_bind.py +43 -0
  154. package/xflow/atoms/c1_mem.py +54 -0
  155. package/xflow/atoms/e6_gate_local_precheck.py +23 -0
  156. package/xflow/atoms/h1_design_lite_gate.py +74 -0
  157. package/xflow/atoms/i6a_tdd_run.py +104 -0
  158. package/xflow/atoms/i6b_tdd_proof_validate.py +165 -0
  159. package/xflow/atoms/i6c_tdd_quality_review.py +357 -0
  160. package/xflow/atoms/j1_tests_run.py +129 -0
  161. package/xflow/atoms/j4a_spec_consistency_structural.py +105 -0
  162. package/xflow/atoms/j4b_spec_delta_review.py +316 -0
  163. package/xflow/atoms/j4c_openspec_migration_map.py +121 -0
  164. package/xflow/atoms/j4d_spec_clarify_gate.py +373 -0
  165. package/xflow/atoms/j6_cr_review.py +443 -0
  166. package/xflow/atoms/k1_artifacts_complete_check.py +39 -0
  167. package/xflow/atoms/k2_merge_snippets_apply.py +11 -0
  168. package/xflow/atoms/k3_handoff_refresh.py +14 -0
  169. package/xflow/atoms/k4_mem_lesson_persist.py +65 -0
  170. package/xflow/atoms/k5_archive_publish.py +21 -0
  171. package/xflow/atoms/k6_aha_merge.py +42 -0
  172. package/xflow/atoms/tdd_lib.py +747 -0
  173. package/xflow/corps/SKILL.md +109 -0
  174. package/xflow/exec/scripts/set_issue_in_progress.py +159 -0
  175. package/xflow/goal/SKILL.md +150 -0
  176. package/xflow/handoff/SKILL.md +95 -0
  177. package/xflow/handoff/scripts/scaffold_handoff.py +304 -0
  178. package/xflow/lookback/SKILL.md +66 -0
  179. package/xflow/lookback/scripts/lookback_digest.py +46 -0
  180. package/xflow/openissue/scripts/open_issue_flow.py +438 -0
  181. package/xflow/plan/SKILL.md +38 -0
  182. package/xflow/ralph/SKILL.md +123 -0
  183. package/xflow/scripts/check_installed_xflow_skill_sync.sh +44 -0
  184. package/xflow/scripts/common.py +480 -0
  185. package/xflow/scripts/doctor.py +278 -0
  186. package/xflow/scripts/sync_installed_xflow_skill.sh +134 -0
  187. package/xflow/takein/SKILL.md +81 -0
  188. package/xflow/takein/scripts/takein_digest.py +88 -0
  189. package/xflow/yolo/SKILL.md +66 -0
  190. package/xflow/yolo/scripts/scaffold_specs_change.py +673 -0
  191. package/xflow/yolo/scripts/yolo_gate.py +312 -0
  192. package/xflow/yolo/templates/DESIGN.md +179 -0
@@ -0,0 +1,312 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import json
4
+ import sys
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ sys.path.append(str(Path(__file__).resolve().parents[2] / "scripts"))
9
+
10
+ from common import assert_stage_transition_allowed, assert_status_transition_allowed, load_status # noqa: E402
11
+ from doctor import run_doctor_checks # noqa: E402
12
+
13
+
14
+ BASE_ARTIFACTS = ("proposal.md", "plan.md", "tasks.md", "status.json")
15
+
16
+
17
+ def check(name: str, ok: bool, detail: str, *, severity: str = "error", value: Any | None = None) -> dict[str, Any]:
18
+ payload: dict[str, Any] = {
19
+ "name": name,
20
+ "ok": ok,
21
+ "detail": detail,
22
+ "severity": severity,
23
+ }
24
+ if value is not None:
25
+ payload["value"] = value
26
+ return payload
27
+
28
+
29
+ def parse_args() -> argparse.Namespace:
30
+ parser = argparse.ArgumentParser(
31
+ description="Run deterministic Superflow Yolo gate checks before entering the next workflow phase.",
32
+ )
33
+ parser.add_argument("--project-root", default=".", help="Project root containing specs/changes.")
34
+ parser.add_argument("--change-id", required=True, help="Superflow change id.")
35
+ parser.add_argument(
36
+ "--phase",
37
+ required=True,
38
+ choices=["pre-openissue", "post-openissue", "pre-exec", "pre-archive"],
39
+ help="Named Yolo gate to validate.",
40
+ )
41
+ parser.add_argument("--json", action="store_true", help="Print machine-readable JSON output.")
42
+ return parser.parse_args()
43
+
44
+
45
+ def run_yolo_gate(project_root: str | Path, change_id: str, phase: str) -> dict[str, Any]:
46
+ status_path, status = load_status(project_root, change_id)
47
+ project_root_path = Path(project_root).expanduser().resolve()
48
+ change_root = project_root_path / "specs" / "changes" / change_id
49
+ change_type = status.get("change_type", "backend")
50
+ issue_doc_path = change_root / "issue.md"
51
+ checks: list[dict[str, Any]] = []
52
+
53
+ checks.append(
54
+ check(
55
+ "status-file",
56
+ status_path.exists(),
57
+ f"Loaded status file {status_path}" if status_path.exists() else f"Missing status file {status_path}",
58
+ value=str(status_path),
59
+ )
60
+ )
61
+
62
+ for artifact in BASE_ARTIFACTS:
63
+ artifact_path = change_root / artifact
64
+ checks.append(
65
+ check(
66
+ f"artifact-{artifact}",
67
+ artifact_path.exists(),
68
+ f"Found {artifact}" if artifact_path.exists() else f"Missing required artifact {artifact}",
69
+ value=str(artifact_path),
70
+ )
71
+ )
72
+
73
+ checks.append(
74
+ check(
75
+ "artifact-issue-md",
76
+ issue_doc_path.exists(),
77
+ "Found issue.md" if issue_doc_path.exists() else "Missing required issue.md",
78
+ value=str(issue_doc_path),
79
+ )
80
+ )
81
+
82
+ needs_design = change_type in {"frontend", "full-stack"}
83
+ if needs_design:
84
+ design_path = change_root / "design.md"
85
+ checks.append(
86
+ check(
87
+ "artifact-design-md",
88
+ design_path.exists(),
89
+ "Found design.md for UI-bearing change" if design_path.exists() else "Missing design.md for frontend/full-stack change",
90
+ value=str(design_path),
91
+ )
92
+ )
93
+ checks.append(
94
+ check(
95
+ "design-alignment-not-rejected",
96
+ status.get("design_aligned") != "no",
97
+ "design_aligned is not rejected" if status.get("design_aligned") != "no" else "design_aligned=no blocks further Yolo progression",
98
+ value=status.get("design_aligned"),
99
+ )
100
+ )
101
+
102
+ current_stage = status.get("current_stage")
103
+ status_value = status.get("status")
104
+ verification_status = status.get("verification_status")
105
+ archival_status = status.get("archival_status")
106
+ repo = status.get("target_repo")
107
+ issue_number = status.get("issue_number")
108
+ branch_name = status.get("branch_name")
109
+ checkout_path = status.get("checkout_path")
110
+ issue_title = status.get("issue_title") or status.get("title")
111
+ issue_body = issue_doc_path.read_text(encoding="utf-8") if issue_doc_path.exists() else None
112
+ checkout_exists = bool(checkout_path) and Path(checkout_path).expanduser().exists()
113
+
114
+ if phase == "pre-openissue":
115
+ stage_ok = True
116
+ status_ok = True
117
+ try:
118
+ assert_stage_transition_allowed(current_stage, "plan", current_status=status_value)
119
+ except SystemExit as exc:
120
+ stage_ok = False
121
+ stage_detail = str(exc)
122
+ else:
123
+ stage_detail = f"current_stage={current_stage} can advance to plan/openissue"
124
+ try:
125
+ assert_status_transition_allowed(status_value, "active")
126
+ except SystemExit as exc:
127
+ status_ok = False
128
+ status_detail = str(exc)
129
+ else:
130
+ status_detail = f"status={status_value} can advance to active"
131
+ checks.append(
132
+ check(
133
+ "stage-ready-for-openissue",
134
+ stage_ok,
135
+ stage_detail,
136
+ value=current_stage,
137
+ )
138
+ )
139
+ checks.append(check("status-ready-for-openissue", status_ok, status_detail, value=status_value))
140
+ checks.append(
141
+ check(
142
+ "archival-not-finished",
143
+ archival_status != "archived",
144
+ "Change is not archived yet" if archival_status != "archived" else "Change is already archived",
145
+ value=archival_status,
146
+ )
147
+ )
148
+ checks.append(check("issue-title-present", bool(issue_title), "Issue title is present" if issue_title else "Issue title is required before openissue", value=issue_title))
149
+ checks.append(check("issue-body-present", bool(issue_body and issue_body.strip()), "issue.md has body content" if issue_body and issue_body.strip() else "issue.md must contain body content before openissue", value=str(issue_doc_path)))
150
+ elif phase == "post-openissue":
151
+ checks.extend(
152
+ [
153
+ check("status-target-repo", bool(repo), "target_repo recorded" if repo else "target_repo missing after openissue", value=repo),
154
+ check("status-issue-number", bool(issue_number), "issue_number recorded" if issue_number else "issue_number missing after openissue", value=issue_number),
155
+ check("status-branch-name", bool(branch_name), "branch_name recorded" if branch_name else "branch_name missing after openissue", value=branch_name),
156
+ check("status-checkout-path", bool(checkout_path), "checkout_path recorded" if checkout_path else "checkout_path missing after openissue", value=checkout_path),
157
+ check("issue-title-present", bool(issue_title), "Issue title is present" if issue_title else "Issue title is required", value=issue_title),
158
+ check("issue-body-present", bool(issue_body and issue_body.strip()), "issue.md has body content" if issue_body and issue_body.strip() else "issue.md must contain body content", value=str(issue_doc_path)),
159
+ check("checkout-path-exists", checkout_exists, "checkout_path exists" if checkout_exists else "checkout_path must point to an existing checkout", value=checkout_path),
160
+ ]
161
+ )
162
+ elif phase == "pre-exec":
163
+ stage_ok = True
164
+ status_ok = True
165
+ try:
166
+ assert_stage_transition_allowed(current_stage, "tdd", current_status=status_value)
167
+ except SystemExit as exc:
168
+ stage_ok = False
169
+ stage_detail = str(exc)
170
+ else:
171
+ stage_detail = f"current_stage={current_stage} can advance to tdd/exec"
172
+ try:
173
+ assert_status_transition_allowed(status_value, "active")
174
+ except SystemExit as exc:
175
+ status_ok = False
176
+ status_detail = str(exc)
177
+ else:
178
+ status_detail = f"status={status_value} can advance/remain active"
179
+ checks.extend(
180
+ [
181
+ check("status-target-repo", bool(repo), "target_repo recorded" if repo else "target_repo missing before exec", value=repo),
182
+ check("status-issue-number", bool(issue_number), "issue_number recorded" if issue_number else "issue_number missing before exec", value=issue_number),
183
+ check("status-branch-name", bool(branch_name), "branch_name recorded" if branch_name else "branch_name missing before exec", value=branch_name),
184
+ check("status-checkout-path", bool(checkout_path), "checkout_path recorded" if checkout_path else "checkout_path missing before exec", value=checkout_path),
185
+ check("issue-title-present", bool(issue_title), "Issue title is present" if issue_title else "Issue title is required", value=issue_title),
186
+ check("checkout-path-exists", checkout_exists, "checkout_path exists" if checkout_exists else "checkout_path must point to an existing checkout", value=checkout_path),
187
+ check(
188
+ "stage-ready-for-exec",
189
+ stage_ok,
190
+ stage_detail,
191
+ value=current_stage,
192
+ ),
193
+ check("status-ready-for-exec", status_ok, status_detail, value=status_value),
194
+ check(
195
+ "status-not-archived",
196
+ archival_status != "archived",
197
+ "Change is not archived yet" if archival_status != "archived" else "Change is already archived",
198
+ value=archival_status,
199
+ ),
200
+ ]
201
+ )
202
+ elif phase == "pre-archive":
203
+ stage_ok = True
204
+ status_done_ok = True
205
+ try:
206
+ assert_stage_transition_allowed(
207
+ current_stage,
208
+ "archive",
209
+ current_status=status_value,
210
+ allow_terminal_status_override=("done", "blocked"),
211
+ )
212
+ except SystemExit as exc:
213
+ stage_ok = False
214
+ stage_detail = str(exc)
215
+ else:
216
+ stage_detail = f"current_stage={current_stage} / status={status_value} can advance to archive"
217
+ try:
218
+ if status_value == "blocked":
219
+ assert_status_transition_allowed(status_value, "blocked", allow_terminal_status_override=("blocked",))
220
+ elif status_value == "done":
221
+ assert_status_transition_allowed(status_value, "done", allow_terminal_status_override=("done",))
222
+ else:
223
+ assert_status_transition_allowed(status_value, "done")
224
+ except SystemExit as exc:
225
+ status_done_ok = False
226
+ status_done_detail = str(exc)
227
+ else:
228
+ status_done_detail = f"status={status_value} can advance/finalize for archive"
229
+ checks.extend(
230
+ [
231
+ check("status-target-repo", bool(repo), "target_repo recorded" if repo else "target_repo missing before archive", value=repo),
232
+ check("status-issue-number", bool(issue_number), "issue_number recorded" if issue_number else "issue_number missing before archive", value=issue_number),
233
+ check("status-branch-name", bool(branch_name), "branch_name recorded" if branch_name else "branch_name missing before archive", value=branch_name),
234
+ check("status-checkout-path", bool(checkout_path), "checkout_path recorded" if checkout_path else "checkout_path missing before archive", value=checkout_path),
235
+ check(
236
+ "verification-ready",
237
+ verification_status == "passed" or status_value == "blocked",
238
+ "Verification is passed or change is blocked" if (verification_status == "passed" or status_value == "blocked") else "verification_status must be passed before archive unless change is blocked",
239
+ value={"status": status_value, "verification_status": verification_status},
240
+ ),
241
+ check(
242
+ "stage-ready-for-archive",
243
+ stage_ok,
244
+ stage_detail,
245
+ value={"current_stage": current_stage, "status": status_value},
246
+ ),
247
+ check("status-ready-for-archive", status_done_ok, status_done_detail, value=status_value),
248
+ ]
249
+ )
250
+
251
+ doctor_phases = {"post-openissue", "pre-exec", "pre-archive"}
252
+ doctor_should_run = phase in doctor_phases and all([repo, issue_number, branch_name, checkout_path])
253
+ if doctor_should_run:
254
+ doctor_result = run_doctor_checks(
255
+ project_root=project_root_path,
256
+ change_id=change_id,
257
+ repo=repo,
258
+ issue_number=int(issue_number),
259
+ branch_name=branch_name,
260
+ checkout_path_override=checkout_path,
261
+ )
262
+ checks.append(
263
+ check(
264
+ "doctor-gate",
265
+ doctor_result["ok"],
266
+ "doctor checks passed" if doctor_result["ok"] else "doctor checks failed",
267
+ value={"hard_failures": doctor_result["hard_failures"], "warnings": doctor_result["warnings"]},
268
+ )
269
+ )
270
+ elif phase in doctor_phases:
271
+ checks.append(
272
+ check(
273
+ "doctor-gate",
274
+ False,
275
+ "doctor prerequisites missing from status.json",
276
+ value={
277
+ "target_repo": repo,
278
+ "issue_number": issue_number,
279
+ "branch_name": branch_name,
280
+ "checkout_path": checkout_path,
281
+ },
282
+ )
283
+ )
284
+
285
+ ok = all(item["ok"] or item["severity"] == "warn" for item in checks)
286
+ hard_failures = [item for item in checks if not item["ok"] and item["severity"] != "warn"]
287
+ warnings = [item for item in checks if not item["ok"] and item["severity"] == "warn"]
288
+ return {
289
+ "change_id": change_id,
290
+ "phase": phase,
291
+ "ok": ok,
292
+ "hard_failures": len(hard_failures),
293
+ "warnings": len(warnings),
294
+ "checks": checks,
295
+ }
296
+
297
+
298
+ def main() -> int:
299
+ args = parse_args()
300
+ result = run_yolo_gate(args.project_root, args.change_id, args.phase)
301
+ if args.json:
302
+ print(json.dumps(result, indent=2))
303
+ else:
304
+ print(f"Yolo gate: {result['phase']} for {result['change_id']}")
305
+ for item in result["checks"]:
306
+ prefix = "PASS" if item["ok"] else ("WARN" if item["severity"] == "warn" else "FAIL")
307
+ print(f"[{prefix}] {item['name']}: {item['detail']}")
308
+ return 0 if result["ok"] else 1
309
+
310
+
311
+ if __name__ == "__main__":
312
+ raise SystemExit(main())
@@ -0,0 +1,179 @@
1
+ # Design System Template
2
+
3
+ > This template follows the DESIGN.md format from Google Stitch / awesome-design-md.
4
+ > Drop into project root as `DESIGN.md` or merge into `specs/ux.md`.
5
+
6
+ ## Brand & Purpose
7
+
8
+ - Product: [what the product is]
9
+ - Audience: [who uses it]
10
+ - Core value: [one-line positioning statement]
11
+
12
+ ## Visual Tone
13
+
14
+ - Primary tone: [minimal | maximalist | brutalist | editorial | organic | luxury | playful | industrial | retro-futuristic | dark-mode-first]
15
+ - Secondary tone: [optional refinement or modifier]
16
+ - Reference brand: [optional, e.g., "similar to Linear" or "inspired by Notion"]
17
+
18
+ ## Color System
19
+
20
+ | Token | Value | Usage |
21
+ |-------|-------|-------|
22
+ | Background | [color] | Primary page background |
23
+ | Surface | [color] | Cards, panels, elevated surfaces |
24
+ | Primary | [color] | Main brand color, key actions |
25
+ | Accent | [color] | Highlights, links, focus states |
26
+ | Text | [color] | Primary text content |
27
+ | Text Muted | [color] | Secondary text, placeholders |
28
+ | Border | [color] | Dividers, input borders |
29
+ | Success | [color] | Positive states, confirmations |
30
+ | Error | [color] | Errors, destructive actions |
31
+ | Warning | [color] | Caution states |
32
+
33
+ Define as CSS variables:
34
+
35
+ ```css
36
+ :root {
37
+ --color-background: [value];
38
+ --color-surface: [value];
39
+ --color-primary: [value];
40
+ --color-accent: [value];
41
+ --color-text: [value];
42
+ --color-text-muted: [value];
43
+ --color-border: [value];
44
+ --color-success: [value];
45
+ --color-error: [value];
46
+ --color-warning: [value];
47
+ }
48
+ ```
49
+
50
+ ## Typography
51
+
52
+ | Role | Font | Weight | Size |
53
+ |------|------|--------|------|
54
+ | Display | [font family] | [weight] | [size range] |
55
+ | Heading | [font family] | [weight] | [size range] |
56
+ | Body | [font family] | [weight] | [base size] |
57
+ | Mono | [font family] | [weight] | [size] |
58
+ | Label | [font family] | [weight] | [size] |
59
+
60
+ Typography scale (optional):
61
+
62
+ ```css
63
+ :root {
64
+ --font-display: [family];
65
+ --font-body: [family];
66
+ --font-mono: [family];
67
+ --text-xs: [size];
68
+ --text-sm: [size];
69
+ --text-base: [size];
70
+ --text-lg: [size];
71
+ --text-xl: [size];
72
+ --text-2xl: [size];
73
+ }
74
+ ```
75
+
76
+ ## Layout & Spacing
77
+
78
+ - Density: [dense | balanced | sparse]
79
+ - Max width: [content width limit, e.g., 1200px]
80
+ - Grid: [column system, e.g., 12-column]
81
+ - Spacing base: [4px | 8px]
82
+
83
+ Spacing scale:
84
+
85
+ ```css
86
+ :root {
87
+ --space-1: [base * 0.5];
88
+ --space-2: [base * 1];
89
+ --space-3: [base * 2];
90
+ --space-4: [base * 3];
91
+ --space-5: [base * 4];
92
+ --space-6: [base * 6];
93
+ }
94
+ ```
95
+
96
+ ## Motion
97
+
98
+ - Animation level: [none | subtle | moderate | rich]
99
+ - Transition timing: [fast ~100ms | normal ~200ms | slow ~300ms]
100
+ - Micro-interactions: [hover states, loading states, focus effects]
101
+
102
+ Motion guidelines:
103
+
104
+ - Entrance: [stagger | fade | slide | none]
105
+ - Exit: [fade | slide | none]
106
+ - Hover: [scale | color shift | underline | shadow]
107
+ - Loading: [spinner | skeleton | progress bar]
108
+
109
+ ## Visual Details
110
+
111
+ - Border radius: [sharp 0px | soft 4-8px | round 12px+]
112
+ - Shadow level: [none | subtle | moderate | strong]
113
+ - Icon style: [outline | solid | minimal | custom]
114
+ - Illustration style: [none | abstract | realistic | brand-specific]
115
+
116
+ ## Component Patterns
117
+
118
+ ### Buttons
119
+
120
+ | Variant | Style |
121
+ |---------|-------|
122
+ | Primary | [background, text, radius, shadow] |
123
+ | Secondary | [background, text, radius] |
124
+ | Ghost | [no background, text only] |
125
+ | Destructive | [error color variant] |
126
+
127
+ ### Cards
128
+
129
+ - Border: [none | visible | shadow-only]
130
+ - Padding: [spacing value]
131
+ - Radius: [border radius]
132
+ - Shadow: [shadow level]
133
+
134
+ ### Inputs
135
+
136
+ - Border: [width, color]
137
+ - Focus: [ring color, ring width]
138
+ - Error: [border color, icon]
139
+ - Radius: [border radius]
140
+
141
+ ### Navigation
142
+
143
+ - Style: [sidebar | topbar | tabs | mix]
144
+ - Active state: [background change | border | indicator]
145
+ - Collapsed: [icon-only | hidden | responsive]
146
+
147
+ ## Best For
148
+
149
+ - Ideal use cases:
150
+ - [when this design works best]
151
+ - [suitable product types]
152
+ - [appropriate audience]
153
+
154
+ - Avoid:
155
+ - [when not to use this direction]
156
+ - [mismatched product types]
157
+
158
+ ## Design Decisions Log
159
+
160
+ Record design decisions that outlive individual changes:
161
+
162
+ - [YYYY-MM-DD] [change-id]: [decision made] — [reasoning]
163
+ - [YYYY-MM-DD] [change-id]: [decision made] — [reasoning]
164
+
165
+ ---
166
+
167
+ ## Quick Tone Reference
168
+
169
+ When choosing a visual tone, consider:
170
+
171
+ | Tone | Best For | Key Brands |
172
+ |------|----------|------------|
173
+ | Minimal Clean | Tools, dashboards, productivity | Linear, Vercel, Raycast |
174
+ | Editorial Warm | Content, docs, blogs | Notion, Medium, Mintlify |
175
+ | Dark Cinematic | Media, AI tools, dev tools | ElevenLabs, Cursor, RunwayML |
176
+ | Developer-First | Terminal, CLI, APIs | Ollama, Warp, Supabase |
177
+ | Friendly Playful | Consumer apps, SaaS | Lovable, Zapier, Cal.com |
178
+ | Enterprise Clean | B2B, infrastructure | HashiCorp, MongoDB, ClickHouse |
179
+ | Luxury Refined | Premium products | Apple, Figma, Linear (pro) |