@tiic-tech/openworkflow 0.1.0

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 (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/adapters/codex/src/doctorCodexAdapter.d.ts +6 -0
  4. package/dist/adapters/codex/src/doctorCodexAdapter.js +124 -0
  5. package/dist/adapters/codex/src/doctorCodexAdapter.js.map +1 -0
  6. package/dist/adapters/codex/src/generateAgents.d.ts +2 -0
  7. package/dist/adapters/codex/src/generateAgents.js +40 -0
  8. package/dist/adapters/codex/src/generateAgents.js.map +1 -0
  9. package/dist/adapters/codex/src/generateCodexAdapter.d.ts +9 -0
  10. package/dist/adapters/codex/src/generateCodexAdapter.js +59 -0
  11. package/dist/adapters/codex/src/generateCodexAdapter.js.map +1 -0
  12. package/dist/adapters/codex/src/generateCommands.d.ts +6 -0
  13. package/dist/adapters/codex/src/generateCommands.js +205 -0
  14. package/dist/adapters/codex/src/generateCommands.js.map +1 -0
  15. package/dist/adapters/codex/src/generateSkills.d.ts +7 -0
  16. package/dist/adapters/codex/src/generateSkills.js +60 -0
  17. package/dist/adapters/codex/src/generateSkills.js.map +1 -0
  18. package/dist/adapters/codex/src/generatedFiles.d.ts +4 -0
  19. package/dist/adapters/codex/src/generatedFiles.js +67 -0
  20. package/dist/adapters/codex/src/generatedFiles.js.map +1 -0
  21. package/dist/adapters/codex/src/manifest.d.ts +4 -0
  22. package/dist/adapters/codex/src/manifest.js +40 -0
  23. package/dist/adapters/codex/src/manifest.js.map +1 -0
  24. package/dist/adapters/codex/src/templates.d.ts +7 -0
  25. package/dist/adapters/codex/src/templates.js +6 -0
  26. package/dist/adapters/codex/src/templates.js.map +1 -0
  27. package/dist/cli/src/args.d.ts +8 -0
  28. package/dist/cli/src/args.js +34 -0
  29. package/dist/cli/src/args.js.map +1 -0
  30. package/dist/cli/src/commands/doctor.d.ts +1 -0
  31. package/dist/cli/src/commands/doctor.js +26 -0
  32. package/dist/cli/src/commands/doctor.js.map +1 -0
  33. package/dist/cli/src/commands/init.d.ts +1 -0
  34. package/dist/cli/src/commands/init.js +52 -0
  35. package/dist/cli/src/commands/init.js.map +1 -0
  36. package/dist/cli/src/commands/shared.d.ts +4 -0
  37. package/dist/cli/src/commands/shared.js +19 -0
  38. package/dist/cli/src/commands/shared.js.map +1 -0
  39. package/dist/cli/src/commands/sync.d.ts +1 -0
  40. package/dist/cli/src/commands/sync.js +27 -0
  41. package/dist/cli/src/commands/sync.js.map +1 -0
  42. package/dist/cli/src/commands/validate.d.ts +1 -0
  43. package/dist/cli/src/commands/validate.js +17 -0
  44. package/dist/cli/src/commands/validate.js.map +1 -0
  45. package/dist/cli/src/dev/validateRepositoryContractsCli.d.ts +2 -0
  46. package/dist/cli/src/dev/validateRepositoryContractsCli.js +37 -0
  47. package/dist/cli/src/dev/validateRepositoryContractsCli.js.map +1 -0
  48. package/dist/cli/src/dev/verifyRuntimeSurface.d.ts +2 -0
  49. package/dist/cli/src/dev/verifyRuntimeSurface.js +344 -0
  50. package/dist/cli/src/dev/verifyRuntimeSurface.js.map +1 -0
  51. package/dist/cli/src/dev/verifyWorkflowE2E.d.ts +2 -0
  52. package/dist/cli/src/dev/verifyWorkflowE2E.js +366 -0
  53. package/dist/cli/src/dev/verifyWorkflowE2E.js.map +1 -0
  54. package/dist/cli/src/index.d.ts +2 -0
  55. package/dist/cli/src/index.js +51 -0
  56. package/dist/cli/src/index.js.map +1 -0
  57. package/dist/core/src/artifacts/registry.d.ts +53 -0
  58. package/dist/core/src/artifacts/registry.js +483 -0
  59. package/dist/core/src/artifacts/registry.js.map +1 -0
  60. package/dist/core/src/commands/registry.d.ts +36 -0
  61. package/dist/core/src/commands/registry.js +539 -0
  62. package/dist/core/src/commands/registry.js.map +1 -0
  63. package/dist/core/src/contracts/index.d.ts +23 -0
  64. package/dist/core/src/contracts/index.js +16 -0
  65. package/dist/core/src/contracts/index.js.map +1 -0
  66. package/dist/core/src/contracts/yaml.d.ts +2 -0
  67. package/dist/core/src/contracts/yaml.js +12 -0
  68. package/dist/core/src/contracts/yaml.js.map +1 -0
  69. package/dist/core/src/contracts.d.ts +23 -0
  70. package/dist/core/src/contracts.js +15 -0
  71. package/dist/core/src/contracts.js.map +1 -0
  72. package/dist/core/src/fs/index.d.ts +4 -0
  73. package/dist/core/src/fs/index.js +28 -0
  74. package/dist/core/src/fs/index.js.map +1 -0
  75. package/dist/core/src/fs.d.ts +4 -0
  76. package/dist/core/src/fs.js +28 -0
  77. package/dist/core/src/fs.js.map +1 -0
  78. package/dist/core/src/initOpenWorkflow.d.ts +7 -0
  79. package/dist/core/src/initOpenWorkflow.js +220 -0
  80. package/dist/core/src/initOpenWorkflow.js.map +1 -0
  81. package/dist/core/src/validateOpenWorkflow.d.ts +5 -0
  82. package/dist/core/src/validateOpenWorkflow.js +145 -0
  83. package/dist/core/src/validateOpenWorkflow.js.map +1 -0
  84. package/dist/core/src/validators/validateOpenWorkflow.d.ts +5 -0
  85. package/dist/core/src/validators/validateOpenWorkflow.js +551 -0
  86. package/dist/core/src/validators/validateOpenWorkflow.js.map +1 -0
  87. package/dist/core/src/validators/validateRepositoryContracts.d.ts +2 -0
  88. package/dist/core/src/validators/validateRepositoryContracts.js +827 -0
  89. package/dist/core/src/validators/validateRepositoryContracts.js.map +1 -0
  90. package/dist/core/src/workflow/initOpenWorkflow.d.ts +7 -0
  91. package/dist/core/src/workflow/initOpenWorkflow.js +182 -0
  92. package/dist/core/src/workflow/initOpenWorkflow.js.map +1 -0
  93. package/dist/core/src/yaml.d.ts +2 -0
  94. package/dist/core/src/yaml.js +12 -0
  95. package/dist/core/src/yaml.js.map +1 -0
  96. package/package.json +55 -0
  97. package/references/artifact-authoring-templates.md +78 -0
  98. package/references/audit-first-discovery-loop.md +85 -0
  99. package/references/contract-graph.md +129 -0
  100. package/references/discovery-artifact-contracts.md +155 -0
  101. package/references/engineering-skill-reference-research.md +204 -0
  102. package/references/npm-cli-architecture.md +63 -0
  103. package/references/runtime-command-surface.md +169 -0
  104. package/schemas/artifact-contracts.schema.json +130 -0
  105. package/schemas/change.schema.json +71 -0
  106. package/schemas/contract-graph.schema.json +80 -0
  107. package/schemas/decision-record.schema.json +92 -0
  108. package/schemas/disclosure-levels.schema.json +66 -0
  109. package/schemas/openworkflow-contract.schema.json +88 -0
  110. package/schemas/product-design.schema.json +356 -0
  111. package/schemas/prototype-evidence.schema.json +325 -0
  112. package/schemas/prototype.schema.json +149 -0
  113. package/schemas/validation-target.schema.json +127 -0
  114. package/schemas/validation.schema.json +123 -0
  115. package/schemas/vision-session.schema.json +78 -0
  116. package/schemas/work-items.schema.json +87 -0
  117. package/schemas/workflow-index.schema.json +70 -0
  118. package/skills/build-prototype/SKILL.md +87 -0
  119. package/skills/build-prototype/agents/openai.yaml +4 -0
  120. package/skills/build-prototype/references/prototype-protocol.md +56 -0
  121. package/skills/build-prototype/scripts/init_prototype.py +260 -0
  122. package/skills/build-team/SKILL.md +292 -0
  123. package/skills/build-team/agents/openai.yaml +4 -0
  124. package/skills/build-team/references/runtime-schema.md +275 -0
  125. package/skills/build-team/references/team-protocol.md +244 -0
  126. package/skills/build-team/scripts/init_team_runtime.py +431 -0
  127. package/skills/build-validation/SKILL.md +81 -0
  128. package/skills/build-validation/agents/openai.yaml +4 -0
  129. package/skills/build-validation/references/validation-protocol.md +51 -0
  130. package/skills/build-validation/scripts/init_validation.py +194 -0
  131. package/skills/build-workflow/SKILL.md +65 -0
  132. package/skills/build-workflow/agents/openai.yaml +4 -0
  133. package/skills/build-workflow/references/workflow-layout.md +57 -0
  134. package/skills/build-workflow/scripts/init_workflow.py +423 -0
  135. package/skills/run-team/SKILL.md +93 -0
  136. package/skills/run-team/agents/openai.yaml +4 -0
  137. package/skills/run-team/references/delegation-and-agent-lifecycle.md +78 -0
  138. package/skills/run-team/references/run-loop.md +73 -0
  139. package/skills/run-team/references/runtime-audit.md +56 -0
  140. package/skills/run-team/references/scope-selection.md +64 -0
  141. package/skills/run-team/scripts/audit_team_runtime.py +173 -0
  142. package/skills/run-team/scripts/init_next_scope.py +304 -0
  143. package/templates/README.md +5 -0
  144. package/templates/codex/README.md +4 -0
  145. package/templates/openworkflow/README.md +4 -0
@@ -0,0 +1,431 @@
1
+ #!/usr/bin/env python3
2
+ """Initialize a repo-local Agent Team runtime skeleton.
3
+
4
+ The script is intentionally conservative: it creates missing directories and
5
+ files, but it does not overwrite existing runtime state unless --force is set.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import json
12
+ import re
13
+ import subprocess
14
+ from dataclasses import dataclass
15
+ from pathlib import Path
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class Milestone:
20
+ milestone_id: str
21
+ title: str
22
+
23
+
24
+ def q(value: str | None) -> str:
25
+ if value is None:
26
+ return "null"
27
+ return json.dumps(value)
28
+
29
+
30
+ def slugify(value: str) -> str:
31
+ slug = re.sub(r"[^a-zA-Z0-9]+", "-", value.strip().lower()).strip("-")
32
+ return slug or "milestone"
33
+
34
+
35
+ def git_ref(root: Path) -> str | None:
36
+ try:
37
+ result = subprocess.run(
38
+ ["git", "rev-parse", "--short", "HEAD"],
39
+ cwd=root,
40
+ check=True,
41
+ text=True,
42
+ stdout=subprocess.PIPE,
43
+ stderr=subprocess.DEVNULL,
44
+ )
45
+ except (OSError, subprocess.CalledProcessError):
46
+ return None
47
+ ref = result.stdout.strip()
48
+ return ref or None
49
+
50
+
51
+ def parse_milestone(raw: str) -> Milestone:
52
+ for separator in (":", "=", "|"):
53
+ if separator in raw:
54
+ left, right = raw.split(separator, 1)
55
+ milestone_id = left.strip()
56
+ title = right.strip()
57
+ if milestone_id and title:
58
+ return Milestone(milestone_id=milestone_id, title=title)
59
+ cleaned = raw.strip()
60
+ if not cleaned:
61
+ raise ValueError("milestone cannot be empty")
62
+ match = re.match(r"^(M\d+)\s+(.+)$", cleaned, flags=re.IGNORECASE)
63
+ if match:
64
+ return Milestone(milestone_id=match.group(1).upper(), title=match.group(2).strip())
65
+ raise ValueError(f"milestone must look like M01:Title, got {raw!r}")
66
+
67
+
68
+ def detect_source_artifacts(root: Path) -> list[str]:
69
+ candidates = [
70
+ "AGENT.md",
71
+ "README.md",
72
+ "README",
73
+ "ROADMAP.md",
74
+ "SPEC.md",
75
+ "LAUNCH_CHECKLIST.md",
76
+ ]
77
+ found = [candidate for candidate in candidates if (root / candidate).exists()]
78
+ if (root / "DESIGN_SPEC").is_dir():
79
+ found.append("DESIGN_SPEC/")
80
+ if (root / "docs").is_dir():
81
+ found.append("docs/")
82
+ return found or ["AGENT.md"]
83
+
84
+
85
+ def detect_application_roots(root: Path) -> list[str]:
86
+ roots: list[str] = []
87
+ for candidate in ("frontend", "app", "src", "packages", "backend", "server", "api"):
88
+ if (root / candidate).exists():
89
+ roots.append(f"{candidate}/")
90
+ for manifest in ("package.json", "pyproject.toml", "Cargo.toml", "go.mod"):
91
+ if (root / manifest).exists():
92
+ roots.append(manifest)
93
+ return roots
94
+
95
+
96
+ def list_yaml(items: list[str], indent: int = 0) -> str:
97
+ prefix = " " * indent
98
+ if not items:
99
+ return f"{prefix}[]\n"
100
+ return "".join(f"{prefix}- {q(item)}\n" for item in items)
101
+
102
+
103
+ def ensure_dir(path: Path, dry_run: bool) -> None:
104
+ if dry_run:
105
+ print(f"DIR {path}")
106
+ return
107
+ path.mkdir(parents=True, exist_ok=True)
108
+
109
+
110
+ def write_file(path: Path, content: str, force: bool, dry_run: bool) -> None:
111
+ if path.exists() and not force:
112
+ print(f"SKIP {path}")
113
+ return
114
+ if dry_run:
115
+ action = "OVERWRITE" if path.exists() else "WRITE"
116
+ print(f"{action} {path}")
117
+ return
118
+ path.parent.mkdir(parents=True, exist_ok=True)
119
+ path.write_text(content, encoding="utf-8")
120
+ print(f"WRITE {path}")
121
+
122
+
123
+ def touch_gitkeep(path: Path, dry_run: bool) -> None:
124
+ gitkeep = path / ".gitkeep"
125
+ if gitkeep.exists():
126
+ return
127
+ if dry_run:
128
+ print(f"WRITE {gitkeep}")
129
+ return
130
+ gitkeep.write_text("", encoding="utf-8")
131
+
132
+
133
+ def runtime_index(scope_id: str, scope_title: str, source: str, ref: str | None) -> str:
134
+ return (
135
+ f"active_scope: {scope_id}\n"
136
+ "scopes:\n"
137
+ f" - scope_id: {scope_id}\n"
138
+ f" title: {q(scope_title)}\n"
139
+ " status: active\n"
140
+ f" source: {q(source)}\n"
141
+ f" path: .codex/runtime/scopes/{scope_id}/\n"
142
+ f" base_git_ref: {q(ref) if ref else 'null'}\n"
143
+ )
144
+
145
+
146
+ def scope_yaml(
147
+ scope_id: str,
148
+ scope_title: str,
149
+ sources: list[str],
150
+ app_roots: list[str],
151
+ ref: str | None,
152
+ ) -> str:
153
+ return (
154
+ f"scope_id: {scope_id}\n"
155
+ f"title: {q(scope_title)}\n"
156
+ "status: active\n"
157
+ "source_artifacts:\n"
158
+ f"{list_yaml(sources, 2)}"
159
+ f"base_git_ref: {q(ref) if ref else 'null'}\n"
160
+ "runtime_protocol:\n"
161
+ " agent_team_protocol: .codex/agents/README.md\n"
162
+ " orchestrator_role: .codex/agents/orchestrator.md\n"
163
+ f" agent_roster: .codex/runtime/scopes/{scope_id}/AGENT_ROSTER.yaml\n"
164
+ "boundary:\n"
165
+ " application_roots:\n"
166
+ f"{list_yaml(app_roots, 4)}"
167
+ " protected_roots:\n"
168
+ " - .git/\n"
169
+ " - .codex/runtime/\n"
170
+ )
171
+
172
+
173
+ def milestones_yaml(scope_id: str, sources: list[str], milestones: list[Milestone]) -> str:
174
+ lines = [f"scope_id: {scope_id}", "source_artifacts:"]
175
+ lines.extend(f" - {q(source)}" for source in sources)
176
+ lines.append("milestones:")
177
+ for index, milestone in enumerate(milestones):
178
+ status = "active" if index == 0 else "planned"
179
+ lines.extend(
180
+ [
181
+ f" - milestone_id: {milestone.milestone_id}",
182
+ f" title: {q(milestone.title)}",
183
+ f" status: {status}",
184
+ f" scope: {q('Define and deliver ' + milestone.title + '.')}",
185
+ f" target: {q('Complete the milestone artifacts and checks.')}",
186
+ " dependencies: []",
187
+ " required_specs:",
188
+ ]
189
+ )
190
+ lines.extend(f" - {q(source)}" for source in sources)
191
+ lines.extend(
192
+ [
193
+ " expected_artifacts: []",
194
+ " estimated_atom_tasks: 3-8",
195
+ f" task_file: .codex/runtime/scopes/{scope_id}/milestones/{milestone.milestone_id}/IMPLEMENT_TASKS.yaml",
196
+ f" issue_file: .codex/runtime/scopes/{scope_id}/milestones/{milestone.milestone_id}/IMPLEMENT_ISSUES.yaml",
197
+ " qa_gate:",
198
+ " - required checks pass or skipped checks are documented",
199
+ " acceptance:",
200
+ " - runtime state matches implementation reality",
201
+ ]
202
+ )
203
+ return "\n".join(lines) + "\n"
204
+
205
+
206
+ def implement_index(scope_id: str, milestones: list[Milestone]) -> str:
207
+ active = milestones[0].milestone_id if milestones else "M01"
208
+ lines = [f"scope_id: {scope_id}", f"active_milestone: {active}", "milestones:"]
209
+ for index, milestone in enumerate(milestones):
210
+ status = "active" if index == 0 else "planned"
211
+ branch = f"feat/{milestone.milestone_id.lower()}-{slugify(milestone.title)}"
212
+ lines.extend(
213
+ [
214
+ f" - milestone_id: {milestone.milestone_id}",
215
+ f" status: {status}",
216
+ f" title: {q(milestone.title)}",
217
+ f" task_file: .codex/runtime/scopes/{scope_id}/milestones/{milestone.milestone_id}/IMPLEMENT_TASKS.yaml",
218
+ f" issue_file: .codex/runtime/scopes/{scope_id}/milestones/{milestone.milestone_id}/IMPLEMENT_ISSUES.yaml",
219
+ " qa_report: null",
220
+ f" branch: {branch}",
221
+ " last_checkpoint: null",
222
+ ]
223
+ )
224
+ return "\n".join(lines) + "\n"
225
+
226
+
227
+ def agent_roster(scope_id: str, app_roots: list[str]) -> str:
228
+ owns_frontend = ["frontend/src/app/", "frontend/src/components/", "frontend/src/systems/", "frontend/tests/"]
229
+ if not any(root.startswith("frontend") for root in app_roots):
230
+ owns_frontend = ["src/", "tests/"]
231
+ return "\n".join(
232
+ [
233
+ f"scope_id: {scope_id}",
234
+ "roster_version: 1",
235
+ "updated_at: null",
236
+ "lifecycle_status_values:",
237
+ " - available",
238
+ " - active",
239
+ " - idle",
240
+ " - blocked",
241
+ " - closed",
242
+ " - archived",
243
+ " - legacy_untracked",
244
+ "session_policies:",
245
+ " persistent:",
246
+ " purpose: Keep domain agents mounted across related atom tasks and issue-fix loops.",
247
+ " reuse_rule: Resume the existing matching agent_id before spawning a replacement.",
248
+ " event:",
249
+ " purpose: Run async or one-off review, security, QA, and git drafting work.",
250
+ " reuse_rule: Close after handoff unless the Orchestrator records a reason to keep it idle.",
251
+ "persistent_agents:",
252
+ " - agent_name: tech-prompt-agent",
253
+ " agent_id: null",
254
+ " lifecycle_status: available",
255
+ " session_policy: persistent",
256
+ " owns:",
257
+ f" - .codex/runtime/scopes/{scope_id}/milestones/*/prompts/",
258
+ " current_task: null",
259
+ " last_completed_task: null",
260
+ " active_milestone: null",
261
+ " notes: Spawn once for planning work, then resume for related task prompt creation.",
262
+ " - agent_name: frontend-agent",
263
+ " agent_id: null",
264
+ " lifecycle_status: available",
265
+ " session_policy: persistent",
266
+ " owns:",
267
+ *(f" - {path}" for path in owns_frontend),
268
+ " current_task: null",
269
+ " last_completed_task: null",
270
+ " active_milestone: null",
271
+ " notes: Use only when this repo has frontend or browser-facing work; otherwise replace with a domain implementation agent.",
272
+ "event_agents:",
273
+ " - agent_name: code-review-agent",
274
+ " agent_id: null",
275
+ " lifecycle_status: available",
276
+ " session_policy: event",
277
+ " trigger: artifact_ready",
278
+ " closes_after_handoff: true",
279
+ " notes: Writes review artifacts and issue logs, then closes.",
280
+ " - agent_name: security-review-agent",
281
+ " agent_id: null",
282
+ " lifecycle_status: available",
283
+ " session_policy: event",
284
+ " trigger: security_sensitive_change",
285
+ " closes_after_handoff: true",
286
+ " notes: Spawn for auth, secrets, external input, APIs, dependencies, deployment, analytics, or infrastructure.",
287
+ " - agent_name: tdd-qa-agent",
288
+ " agent_id: null",
289
+ " lifecycle_status: available",
290
+ " session_policy: event",
291
+ " trigger: qa_gate",
292
+ " closes_after_handoff: true",
293
+ " notes: Keep event-driven unless it is actively authoring a long test suite across tasks.",
294
+ " - agent_name: git-release-agent",
295
+ " agent_id: null",
296
+ " lifecycle_status: available",
297
+ " session_policy: event",
298
+ " trigger: checkpoint_or_release",
299
+ " closes_after_handoff: true",
300
+ " notes: Drafts branch, commit, PR, and release text only; Orchestrator performs git actions.",
301
+ "legacy_tracking:",
302
+ " task_agent_ids_before_roster: legacy_untracked",
303
+ " note: Do not invent ids for historical null task agent_id values.",
304
+ ]
305
+ ) + "\n"
306
+
307
+
308
+ def state_machine_doc(scope_id: str) -> str:
309
+ return f"""# Agent Team Runtime State Machine
310
+
311
+ Active scope: `{scope_id}`
312
+
313
+ Flow:
314
+
315
+ ```txt
316
+ repo_scan
317
+ -> user_parameter_question
318
+ -> scope_design
319
+ -> runtime_bootstrap
320
+ -> milestone_plan
321
+ -> atom_task_plan
322
+ -> delegation_boundary_check
323
+ -> persistent_or_event_agent_selection
324
+ -> prompt_preparation
325
+ -> spawn_or_resume_agent
326
+ -> record_agent_id_in_roster_and_task
327
+ -> implementation_or_event_work
328
+ -> artifact_ready
329
+ -> async_review
330
+ -> issue_fix_loop
331
+ -> resume_original_persistent_agent_for_fix
332
+ -> milestone_qa
333
+ -> git_checkpoint_decision
334
+ -> archive_or_freeze
335
+ -> next_milestone
336
+ ```
337
+
338
+ Task status values:
339
+
340
+ ```txt
341
+ planned, prompted, claimed, in_progress, artifact_ready, review_pending,
342
+ reviewed, fix_required, qa_ready, done, blocked, archived
343
+ ```
344
+
345
+ Runtime maintenance rules:
346
+
347
+ - Update runtime state when task reality changes.
348
+ - Update AGENT_ROSTER.yaml when agent lifecycle changes.
349
+ - New delegated tasks must not leave agent_id null.
350
+ - Orchestrator direct execution requires an orchestrator_exception note.
351
+ - Keep detailed reasoning in prompts and reviews, not YAML indexes.
352
+ - Preserve stale plans and superseded evidence in `archive/`.
353
+ - Do not infer completion from file existence alone.
354
+ """
355
+
356
+
357
+ def build_runtime(args: argparse.Namespace) -> None:
358
+ root = Path(args.root).expanduser().resolve()
359
+ scope_id = args.scope_id.upper()
360
+ sources = args.source_artifact or detect_source_artifacts(root)
361
+ app_roots = args.application_root or detect_application_roots(root)
362
+ milestones = [parse_milestone(raw) for raw in args.milestone]
363
+ if not milestones:
364
+ milestones = [Milestone("M01", "Workflow baseline")]
365
+
366
+ runtime_root = root / ".codex" / "runtime"
367
+ scope_root = runtime_root / "scopes" / scope_id
368
+ base_ref = git_ref(root)
369
+
370
+ for directory in [
371
+ runtime_root,
372
+ runtime_root / "archive",
373
+ runtime_root / "scopes",
374
+ scope_root,
375
+ scope_root / "archive",
376
+ scope_root / "milestones",
377
+ ]:
378
+ ensure_dir(directory, args.dry_run)
379
+
380
+ for directory in [runtime_root / "archive", scope_root / "archive"]:
381
+ touch_gitkeep(directory, args.dry_run)
382
+
383
+ write_file(
384
+ runtime_root / "RUNTIME_INDEX.yaml",
385
+ runtime_index(scope_id, args.scope_title, sources[0], base_ref),
386
+ args.force,
387
+ args.dry_run,
388
+ )
389
+ write_file(runtime_root / "STATE_MACHINE.md", state_machine_doc(scope_id), args.force, args.dry_run)
390
+ write_file(scope_root / "SCOPE.yaml", scope_yaml(scope_id, args.scope_title, sources, app_roots, base_ref), args.force, args.dry_run)
391
+ write_file(scope_root / "MILESTONES.yaml", milestones_yaml(scope_id, sources, milestones), args.force, args.dry_run)
392
+ write_file(scope_root / "IMPLEMENT_INDEX.yaml", implement_index(scope_id, milestones), args.force, args.dry_run)
393
+ write_file(scope_root / "IMPLEMENT_ISSUE_INDEX.yaml", f"scope_id: {scope_id}\nissues: []\n", args.force, args.dry_run)
394
+ write_file(scope_root / "AGENT_ROSTER.yaml", agent_roster(scope_id, app_roots), args.force, args.dry_run)
395
+
396
+ for milestone in milestones:
397
+ milestone_root = scope_root / "milestones" / milestone.milestone_id
398
+ for directory in [
399
+ milestone_root,
400
+ milestone_root / "prompts",
401
+ milestone_root / "reviews",
402
+ milestone_root / "archive",
403
+ ]:
404
+ ensure_dir(directory, args.dry_run)
405
+ for directory in [milestone_root / "prompts", milestone_root / "reviews", milestone_root / "archive"]:
406
+ touch_gitkeep(directory, args.dry_run)
407
+ write_file(milestone_root / "IMPLEMENT_TASKS.yaml", "tasks: []\n", args.force, args.dry_run)
408
+ write_file(milestone_root / "IMPLEMENT_ISSUES.yaml", "issues: []\n", args.force, args.dry_run)
409
+
410
+
411
+ def parser() -> argparse.ArgumentParser:
412
+ p = argparse.ArgumentParser(description="Initialize .codex/runtime for an Agent Team workflow.")
413
+ p.add_argument("--root", default=".", help="Repository root. Defaults to current directory.")
414
+ p.add_argument("--scope-id", default="MVP", help="Scope id, for example MVP or V1.")
415
+ p.add_argument("--scope-title", default="MVP implementation", help="Human-readable scope title.")
416
+ p.add_argument("--source-artifact", action="append", default=[], help="Source-of-truth artifact path. Repeatable.")
417
+ p.add_argument("--application-root", action="append", default=[], help="Application root path. Repeatable.")
418
+ p.add_argument("--milestone", action="append", default=[], help="Milestone as M01:Title. Repeatable.")
419
+ p.add_argument("--force", action="store_true", help="Overwrite existing runtime files.")
420
+ p.add_argument("--dry-run", action="store_true", help="Print planned writes without changing files.")
421
+ return p
422
+
423
+
424
+ def main() -> int:
425
+ args = parser().parse_args()
426
+ build_runtime(args)
427
+ return 0
428
+
429
+
430
+ if __name__ == "__main__":
431
+ raise SystemExit(main())
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: build-validation
3
+ description: Create validation-first prioritization artifacts from a product vision or change idea. Use when the user asks what should be prioritized, what must be proven first, which feature is core versus supporting, or when a broad idea needs a prototype brief before /ow:change, /ow:team, or implementation work.
4
+ ---
5
+
6
+ # Build Validation
7
+
8
+ ## Purpose
9
+
10
+ Identify the smallest proof needed to make a vision credible before converting
11
+ it into implementation scope. This skill ranks assumptions, not backlog tasks.
12
+
13
+ It answers:
14
+
15
+ - Which feature is existential to the vision?
16
+ - Which features support the core experience?
17
+ - Which features are later, operational, or out of scope for validation?
18
+ - What is the smallest prototype that can prove or disprove the core assumption?
19
+ - What evidence decides whether to continue, pivot, stop, or gather more data?
20
+
21
+ ## Inputs
22
+
23
+ Read only the relevant upstream contracts:
24
+
25
+ - `.codex/workflow/WORKFLOW_INDEX.yaml`
26
+ - `.codex/workflow/CONTRACT_GRAPH.yaml`
27
+ - `.codex/context/CONTEXT_MAP.yaml` when present and relevant
28
+ - `.codex/vision/VISION_CONTRACT.yaml` or the user's product vision
29
+ - `.codex/decisions/DECISION_INDEX.yaml` when decisions constrain the prototype
30
+ - `.codex/spec/SPEC_INDEX.yaml` only for directly relevant binding constraints
31
+
32
+ Avoid loading archives, unrelated specs, reviews, or runtime state unless the
33
+ user asks for historical evidence.
34
+
35
+ ## Output
36
+
37
+ Write validation artifacts under:
38
+
39
+ ```txt
40
+ .codex/validation/<validation_id>/
41
+ VALIDATION.yaml
42
+ PROTOTYPE_BRIEF.md
43
+ RESULT.md
44
+ archive/
45
+ ```
46
+
47
+ `RESULT.md` may remain a placeholder until a prototype is tested.
48
+
49
+ ## Workflow
50
+
51
+ 1. Restate the vision in one sentence.
52
+ 2. Build a feature landscape:
53
+ - `existential`: without this, the vision does not hold
54
+ - `supporting`: makes the core feature useful
55
+ - `later`: valuable after the core assumption is proven
56
+ - `out_of_scope`: explicitly excluded from validation
57
+ 3. Identify critical assumptions and rank the riskiest first.
58
+ 4. Define one minimum prototype scope.
59
+ 5. Define acceptance as evidence questions, not implementation completeness.
60
+ 6. Initialize artifacts with `scripts/init_validation.py`.
61
+ 7. Validate with `npm run validate` when the repository validator exists.
62
+
63
+ ## Boundaries
64
+
65
+ - Do not create full implementation tasks.
66
+ - Do not write large product specs.
67
+ - Do not solve authentication, persistence, deployment, billing, or admin work
68
+ unless those are the existential assumption.
69
+ - Do not treat feature count as progress.
70
+ - Prefer a small prototype brief over a broad spec when uncertainty is high.
71
+
72
+ ## Handoff
73
+
74
+ If validation is planned, hand off to `/ow:prototype` or an implementation
75
+ agent with the prototype brief only.
76
+
77
+ If validation passes, feed `VALIDATION.yaml` and `RESULT.md` into
78
+ `/ow:decision`, `/ow:spec`, or `/ow:change`.
79
+
80
+ If validation fails, revise the vision or create a new validation contract
81
+ before generating implementation tasks.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Build Validation"
3
+ short_description: "Prioritize the core assumption to validate first"
4
+ default_prompt: "Use /ow:validation to identify what must be proven before implementation."
@@ -0,0 +1,51 @@
1
+ # Validation-First Protocol
2
+
3
+ Use this reference when deciding what should happen before implementation.
4
+
5
+ ## Priority Means Validation Order
6
+
7
+ OpenWorkflow priority is not a sorted backlog. It is the order in which the
8
+ vision's critical assumptions must be proven.
9
+
10
+ Ask:
11
+
12
+ - What feature makes the idea distinct?
13
+ - If this feature fails, does the product collapse into a generic app?
14
+ - What can be faked, mocked, or hardcoded to test that feature?
15
+ - What should be excluded because it does not answer the core question?
16
+
17
+ ## Feature Classes
18
+
19
+ `existential`:
20
+
21
+ - The vision fails without it.
22
+ - It should usually be validated first.
23
+
24
+ `supporting`:
25
+
26
+ - It helps the existential feature become useful.
27
+ - It can be mocked if the validation question does not depend on full fidelity.
28
+
29
+ `later`:
30
+
31
+ - Valuable after the core experience works.
32
+ - Usually includes auth, sharing, import/export, admin, analytics, billing, and
33
+ scale work unless the vision is specifically about those capabilities.
34
+
35
+ `out_of_scope`:
36
+
37
+ - Explicitly excluded from this validation loop.
38
+
39
+ ## Prototype Brief Rule
40
+
41
+ The prototype should include the minimum surface that lets a user, reviewer, or
42
+ agent answer the core question. It should exclude production hardening unless
43
+ that hardening is the core assumption.
44
+
45
+ Example:
46
+
47
+ For an AI-native travel memory globe, the first validation is not login,
48
+ database schema, upload flow, or chat orchestration. It is whether an
49
+ interactive globe with flags, hover photo previews, and a detail panel can feel
50
+ like the product's central experience.
51
+