@bvdm/delano 0.2.4 → 0.2.6

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 (27) hide show
  1. package/.delano/viewer/public/styles.css +1 -1
  2. package/README.md +35 -0
  3. package/assets/install-manifest.json +9 -0
  4. package/assets/payload/.agents/adapters/manifest.schema.json +103 -0
  5. package/assets/payload/.agents/adapters/spec-kit/adapter.json +71 -0
  6. package/assets/payload/.agents/schemas/status-transitions.json +17 -0
  7. package/assets/payload/.agents/scripts/check-status-transitions.mjs +83 -2
  8. package/assets/payload/.agents/scripts/pm/import-spec-kit.sh +605 -0
  9. package/assets/payload/.agents/scripts/pm/init.sh +31 -2
  10. package/assets/payload/.agents/scripts/pm/research.sh +296 -0
  11. package/assets/payload/.agents/scripts/pm/validate.sh +15 -0
  12. package/assets/payload/.agents/skills/README.md +1 -0
  13. package/assets/payload/.agents/skills/research-skill/SKILL.md +66 -0
  14. package/assets/payload/.agents/skills/research-skill/references/runbook.md +59 -0
  15. package/assets/payload/.agents/skills/research-skill/templates/fold-forward-checklist.md +9 -0
  16. package/assets/payload/.agents/skills/research-skill/templates/research-summary.md +21 -0
  17. package/assets/payload/.delano/viewer/public/styles.css +1 -1
  18. package/assets/payload/.project/templates/decisions.md +18 -0
  19. package/assets/payload/.project/templates/plan.md +17 -0
  20. package/assets/payload/.project/templates/spec.md +12 -0
  21. package/assets/payload/.project/templates/task.md +6 -0
  22. package/assets/payload/.project/templates/workstream.md +1 -0
  23. package/package.json +4 -2
  24. package/src/cli/commands/state.js +689 -0
  25. package/src/cli/commands/wrapper.js +16 -3
  26. package/src/cli/index.js +119 -7
  27. package/src/cli/lib/project-state.js +918 -0
@@ -0,0 +1,605 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ usage() {
5
+ cat <<'USAGE'
6
+ Usage:
7
+ import-spec-kit.sh <slug> <source-md> [options]
8
+ import-spec-kit.sh <slug> <source-md> [project-name] [owner] [lead]
9
+
10
+ Creates a planned Delano project from the first supported Spec Kit-style markdown fixture.
11
+
12
+ Required arguments:
13
+ slug Target Delano project slug in kebab-case
14
+ source-md Path to a markdown source artifact
15
+
16
+ Options:
17
+ --name <project-name> Project name override
18
+ --owner <owner> Project owner, defaults to team
19
+ --lead <lead> Project lead, defaults to owner
20
+ --no-validate Create artifacts without running Delano validation
21
+ --json Print a single machine-readable JSON result
22
+ -h, --help Show this help
23
+
24
+ Agent notes:
25
+ - Prefer named options over positional metadata.
26
+ - Use --json when another agent/tool will parse the result.
27
+ - The command refuses to overwrite an existing .project/projects/<slug>/ folder.
28
+ - Generated artifacts stay planned/ready and still require Delano evidence gates.
29
+ USAGE
30
+ }
31
+
32
+ resolve_python() {
33
+ if command -v python3 >/dev/null 2>&1 && python3 -c "import sys" >/dev/null 2>&1; then
34
+ PYTHON_CMD=(python3)
35
+ elif command -v py >/dev/null 2>&1 && py -3 -c "import sys" >/dev/null 2>&1; then
36
+ PYTHON_CMD=(py -3)
37
+ elif command -v python >/dev/null 2>&1 && python -c "import sys" >/dev/null 2>&1; then
38
+ PYTHON_CMD=(python)
39
+ else
40
+ echo "Error: Python runtime not found. Install python3, python, or py -3." >&2
41
+ exit 1
42
+ fi
43
+ }
44
+
45
+ resolve_python
46
+
47
+ json_escape() {
48
+ "${PYTHON_CMD[@]}" -c 'import json,sys; print(json.dumps(sys.stdin.read().rstrip("\n")))'
49
+ }
50
+
51
+ if [[ "${1:-}" == "" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
52
+ usage
53
+ exit 0
54
+ fi
55
+
56
+ if [[ "${2:-}" == "" ]]; then
57
+ usage
58
+ exit 1
59
+ fi
60
+
61
+ slug="$1"
62
+ source_md="$2"
63
+ shift 2
64
+
65
+ project_name=""
66
+ owner="team"
67
+ lead=""
68
+ validate="true"
69
+ json="false"
70
+ positional=()
71
+
72
+ while [[ $# -gt 0 ]]; do
73
+ case "$1" in
74
+ --name)
75
+ project_name="${2:-}"
76
+ if [[ -z "$project_name" ]]; then echo "Error: --name requires a value"; exit 1; fi
77
+ shift 2
78
+ ;;
79
+ --owner)
80
+ owner="${2:-}"
81
+ if [[ -z "$owner" ]]; then echo "Error: --owner requires a value"; exit 1; fi
82
+ shift 2
83
+ ;;
84
+ --lead)
85
+ lead="${2:-}"
86
+ if [[ -z "$lead" ]]; then echo "Error: --lead requires a value"; exit 1; fi
87
+ shift 2
88
+ ;;
89
+ --no-validate)
90
+ validate="false"
91
+ shift
92
+ ;;
93
+ --json)
94
+ json="true"
95
+ shift
96
+ ;;
97
+ -h|--help)
98
+ usage
99
+ exit 0
100
+ ;;
101
+ --)
102
+ shift
103
+ while [[ $# -gt 0 ]]; do positional+=("$1"); shift; done
104
+ ;;
105
+ --*)
106
+ echo "Error: unknown option: $1"
107
+ exit 1
108
+ ;;
109
+ *)
110
+ positional+=("$1")
111
+ shift
112
+ ;;
113
+ esac
114
+ done
115
+
116
+ # Backward-compatible positional metadata: [project-name] [owner] [lead].
117
+ if [[ ${#positional[@]} -gt 0 && -z "$project_name" ]]; then
118
+ project_name="${positional[0]}"
119
+ fi
120
+ if [[ ${#positional[@]} -gt 1 && "$owner" == "team" ]]; then
121
+ owner="${positional[1]}"
122
+ fi
123
+ if [[ ${#positional[@]} -gt 2 && -z "$lead" ]]; then
124
+ lead="${positional[2]}"
125
+ fi
126
+ if [[ ${#positional[@]} -gt 3 ]]; then
127
+ echo "Error: too many positional arguments"
128
+ exit 1
129
+ fi
130
+
131
+ lead="${lead:-$owner}"
132
+
133
+ if [[ ! "$slug" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
134
+ echo "Error: slug must be kebab-case"
135
+ exit 1
136
+ fi
137
+
138
+ invocation_cwd="$PWD"
139
+ root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
140
+ if [[ "$source_md" != /* ]]; then
141
+ source_md="$invocation_cwd/$source_md"
142
+ fi
143
+ cd "$root"
144
+
145
+ if [[ ! -f "$source_md" ]]; then
146
+ echo "Error: source markdown not found: $source_md"
147
+ exit 1
148
+ fi
149
+
150
+ project_dir=".project/projects/$slug"
151
+ if [[ -d "$project_dir" ]]; then
152
+ echo "Error: project already exists at $project_dir"
153
+ exit 1
154
+ fi
155
+
156
+ "${PYTHON_CMD[@]}" - "$slug" "$source_md" "$project_name" "$owner" "$lead" <<'PY'
157
+ import re
158
+ import sys
159
+ from datetime import datetime, timezone
160
+ from pathlib import Path
161
+
162
+ slug, source_arg, project_name_arg, owner, lead = sys.argv[1:]
163
+ source_path = Path(source_arg)
164
+ root = Path.cwd()
165
+ source_text = source_path.read_text(encoding="utf-8")
166
+ now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
167
+ today = now[:10]
168
+
169
+ def write_file(path, text):
170
+ with path.open("w", encoding="utf-8", newline="\n") as handle:
171
+ handle.write(text)
172
+
173
+ heading_match = re.search(r"^#\s+(?:Specification|Spec):\s+(.+?)\s*$", source_text, re.MULTILINE | re.IGNORECASE)
174
+ if project_name_arg:
175
+ project_name = project_name_arg.strip()
176
+ elif heading_match:
177
+ project_name = heading_match.group(1).strip()
178
+ else:
179
+ project_name = slug.replace("-", " ").title()
180
+
181
+ sections = {}
182
+ current = None
183
+ for line in source_text.splitlines():
184
+ match = re.match(r"^##\s+(.+?)\s*$", line)
185
+ if match:
186
+ current = match.group(1).strip().lower()
187
+ sections[current] = []
188
+ continue
189
+ if current:
190
+ sections[current].append(line)
191
+
192
+ for key in list(sections):
193
+ sections[key] = "\n".join(sections[key]).strip()
194
+
195
+ def section(*names):
196
+ for name in names:
197
+ value = sections.get(name.lower())
198
+ if value:
199
+ return value
200
+ return ""
201
+
202
+ def bullet_lines(text):
203
+ items = []
204
+ for line in text.splitlines():
205
+ stripped = line.strip()
206
+ if stripped.startswith("- "):
207
+ items.append(stripped)
208
+ return items
209
+
210
+ user_stories = bullet_lines(section("User Stories"))
211
+ acceptance = bullet_lines(section("Acceptance Scenarios"))
212
+ requirements = bullet_lines(section("Requirements"))
213
+ non_functional = bullet_lines(section("Non-Functional Requirements"))
214
+ assumptions = bullet_lines(section("Assumptions"))
215
+ clarifications = bullet_lines(section("Clarifications", "Needs Clarification"))
216
+ implementation_plan = bullet_lines(section("Implementation Plan"))
217
+ raw_tasks = bullet_lines(section("Tasks"))
218
+
219
+ recognized_content = user_stories + acceptance + requirements + non_functional + assumptions + clarifications + implementation_plan + raw_tasks
220
+ if not recognized_content:
221
+ raise SystemExit("unsupported Spec Kit-style source: expected at least one recognized section such as User Stories, Acceptance Scenarios, Requirements, Implementation Plan, or Tasks")
222
+
223
+ project_dir = root / ".project" / "projects" / slug
224
+ (project_dir / "tasks").mkdir(parents=True)
225
+ (project_dir / "workstreams").mkdir()
226
+ (project_dir / "updates").mkdir()
227
+
228
+ source_display = source_path.as_posix()
229
+ if source_path.is_absolute():
230
+ try:
231
+ source_display = source_path.resolve().relative_to(root).as_posix()
232
+ except ValueError:
233
+ source_display = "external markdown source"
234
+
235
+ def md_list(items, fallback="- None recorded."):
236
+ return "\n".join(items) if items else fallback
237
+
238
+ def yaml_scalar(value):
239
+ return str(value).replace("\n", " ").replace(":", " -")
240
+
241
+ spec = f"""---
242
+ name: {yaml_scalar(project_name)}
243
+ slug: {slug}
244
+ owner: {yaml_scalar(owner)}
245
+ status: planned
246
+ created: {now}
247
+ updated: {now}
248
+ outcome: Imported Spec Kit-style intent is normalized into Delano delivery contracts and validated before execution.
249
+ uncertainty: medium
250
+ probe_required: true
251
+ probe_status: pending
252
+ ---
253
+
254
+ # Spec: {project_name}
255
+
256
+ ## Executive Summary
257
+
258
+ Imported from a Spec Kit-style markdown artifact. This project is planned until clarification, probe, and validation gates confirm the generated contracts are execution-ready.
259
+
260
+ ## Problem and Users
261
+
262
+ {md_list(user_stories)}
263
+
264
+ ## Outcome and Success Metrics
265
+
266
+ Acceptance scenarios imported as success signals:
267
+
268
+ {md_list(acceptance)}
269
+
270
+ ## User Stories
271
+
272
+ {md_list(user_stories)}
273
+
274
+ ## Acceptance Scenarios
275
+
276
+ {md_list(acceptance)}
277
+
278
+ ## Scope
279
+
280
+ ### In Scope
281
+
282
+ {md_list(requirements)}
283
+
284
+ ### Out of Scope
285
+
286
+ - Automatic execution before Delano validation and approval.
287
+ - Automatic external sync writes.
288
+
289
+ ## Functional Requirements
290
+
291
+ {md_list(requirements)}
292
+
293
+ ## Non-Functional Requirements
294
+
295
+ {md_list(non_functional)}
296
+
297
+ ## Assumptions
298
+
299
+ {md_list(assumptions)}
300
+
301
+ ## Needs Clarification
302
+
303
+ {md_list(clarifications)}
304
+
305
+ ## Hypotheses and Unknowns
306
+
307
+ Assumptions imported from source:
308
+
309
+ {md_list(assumptions)}
310
+
311
+ ## Touchpoints to Exercise
312
+
313
+ - Generated Delano project contracts.
314
+ - Task dependency and evidence validation.
315
+ - Import update note.
316
+
317
+ ## Probe Findings
318
+
319
+ Pending. Run a delivery probe before activating this spec.
320
+
321
+ ## Footguns Discovered
322
+
323
+ - Imported intent may contain assumptions that need operator confirmation.
324
+ - Imported tasks may not include enough evidence detail for closure.
325
+
326
+ ## Remaining Unknowns
327
+
328
+ {md_list(clarifications)}
329
+
330
+ ## Dependencies
331
+
332
+ - Source artifact: `{source_display}`
333
+
334
+ ## Approval Notes
335
+
336
+ Imported by `delano import-spec-kit`. Review before activation.
337
+ """
338
+ write_file(project_dir / "spec.md", spec)
339
+
340
+ plan = f"""---
341
+ name: {yaml_scalar(project_name)}
342
+ status: planned
343
+ lead: {yaml_scalar(lead)}
344
+ created: {now}
345
+ updated: {now}
346
+ linear_project_id:
347
+ risk_level: medium
348
+ spec_status_at_plan_time: planned
349
+ ---
350
+
351
+ # Delivery Plan: {project_name}
352
+
353
+ ## What Changed After Probe
354
+
355
+ No probe has been run yet. This plan was imported from a Spec Kit-style source and requires review.
356
+
357
+ ## Architecture Decisions
358
+
359
+ Imported implementation plan:
360
+
361
+ {md_list(implementation_plan)}
362
+
363
+ ## Probe-Driven Architecture Changes
364
+
365
+ Pending probe.
366
+
367
+ ## Workstream Design
368
+
369
+ - WS-A Imported Delivery Foundation: first normalized workstream for imported tasks.
370
+
371
+ ## Milestone Strategy
372
+
373
+ 1. Review imported spec and clarify open questions.
374
+ 2. Run required probe.
375
+ 3. Execute ready tasks with Delano evidence gates.
376
+
377
+ ## Rollout Strategy
378
+
379
+ Start with local validation and evidence collection. Do not sync externally until identity mappings are reviewed.
380
+
381
+ ## Test Strategy
382
+
383
+ - Run `delano validate` after import.
384
+ - Add task-specific tests before closure.
385
+
386
+ ## Rollback Strategy
387
+
388
+ If the import is wrong, remove `.project/projects/{slug}` before external sync or activation.
389
+
390
+ ## Remaining Delivery Risks
391
+
392
+ - Source assumptions may be incomplete.
393
+ - Imported task boundaries may need workstream refinement.
394
+ - Clarifications may block activation.
395
+ """
396
+ write_file(project_dir / "plan.md", plan)
397
+
398
+ write_file(project_dir / "decisions.md", "# Decisions\n\nTrack key project decisions with context and rationale.\n")
399
+
400
+ workstream = f"""---
401
+ name: WS-A Imported Delivery Foundation
402
+ owner: {yaml_scalar(owner)}
403
+ status: planned
404
+ created: {now}
405
+ updated: {now}
406
+ ---
407
+
408
+ # Workstream: WS-A Imported Delivery Foundation
409
+
410
+ ## Objective
411
+
412
+ Normalize and execute the imported Spec Kit-style task set under Delano governance.
413
+
414
+ ## Owned Files/Areas
415
+
416
+ - `.project/projects/{slug}/`
417
+
418
+ ## Dependencies
419
+
420
+ - Source artifact review.
421
+ - Delano validation.
422
+
423
+ ## Risks
424
+
425
+ - Imported tasks may require clarification before execution.
426
+ - Parallel markers are hints and still need conflict review.
427
+
428
+ ## Handoff Criteria
429
+
430
+ - Tasks have evidence logs.
431
+ - Validation passes before closure.
432
+ """
433
+ write_file(project_dir / "workstreams" / "WS-A-imported-delivery-foundation.md", workstream)
434
+
435
+ def slugify(text):
436
+ text = re.sub(r"^T\d+\s+", "", text.strip(), flags=re.IGNORECASE)
437
+ text = re.sub(r"[^a-zA-Z0-9]+", "-", text.lower()).strip("-")
438
+ return text or "imported-task"
439
+
440
+ if not raw_tasks:
441
+ raw_tasks = ["- [ ] Review imported Spec Kit artifact and define executable Delano tasks."]
442
+
443
+ acceptance_ids = []
444
+ for index, item in enumerate(acceptance, start=1):
445
+ match = re.search(r"\bAC[-_ ]?(\d{1,3})\b", item, re.IGNORECASE)
446
+ acceptance_ids.append(f"AC-{int(match.group(1)):03d}" if match else f"AC-{index:03d}")
447
+
448
+ def parse_task(raw, index):
449
+ text = raw.strip()
450
+ parallel = bool(re.search(r"\[(?:P|p)\]", text))
451
+ source_task_match = re.search(r"\bT[-_ ]?(\d{1,4})\b", text, re.IGNORECASE)
452
+ story_match = re.search(r"\b(?:US|Story)[-_ ]?(\d{1,3})\b", text, re.IGNORECASE)
453
+ story_id = f"US-{int(story_match.group(1)):03d}" if story_match else ""
454
+
455
+ title = re.sub(r"^-\s*", "", text).strip()
456
+ title = re.sub(r"^\[(?: |x|X|P|p)\]\s*", "", title).strip()
457
+ title = re.sub(r"\[(?:P|p)\]", "", title).strip()
458
+ title = re.sub(r"\[(?:US|Story)[-_ ]?\d{1,3}\]", "", title, flags=re.IGNORECASE).strip()
459
+ title = re.sub(r"^T[-_ ]?\d{1,4}[:.)-]?\s*", "", title, flags=re.IGNORECASE).strip()
460
+ title = re.sub(r"^\[[^\]]+\]\s*", "", title).strip()
461
+ title = title or f"Review imported task {index}"
462
+
463
+ vague = bool(re.search(r"\b(tbd|todo|clarify|needs clarification|unknown|investigate|research)\b", raw, re.IGNORECASE))
464
+ generated_review_task = index == 1 and "Review imported Spec Kit artifact" in raw
465
+ blocked = bool(clarifications) or vague or generated_review_task
466
+ status = "blocked" if blocked else "ready"
467
+ reason = "Open clarifications or vague source wording require review before execution." if blocked else "No source clarification blocker detected by importer."
468
+ source_task_id = f"T{int(source_task_match.group(1)):03d}" if source_task_match else ""
469
+ return title, parallel, status, reason, story_id, source_task_id
470
+
471
+ for index, raw in enumerate(raw_tasks, start=1):
472
+ title, parallel, status, block_reason, story_id, source_task_id = parse_task(raw, index)
473
+ task_id = f"T-{index:03d}"
474
+ task_slug = slugify(title)
475
+ acceptance_yaml = "[" + ", ".join(acceptance_ids) + "]" if acceptance_ids else "[]"
476
+ blocker_frontmatter = ""
477
+ blocker_section = ""
478
+ if status == "blocked":
479
+ blocker_frontmatter = f"blocked_owner: {yaml_scalar(owner)}\nblocked_check_back: {today}\n"
480
+ blocker_section = f"\n## Blocker\n\n{block_reason}\n"
481
+ task = f"""---
482
+ id: {task_id}
483
+ name: {yaml_scalar(title)}
484
+ status: {status}
485
+ workstream: WS-A
486
+ created: {now}
487
+ updated: {now}
488
+ linear_issue_id:
489
+ github_issue:
490
+ github_pr:
491
+ depends_on: []
492
+ conflicts_with: []
493
+ parallel: {str(parallel).lower()}
494
+ priority: medium
495
+ estimate: M
496
+ story_id: {story_id}
497
+ acceptance_criteria_ids: {acceptance_yaml}
498
+ {blocker_frontmatter}---
499
+
500
+ # Task: {title}
501
+
502
+ ## Description
503
+
504
+ Imported from Spec Kit-style source task: `{raw}`
505
+
506
+ ## Acceptance Criteria
507
+
508
+ - [ ] Task has been reviewed against the imported acceptance scenarios.
509
+ - [ ] Implementation satisfies relevant Delano evidence requirements.
510
+
511
+ ## Traceability
512
+
513
+ - Source task id: {source_task_id or "none detected"}
514
+ - Story: {story_id or "none detected"}
515
+ - Acceptance criteria: {", ".join(acceptance_ids) if acceptance_ids else "none detected"}
516
+ {blocker_section}
517
+ ## Technical Notes
518
+
519
+ - Source artifact: `{source_display}`
520
+ - Parallel marker imported: `{str(parallel).lower()}`
521
+ - Initial status: `{status}`
522
+
523
+ ## Definition of Done
524
+
525
+ - [ ] Implementation complete
526
+ - [ ] Tests pass
527
+ - [ ] Review complete
528
+ - [ ] Docs updated if behavior is user-visible
529
+ - [ ] Evidence recorded
530
+
531
+ ## Evidence Log
532
+
533
+ - {now}: Imported from Spec Kit-style markdown by `delano import-spec-kit`.
534
+ """
535
+ write_file(project_dir / "tasks" / f"{task_id}-{task_slug}.md", task)
536
+
537
+ update = f"""# Imported from Spec Kit-style artifact
538
+
539
+ Imported `{source_display}` into Delano project `{slug}`.
540
+
541
+ ## Source classification
542
+
543
+ - Shape: single-file Spec Kit-style markdown fixture.
544
+ - Confidence: initial supported fixture shape.
545
+
546
+ ## Imported counts
547
+
548
+ - User stories: {len(user_stories)}
549
+ - Acceptance scenarios: {len(acceptance)}
550
+ - Functional requirements: {len(requirements)}
551
+ - Non-functional requirements: {len(non_functional)}
552
+ - Clarifications: {len(clarifications)}
553
+ - Tasks: {len(raw_tasks)}
554
+
555
+ ## Unresolved clarifications
556
+
557
+ {md_list(clarifications)}
558
+
559
+ ## Next step
560
+
561
+ Review the generated project, then run Delano validation and a probe before activation.
562
+ """
563
+ write_file(project_dir / "updates" / f"{today}-imported-from-spec-kit.md", update)
564
+ PY
565
+
566
+ validation_status="skipped"
567
+ ok="true"
568
+ error=""
569
+ if [[ "$validate" == "true" ]]; then
570
+ if [[ "$json" == "true" ]]; then
571
+ validation_log="$(mktemp)"
572
+ if "$root/.agents/scripts/pm/validate.sh" >"$validation_log" 2>&1; then
573
+ validation_status="passed"
574
+ else
575
+ validation_status="failed"
576
+ ok="false"
577
+ error="validation_failed"
578
+ fi
579
+ rm -f "$validation_log"
580
+ else
581
+ "$root/.agents/scripts/pm/validate.sh"
582
+ validation_status="passed"
583
+ fi
584
+ fi
585
+
586
+ if [[ "$json" == "true" ]]; then
587
+ project_json="$(printf '%s' "$project_dir" | json_escape)"
588
+ source_display="$source_md"
589
+ case "$source_display" in
590
+ "$root"/*) source_display="${source_display#"$root/"}" ;;
591
+ esac
592
+ source_json="$(printf '%s' "$source_display" | json_escape)"
593
+ validation_json="$(printf '%s' "$validation_status" | json_escape)"
594
+ if [[ "$ok" == "true" ]]; then
595
+ printf '{"ok":true,"command":"import-spec-kit","project":%s,"source":%s,"validation":%s}\n' "$project_json" "$source_json" "$validation_json"
596
+ else
597
+ error_json="$(printf '%s' "$error" | json_escape)"
598
+ printf '{"ok":false,"command":"import-spec-kit","project":%s,"source":%s,"validation":%s,"error":%s}\n' "$project_json" "$source_json" "$validation_json" "$error_json"
599
+ exit 1
600
+ fi
601
+ else
602
+ echo "Created Delano project from Spec Kit-style artifact: $project_dir"
603
+ echo "Validation: $validation_status"
604
+ echo "Next: review $project_dir/spec.md, then run a probe before activation."
605
+ fi
@@ -32,7 +32,7 @@ cat > "$project_dir/spec.md" <<SPEC
32
32
  name: $name
33
33
  slug: $slug
34
34
  owner: $owner
35
- status: draft
35
+ status: planned
36
36
  created: $now
37
37
  updated: $now
38
38
  outcome: <measurable target>
@@ -49,6 +49,12 @@ probe_status: <pending|skipped|completed>
49
49
 
50
50
  ## Outcome and Success Metrics
51
51
 
52
+ ## User Stories
53
+ - US-001: As a <user>, I want <capability>, so that <outcome>.
54
+
55
+ ## Acceptance Scenarios
56
+ - AC-001: Given <context>, when <action>, then <observable result>.
57
+
52
58
  ## Scope
53
59
  ### In Scope
54
60
  ### Out of Scope
@@ -57,6 +63,12 @@ probe_status: <pending|skipped|completed>
57
63
 
58
64
  ## Non-Functional Requirements
59
65
 
66
+ ## Assumptions
67
+ - <assumption to validate>
68
+
69
+ ## Needs Clarification
70
+ - <question that must be answered before activation or execution>
71
+
60
72
  ## Hypotheses and Unknowns
61
73
 
62
74
  ## Touchpoints to Exercise
@@ -81,15 +93,32 @@ created: $now
81
93
  updated: $now
82
94
  linear_project_id:
83
95
  risk_level: <low|medium|high>
84
- spec_status_at_plan_time: <approved|active>
96
+ spec_status_at_plan_time: planned
85
97
  ---
86
98
 
87
99
  # Delivery Plan: $name
88
100
 
89
101
  ## What Changed After Probe
90
102
 
103
+ ## Technical Context
104
+
91
105
  ## Architecture Decisions
92
106
 
107
+ ## Policy and Contract Checks
108
+ - [ ] `.project` remains the execution source of truth
109
+ - [ ] Probe decision is explicit
110
+ - [ ] Evidence gates are defined before handoff
111
+ - [ ] External sync writes require dry-run or operator approval
112
+
113
+ ## Generated Artifact Map
114
+ - `spec.md`: <source or generation notes>
115
+ - `plan.md`: <source or generation notes>
116
+ - `workstreams/`: <source or generation notes>
117
+ - `tasks/`: <source or generation notes>
118
+
119
+ ## Complexity Exceptions
120
+ - <exception, rationale, and owner>
121
+
93
122
  ## Probe-Driven Architecture Changes
94
123
 
95
124
  ## Workstream Design