specfuse-loop 0.2.0__tar.gz → 0.3.1__tar.gz

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 (130) hide show
  1. {specfuse_loop-0.2.0/specfuse_loop.egg-info → specfuse_loop-0.3.1}/PKG-INFO +23 -18
  2. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/README.md +22 -17
  3. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/pyproject.toml +8 -4
  4. specfuse_loop-0.3.1/specfuse/loop/data/LEARNINGS.template.md +69 -0
  5. specfuse_loop-0.3.1/specfuse/loop/data/VERSION +1 -0
  6. specfuse_loop-0.3.1/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +97 -0
  7. specfuse_loop-0.3.1/specfuse/loop/data/docs/concepts/ralph-lineage.md +66 -0
  8. specfuse_loop-0.3.1/specfuse/loop/data/docs/getting-started.md +221 -0
  9. specfuse_loop-0.3.1/specfuse/loop/data/docs/methodology.md +322 -0
  10. specfuse_loop-0.3.1/specfuse/loop/data/docs/skills.md +132 -0
  11. specfuse_loop-0.3.1/specfuse/loop/data/gitignore.snippet +11 -0
  12. specfuse_loop-0.3.1/specfuse/loop/data/roadmap.template.md +37 -0
  13. specfuse_loop-0.3.1/specfuse/loop/data/rules/correlation-ids.md +197 -0
  14. specfuse_loop-0.3.1/specfuse/loop/data/rules/never-touch.md +81 -0
  15. specfuse_loop-0.3.1/specfuse/loop/data/rules/result-contract.md +113 -0
  16. specfuse_loop-0.3.1/specfuse/loop/data/rules/security-boundaries.md +102 -0
  17. specfuse_loop-0.3.1/specfuse/loop/data/templates/GATE.template.md +43 -0
  18. specfuse_loop-0.3.1/specfuse/loop/data/templates/PLAN.template.md +74 -0
  19. specfuse_loop-0.3.1/specfuse/loop/data/templates/WU.template.md +103 -0
  20. specfuse_loop-0.3.1/specfuse/loop/data/verification.yml.example +53 -0
  21. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/lint_plan.py +26 -1
  22. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/loop.py +478 -33
  23. specfuse_loop-0.3.1/specfuse/loop/scaffold.py +630 -0
  24. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1/specfuse_loop.egg-info}/PKG-INFO +23 -18
  25. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse_loop.egg-info/SOURCES.txt +40 -0
  26. specfuse_loop-0.3.1/tests/test_arm_gate_edits_uncommitted.py +165 -0
  27. specfuse_loop-0.3.1/tests/test_autosync.py +200 -0
  28. specfuse_loop-0.3.1/tests/test_autosync_consent.py +294 -0
  29. specfuse_loop-0.3.1/tests/test_autosync_firstrun.py +146 -0
  30. specfuse_loop-0.3.1/tests/test_autosync_plugin.py +245 -0
  31. specfuse_loop-0.3.1/tests/test_bookkeeping_commit_crash_run.py +121 -0
  32. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_closing_deliverable_guard.py +55 -0
  33. specfuse_loop-0.3.1/tests/test_doctor.py +269 -0
  34. specfuse_loop-0.3.1/tests/test_init_integration.py +389 -0
  35. specfuse_loop-0.3.1/tests/test_leak_findings_redaction.py +109 -0
  36. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_leak_scan.py +9 -0
  37. specfuse_loop-0.3.1/tests/test_lint_bare_produces_path.py +153 -0
  38. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_orchestration.py +3 -3
  39. specfuse_loop-0.3.1/tests/test_migrate_legacy.py +268 -0
  40. specfuse_loop-0.3.1/tests/test_scaffold_data_in_sync.py +104 -0
  41. specfuse_loop-0.3.1/tests/test_scaffold_docs.py +101 -0
  42. specfuse_loop-0.3.1/tests/test_scaffold_init.py +133 -0
  43. specfuse_loop-0.3.1/tests/test_scaffold_manifest.py +144 -0
  44. specfuse_loop-0.3.1/tests/test_scaffold_resources.py +71 -0
  45. specfuse_loop-0.3.1/tests/test_scaffold_seed_sanity.py +80 -0
  46. specfuse_loop-0.3.1/tests/test_scaffold_upgrade.py +184 -0
  47. specfuse_loop-0.3.1/tests/test_scaffold_wiring.py +325 -0
  48. specfuse_loop-0.3.1/tests/test_untracked_feature_folder.py +153 -0
  49. specfuse_loop-0.3.1/tests/test_upgrade_integration.py +391 -0
  50. specfuse_loop-0.3.1/tests/test_version_consistency.py +120 -0
  51. specfuse_loop-0.3.1/tests/test_version_skew.py +115 -0
  52. specfuse_loop-0.2.0/tests/test_version_skew.py +0 -95
  53. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/LICENSE +0 -0
  54. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/NOTICE +0 -0
  55. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/setup.cfg +0 -0
  56. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/__init__.py +0 -0
  57. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/_miniyaml.py +0 -0
  58. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/adopt_feature.py +0 -0
  59. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/gate_eval.py +0 -0
  60. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/gh_backend.py +0 -0
  61. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/gh_features.py +0 -0
  62. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse/loop/validate_event.py +0 -0
  63. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse_loop.egg-info/dependency_links.txt +0 -0
  64. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse_loop.egg-info/entry_points.txt +0 -0
  65. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse_loop.egg-info/requires.txt +0 -0
  66. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/specfuse_loop.egg-info/top_level.txt +0 -0
  67. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_adopt_feature.py +0 -0
  68. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_attempt_outcome_emission.py +0 -0
  69. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_backend.py +0 -0
  70. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
  71. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_cost_tracking.py +0 -0
  72. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_deliverable_presence_gate.py +0 -0
  73. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_driver_integration.py +0 -0
  74. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_driver_lock.py +0 -0
  75. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_duration_tracking.py +0 -0
  76. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_empty_files_escalation.py +0 -0
  77. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_ensure_feature_branch.py +0 -0
  78. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_extra_gates.py +0 -0
  79. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_force_full_close.py +0 -0
  80. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_gate_eval.py +0 -0
  81. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_gate_eval_calibration.py +0 -0
  82. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_gate_eval_intermediate_wiring.py +0 -0
  83. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_gate_eval_terminal_wiring.py +0 -0
  84. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_gh_backend.py +0 -0
  85. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_gh_features.py +0 -0
  86. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_git_env_isolation.py +0 -0
  87. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_hashed_denylist.py +0 -0
  88. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_hashed_denylist_ci.py +0 -0
  89. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_leak_scan_content.py +0 -0
  90. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_legacy_4wu_terminal_flips.py +0 -0
  91. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lifecycle_integration.py +0 -0
  92. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_close_intermediate.py +0 -0
  93. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_close_wu.py +0 -0
  94. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_correlation_id.py +0 -0
  95. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
  96. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_oracle_env.py +0 -0
  97. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_plan_errors.py +0 -0
  98. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_plan_next_draft.py +0 -0
  99. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_produces_driver_helper.py +0 -0
  100. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_sections.py +0 -0
  101. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_lint_task_graph_yaml_selection.py +0 -0
  102. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_auto_archive.py +0 -0
  103. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_caveman_preamble.py +0 -0
  104. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_close_intermediate.py +0 -0
  105. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_defaults_by_type.py +0 -0
  106. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_effort.py +0 -0
  107. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_failure_note_cap.py +0 -0
  108. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_files_changed_guard.py +0 -0
  109. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_gate_budget.py +0 -0
  110. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_model_alias.py +0 -0
  111. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_post_pass_invariant.py +0 -0
  112. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_reset_preserving_events.py +0 -0
  113. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_smoke_runner.py +0 -0
  114. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_unsandboxed.py +0 -0
  115. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_loop_zero_token_guard.py +0 -0
  116. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_miniyaml_equivalence.py +0 -0
  117. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_miniyaml_negative.py +0 -0
  118. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_planned_cost_lint.py +0 -0
  119. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_produces_field.py +0 -0
  120. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_result_block.py +0 -0
  121. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_roadmap_add_skill.py +0 -0
  122. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_roadmap_archive_skill.py +0 -0
  123. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_roadmap_row_parser.py +0 -0
  124. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_squash_commit_hook_crash.py +0 -0
  125. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_template_closing_shapes.py +0 -0
  126. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_terminal_flip_ownership.py +0 -0
  127. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_terminal_flips.py +0 -0
  128. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_validate_event.py +0 -0
  129. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_verdict_coupling.py +0 -0
  130. {specfuse_loop-0.2.0 → specfuse_loop-0.3.1}/tests/test_verify_empty_gate_set.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfuse-loop
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology.
5
5
  Author: Specfuse contributors
6
6
  License: Apache-2.0
@@ -77,8 +77,8 @@ the planning rigor Ralph's bare task list lacks.
77
77
  `.specfuse/scripts/adopt_feature.py <repo> <issue-number>` (or the
78
78
  interactive `/adopt-feature` skill) to scaffold a dispatchable feature
79
79
  folder from a picked issue.
80
- - The **driver** (`.specfuse/scripts/loop.py`) walks the current gate's ready
81
- work units, dispatches each as a fresh `claude -p` session, runs the unit's
80
+ - The **driver** (`specfuse-loop`, from the pip package) walks the current gate's
81
+ ready work units, dispatches each as a fresh `claude -p` session, runs the unit's
82
82
  verification itself as the exit oracle, and commits one squashed,
83
83
  trailer-carrying commit per unit. A failed gate is retried with a fresh
84
84
  session carrying the failure evidence, up to three attempts, then escalated.
@@ -101,29 +101,34 @@ In a target single-repo project:
101
101
  cloning to enable the pre-push hook (runs `scripts/smoke-test.sh` — same
102
102
  checks CI runs — before each `git push`). Bypass with `git push --no-verify`.
103
103
 
104
- The driver installs from PyPI and the skills from the Claude Code marketplace:
104
+ The driver installs from PyPI and the skills ship as a Claude Code plugin:
105
105
 
106
106
  ```bash
107
- pip install specfuse-loop # the driver: `specfuse-loop` on PATH
108
- # in Claude Code: skills under the /specfuse: namespace
107
+ pipx install specfuse # umbrella CLI; pulls specfuse-loop>=0.3.0
108
+ # gives you: specfuse, specfuse-loop, specfuse-lint (or: python3 -m pip install specfuse, in a venv)
109
+
110
+ # in Claude Code, enable the skills plugin (one-time):
109
111
  # /plugin marketplace add specfuse/specfuse
110
112
  # /plugin install specfuse@specfuse
111
113
 
112
- # scaffold a target repo's .specfuse/ state (templates, rules, verification.yml)
113
- ./init.sh /path/to/your-project # legacy installer (v1.0; removed in v1.1)
114
+ specfuse init /path/to/your-project # scaffold .specfuse/ + wire .claude/ (--dry-run previews)
114
115
 
115
116
  cd /path/to/your-project
116
117
  $EDITOR .specfuse/verification.yml # match the `code` gates to your stack
117
- # author your first feature folder under .specfuse/features/ from .specfuse/templates/
118
- specfuse-loop --dry-run # or: python .specfuse/scripts/loop.py --dry-run
119
- specfuse-loop
118
+ # author your first feature (in Claude Code: /draft-feature)
119
+ specfuse-loop --dry-run # show the gate walk, no dispatch
120
+ specfuse-loop # the real run
120
121
  ```
121
122
 
122
- > **Distribution (FEAT-2026-0019).** Code ships via pip (`specfuse-loop`), the
123
- > `specfuse` umbrella CLI bridges pip plugin (`specfuse upgrade`), and Claude
124
- > assets ship via the [`specfuse/specfuse`](https://github.com/specfuse/specfuse)
125
- > marketplace. `init.sh` remains the scaffold bootstrap (laying down `.specfuse/`
126
- > state) until pip-native scaffolding lands; it prints a deprecation banner.
123
+ > **Distribution.** Code ships via pip `specfuse` (umbrella CLI: `init` /
124
+ > `upgrade`) pulls `specfuse-loop` (the driver); Claude assets ship via the
125
+ > [`specfuse/specfuse`](https://github.com/specfuse/specfuse) plugin marketplace.
126
+ > `specfuse init` lays down `.specfuse/` and wires `.claude/`; `specfuse upgrade`
127
+ > overlays a newer scaffold and pip-upgrades both packages. Every `specfuse-loop`
128
+ > run self-provisions (version-syncs `.specfuse/` from the installed package), so
129
+ > an upgrade reaches existing projects on their next run. (`./init.sh` is a
130
+ > deprecated v1.0 shim that delegates to `specfuse init`/`upgrade`; slated for
131
+ > removal.)
127
132
 
128
133
  > **One driver per working tree.** The driver holds an exclusive advisory lock on
129
134
  > `.specfuse/.loop.lock` for the duration of a run; a second driver targeting the
@@ -145,7 +150,7 @@ python .specfuse/scripts/loop.py --dry-run
145
150
  ```
146
151
  specfuse-loop/
147
152
  ├── LICENSE NOTICE CONTRIBUTING.md README.md .gitignore
148
- ├── init.sh scaffold .specfuse/ into a target repo
153
+ ├── init.sh deprecated v1.0 shim delegates to `specfuse init`/`upgrade`
149
154
  ├── docs/
150
155
  │ ├── getting-started.md narrated first-feature + operator walkthrough
151
156
  │ ├── methodology.md the gate-cycle contract (shared with the orchestrator)
@@ -164,7 +169,7 @@ specfuse-loop/
164
169
  └── features/FEAT-2026-0001-health-endpoint/ (the worked example)
165
170
  ```
166
171
 
167
- `init.sh` also ships the durable docs — `methodology.md`, `skills.md`, and
172
+ `specfuse init` also ships the durable docs — `methodology.md`, `skills.md`, and
168
173
  `concepts/` — into a target's `.specfuse/docs/`, so an initialized repo is
169
174
  self-documenting without this checkout.
170
175
 
@@ -48,8 +48,8 @@ the planning rigor Ralph's bare task list lacks.
48
48
  `.specfuse/scripts/adopt_feature.py <repo> <issue-number>` (or the
49
49
  interactive `/adopt-feature` skill) to scaffold a dispatchable feature
50
50
  folder from a picked issue.
51
- - The **driver** (`.specfuse/scripts/loop.py`) walks the current gate's ready
52
- work units, dispatches each as a fresh `claude -p` session, runs the unit's
51
+ - The **driver** (`specfuse-loop`, from the pip package) walks the current gate's
52
+ ready work units, dispatches each as a fresh `claude -p` session, runs the unit's
53
53
  verification itself as the exit oracle, and commits one squashed,
54
54
  trailer-carrying commit per unit. A failed gate is retried with a fresh
55
55
  session carrying the failure evidence, up to three attempts, then escalated.
@@ -72,29 +72,34 @@ In a target single-repo project:
72
72
  cloning to enable the pre-push hook (runs `scripts/smoke-test.sh` — same
73
73
  checks CI runs — before each `git push`). Bypass with `git push --no-verify`.
74
74
 
75
- The driver installs from PyPI and the skills from the Claude Code marketplace:
75
+ The driver installs from PyPI and the skills ship as a Claude Code plugin:
76
76
 
77
77
  ```bash
78
- pip install specfuse-loop # the driver: `specfuse-loop` on PATH
79
- # in Claude Code: skills under the /specfuse: namespace
78
+ pipx install specfuse # umbrella CLI; pulls specfuse-loop>=0.3.0
79
+ # gives you: specfuse, specfuse-loop, specfuse-lint (or: python3 -m pip install specfuse, in a venv)
80
+
81
+ # in Claude Code, enable the skills plugin (one-time):
80
82
  # /plugin marketplace add specfuse/specfuse
81
83
  # /plugin install specfuse@specfuse
82
84
 
83
- # scaffold a target repo's .specfuse/ state (templates, rules, verification.yml)
84
- ./init.sh /path/to/your-project # legacy installer (v1.0; removed in v1.1)
85
+ specfuse init /path/to/your-project # scaffold .specfuse/ + wire .claude/ (--dry-run previews)
85
86
 
86
87
  cd /path/to/your-project
87
88
  $EDITOR .specfuse/verification.yml # match the `code` gates to your stack
88
- # author your first feature folder under .specfuse/features/ from .specfuse/templates/
89
- specfuse-loop --dry-run # or: python .specfuse/scripts/loop.py --dry-run
90
- specfuse-loop
89
+ # author your first feature (in Claude Code: /draft-feature)
90
+ specfuse-loop --dry-run # show the gate walk, no dispatch
91
+ specfuse-loop # the real run
91
92
  ```
92
93
 
93
- > **Distribution (FEAT-2026-0019).** Code ships via pip (`specfuse-loop`), the
94
- > `specfuse` umbrella CLI bridges pip plugin (`specfuse upgrade`), and Claude
95
- > assets ship via the [`specfuse/specfuse`](https://github.com/specfuse/specfuse)
96
- > marketplace. `init.sh` remains the scaffold bootstrap (laying down `.specfuse/`
97
- > state) until pip-native scaffolding lands; it prints a deprecation banner.
94
+ > **Distribution.** Code ships via pip `specfuse` (umbrella CLI: `init` /
95
+ > `upgrade`) pulls `specfuse-loop` (the driver); Claude assets ship via the
96
+ > [`specfuse/specfuse`](https://github.com/specfuse/specfuse) plugin marketplace.
97
+ > `specfuse init` lays down `.specfuse/` and wires `.claude/`; `specfuse upgrade`
98
+ > overlays a newer scaffold and pip-upgrades both packages. Every `specfuse-loop`
99
+ > run self-provisions (version-syncs `.specfuse/` from the installed package), so
100
+ > an upgrade reaches existing projects on their next run. (`./init.sh` is a
101
+ > deprecated v1.0 shim that delegates to `specfuse init`/`upgrade`; slated for
102
+ > removal.)
98
103
 
99
104
  > **One driver per working tree.** The driver holds an exclusive advisory lock on
100
105
  > `.specfuse/.loop.lock` for the duration of a run; a second driver targeting the
@@ -116,7 +121,7 @@ python .specfuse/scripts/loop.py --dry-run
116
121
  ```
117
122
  specfuse-loop/
118
123
  ├── LICENSE NOTICE CONTRIBUTING.md README.md .gitignore
119
- ├── init.sh scaffold .specfuse/ into a target repo
124
+ ├── init.sh deprecated v1.0 shim delegates to `specfuse init`/`upgrade`
120
125
  ├── docs/
121
126
  │ ├── getting-started.md narrated first-feature + operator walkthrough
122
127
  │ ├── methodology.md the gate-cycle contract (shared with the orchestrator)
@@ -135,7 +140,7 @@ specfuse-loop/
135
140
  └── features/FEAT-2026-0001-health-endpoint/ (the worked example)
136
141
  ```
137
142
 
138
- `init.sh` also ships the durable docs — `methodology.md`, `skills.md`, and
143
+ `specfuse init` also ships the durable docs — `methodology.md`, `skills.md`, and
139
144
  `concepts/` — into a target's `.specfuse/docs/`, so an initialized repo is
140
145
  self-documenting without this checkout.
141
146
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specfuse-loop"
7
- version = "0.2.0"
7
+ version = "0.3.1"
8
8
  description = "Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -56,8 +56,12 @@ specfuse-lint = "specfuse.loop.lint_plan:main"
56
56
 
57
57
  [tool.setuptools.packages.find]
58
58
  # Ship ONLY the specfuse namespace package. Without this scope, setuptools'
59
- # auto-discovery sweeps tests/, docs/, and scripts/ into the wheel. The driver's
60
- # data (templates, rules, features) lives in the consumer's `.specfuse/`, not in
61
- # the wheel, so the package is pure code.
59
+ # auto-discovery sweeps tests/, docs/, and scripts/ into the wheel.
62
60
  include = ["specfuse*"]
63
61
  namespaces = true
62
+
63
+ [tool.setuptools.package-data]
64
+ # Include the scaffold seed so `specfuse init` / `specfuse upgrade` can copy
65
+ # templates, rules, and other seed files out of the wheel without needing the
66
+ # loop source repo on disk.
67
+ "specfuse.loop" = ["data/**/*", "data/*"]
@@ -0,0 +1,69 @@
1
+ # LEARNINGS
2
+
3
+ Durable, reusable rules distilled from every gate's retrospective. The `lessons` work
4
+ unit appends here; planning reads here before detailing any new feature. This is the
5
+ feedback loop that makes each plan better than the last.
6
+
7
+ Append only. Phrase each entry as a rule that would change how a FUTURE work unit is
8
+ written or executed, not a one-off observation. De-duplicate against what is here.
9
+ Feature-specific observations stay in that feature's `RETROSPECTIVE.md` and are not
10
+ promoted here.
11
+
12
+ ## Format
13
+
14
+ ```
15
+ - [FEAT-YYYY-NNNN/G1] Implementation WUs must name the module a new route/handler
16
+ lives in; "add it to the router" cost a blocked attempt when no router existed yet.
17
+ ```
18
+
19
+ ## Entries
20
+
21
+ <!-- lessons work units append below this line -->
22
+ <!--
23
+ The entries below are GENERIC methodology lessons that ship with the scaffold —
24
+ they are about how to write and run work units, not about any one project. Your
25
+ project's own `lessons` work units append project-specific rules beneath them.
26
+ -->
27
+
28
+ - [meta/first-live-use] Scope a feature's acceptance criteria to the feature's
29
+ own footprint — its slug, the paths it creates or edits, the symbols it
30
+ introduces. Acceptance criteria that grep or scan the WHOLE repo will trip
31
+ on pre-existing, unrelated state and (correctly) cause the agent to emit
32
+ `status: blocked` even when the WU's own work is fine. Example failure mode:
33
+ a "no TODO comments anywhere in the tree" check that fires on legacy code
34
+ the WU never touches. Rule: bound checks to the feature's path prefixes
35
+ (e.g. `src/<slug>/**`) or to files the WU declares in `generated_surfaces` /
36
+ `files_changed`; repo-wide invariants belong in a separate hygiene WU or in
37
+ the repo's `code` gate set, not in a per-feature acceptance criterion.
38
+
39
+ - [meta/first-live-use] Name what the WU is expected to PRODUCE, not only what
40
+ it must NOT touch. The "Do not touch" section bounds the WU on one side;
41
+ without an equally-explicit "produces" list, an agent can helpfully write
42
+ files that should belong to a later WU (e.g. docs that were T92's job
43
+ showing up in T01's commit) without the verification gates objecting. Rule:
44
+ in addition to the "Do not touch" list, the WU's Acceptance criteria should
45
+ name the specific files/sections the WU is expected to author. A reviewer
46
+ reading the diff should be able to point at every changed file and find it
47
+ in either the WU's produces-list or the gate's verification output.
48
+
49
+ - [meta/first-live-use] The "hygiene WU" pattern — when a substantive WU
50
+ discovers a pre-existing bug in a path its "Do not touch" rule forbids
51
+ (typical case: shared module, infrastructure config, dependency version),
52
+ the right move is to insert a narrow hygiene WU EARLIER in the gate (or as
53
+ a precursor gate) that fixes only that issue. Not: loosen the blocked WU's
54
+ scope to permit the cross-cutting fix (muddies its boundary). Not: fix it
55
+ manually out-of-loop and pretend the gate ran clean (silent drift between
56
+ the methodology's history and git's). The hygiene WU should have a single,
57
+ obvious acceptance criterion and pass on its own verification; the original
58
+ blocked WU then runs after, unmodified.
59
+
60
+ - [meta/loop-driver-bugs] Driver bookkeeping (frontmatter status flips,
61
+ events.jsonl appends, per-attempt notes) must be committed if it should
62
+ survive across WUs — uncommitted writes are wiped by the inter-attempt
63
+ `git reset --hard`. Agent-work commits (per-WU squash) are separate from
64
+ bookkeeping commits (`chore(loop): ...`). When authoring WUs whose
65
+ verification commands themselves write to disk, remember the agent's
66
+ working tree is reset between failed attempts — scratch files written
67
+ during a failed attempt won't persist into the next attempt's prompt unless
68
+ the agent explicitly buffers them in the prompt-facing failure note the
69
+ driver hands to the next attempt.
@@ -0,0 +1 @@
1
+ 0.3.1
@@ -0,0 +1,97 @@
1
+ # Architecture Addendum — Gates and the iterative planning cycle (Model B)
2
+
3
+ > **Status: adopted (2026-06).** Gate placement is resolved as **Model B — gates live in the
4
+ > loop, per component, NOT in the orchestrator PM.** The gate cycle was proven on a real
5
+ > multi-gate feature (loop `FEAT-2026-0003`: plan-next drafted real, armable next gates across
6
+ > three cycles). This addendum records that decision and what it means for the orchestrator.
7
+ >
8
+ > **This supersedes the earlier Model-A proposal** (an earlier revision of this file that
9
+ > proposed folding gate identification / `plan-next` / per-gate `plan_review` into the PM agent as
10
+ > a `v1.7.0` behavioral change). That fold-in was **not adopted**; the PM does not gain gate
11
+ > machinery. See the orchestrator repo's `docs/gate-placement-proposal.md` (Model A vs B, decision
12
+ > criteria) and `docs/naming-convention.md` for the canonical contracts.
13
+
14
+ ---
15
+
16
+ ## 1. The decision
17
+
18
+ The orchestrator coordinates one level above a single-repo goal. An **initiative**
19
+ (`INIT-YYYY-NNNN`) is decomposed by the PM into a **`feature_graph`** of **features**
20
+ (`INIT-YYYY-NNNN/FNN`), each a single-repo goal dispatched to one component. **Each dispatched
21
+ implementation feature == a loop feature**: the receiving component's loop decomposes it into
22
+ **gates** and **work units** and grinds it through its gate cycle.
23
+
24
+ So gates are **internal to the loop**, not orchestrator state. The orchestrator owns
25
+ `initiative → feature` decomposition, cross-repo dependency ordering, and the spec/generated
26
+ interface contracts between features; it does **not** identify gates, run `plan-next`, or hold a
27
+ per-gate `plan_review`. The loop owns all of that, per [`methodology.md`](methodology.md).
28
+
29
+ **Why Model B (summary).** The loop is single-repo + edit-and-commit; codegen freezes the
30
+ cross-repo interface (generated `emit-*`/`on-*` contracts are immutable `_generated/`), so
31
+ component-loops grind hand-code against frozen boundaries and cannot break each other. This
32
+ dissolves the hardest part of Model A (predicting cross-repo gate boundaries inside the PM) and
33
+ keeps the gate cycle built once, in the loop. Full rationale + the rejected Model A:
34
+ `gate-placement-proposal.md`.
35
+
36
+ ## 2. What changed in the orchestrator (minimal — no PM gate machinery)
37
+
38
+ The orchestrator change is the **initiative/feature reframe**, already folded into
39
+ `orchestrator-architecture.md` §1A and `naming-convention.md`:
40
+
41
+ - **Vocabulary / IDs:** initiative → feature → gate → work unit; `INIT-YYYY-NNNN/FNN/TNN`
42
+ (legacy/component-local `FEAT-…/TNN`). Root token = origin.
43
+ - **State machines (unchanged in shape):** the "feature state machine" is the **initiative**
44
+ lifecycle; the "task state machine" is the **feature** lifecycle. Gates/WUs do **not** appear in
45
+ the orchestrator's state machines — they are loop-internal.
46
+ - **PM agent (reframed, not gate-extended):** `feature-decomposition` (was task-decomposition)
47
+ produces a `feature_graph`; `issue-drafting` files feature issues labelled by type;
48
+ `plan-review` reviews the `feature_graph`; `dependency-recomputation` (runtime `scripts/poller.py`)
49
+ flips features `pending → ready`. **No** gate identification, `plan-next`, or per-gate
50
+ `plan_review` in the PM — those were the Model-A additions and are dropped.
51
+ - **Dispatch by feature type:** `implementation` → the component-loop (loop GitHub feature-pick on
52
+ `specfuse:feature`); `qa_*` → the QA agent (`specfuse:qa-feature`), a distinct cross-repo role,
53
+ **not** a loop. QA is the exception to uniform-loop dispatch.
54
+ - **Per-gate autonomy / arming** lives in the loop (not the PM): autonomy flows orchestrator →
55
+ loop (`review`/`supervised` stop at each gate for a human arm; `auto` self-arms safe gates under
56
+ the methodology §9 conjunction). The merge gate stays human until the QA loop is trusted.
57
+
58
+ The orchestrator's earlier "no gates" behavior is therefore not changed by *adding* gates to it —
59
+ gates were placed in the loop instead.
60
+
61
+ ## 3. What the loop owns (the gate layer)
62
+
63
+ Per [`methodology.md`](methodology.md): the gate cycle (plan → execute → close → review&arm), the
64
+ four-type closing sequence (`retrospective → lessons → docs → plan-next`), `plan-next` drafting
65
+ the next gate (never arming it), `LEARNINGS.md`, and per-gate autonomy. These are **loop-internal**
66
+ to each dispatched feature; the orchestrator sees only the feature's overall state (via issue
67
+ labels) and its completion (PR merge → merge-watcher → `state:done`).
68
+
69
+ ## 4. Reconciliation with the orchestrator (the surface-specific seams)
70
+
71
+ Per the collaboration charter §2 / methodology §10, only these differ between surfaces:
72
+
73
+ | Concern | Loop (single-repo) | Orchestrator (multi-repo) |
74
+ |----------------|------------------------------------------|---------------------------------------------------|
75
+ | State backend | WU/GATE/PLAN frontmatter, git-tracked | GitHub issue labels + the initiative registry |
76
+ | Dispatch | driver shells out (`claude -p`) | poller routes by type → loop / QA agent |
77
+ | Branch / merge | one branch, squash per WU | branch + PR per **feature**, merge watcher |
78
+ | Report-back | RESULT block | `task_completed` event (+ `state:*` labels) via the loop's `GitHubBackend` |
79
+
80
+ The loop's `loop.py` is the reference for the orchestrator's poller (its dispatch/verify/retry/
81
+ gate-stop semantics decompose across the poller, PM dependency-recomputation, and the merge
82
+ watcher); the orchestrator does not import `loop.py`.
83
+
84
+ ## 5. Status of the old Model-A sections
85
+
86
+ The prior revision's §A.2–§A.11 (feature-state `in_progress → plan_review` oscillation, gate
87
+ skeleton in the PM, `plan-next` as a PM skill, per-gate `plan_review`, the auto-arm conjunction in
88
+ the PM, PM `v1.7.0`, the `gates`/`task.gate` frontmatter fields) described **Model A and are not
89
+ implemented.** The `feature-frontmatter.schema.json` `gates` array is not used by the orchestrator
90
+ (gates are loop-internal). If a future need arises to surface gate state at the orchestrator level,
91
+ re-open this addendum deliberately.
92
+
93
+ ## 6. Remaining (gated)
94
+
95
+ - `specfuse/methodology` extraction — once the gate-cycle contracts stop changing run-to-run
96
+ (charter §4; two contract fixes landed during the FEAT-2026-0003 dogfood — let them soak).
97
+ - Loop kit → `stable` in the orchestrator distribution manifest (same soak gate).
@@ -0,0 +1,66 @@
1
+ # Why the loop exists — lineage and positioning
2
+
3
+ ## The Ralph lineage
4
+
5
+ The loop descends from the "Ralph" technique: in its purest form, a bash loop
6
+ that feeds a prompt to a coding agent repeatedly until the work is done, with a
7
+ fresh context each iteration and durable state kept in files (git history, a
8
+ progress file, a task list) rather than in the context window. Its insight is
9
+ that for large work, *stubbornness plus fresh context* beats a single clever
10
+ pass — the loop is the hero, not the model.
11
+
12
+ Ralph's known weakness is the thinness of its task list: a bare list of TODOs
13
+ gives an agent nothing to enforce patterns against, so it drifts. The ecosystem's
14
+ answer to "that's too coarse for serious work" has been to make the units of work
15
+ granular and self-contained enough that ephemeral workers can pick them up,
16
+ execute, and hand off — orchestration of many such workers ("Gas Town"-style).
17
+
18
+ The Specfuse Loop is that idea with the planning rigor added back in. It keeps
19
+ Ralph's fresh-context-per-iteration property but moves it to **work-unit
20
+ granularity**, and it replaces the thin task list with the **Plan + Work Unit**
21
+ pattern: crisp work units with hard "do not touch" boundaries, explicit
22
+ acceptance criteria, and machine-checkable verification gates. The up-front
23
+ planning investment is precisely what earns the right to let execution run
24
+ unattended — the richer the unit, the longer the loop can safely run before a
25
+ human checkpoint.
26
+
27
+ Two things distinguish it from vanilla Ralph:
28
+
29
+ - **Verification is the exit oracle, not the agent's say-so.** The driver re-runs
30
+ the unit's gates and they decide done — eliminating Ralph's classic
31
+ premature-"done" failure.
32
+ - **Gates are human checkpoints by design.** The loop runs unattended *within* a
33
+ gate and stops *at* it. Reflection, a cross-feature learnings rollup, and
34
+ drafting the next batch happen systematically as the gate's closing sequence,
35
+ not when someone remembers to ask.
36
+
37
+ ## Where it sits in Specfuse
38
+
39
+ Specfuse is a methodology and an organization, not a single tool. Three
40
+ independently-adoptable projects live under it:
41
+
42
+ - **`specfuse/codegen`** turns OpenAPI / AsyncAPI / Arazzo specifications into
43
+ deterministic source code — the boilerplate no one should hand-write and no
44
+ agent should hallucinate.
45
+ - **`specfuse/loop`** (this project) executes the Plan + Work Unit pattern in a
46
+ single repository, with no specification required and no agent-coordination
47
+ overhead. The lightweight surface.
48
+ - **`specfuse/orchestrator`** coordinates specialized agents across many
49
+ component repositories from validated specifications — the heavyweight surface
50
+ for multi-repo, spec-first feature delivery.
51
+
52
+ The loop and the orchestrator are two execution surfaces of **one** methodology
53
+ (see [`methodology.md`](methodology.md)); they share the gate cycle, the
54
+ work-unit contract, the correlation-ID scheme, and the verification discipline.
55
+ The loop is the right home for work that lives in one repo or has no formal
56
+ spec; the orchestrator is the right home when the work genuinely spans repos and
57
+ is driven by specifications that `codegen` can turn into a stable foundation.
58
+
59
+ ## What it is not
60
+
61
+ - Not a general-purpose AI coding platform. It does one shape of work:
62
+ plan-driven, gated, fresh-context execution in a single repo.
63
+ - Not a replacement for human judgment. Every gate is a human checkpoint; the
64
+ loop keeps agents *inside* a loop, it does not remove the loop.
65
+ - Not a hosted service. It runs on your machine, against your repo, under your
66
+ accounts.
@@ -0,0 +1,221 @@
1
+ # Getting started
2
+
3
+ This walks you from an empty project to a feature delivered by the loop, then
4
+ shows what to do when a run halts. It assumes you've read the one-minute pitch in
5
+ the [README](../README.md); for the full contracts see
6
+ [`methodology.md`](methodology.md) and for the interactive operations see
7
+ [`skills.md`](skills.md).
8
+
9
+ The driver is pure-stdlib Python; it installs from PyPI, and the interactive
10
+ skills ship as a Claude Code plugin. You install the tooling once, then scaffold
11
+ each project you want to drive with one command.
12
+
13
+ ---
14
+
15
+ ## 1. Install the tooling and scaffold your project
16
+
17
+ Install the umbrella package — it pulls the driver (`specfuse-loop>=0.3.0`) as a
18
+ dependency and puts the `specfuse`, `specfuse-loop`, and `specfuse-lint` commands
19
+ on your PATH. It's a command-line app, so **pipx** is the recommended installer
20
+ (isolated environment, no `--break-system-packages` on PEP 668 / externally-
21
+ managed Pythons):
22
+
23
+ ```bash
24
+ pipx install specfuse # recommended
25
+ # or, inside a virtualenv you control:
26
+ python3 -m pip install specfuse
27
+ ```
28
+
29
+ > On Debian/Ubuntu/macOS-Homebrew Pythons a bare `pip install` into the system
30
+ > interpreter is blocked (`externally-managed-environment`). Use `pipx` (or a
31
+ > venv) — that's what puts `specfuse-loop` / `specfuse-lint` on PATH for the gate
32
+ > commands to find.
33
+
34
+ Enable the skills plugin in Claude Code (one-time):
35
+
36
+ ```
37
+ /plugin marketplace add specfuse/specfuse
38
+ /plugin install specfuse@specfuse
39
+ ```
40
+
41
+ Then scaffold the repo you want to drive:
42
+
43
+ ```bash
44
+ specfuse init /path/to/your-project # add --dry-run to preview, writes nothing
45
+ ```
46
+
47
+ This writes `.specfuse/` (templates, rules, the durable docs, `verification.yml`,
48
+ and an empty `features/`) into your project and merge-safely wires `.claude/`
49
+ (`CLAUDE.md`, `settings.json` enabling the `specfuse@specfuse` plugin) plus a
50
+ `.gitignore` snippet. It refuses if `.specfuse/` already exists — use
51
+ `specfuse upgrade /path/to/your-project` to overlay a newer scaffold in place
52
+ without touching your authored files. (The skills come from the plugin, not from
53
+ files copied into your repo.)
54
+
55
+ > **Don't gitignore `.specfuse/`.** The loop's durable state lives there and must
56
+ > be committed for the loop to work.
57
+
58
+ > **Self-provisioning.** Every `specfuse-loop` run first version-syncs `.specfuse/`
59
+ > from the installed package (missing → scaffold, older → overlay, equal → no-op,
60
+ > never downgrades). So `pip install -U specfuse` followed by a run keeps the
61
+ > scaffold current — `specfuse upgrade` is the explicit equivalent. Disable with
62
+ > `--no-autosync` or `autosync: false` in `.specfuse/config`.
63
+
64
+ ## 2. Match verification to your stack
65
+
66
+ `specfuse init` seeds `.specfuse/verification.yml`. Open it and make the `code`
67
+ gate set run *your* project's checks:
68
+
69
+ ```yaml
70
+ code:
71
+ - name: tests
72
+ command: "pytest -q"
73
+ - name: coverage
74
+ command: "coverage report --fail-under=90"
75
+ - name: lint
76
+ command: "ruff check ."
77
+ - name: security
78
+ command: "bandit -r src -ll"
79
+ ```
80
+
81
+ These commands are the **exit oracle**: the driver re-runs them itself after every
82
+ work unit and *they* decide whether the unit is done — the agent's own self-report
83
+ is advisory only ([methodology §5](methodology.md)). Keep this set in lock-step
84
+ with your GitHub branch protection, or an agent can pass locally and still be
85
+ unmergeable.
86
+
87
+ If your repo already has CI worth deriving from, run **`/derive-verification`** in
88
+ Claude Code instead of editing by hand — it inspects your CI and tooling and
89
+ drafts the file for you.
90
+
91
+ ## 3. Author your first feature
92
+
93
+ Two ways to create a feature folder under `.specfuse/features/`:
94
+
95
+ - **Interactively (recommended):** run **`/pick-feature`** to choose from your
96
+ roadmap, then **`/draft-feature`**. Draft-feature asks framing questions, then
97
+ proposes a gate skeleton and gate 1's work units, writing only on your accept.
98
+ - **By hand:** start from the bare templates in `.specfuse/templates/`
99
+ (`PLAN`, `GATE`, `WU`) and fill in a small first feature. (The
100
+ `specfuse/loop` source repo also carries a worked example,
101
+ `FEAT-2026-0001-health-endpoint`, if you want a complete reference to copy
102
+ from.)
103
+
104
+ A feature folder holds:
105
+
106
+ | File | Owns | Who writes it |
107
+ |------|------|---------------|
108
+ | `PLAN.md` | the *shape*: gate order, WU membership, dependency edges, feature status | you / `draft-feature` (gate 1); `plan-next` (later gates) |
109
+ | `GATE-NN.md` | one gate's status and definition of done | you / the planner |
110
+ | `WU-*.md` | a single work unit: frontmatter + the prompt a fresh session receives | you / `draft-feature` / `plan-next` |
111
+
112
+ Then create the branch named in `PLAN.md`'s frontmatter (`branch:`).
113
+
114
+ ## 4. Validate before running
115
+
116
+ ```bash
117
+ specfuse-lint .specfuse/features/FEAT-YYYY-NNNN-your-feature
118
+ ```
119
+
120
+ The linter checks structure: every WU has the five mandatory sections, the closing
121
+ sequence is present and well-formed, dependencies resolve, IDs are well-formed.
122
+ Fix anything it flags before dispatching — it's far cheaper than a failed
123
+ dispatch.
124
+
125
+ ## 5. Dry-run, then run
126
+
127
+ ```bash
128
+ specfuse-loop --dry-run # show the gate walked, in dep order, no dispatch
129
+ specfuse-loop # the real thing
130
+ ```
131
+
132
+ With no `--feature` flag the driver picks the single `active` feature. For each
133
+ ready work unit it:
134
+
135
+ 1. marks the WU `in_progress`,
136
+ 2. dispatches a **fresh** `claude -p` session with that unit's model and prompt,
137
+ 3. runs the unit's verification **itself** as the exit oracle,
138
+ 4. on pass, makes **one squashed commit** carrying the `Feature: FEAT-.../TNN`
139
+ trailer.
140
+
141
+ A failed gate is discarded and re-dispatched to a fresh session carrying the
142
+ failure evidence, up to three attempts, then the unit is escalated to
143
+ `blocked_human` and the gate halts.
144
+
145
+ > **One driver per working tree.** The driver holds an exclusive lock on
146
+ > `.specfuse/.loop.lock`. A second driver on the same checkout exits immediately.
147
+ > To run two features at once, use separate `git worktree` checkouts. `--dry-run`
148
+ > is exempt.
149
+
150
+ ## 6. The gate boundary — where you come back in
151
+
152
+ A gate ends with a **closing sequence** that runs automatically: it writes a
153
+ retrospective, promotes durable lessons to `LEARNINGS.md`, reconciles docs, and —
154
+ crucially — **drafts the next gate's work units** (as `draft`) so the next gate is
155
+ waiting for you to review.
156
+
157
+ Two things can happen at the boundary:
158
+
159
+ - **The gate auto-closes.** On a clean, on-plan gate the deterministic predicate
160
+ (`gate_eval.py`) closes it without a reflective session — but `plan-next` still
161
+ drafts the next gate, so the human review step still fires
162
+ ([methodology §3](methodology.md)).
163
+ - **The driver halts with `awaiting_review`.** The next gate's WUs are in `draft`
164
+ and the driver will refuse to execute them until you arm them. **Arming is the
165
+ human checkpoint and is deliberately not automated.**
166
+
167
+ Run **`/arm-gate`**. It walks each drafted WU — accept / revise / reject — flips
168
+ the ones you accept to `pending`, marks the finished gate `passed`, and prints the
169
+ resume command. Read the `GATE-NN-REVIEW.md` the planner wrote first: it's
170
+ weighted toward where the planner was *least* certain.
171
+
172
+ Then re-run `specfuse-loop`. Repeat until the terminal gate is `done`.
173
+
174
+ ## 7. Wrap up
175
+
176
+ When the terminal gate is `done`, run **`/wrap-feature`**: it pushes the feature
177
+ branch, opens a PR, optionally watches CI, and points at the next pick. Then
178
+ **`/roadmap-archive`** moves the finished feature's detail out of the active
179
+ roadmap.
180
+
181
+ ---
182
+
183
+ ## Operating a running loop
184
+
185
+ The driver runs unattended within a gate, but real runs hit snags. The map:
186
+
187
+ | Symptom | What it means | Do this |
188
+ |---------|---------------|---------|
189
+ | Driver halts, a WU is `blocked_human` | A unit failed three attempts or hit an escalation trigger | Run **`/gate-status`** for a diagnosis (root cause, options, recommended action) |
190
+ | You fixed the blocker (creds, dep, spec) | The WU is still `blocked_human` | Run **`/unblock-wu`** to re-arm it (`blocked_human → pending`, attempts reset), then re-run |
191
+ | Driver exits "could not acquire lock" | Another driver owns this checkout | Find/stop the other driver, or use a separate `git worktree` |
192
+ | A gate is `awaiting_review` | Normal gate boundary | Run **`/arm-gate`** (§6) |
193
+ | The feature isn't worth finishing | — | Run **`/abandon-feature`** — flips every WU/gate/PLAN/roadmap surface cleanly |
194
+ | A WU "passed" but wrote no code | Hollow pass | Tighten the WU's acceptance criteria and verification; see [`authoring-work-units`](skills.md) |
195
+
196
+ **Where the durable state lives** (nothing important is in a context window):
197
+
198
+ - `PLAN.md` / `GATE-NN.md` / `WU-*.md` frontmatter — current status of everything.
199
+ - `events.jsonl` (per feature) — the event log; every dispatch emits an
200
+ `attempt_outcome`.
201
+ - `RETROSPECTIVE.md` — feature-local raw observations from each close.
202
+ - `LEARNINGS.md` (repo root of `.specfuse/`) — cross-feature durable lessons, read
203
+ at planning time so each plan is better than the last. Run
204
+ **`/learnings-suggest`** periodically to mine recurring failures into new
205
+ entries.
206
+
207
+ When in doubt after a halt, start with **`/gate-status`** — it reads all of the
208
+ above and tells you where you stand.
209
+
210
+ ## Fixing a bug (not a feature)
211
+
212
+ Bugs don't go through the feature methodology. Run **`/fix-bug`** with the issue
213
+ number or report: it's 1 bug = 1 branch = 1 PR, test-first. It refuses and
214
+ proposes promoting to a feature if the work turns out large or risky.
215
+
216
+ ## Next
217
+
218
+ - [`methodology.md`](methodology.md) — the full gate-cycle contract.
219
+ - [`skills.md`](skills.md) — every skill, by lifecycle phase.
220
+ - [`concepts/ralph-lineage.md`](concepts/ralph-lineage.md) — why the loop is
221
+ shaped the way it is.