theslopmachine 1.0.22 → 1.0.24

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.
package/MANUAL.md CHANGED
@@ -15,30 +15,36 @@ The installer copies OpenCode agents to `~/.config/opencode/agents`, Claude asse
15
15
  ## Initialize A Task
16
16
 
17
17
  ```sh
18
- slopmachine init /path/to/task-root
18
+ slopmachine init <github-url>
19
19
  ```
20
20
 
21
- The initialized root is intentionally sparse and packaging-friendly. Product code belongs in `repo/`; product-facing docs belong in `docs/`; final kept reports belong in `.tmp/`; project facts belong in `metadata.json`.
21
+ Run init from an empty workflow root. The GitHub repository name becomes the task root directory name. For example, `slopmachine init https://github.com/example/t178.git` clones into `./t178/`.
22
22
 
23
- Use `--claude` for `slopmachine-claude` runs:
23
+ The cloned task root must already contain the task-facing structure: product code in `repo/`, product-facing docs in `docs/`, final kept reports in `.tmp/`, and project facts in `metadata.json`. SlopMachine creates workflow-private state in sibling `./.ai` and `./.beads` directories.
24
+
25
+ Init relies on normal git authentication. If the repository is private and local git cannot access it, clone fails.
26
+
27
+ SlopMachine no longer seeds developer-facing docs, API spec placeholders, product README content, `AGENTS.md`, or `.claude/settings.json`. It only writes the allowed task-root `CLAUDE.md` rulebook.
28
+
29
+ Use `-o` to open OpenCode after bootstrap:
24
30
 
25
31
  ```sh
26
- slopmachine init --claude /path/to/task-root
32
+ slopmachine init https://github.com/example/t178.git -o
27
33
  ```
28
34
 
29
- The active developer rulebook is recorded in `../.ai/metadata.json` as `developer_rulebook_file`. The unused rulebook is removed from the task folder.
35
+ The active developer rulebook is recorded in `../.ai/metadata.json` as `developer_rulebook_file`.
30
36
 
31
37
  ## Continue From A Phase Alias
32
38
 
33
39
  ```sh
34
- slopmachine init --continue-from P5 /path/to/task-root
40
+ slopmachine init <github-url> --continue-from P5
35
41
  ```
36
42
 
37
43
  Legacy aliases remain accepted for CLI compatibility, but owner-facing language uses Phase 1 through Phase 8.
38
44
 
39
45
  ## Developer Rulebooks
40
46
 
41
- OpenCode developer agents read `AGENTS.md`. Claude developer agents read `CLAUDE.md`. Only the selected rulebook is seeded into a task root. These files are product engineering rulebooks, not owner workflow instructions.
47
+ Claude developer lanes read `CLAUDE.md`. SlopMachine seeds only this product engineering rulebook into the task root; it is not an owner workflow instruction file.
42
48
 
43
49
  ## Verification
44
50
 
package/README.md CHANGED
@@ -27,12 +27,11 @@ slopmachine install
27
27
  ```sh
28
28
  slopmachine --help
29
29
  slopmachine install
30
- slopmachine init <target-dir>
31
- slopmachine init --claude <target-dir>
30
+ slopmachine init <github-url>
32
31
  slopmachine set-token
33
32
  ```
34
33
 
35
- Use `slopmachine init` to create or adopt a task root. By default it seeds `AGENTS.md` for OpenCode developer lanes. Use `slopmachine init --claude` to seed `CLAUDE.md` and `.claude/` for script-managed Claude Code lanes. The unused rulebook is not left in the task folder, and `../.ai/metadata.json` records the active `developer_rulebook_file`.
34
+ Use `slopmachine init <github-url>` from an empty workflow root. The CLI clones the GitHub repository into `./<repo-name>/`, uses that cloned folder as the task root, creates workflow-private state under `./.ai` and `./.beads`, and records the repo name as `task_root` and `run_id`. The cloned task root is expected to contain the task-facing `docs/`, `.tmp/`, `metadata.json`, and `repo/` structure. SlopMachine no longer seeds developer-facing docs or product README content; it only writes the allowed task-root `CLAUDE.md` rulebook.
36
35
 
37
36
  ## Phase Map
38
37
 
@@ -69,4 +68,4 @@ npm run check
69
68
 
70
69
  ## Developer-Facing Boundaries
71
70
 
72
- Developer-facing prompts and rulebooks avoid owner workflow mechanics. They focus on good engineering practice: read the code, follow `AGENTS.md` or `CLAUDE.md`, implement real behavior, keep README claims honest, test meaningful behavior, avoid secrets, do not run Docker or `run_tests.sh` unless asked, and provide proof for completed work.
71
+ Developer-facing prompts and the task-root `CLAUDE.md` rulebook avoid owner workflow mechanics. They focus on good engineering practice: read the code, implement real behavior, keep README claims honest, test meaningful behavior, avoid secrets, do not run Docker or `run_tests.sh` unless asked, and provide proof for completed work.
package/RELEASE.md CHANGED
@@ -5,6 +5,6 @@
5
5
  - Preserves the reference CLI/package behavior.
6
6
  - Rebuilds owner agents around Phase 1 through Phase 8 terminology.
7
7
  - Adds generic developer prompts for OpenCode and Claude.
8
- - Adds task-root `AGENTS.md` and `CLAUDE.md` templates focused on product engineering practice.
8
+ - Seeds only the task-root `CLAUDE.md` rulebook; developer-facing docs and product README content come from the cloned task repository and implementation lane work.
9
9
  - Includes Claude-specific worker skills and all required slopmachine utility scripts.
10
10
  - Keeps legacy `P*` phase aliases for CLI compatibility.
@@ -108,6 +108,8 @@ Good Claude-message style:
108
108
 
109
109
  ## Owner Direct Fixes And Developer Awareness
110
110
 
111
+ The owner may directly make small safe edits to existing docs, config, wrappers, cleanup, and light glue when the change does not require product-design judgment, broad debugging, new product behavior, or new tests. Inside `./repo`, owner-side edits are limited to existing configuration, Docker files, test wrappers, run scripts, verification scripts, cleanup scripts, and similarly narrow glue. The owner must never create a new file anywhere under `./repo`. New product files, meaningful implementation work, new tests, behavioral changes, and larger fixes must go to the active Claude lane.
112
+
111
113
  When the owner makes direct edits to the task directory (README, config, scripts, docs, glue code, cleanup), the active Claude lane (develop-1, bugfix-1, or test-coverage-1) must always be informed of what changed. Batching is required: make a group of fixes, batch them together, then inform the lane once. Do not notify the lane turn by turn for every small edit.
112
114
 
113
115
  This rule applies strictly to the persistent implementation lanes — develop-1, bugfix-1, and test-coverage-1. It does not apply to evaluator sessions, clarification workers, faithfulness reviewers, planning subagents, or other temporary owner-side sessions.
@@ -148,7 +150,7 @@ Example: `I made a few edits to the README for the startup docs and fixed a conf
148
150
  - Never use `task` with `developer`, `implement`, `helper`, maintenance, or ad hoc coding subagents for product implementation, product bugfixes, product test authoring, product docs authored by the implementation lane, or implementation verification guidance. Those must go through live Claude lanes using the packaged Claude utilities.
149
151
  - Do not use OpenCode subagents, local edits, raw `claude` commands, manual tmux typing, or untracked helper scripts as a substitute for Claude live-lane implementation. The only normal interaction path with Claude lanes is `claude_live_launch.mjs`, `claude_live_turn.mjs`, `claude_live_status.mjs`, and `claude_live_stop.mjs`.
150
152
  - Use `question` only for material user decisions that cannot be resolved by a prompt-faithful default.
151
- - Use `edit`/`write` only for owner-side workflow files, reports, and tiny safe owner fixes that do not substitute for Claude implementation work. The owner may directly make small safe edits to docs, config, wrappers, cleanup, and light glue when the change does not require product-design judgment, broad debugging, new product behavior, or new tests. The owner must not create new files under `./repo`; new product files, meaningful implementation work, and larger fixes must go to the active Claude lane. Do not edit installed packaged prompt assets; those must always be read fresh and pasted verbatim under the non-negotiable verbatim prompt paste rule at the top of this file. If a tiny owner fix touches product code/docs, notify the active Claude lane and ask it to inspect/acknowledge before continuing.
153
+ - Use `edit`/`write` only for owner-side workflow files, reports, and tiny safe owner fixes that do not substitute for Claude implementation work. Inside `./repo`, owner-side edits are limited to existing configuration, Docker files, test wrappers, run scripts, verification scripts, cleanup scripts, and similarly narrow glue. The owner must never create a new file anywhere under `./repo`; new product files, meaningful implementation work, new tests, behavioral changes, and larger fixes must go to the active Claude lane. Do not edit installed packaged prompt assets; those must always be read fresh and pasted verbatim under the non-negotiable verbatim prompt paste rule at the top of this file. If a tiny owner fix touches product code/docs, notify the active Claude lane and ask it to inspect/acknowledge before continuing.
152
154
  - Use `todowrite` for substantial multi-step owner work when tracking improves reliability.
153
155
  - Use Context7/Exa only when current documentation or external facts are needed.
154
156
 
@@ -228,7 +230,7 @@ Use these sequential names as the canonical workflow model. Legacy `P*` names ar
228
230
 
229
231
  - Required skills: `beads-operations`, `developer-session-lifecycle`, `claude-worker-management`, `planning-guidance`, `planning-gate`, `owner-evidence-discipline`, and `report-output-discipline` when reports are long or reusable.
230
232
  - Establish or resume the primary Claude lane and start design/planning.
231
- - Follow the deterministic planning sequence in `planning-guidance` exactly: (1) send original prompt with only "don't write code yet" appended, (2) after acknowledgement send clarifications, (3) after acknowledgement send the design prompt verbatim.
233
+ - Follow the deterministic planning sequence in `planning-guidance` exactly: (1) send original prompt with only the required planning/placeholder sentences appended, (2) after acknowledgement send clarifications, (3) after acknowledgement send the design prompt verbatim.
232
234
  - Delegate owner-private `../.ai/plan.md` creation to a general owner-side subagent. Read the installed `~/slopmachine/phase-2-execution-planning-prompt.md` and `~/slopmachine/phase-2-plan-template.md` fresh. Paste both bodies verbatim into the subagent message.
233
235
  - Record lane/session and artifact decisions in metadata and Beads.
234
236
  - Exit only when `planning-gate` is satisfied.
@@ -108,7 +108,7 @@ Good worker-message style:
108
108
 
109
109
  ## Owner Direct Fixes And Developer Awareness
110
110
 
111
- The owner may directly make small safe edits to docs, config, wrappers, cleanup, and light glue when the change does not require product-design judgment, broad debugging, new product behavior, or new tests. The owner must not create new files under `./repo`; new product files, meaningful implementation work, and larger fixes must go to the active developer/bugfix/test-coverage lane.
111
+ The owner may directly make small safe edits to existing docs, config, wrappers, cleanup, and light glue when the change does not require product-design judgment, broad debugging, new product behavior, or new tests. Inside `./repo`, owner-side edits are limited to existing configuration, Docker files, test wrappers, run scripts, verification scripts, cleanup scripts, and similarly narrow glue. The owner must never create a new file anywhere under `./repo`. New product files, meaningful implementation work, new tests, behavioral changes, and larger fixes must go to the active developer/bugfix/test-coverage lane.
112
112
 
113
113
  When the owner makes direct edits to the task directory (README, config, scripts, docs, glue code, cleanup), the active developer/bugfix/test-coverage lane must always be informed of what changed. Batching is required: make a group of fixes, batch them together, then inform the lane once. Do not notify the lane turn by turn for every small edit.
114
114
 
@@ -149,7 +149,7 @@ Example: `I made a few edits to the README for the startup docs and fixed a conf
149
149
  - Do not use `implement`, `helper`, maintenance, or extra ad hoc subagents for product implementation unless the user explicitly asks. Keep implementation in the tracked active developer session except for evaluator-isolated work or a recorded recovery/context reason.
150
150
  - Use `question` only for material user decisions that cannot be resolved by a prompt-faithful default.
151
151
  - Use `bash` for git, package managers, tests, Docker, CLIs, runtime checks, and artifact commands.
152
- - Use `edit`/`write` for owner-side workflow files, tiny safe fixes, and reports. Do not edit installed packaged prompt assets; those must always be read fresh and pasted verbatim under the non-negotiable verbatim prompt paste rule at the top of this file.
152
+ - Use `edit`/`write` for owner-side workflow files, reports, and tiny safe edits to existing docs/config/wrappers/scripts/glue. Inside `./repo`, never use owner-side editing to create new files; new repo files must be created by the active developer/bugfix/test-coverage lane. Do not edit installed packaged prompt assets; those must always be read fresh and pasted verbatim under the non-negotiable verbatim prompt paste rule at the top of this file.
153
153
  - Use `todowrite` for substantial multi-step owner work when tracking improves reliability.
154
154
  - Use Context7/Exa only when current documentation or external facts are needed.
155
155
 
@@ -197,7 +197,7 @@ Use these sequential names as the canonical workflow model. Legacy `P*` names ar
197
197
 
198
198
  - Required skills: `beads-operations`, `developer-session-lifecycle`, `planning-guidance`, `planning-gate`, `owner-evidence-discipline`, and `report-output-discipline` when reports are long or reusable.
199
199
  - Establish or resume the primary developer session and start design/planning.
200
- - Follow the deterministic planning sequence in `planning-guidance` exactly: (1) send original prompt with only "don't write code yet" appended, (2) after acknowledgement send clarifications, (3) after acknowledgement send the design prompt verbatim.
200
+ - Follow the deterministic planning sequence in `planning-guidance` exactly: (1) send original prompt with only the required planning/placeholder sentences appended, (2) after acknowledgement send clarifications, (3) after acknowledgement send the design prompt verbatim.
201
201
  - Delegate owner-private `../.ai/plan.md` creation to a general owner-side subagent. Read the installed `~/slopmachine/phase-2-execution-planning-prompt.md` and `~/slopmachine/phase-2-plan-template.md` fresh. Paste both bodies verbatim into the subagent message.
202
202
  - Record session and artifact decisions in metadata and Beads.
203
203
  - Exit only when `planning-gate` is satisfied.
@@ -272,7 +272,19 @@ def main():
272
272
  beads = read_beads(project_path)
273
273
  ai_data = read_ai_metadata(project_path)
274
274
  task_dir = project_path if os.path.isdir(os.path.join(project_path, "docs")) \
275
- else os.path.join(project_path, "task")
275
+ else None
276
+ if not task_dir:
277
+ ai_meta = os.path.join(project_path, ".ai", "metadata.json")
278
+ if os.path.isfile(ai_meta):
279
+ with open(ai_meta) as f:
280
+ ai_data = json.load(f)
281
+ task_root_name = ai_data.get("task_root") if isinstance(ai_data, dict) else None
282
+ candidate = os.path.join(project_path, task_root_name)
283
+ if os.path.isdir(os.path.join(candidate, "docs")):
284
+ task_dir = candidate
285
+ if not task_dir:
286
+ print(f" Warning: could not find task root at {project_path} (no docs/ and no .ai/metadata.json with task_root)")
287
+ task_dir = project_path
276
288
  task_docs = read_task_docs(task_dir)
277
289
  audit_reports = read_audit_reports(task_dir)
278
290
  print(f" Beads: {len(beads)}, Audit reports: {len(audit_reports)}")
@@ -238,3 +238,4 @@ Implementation must:
238
238
  10. **Module isolation:** Modules built in isolation with no cross-module integration tests proving data/behavior flow between them
239
239
  11. **Skipped evaluator passes:** Fewer than 5 internal evaluator passes run in Phase 4
240
240
  12. **No browser verification before P6:** Web/fullstack projects reach P6 without any browser verification, finding crashes that should have been caught in P3 or P4
241
+ 13. **Owner-created repo files:** Owner creates new files under repo/ instead of routing file creation through the active developer lane
@@ -12,7 +12,7 @@ Use this skill for startup preflight, session policy, metadata consistency, lane
12
12
  Sessions are the primary deliverable. An incomplete or corrupted session dataset invalidates the submission regardless of code quality. Every session must be preserved, continuous, and authentic.
13
13
 
14
14
  - Do not edit, rename, restructure, rewrite, clean, delete, or fabricate session files or trajectory records. They are immutable evidence.
15
- - Do not perform untracked implementation work. Developer/Claude implementation, debugging, and substantive product fixes must happen inside a tracked implementation session. Owner orchestration, verification commands, package checks, and tiny safe owner-side docs/config/wrapper/glue fixes are allowed when recorded in metadata/Beads and the active implementation lane is notified afterward.
15
+ - Do not perform untracked implementation work. Developer/Claude implementation, debugging, and substantive product fixes must happen inside a tracked implementation session. Owner orchestration, verification commands, package checks, and tiny safe owner-side edits to existing docs/config/wrappers/scripts/glue are allowed when recorded in metadata/Beads and the active implementation lane is notified afterward. The owner must never create a new file anywhere under `./repo`; new repo files must be created by the active developer/Claude lane.
16
16
  - Sessions must progress strictly forward. Never return to a closed session. The lifecycle is:
17
17
  1. Development session → complete → stop/close
18
18
  2. Bugfix session → complete both audit cycles → close
@@ -23,7 +23,7 @@ Sessions are the primary deliverable. An incomplete or corrupted session dataset
23
23
  ## Preflight
24
24
 
25
25
  - Confirm cwd is task root `./`.
26
- - Confirm the current working directory is the task root (the directory containing `repo/`, `docs/`, and `metadata.json`). If the root is not `task/` or its equivalent, stop and reject: sessions must be started from the task root, not from inside `repo/` or any subdirectory.
26
+ - Confirm the current working directory is the task root (the directory containing `repo/`, `docs/`, and `metadata.json`). If the root does not contain these expected paths, stop and reject: sessions must be started from the task root, not from inside `repo/` or any subdirectory.
27
27
  - Confirm product repo exists at `./repo`.
28
28
  - Confirm workflow-private root exists at `../.ai`, workflow state exists at `../.ai/metadata.json`, and Beads root exists at `../.beads` when initialized.
29
29
  - Confirm task docs are limited to `./docs/questions.md`, `./docs/design.md`, and `./docs/api-spec.md` when applicable.
@@ -48,7 +48,7 @@ Sessions are the primary deliverable. An incomplete or corrupted session dataset
48
48
  - Phase 5 uses fresh evaluator sessions for full audits. Evaluator-session reuse occurs in three cases: (1) fail-regeneration — same session receives only the regeneration prompt after fixes; (2) Partial Pass fix-check — same session verifies all scoped issues are fixed; (3) Pass-with-items fix-check — same session verifies all scoped recommendations are closed.
49
49
  - Audit Cycle 1 and Audit Cycle 2 fixes go through the dedicated bugfix lane. After both audit cycles complete, the bugfix lane is closed and a new test-coverage/final-reconciliation lane takes over for coverage/README remediation.
50
50
  - Phase 6 reconciliation uses the currently active developer/Claude lane for Docker, runtime, browser, account, `run_tests.sh`, coverage, README, and final readiness fixes unless a new lane is explicitly justified by context limits or isolation risk.
51
- - If the owner directly changes docs, wrappers, config, cleanup, or light glue, send the active lane a minimal acknowledgement request that names the changed surface and asks it to inspect/confirm before readiness continues.
51
+ - If the owner directly changes existing docs, wrappers, config, cleanup, scripts, or light glue, send the active lane a minimal acknowledgement request that names the changed surface and asks it to inspect/confirm before readiness continues.
52
52
 
53
53
  ## Metadata Discipline
54
54
 
@@ -58,7 +58,7 @@ No other full-audit or fail-regeneration prompt is allowed. In particular, the o
58
58
 
59
59
  If any deviation is found from either allowed prompt send, the current audit cycle is invalid. Archive every report or candidate report generated during that invalid cycle unchanged under `../.ai/archive/`, record the restart reason in metadata and Beads, then restart that audit cycle from a fresh evaluator session using the installed asset and exact saved send packet. Do not patch, rename, or reuse invalid-cycle reports as kept reports.
60
60
 
61
- Record the installed prompt asset path, prepared prompt path, exact send packet path, evaluator session id, and report path in metadata and Beads. Treat evaluator reports as immutable once written.
61
+ Record the installed prompt asset path, prepared prompt path, exact send packet path, evaluator session id, and report path in metadata and Beads. Treat evaluator reports as immutable once written except for the narrow minor wording cleanup allowed by cycle validation below.
62
62
 
63
63
  ## Report Paths And Names
64
64
 
@@ -152,6 +152,8 @@ Run this procedure twice: once for Audit Cycle 1 and once for Audit Cycle 2.
152
152
 
153
153
  Before a cycle can close, validate the whole cycle as a hard gate. If any item fails, archive every candidate/kept/fix-check report produced in that cycle unchanged under `../.ai/archive/`, record the reason, and restart that audit cycle from a fresh evaluator session using the non-negotiable full-audit prompt block.
154
154
 
155
+ Exception: if the only issue is minor wording that does not change findings, verdict, severity, evidence, scoped issue identity, fix status, or report meaning, the owner may patch that wording directly in the kept report or fix-check report instead of restarting the cycle. Record the exact wording cleanup, file path, and reason in metadata and Beads. Do not use this exception to alter verdicts, remove real findings, add missing fix evidence, repair a mismatched issue list, or hide a materially invalid regeneration/fix-check.
156
+
155
157
  Required for each cycle:
156
158
  - the installed evaluation prompt asset path is recorded and matches the project type;
157
159
  - the exact saved send packet path is recorded;
@@ -160,8 +162,10 @@ Required for each cycle:
160
162
  - the kept audit report exists at `./.tmp/audit_report-<N>.md`;
161
163
  - the kept audit report is rich and complete: at least 150 lines and not materially shallower than the installed prompt's required output structure;
162
164
  - the kept audit report includes the required verdict, scope/boundary, prompt/repository mapping, section review or blocker/high panel as applicable, issues/suggestions or explicit no-issue statement, security/data-risk review where applicable, and test/logging/coverage sections required by the installed prompt;
165
+ - the kept audit report has no language that reveals or implies it is a regeneration, rerun, continuation, post-fix report, or comparison against an earlier audit. Forbidden examples include: `regenerated`, `regeneration`, `rerun`, `previous audit`, `previous report`, `prior audit`, `after fixes`, `after the fixes`, `fixed since`, `remaining`, `still`, `now fixed`, `resolved`, `no longer`, `left`, `updated verdict`, or equivalent wording that exposes audit history. If this language is only incidental wording and does not affect findings or meaning, patch it and record the cleanup. If the report is continuation-shaped, fix-oriented, or materially depends on prior audit history, archive and restart the cycle;
163
166
  - the cycle fix-check report exists at `./.tmp/audit_report-<N>-fix_check.md`;
164
167
  - the cycle fix-check report confirms every issue/recommendation/caveat/suggestion/action item/requested change from the kept audit report is fixed, or explicitly confirms the kept audit report had zero scoped items to close;
168
+ - the scoped issue list in the fix-check exactly matches the scoped issue list from the corresponding kept audit report. Every kept-audit issue/recommendation/caveat/suggestion/action item/requested change must appear in the fix-check with a fixed status and evidence, and the fix-check must not silently drop, merge beyond recognition, rename into a different issue, or add unrelated new audit issues. If the lists do not match, the cycle is invalid and must restart unless the mismatch is only a harmless wording/label discrepancy that can be patched without changing issue identity, fix status, evidence, or meaning;
165
169
  - the fix-check report does not perform a broader new audit and does not use history-exposing comparison language.
166
170
 
167
171
  No audit cycle is complete without both `./.tmp/audit_report-<N>.md` and `./.tmp/audit_report-<N>-fix_check.md` passing this validation gate.
@@ -74,7 +74,7 @@ If any final runtime, test, browser, account, or platform check cannot run, read
74
74
 
75
75
  ## Owner Direct Fixes
76
76
 
77
- - The owner may directly fix only minor, safe docs, wrapper, config, cleanup, or light glue issues when the change does not require product-design judgment, new tests, behavioral changes, or non-trivial debugging.
77
+ - The owner may directly fix only minor, safe existing docs, wrapper, config, cleanup, run-script, verification-script, or light glue issues when the change does not require product-design judgment, new tests, behavioral changes, or non-trivial debugging. The owner must never create a new file anywhere under `./repo`; any new repo file must be created by the active developer/Claude lane.
78
78
  - If the reconciliation issue is large enough to need real implementation work, meaningful test updates, runtime debugging, README/runtime restructuring, or product judgment, do not fix it owner-side. Send it to the currently active developer/Claude lane.
79
79
  - Batch multiple direct fixes into a group, then inform the lane once. Do not notify turn by turn for every small edit. After all fixes in the batch are complete, send a single note describing all changed surfaces and ask the lane to inspect and acknowledge.
80
80
  - The note should be concise and developer-facing, not a workflow report.
@@ -22,7 +22,7 @@ Phase 2 establishes the primary developer session and produces the accepted plan
22
22
  - Accepted `./docs/questions.md`.
23
23
  - Accepted `../.ai/requirements-breakdown.md`.
24
24
  - Accepted `../.ai/clarification-faithfulness-review.md`.
25
- - Packaged design prompt and design template.
25
+ - Packaged design prompt.
26
26
  - Packaged execution planning prompt and plan template.
27
27
 
28
28
  ## Deterministic Planning Sequence (Must Follow Exactly)
@@ -31,10 +31,11 @@ This sequence is strict. Do not combine, reorder, skip, or batch these steps. Ea
31
31
 
32
32
  ### Step 1: Send Original Prompt
33
33
 
34
- Send the original product prompt from `./metadata.json` exactly as-is. No prefix, no introduction, no context, no clarifications. Append only this exact sentence at the end:
34
+ Send the original product prompt from `./metadata.json` exactly as-is. No prefix, no introduction, no context, no clarifications. Append only these exact sentences at the end:
35
35
 
36
36
  ```
37
37
  Don't write code yet — we'll plan this first.
38
+ This folder may contain placeholder docs or repo content from the starting skeleton; please inspect it and remove or replace unrelated placeholder material as we go.
38
39
  ```
39
40
 
40
41
  That is the entire message. Wait for the developer to acknowledge before proceeding.
@@ -53,7 +54,7 @@ Wait for the developer to acknowledge before proceeding.
53
54
 
54
55
  ### Step 3: Send Design Prompt
55
56
 
56
- After the developer acknowledges the clarifications, read the installed `~/slopmachine/phase-1-design-prompt.md` fresh from its asset path and paste its full body verbatim under the non-negotiable verbatim prompt paste rule. The design prompt references the context already provided in Steps 1 and 2 and the template already seeded at `./docs/design.md`. Do not paste the template file body — it is already in the workspace.
57
+ After the developer acknowledges the clarifications, read the installed `~/slopmachine/phase-1-design-prompt.md` fresh from its asset path and paste its full body verbatim under the non-negotiable verbatim prompt paste rule. The design prompt references the context already provided in Steps 1 and 2 and tells the lane what design surfaces to cover because `./docs/design.md` may be missing or placeholder-only.
57
58
 
58
59
  The design must:
59
60
  - be a true product/system design, not an execution plan
@@ -72,7 +73,9 @@ Patch small wording/traceability issues directly when meaning is unchanged. Send
72
73
 
73
74
  ### Step 5: Create `./docs/api-spec.md` When Applicable
74
75
 
75
- Use the accepted design as input. Require exact endpoint/interface contracts where APIs exist. If no meaningful API exists, mark `./docs/api-spec.md` as not applicable with a short reason. Record the API spec artifact path and applicability decision in metadata and Beads.
76
+ Use the accepted design as input. Require exact endpoint/interface contracts where APIs exist. If `./docs/api-spec.md` is missing or placeholder-only, the implementation lane must create or replace it. If no meaningful API exists, mark `./docs/api-spec.md` as not applicable with a short reason. Record the API spec artifact path and applicability decision in metadata and Beads.
77
+
78
+ The API spec prompt must ask for, where applicable: endpoint/interface name, purpose, actor/consumer, method/path or call signature, auth and permission model, request fields, response fields, validation rules, success status/result, important error cases, persistence/side effects, frontend or job consumers, and required API/integration tests. Do not provide endpoint conclusions that the design has not established; ask the lane to derive exact contracts from the accepted design and codebase context.
76
79
 
77
80
  ### Step 6: Owner Reviews Design and API Spec Together
78
81
 
@@ -39,7 +39,13 @@ Use casual, direct language. Example:
39
39
  ```text
40
40
  Let's start with the scaffold. Set up the base project in ./repo for the stack described in docs/design.md. Keep this to the framework, runtime, tests, and README foundation with a minimal proof page or endpoint. Do not add product-specific business logic yet.
41
41
 
42
+ The cloned folder may contain placeholder docs, README text, scripts, or config. Remove or replace unrelated placeholder content instead of preserving it.
43
+
42
44
  The scaffold needs a working docker-compose.yml with a profile-gated test service, a run_tests.sh that runs the full test suite through Docker, a separate stack-native local test harness for fast implementation-time checks, a unit_tests directory for unit tests, an API_tests directory for API and integration HTTP tests, and a README baseline with startup, access, verification, and test commands. Make sure the local harness is separate from the Docker test path. The local harness is for fast iteration. run_tests.sh is the broad dockerized verification wrapper for later.
45
+
46
+ The README needs to be enough for a reviewer to run and verify the project later: project type near the top, what the repo delivers, stack, repo layout, primary startup/access command, legacy docker-compose compatibility string when Docker Compose is used, verification method, auth/demo credentials or "No authentication required", seeded data or empty-state note, mock/local/debug disclosures, known limitations, and the Dockerized ./run_tests.sh contract. Do not leave template placeholders in README.
47
+
48
+ The run_tests.sh and Docker config must be real, not placeholders: run_tests.sh should execute the broad Docker-contained test path, docker-compose.yml should include the app services needed for runtime and a profile-gated test service, and the local test harness should remain separate for fast implementation-time checks.
43
49
  ```
44
50
 
45
51
  Adjust the exact wording to the project. Do not over-format the message.
@@ -11,8 +11,8 @@ Packaging is a final-delivery contract, not a reporting exercise. Do not close P
11
11
 
12
12
  ## Package Boundary
13
13
 
14
- - Package root is `task/`.
15
- - Product repo is `task/repo`.
14
+ - Package root is the task root directory (named by the task-id from `../.ai/metadata.json`'s `task_root` field).
15
+ - Product repo is `<task-root>/repo`.
16
16
  - Workflow-private state remains outside package under `../.ai`, `../.beads`, and `../claude-sessions.zip`.
17
17
  - Do not package workflow-private state as product files.
18
18
  - The final task-root package allowlist is `docs/`, `repo/`, `.tmp/`, `metadata.json`, plus explicit VCS/validation exceptions.
@@ -81,7 +81,7 @@ Do not run broad Docker prune commands that can affect unrelated projects.
81
81
  ## Session Export
82
82
 
83
83
  - Export tracked developer sessions before closing packaging.
84
- - Claude-backed lanes produce `../claude-sessions.zip` as a sibling handoff artifact, not as a product file under `task/`.
84
+ - Claude-backed lanes produce `../claude-sessions.zip` as a sibling handoff artifact, not as a product file under the task root.
85
85
  - Use packaged session export utilities when available and preserve prompt-anchored session provenance.
86
86
  - Verify exported session content is anchored to the original prompt from `./metadata.json` strongly enough to support package lineage.
87
87
  - Do not manually edit, rewrite, fabricate, rename, clean, delete, or restructure raw session/trajectory files to make the package look cleaner. Only use packaged export/normalization utilities that preserve provenance.
@@ -1,6 +1,6 @@
1
1
  You are helping create the product/system design for a software project.
2
2
 
3
- The original prompt, stack and context, accepted clarifications, and accepted requirements have already been provided in the previous steps. The design template is already seeded at ./docs/design.md.
3
+ The original prompt, stack and context, accepted clarifications, and accepted requirements have already been provided in the previous steps. The task root may contain placeholder docs from the cloned starting repository; inspect them, keep only relevant true information, and replace unrelated placeholder content.
4
4
 
5
5
  Your task is to write `./docs/design.md`.
6
6
 
@@ -10,6 +10,22 @@ This is planning/design work only. Do not write implementation code.
10
10
 
11
11
  Produce a design document that is faithful to the original prompt and accepted clarifications. The design should be specific enough to guide implementation, but it must not become a step-by-step execution checklist.
12
12
 
13
+ ## Expected Shape
14
+
15
+ Use clear sections that cover these surfaces where applicable:
16
+ - project overview: project type, delivery shape, business objective, success outcome, and stack summary
17
+ - prompt and clarification alignment: accepted requirements, accepted clarifications, safe assumptions, and explicit non-goals that do not narrow the prompt
18
+ - actors, roles, permissions, and the main user/system flows
19
+ - module design: purpose, owned behavior, UI/API/job surfaces, data ownership, failure/security cases, and required test surfaces
20
+ - data design: entities/objects, lifecycle rules, visibility, and access rules
21
+ - UI or interaction design, or a brief not-applicable reason
22
+ - API or interface design, including whether `./docs/api-spec.md` is required
23
+ - security and privacy design: auth, authorization, object isolation, sensitive data, logging/redaction, debug/admin protection, file/path safety, and abuse prevention where relevant
24
+ - runtime and configuration design: runtime model, configuration model, persistence, seed/demo data, external integrations, and README startup/access/auth expectations
25
+ - verification strategy: unit, API/integration, E2E/platform, frontend component, frontend-to-backend, README/runtime, Docker, and known proof boundaries
26
+ - API spec handoff: whether a separate API spec is required and which API/interface families it must cover
27
+ - remaining design risks that still need a decision
28
+
13
29
  ## Required Design Qualities
14
30
 
15
31
  The design must:
@@ -39,6 +55,6 @@ The design should define what the system must be and how its major parts fit tog
39
55
 
40
56
  ## Output
41
57
 
42
- Write the completed design to `./docs/design.md` using the template already seeded at that path. If a section is not applicable, keep it brief and explain why.
58
+ Write the completed design to `./docs/design.md`. If a placeholder file already exists there, replace unrelated placeholder content rather than preserving it. If a section is not applicable, keep it brief and explain why.
43
59
 
44
60
  If the project has meaningful APIs or interface contracts, say that `./docs/api-spec.md` should be completed next and summarize the API families that need specification.
@@ -13,7 +13,7 @@ The current type-check gate covers the Claude/session tooling family because the
13
13
 
14
14
  ## Path Model
15
15
 
16
- - `--task-root` means the workflow task root, usually `<workflow-root>/task`.
16
+ - `--task-root` means the workflow task root directory (named by the task-id from `../.ai/metadata.json`'s `task_root` field).
17
17
  - Product code lives under `<task-root>/repo`.
18
18
  - Workflow-private state lives outside task root under `<workflow-root>/.ai` and `<workflow-root>/.beads`.
19
19
  - Claude project lookup uses the task root because Claude transcripts are keyed by the working directory used to launch Claude.
@@ -115,10 +115,10 @@ Required:
115
115
  - `--task-root <task-root>`
116
116
 
117
117
  Important options:
118
- - `--output <zip-path>` writes the zip to a custom path; default is `<task-root>/claude-sessions.zip`
118
+ - `--output <zip-path>` writes the zip to a custom path; default is `<workflow-root>/claude-sessions.zip`
119
119
  - `--label <text>` adds reporting context
120
120
 
121
- The helper copies the Claude project/session directory as-is, removes `.DS_Store` files and top-level `.jsonl` transcripts under 25KB from the staged copy, zips the folder contents directly, and writes a single zip. It does not normalize or rewrite transcript files.
121
+ The helper copies the Claude project/session directory as-is into a temp directory, removes `.DS_Store` files and top-level `.jsonl` transcripts under 25KB from the staged copy, zips the whole copied folder, and writes a single zip. It does not normalize or rewrite transcript files.
122
122
 
123
123
  ### `analyze_claude_project_dir.mjs`
124
124
 
@@ -18,7 +18,7 @@ Required:
18
18
  --task-root <task-root>
19
19
 
20
20
  Options:
21
- --output <zip-path> Zip output path (default: <task-root>/claude-sessions.zip)
21
+ --output <zip-path> Zip output path (default: <workflow-root>/claude-sessions.zip)
22
22
  --label <text> Optional package label for reporting
23
23
  `)
24
24
  }
@@ -168,7 +168,7 @@ try {
168
168
  }
169
169
 
170
170
  const sourceProjectDir = await resolveClaudeProjectDir(taskRoot)
171
- const outputPath = argv.output ? path.resolve(argv.output) : path.join(taskRoot, 'claude-sessions.zip')
171
+ const outputPath = argv.output ? path.resolve(argv.output) : path.join(path.dirname(taskRoot), 'claude-sessions.zip')
172
172
  const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'slopmachine-claude-project-'))
173
173
  const packageRoot = path.join(tempRoot, path.basename(sourceProjectDir))
174
174
 
@@ -177,7 +177,7 @@ try {
177
177
  await removeDsStoreFiles(packageRoot)
178
178
  const tinyRootTranscriptsRemoved = await removeTinyRootTranscripts(packageRoot)
179
179
  const included = (await listFilesRecursive(packageRoot)).sort((left, right) => left.localeCompare(right))
180
- await createZipArchive(packageRoot, outputPath)
180
+ await createZipArchive(tempRoot, outputPath)
181
181
 
182
182
  emitSuccess(path.basename(sourceProjectDir), {
183
183
  output: outputPath,
@@ -185,7 +185,7 @@ try {
185
185
  label: argv.label || null,
186
186
  included,
187
187
  tiny_root_transcripts_removed: tinyRootTranscriptsRemoved,
188
- packaging_mode: 'raw_claude_project_dir',
188
+ packaging_mode: 'raw_claude_project_dir_folder',
189
189
  })
190
190
  } finally {
191
191
  await fs.rm(tempRoot, { recursive: true, force: true }).catch(() => {})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "theslopmachine",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "SlopMachine installer and project bootstrap CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/cli.js CHANGED
@@ -10,7 +10,7 @@ function printHelp() {
10
10
  Commands:
11
11
  setup Configure slopmachine in the local user environment
12
12
  upgrade Install slopmachine@latest globally and rerun setup
13
- init Bootstrap a workspace (--claude seeds CLAUDE.md, --opencode seeds AGENTS.md, --adopt wraps existing project, -o opens OpenCode)
13
+ init <github-url> Clone a task repository into the current workflow root and bootstrap workflow state (-o opens OpenCode)
14
14
  cleanup Remove/archive obsolete installed agents, skills, and assets (--dry-run previews)
15
15
  set-token Store the upload token in machine config
16
16
  send-data Upload workflow artifacts to Supabase
package/src/constants.js CHANGED
@@ -44,12 +44,10 @@ export const REQUIRED_SLOPMACHINE_FILES = [
44
44
  "clarifier-agent-prompt.md",
45
45
  "clarification-faithfulness-review-prompt.md",
46
46
  "phase-1-design-prompt.md",
47
- "phase-1-design-template.md",
48
47
  "phase-2-execution-planning-prompt.md",
49
48
  "phase-2-plan-template.md",
50
49
  "test-coverage-prompt.md",
51
50
  "owner-verification-checklist.md",
52
- "exact-readme-template.md",
53
51
  "workflow-init.js",
54
52
  "templates/AGENTS.md",
55
53
  "templates/CLAUDE.md",
package/src/init.js CHANGED
@@ -1,111 +1,11 @@
1
- import fs from 'node:fs/promises'
2
- import { randomUUID } from 'node:crypto'
3
1
  import path from 'node:path'
2
+ import fs from 'node:fs/promises'
4
3
 
5
4
  import { PACKAGE_ROOT, buildPaths } from './constants.js'
6
- import { ensureDir, log, pathExists, readJsonIfExists, resolveCommand, runCommand, warn, writeJson } from './utils.js'
7
-
8
- const GITIGNORE_ENTRIES = [
9
- '# OS / editor noise',
10
- '.DS_Store',
11
- '**/.DS_Store',
12
- 'Thumbs.db',
13
- '.idea/',
14
- '.vscode/',
15
- '*.swp',
16
- '*.swo',
17
- '*~',
18
-
19
- '# Environment / secrets',
20
- '.env',
21
- '.env.*',
22
- '!.env.example',
23
- '*.pem',
24
- '*.key',
25
- '*.crt',
26
-
27
- '# Logs',
28
- '*.log',
29
- 'logs/',
30
- 'npm-debug.log*',
31
- 'yarn-debug.log*',
32
- 'yarn-error.log*',
33
- 'pnpm-debug.log*',
34
- 'gh-multi_logs/',
35
- 'antigravity-logs/',
36
-
37
- '# Node / package managers',
38
- 'node_modules/',
39
- '.npm/',
40
- '.pnpm-store/',
41
- '.yarn/cache/',
42
- '.yarn/unplugged/',
43
- '.yarn/build-state.yml',
44
- '.yarn/install-state.gz',
45
-
46
- '# Build / coverage outputs',
47
- 'dist/',
48
- 'build/',
49
- 'out/',
50
- 'coverage/',
51
- '.coverage',
52
- '.nyc_output/',
53
- '.next/',
54
- '.nuxt/',
55
- '.output/',
56
- '.vite/',
57
- 'storybook-static/',
58
-
59
- '# Test / framework caches',
60
- '.cache/',
61
- '.parcel-cache/',
62
- '.turbo/',
63
- '.eslintcache',
64
- '*.tsbuildinfo',
65
- 'playwright-report/',
66
- 'test-results/',
67
- 'blob-report/',
68
-
69
- '# Python caches',
70
- '.pytest_cache/',
71
- '.mypy_cache/',
72
- '.ruff_cache/',
73
- '__pycache__/',
74
- '**/__pycache__/',
75
- '*.py[cod]',
76
- '.venv/',
77
- 'venv/',
78
-
79
- '# Archives / packaged outputs',
80
- '*.tgz',
81
- '*.tar.gz',
82
- '*.zip',
83
- '*.raw',
84
-
85
- '# Local session/runtime artifacts',
86
- 'sessions/',
87
- 'claude-sessions.zip',
88
- 'session-export-*.raw',
89
- '.tmp-*/',
90
- '.tmp-home*/',
91
- '.tmp-project*/',
92
- '.tmp-fakebin/',
93
- 'sync-machine-assets.local.mjs',
94
- ]
5
+ import { ensureDir, log, pathExists, resolveCommand, runCommand, warn } from './utils.js'
95
6
 
96
7
  const ALLOWED_EXISTING_ENTRIES = new Set(['.DS_Store', '.git'])
97
- const INITIAL_COMMIT_PATHS = ['.gitignore', 'AGENTS.md', 'CLAUDE.md', '.claude', 'docs', 'metadata.json', 'repo']
98
- const ADOPTION_ROOT_KEEP = new Set([
99
- '.DS_Store',
100
- '.git',
101
- '.gitignore',
102
- '.ai',
103
- '.beads',
104
- 'task',
105
- 'metadata.json',
106
- ])
107
8
  const VALID_START_PHASES = new Set(['P1', 'P2', 'P3', 'P4', 'P5', 'P7', 'P8', 'P9', 'P10'])
108
- const VALID_PROJECT_TYPES = new Set(['backend', 'fullstack', 'web', 'android', 'ios', 'desktop'])
109
9
  const PHASE_LABELS = {
110
10
  P1: 'Phase 1 Clarification',
111
11
  P2: 'Phase 2 Planning',
@@ -155,11 +55,8 @@ async function resolveBrCommand(paths) {
155
55
 
156
56
  function parseInitArgs(args) {
157
57
  let openAfterInit = false
158
- let adoptExisting = false
159
- let continueFromExisting = false
160
- let targetInput = '.'
58
+ let githubUrl = null
161
59
  let requestedStartPhase = null
162
- let developerRulebookFile = null
163
60
 
164
61
  function setRequestedStartPhase(optionName, phase) {
165
62
  if (!VALID_START_PHASES.has(phase)) {
@@ -179,47 +76,22 @@ function parseInitArgs(args) {
179
76
  continue
180
77
  }
181
78
 
182
- if (arg === '--adopt') {
183
- adoptExisting = true
184
- continue
185
- }
186
-
187
79
  if (arg === '--claude') {
188
- if (developerRulebookFile && developerRulebookFile !== 'CLAUDE.md') {
189
- throw new Error('Conflicting developer rulebook options. Use only one of --claude, --opencode, or --rulebook.')
190
- }
191
- developerRulebookFile = 'CLAUDE.md'
80
+ // Claude is the only seeded developer rulebook now; keep this option as a harmless explicit mode.
192
81
  continue
193
82
  }
194
83
 
195
84
  if (arg === '--opencode') {
196
- if (developerRulebookFile && developerRulebookFile !== 'AGENTS.md') {
197
- throw new Error('Conflicting developer rulebook options. Use only one of --claude, --opencode, or --rulebook.')
198
- }
199
- developerRulebookFile = 'AGENTS.md'
85
+ throw new Error('--opencode is no longer supported for init. The cloned task root keeps only CLAUDE.md as the seeded developer rulebook.')
200
86
  continue
201
87
  }
202
88
 
203
89
  if (arg === '--rulebook') {
204
- const nextArg = args[index + 1]
205
- if (!nextArg) {
206
- throw new Error('Missing value for --rulebook')
207
- }
208
- const normalizedRulebook = normalizeDeveloperRulebookOption(nextArg)
209
- if (developerRulebookFile && developerRulebookFile !== normalizedRulebook) {
210
- throw new Error('Conflicting developer rulebook options. Use only one of --claude, --opencode, or --rulebook.')
211
- }
212
- developerRulebookFile = normalizedRulebook
213
- index += 1
214
- continue
90
+ throw new Error('--rulebook is no longer supported for init. The cloned task root keeps only CLAUDE.md as the seeded developer rulebook.')
215
91
  }
216
92
 
217
93
  if (arg.startsWith('--rulebook=')) {
218
- const normalizedRulebook = normalizeDeveloperRulebookOption(arg.slice('--rulebook='.length))
219
- if (developerRulebookFile && developerRulebookFile !== normalizedRulebook) {
220
- throw new Error('Conflicting developer rulebook options. Use only one of --claude, --opencode, or --rulebook.')
221
- }
222
- developerRulebookFile = normalizedRulebook
94
+ throw new Error('--rulebook is no longer supported for init. The cloned task root keeps only CLAUDE.md as the seeded developer rulebook.')
223
95
  continue
224
96
  }
225
97
 
@@ -244,16 +116,12 @@ function parseInitArgs(args) {
244
116
  if (!nextArg) {
245
117
  throw new Error('Missing value for --continue-from')
246
118
  }
247
- adoptExisting = true
248
- continueFromExisting = true
249
119
  setRequestedStartPhase('--continue-from', nextArg)
250
120
  index += 1
251
121
  continue
252
122
  }
253
123
 
254
124
  if (arg.startsWith('--continue-from=')) {
255
- adoptExisting = true
256
- continueFromExisting = true
257
125
  setRequestedStartPhase('--continue-from', arg.slice('--continue-from='.length))
258
126
  continue
259
127
  }
@@ -262,44 +130,24 @@ function parseInitArgs(args) {
262
130
  throw new Error(`Unknown init option: ${arg}`)
263
131
  }
264
132
 
265
- targetInput = arg
133
+ if (!githubUrl) {
134
+ githubUrl = arg
135
+ } else {
136
+ throw new Error('slopmachine init accepts exactly one GitHub URL positional argument')
137
+ }
266
138
  }
267
139
 
268
- return { openAfterInit, targetInput, adoptExisting, continueFromExisting, requestedStartPhase, developerRulebookFile: developerRulebookFile || 'AGENTS.md' }
269
- }
270
-
271
- function normalizeDeveloperRulebookOption(value) {
272
- const normalized = String(value || '').trim().toLowerCase()
273
- if (['agents', 'agent', 'opencode', 'agents.md'].includes(normalized)) {
274
- return 'AGENTS.md'
140
+ if (!githubUrl) {
141
+ throw new Error('Usage: slopmachine init <github-url> [options]. The cloned repository name is used as the task root directory name.')
275
142
  }
276
- if (['claude', 'claude.md'].includes(normalized)) {
277
- return 'CLAUDE.md'
278
- }
279
- throw new Error("Unsupported --rulebook value. Use 'agents'/'opencode' or 'claude'.")
143
+
144
+ return { openAfterInit, githubUrl, requestedStartPhase, developerRulebookFile: 'CLAUDE.md' }
280
145
  }
281
146
 
282
147
  function normalizeRequestedStartPhase(phase) {
283
148
  return phase === 'P4' ? 'P3' : phase
284
149
  }
285
150
 
286
- function resolveWorkflowRootForInit(targetPath, options) {
287
- if (!options.continueFromExisting) {
288
- return targetPath
289
- }
290
-
291
- if (path.basename(targetPath) === 'task') {
292
- return path.dirname(targetPath)
293
- }
294
-
295
- if (path.basename(targetPath) === 'repo') {
296
- const parent = path.dirname(targetPath)
297
- return path.basename(parent) === 'task' ? path.dirname(parent) : parent
298
- }
299
-
300
- return targetPath
301
- }
302
-
303
151
  async function assertRequiredFiles(paths) {
304
152
  const installedRoot = paths.slopmachineDir
305
153
  const packagedRoot = path.join(PACKAGE_ROOT, 'assets', 'slopmachine')
@@ -307,18 +155,12 @@ async function assertRequiredFiles(paths) {
307
155
  const installedFiles = {
308
156
  runtimeAssetRoot: installedRoot,
309
157
  trackerScript: path.join(installedRoot, 'workflow-init.js'),
310
- agentsTemplate: path.join(installedRoot, 'templates', 'AGENTS.md'),
311
158
  claudeTemplate: path.join(installedRoot, 'templates', 'CLAUDE.md'),
312
- phase1DesignTemplate: path.join(installedRoot, 'phase-1-design-template.md'),
313
- readmeTemplate: path.join(installedRoot, 'exact-readme-template.md'),
314
159
  }
315
160
  const packagedFiles = {
316
161
  runtimeAssetRoot: packagedRoot,
317
162
  trackerScript: path.join(packagedRoot, 'workflow-init.js'),
318
- agentsTemplate: path.join(packagedRoot, 'templates', 'AGENTS.md'),
319
163
  claudeTemplate: path.join(packagedRoot, 'templates', 'CLAUDE.md'),
320
- phase1DesignTemplate: path.join(packagedRoot, 'phase-1-design-template.md'),
321
- readmeTemplate: path.join(packagedRoot, 'exact-readme-template.md'),
322
164
  }
323
165
 
324
166
  const packagedReady = await Promise.all(Object.entries(packagedFiles)
@@ -341,14 +183,6 @@ async function assertRequiredFiles(paths) {
341
183
  )
342
184
  }
343
185
 
344
- async function resolveTarget(targetInput) {
345
- const targetPath = path.resolve(process.cwd(), targetInput)
346
- if (!(await pathExists(targetPath))) {
347
- throw new Error(`Target directory '${targetInput}' does not exist or is not accessible.`)
348
- }
349
- return targetPath
350
- }
351
-
352
186
  async function assertBootstrapTargetIsEmpty(targetPath) {
353
187
  const entries = await fs.readdir(targetPath, { withFileTypes: true })
354
188
  const unexpectedEntries = entries
@@ -359,103 +193,56 @@ async function assertBootstrapTargetIsEmpty(targetPath) {
359
193
  return
360
194
  }
361
195
 
362
- throw new Error(
363
- `slopmachine init expects a new or empty target directory. Found existing entries: ${unexpectedEntries.join(', ')}`,
364
- )
365
- }
366
-
367
- async function moveEntry(sourcePath, targetPath) {
368
- try {
369
- await fs.rename(sourcePath, targetPath)
370
- } catch (error) {
371
- if (error && error.code === 'EXDEV') {
372
- await fs.cp(sourcePath, targetPath, { recursive: true, force: true })
373
- await fs.rm(sourcePath, { recursive: true, force: true })
374
- return
375
- }
376
- throw error
377
- }
196
+ throw new Error(
197
+ `slopmachine init expects a new or empty workflow root. Found existing entries: ${unexpectedEntries.join(', ')}`,
198
+ )
378
199
  }
379
200
 
380
- async function prepareExistingProjectForAdoption(workflowRoot, taskRoot) {
381
- await ensureDir(taskRoot)
382
-
383
- const sourceGitDir = path.join(workflowRoot, '.git')
384
- const taskGitDir = path.join(taskRoot, '.git')
385
- if (await pathExists(sourceGitDir) && !(await pathExists(taskGitDir))) {
386
- await moveEntry(sourceGitDir, taskGitDir)
201
+ function deriveTaskIdFromGitHubUrl(githubUrl) {
202
+ const trimmed = String(githubUrl || '').trim()
203
+ if (!trimmed) {
204
+ throw new Error('Missing GitHub URL')
387
205
  }
388
206
 
389
- const sourceMetadataPath = path.join(workflowRoot, 'metadata.json')
390
- const taskMetadataPath = path.join(taskRoot, 'metadata.json')
391
- if (await pathExists(sourceMetadataPath) && !(await pathExists(taskMetadataPath))) {
392
- await moveEntry(sourceMetadataPath, taskMetadataPath)
207
+ const withoutTrailingSlash = trimmed.replace(/\/+$/, '')
208
+ const lastPathPart = withoutTrailingSlash.split('/').pop()
209
+ const taskId = lastPathPart ? lastPathPart.replace(/\.git$/i, '') : ''
210
+ if (!taskId || taskId === '.' || taskId === '..') {
211
+ throw new Error(`Unable to derive task root directory name from GitHub URL: ${githubUrl}`)
393
212
  }
394
213
 
395
- const entries = await fs.readdir(workflowRoot, { withFileTypes: true })
396
- const namesToMove = entries
397
- .map((entry) => entry.name)
398
- .filter((name) => !ADOPTION_ROOT_KEEP.has(name))
399
-
400
- if (namesToMove.length === 0) {
401
- return { movedEntries: [], adoptedGitignore: false }
402
- }
403
-
404
- const repoPath = path.join(taskRoot, 'repo')
405
- await ensureDir(repoPath)
406
-
407
- let adoptedGitignore = false
408
- const rootGitignorePath = path.join(workflowRoot, '.gitignore')
409
- if (await pathExists(rootGitignorePath)) {
410
- const repoGitignorePath = path.join(repoPath, '.gitignore')
411
- if (!(await pathExists(repoGitignorePath))) {
412
- await moveEntry(rootGitignorePath, repoGitignorePath)
413
- adoptedGitignore = true
414
- }
415
- }
416
-
417
- const movedEntries = []
418
- for (const name of namesToMove) {
419
- const sourcePath = path.join(workflowRoot, name)
420
- const destinationPath = path.join(repoPath, name)
421
- await moveEntry(sourcePath, destinationPath)
422
- movedEntries.push(name)
423
- }
424
-
425
- return { movedEntries, adoptedGitignore }
214
+ return taskId
426
215
  }
427
216
 
428
- async function ensureGitRepo(targetPath) {
429
- const repoCheck = await runCommand('git', ['-C', targetPath, 'rev-parse', '--is-inside-work-tree'])
430
- if (repoCheck.code === 0) {
431
- log('Git repository already initialized')
432
- return
217
+ async function cloneTaskRepository(githubUrl, taskRoot) {
218
+ if (await pathExists(taskRoot)) {
219
+ throw new Error(`Task root already exists: ${taskRoot}`)
433
220
  }
434
221
 
435
- log('Initializing git repository')
436
- const initResult = await runCommand('git', ['-C', targetPath, 'init'], { stdio: 'inherit' })
437
- if (initResult.code !== 0) {
438
- throw new Error('Git repository initialization failed')
222
+ log(`Cloning task repository into ${path.basename(taskRoot)}/`)
223
+ const result = await runCommand('git', ['clone', githubUrl, taskRoot], { stdio: 'inherit' })
224
+ if (result.code !== 0) {
225
+ throw new Error('Git clone failed. Check the GitHub URL and local git authentication, then retry.')
439
226
  }
440
227
  }
441
228
 
442
- async function ensureGitignore(targetPath) {
443
- const gitignorePath = path.join(targetPath, '.gitignore')
444
- await fs.writeFile(gitignorePath, '', { flag: 'a' })
445
- const existingContent = await fs.readFile(gitignorePath, 'utf8')
446
- const existingLines = new Set(existingContent.split(/\r?\n/))
447
-
448
- const linesToAppend = []
449
- for (const entry of GITIGNORE_ENTRIES) {
450
- if (!existingLines.has(entry)) {
451
- linesToAppend.push(entry)
452
- log(`Added .gitignore entry: ${entry}`)
229
+ async function assertClonedTaskStructure(taskRoot) {
230
+ const requiredPaths = [
231
+ 'metadata.json',
232
+ 'docs',
233
+ '.tmp',
234
+ 'repo',
235
+ ]
236
+
237
+ const missing = []
238
+ for (const relativePath of requiredPaths) {
239
+ if (!(await pathExists(path.join(taskRoot, relativePath)))) {
240
+ missing.push(relativePath)
453
241
  }
454
242
  }
455
243
 
456
- if (linesToAppend.length > 0) {
457
- const prefix = existingContent.endsWith('\n') || existingContent.length === 0 ? '' : '\n'
458
- await fs.appendFile(gitignorePath, `${prefix}${linesToAppend.join('\n')}\n`, 'utf8')
244
+ if (missing.length > 0) {
245
+ throw new Error(`Cloned task repository is missing required task-root paths: ${missing.join(', ')}`)
459
246
  }
460
247
  }
461
248
 
@@ -491,147 +278,47 @@ async function writeFileIfMissing(filePath, content) {
491
278
  return true
492
279
  }
493
280
 
494
- function normalizeProjectMetadataString(value) {
495
- return typeof value === 'string' ? value : ''
496
- }
497
-
498
- function buildProjectMetadata(existingMetadata) {
499
- const metadata = existingMetadata && typeof existingMetadata === 'object' && !Array.isArray(existingMetadata)
500
- ? existingMetadata
501
- : {}
502
- const projectType = normalizeProjectMetadataString(metadata.project_type).trim().toLowerCase()
503
-
504
- return {
505
- prompt: normalizeProjectMetadataString(metadata.prompt),
506
- project_type: VALID_PROJECT_TYPES.has(projectType) ? projectType : '',
507
- frontend_language: normalizeProjectMetadataString(metadata.frontend_language),
508
- backend_language: normalizeProjectMetadataString(metadata.backend_language),
509
- database: normalizeProjectMetadataString(metadata.database),
510
- frontend_framework: normalizeProjectMetadataString(metadata.frontend_framework),
511
- backend_framework: normalizeProjectMetadataString(metadata.backend_framework),
512
- }
513
- }
514
-
515
- function projectMetadataMatchesSchema(existingMetadata, normalizedMetadata) {
516
- if (!existingMetadata || typeof existingMetadata !== 'object' || Array.isArray(existingMetadata)) {
517
- return false
518
- }
519
-
520
- const expectedKeys = Object.keys(normalizedMetadata)
521
- const existingKeys = Object.keys(existingMetadata)
522
-
523
- return existingKeys.length === expectedKeys.length
524
- && expectedKeys.every((key) => existingMetadata[key] === normalizedMetadata[key])
525
- }
526
-
527
- async function ensureProjectMetadata(projectMetadataPath) {
528
- const existed = await pathExists(projectMetadataPath)
529
- const existingMetadata = await readJsonIfExists(projectMetadataPath)
530
- const normalizedMetadata = buildProjectMetadata(existingMetadata)
531
-
532
- if (projectMetadataMatchesSchema(existingMetadata, normalizedMetadata)) {
533
- return
534
- }
535
-
536
- log(existed ? 'Normalizing task metadata.json' : 'Creating task metadata.json')
537
- await writeJson(projectMetadataPath, normalizedMetadata)
538
- }
539
-
540
- async function createInitialPhaseArtifacts(taskRoot, workflowRoot, runtimeAssetRoot, options) {
541
- const questionsContent = `# Questions\n\n` +
542
- `This file records only genuine original-prompt ambiguities that needed interpretation because they were unclear, incomplete, contradictory, or materially ambiguous.\n\n` +
543
- `Use this structure for each real clarification item:\n\n` +
544
- `### 1. <short clarification title>\n` +
545
- `- Question: <the exact ambiguity or missing detail that needed to be locked>\n` +
546
- `- My Understanding: <how the prompt was interpreted, why this was ambiguous, and why it matters>\n` +
547
- `- Solution: <the chosen prompt-faithful resolution or safe default, written decisively>\n`
548
- const designContent = await fs.readFile(
549
- path.join(runtimeAssetRoot, 'phase-1-design-template.md'),
550
- 'utf8',
551
- )
552
-
553
- const apiSpecContent = `# API Spec\n\n` +
554
- `Use this owner-maintained external document when API or interface contracts are material to the project.\n\n` +
555
- `If the project has no meaningful API surface, mark this file as not applicable rather than deleting it silently.\n`
556
-
557
- const repoReadmeContent = await fs.readFile(
558
- path.join(runtimeAssetRoot, 'exact-readme-template.md'),
559
- 'utf8',
560
- )
561
-
281
+ async function createOwnerPrivateArtifacts(workflowRoot, options) {
562
282
  const startupContextContent = `# Startup Context\n\n` +
563
- `- Bootstrap mode: ${options.adoptExisting ? 'adopt-existing-project' : 'new-workflow'}\n` +
283
+ `- Bootstrap mode: github-clone\n` +
564
284
  `${options.requestedStartPhase ? `- Requested start phase: ${options.requestedStartPhase}\n` : ''}` +
565
- `${options.adoptExisting ? '- Catch up to the current repo state before trusting the requested phase. Only start from the requested phase if the codebase and evidence support it.\n' : '- Start from normal intake and clarification unless strong existing state already proves otherwise.\n'}` +
285
+ `- The cloned task root may contain placeholder developer-facing docs or repo content. The implementation lane should inspect and clear unrelated placeholders before relying on them.\n` +
566
286
  `- If the user sends a prompt block followed by appended stack/context lines, keep only the prompt block in ./metadata.json under prompt and record the appended stack/context lines separately here.\n`
567
287
 
568
- await writeFileIfMissing(path.join(taskRoot, 'docs', 'questions.md'), questionsContent)
569
- await writeFileIfMissing(path.join(taskRoot, 'docs', 'design.md'), designContent)
570
- await writeFileIfMissing(path.join(taskRoot, 'docs', 'api-spec.md'), apiSpecContent)
571
288
  await writeFileIfMissing(path.join(workflowRoot, '.ai', 'startup-context.md'), startupContextContent)
572
289
  await writeFileIfMissing(path.join(workflowRoot, '.ai', 'plan.md'), '# Owner Private Plan\n\nThis owner-private plan is the internal execution checklist. Do not expose it to Claude as an instruction file; translate each slice into normal human prompts.\n')
573
290
  await writeFileIfMissing(path.join(workflowRoot, '.ai', 'requirements-breakdown.md'), '# Requirements Breakdown\n\nOwner-private requirement extraction goes here before design, API spec, or planning.\n')
574
291
  await writeFileIfMissing(path.join(workflowRoot, '.ai', 'test-coverage.md'), '# Test Coverage Plan\n\nOwner-private coverage planning and audit notes go here when applicable.\n')
575
- await writeFileIfMissing(path.join(taskRoot, 'repo', 'README.md'), repoReadmeContent)
576
292
  }
577
293
 
578
- async function createRepoStructure(workflowRoot, taskRoot, runtimeAssetRoot, agentsTemplate, claudeTemplate, options) {
294
+ async function createWorkflowStructure(workflowRoot, taskRoot, claudeTemplate, options) {
579
295
  const initialPhase = options.requestedStartPhase ? PHASE_LABELS[options.requestedStartPhase] : 'Phase 1 Clarification'
580
- const developerRulebookFile = options.developerRulebookFile || 'AGENTS.md'
296
+ const developerRulebookFile = options.developerRulebookFile || 'CLAUDE.md'
297
+ const taskId = options.taskId
581
298
 
582
- log('Creating task and workflow directories')
583
- await ensureDir(path.join(taskRoot, '.tmp'))
584
- await ensureDir(path.join(taskRoot, 'docs'))
299
+ log('Creating workflow directories')
585
300
  await ensureDir(path.join(workflowRoot, '.ai', 'claude-live'))
586
301
  await ensureDir(path.join(workflowRoot, '.ai', 'worktrees'))
587
302
 
588
- log('Creating repo/ working directory')
589
- await ensureDir(path.join(taskRoot, 'repo'))
590
- const repoAgentsPath = path.join(taskRoot, 'AGENTS.md')
591
303
  const repoClaudePath = path.join(taskRoot, 'CLAUDE.md')
592
304
 
593
- if (developerRulebookFile === 'AGENTS.md') {
594
- log('Copying AGENTS template into task/')
595
- if (await pathExists(repoAgentsPath)) {
596
- await fs.copyFile(repoAgentsPath, path.join(workflowRoot, '.ai', 'original-task-AGENTS.md'))
597
- }
598
- await fs.copyFile(agentsTemplate, repoAgentsPath)
599
- await fs.rm(repoClaudePath, { force: true })
600
- await fs.rm(path.join(taskRoot, '.claude'), { recursive: true, force: true })
601
- } else {
602
- log('Copying CLAUDE template into task/')
603
- if (await pathExists(repoClaudePath)) {
604
- await fs.copyFile(repoClaudePath, path.join(workflowRoot, '.ai', 'original-task-CLAUDE.md'))
605
- }
606
- await fs.copyFile(claudeTemplate, repoClaudePath)
607
- await fs.rm(repoAgentsPath, { force: true })
608
- await ensureDir(path.join(taskRoot, '.claude'))
609
- await writeFileIfMissing(
610
- path.join(taskRoot, '.claude', 'settings.json'),
611
- `${JSON.stringify({
612
- $schema: 'https://json.schemastore.org/claude-code-settings.json',
613
- agent: 'developer',
614
- env: {
615
- CLAUDE_CODE_SUBAGENT_MODEL: 'sonnet',
616
- },
617
- }, null, 2)}\n`,
618
- )
305
+ log(`Copying CLAUDE template into ${taskId}/`)
306
+ if (await pathExists(repoClaudePath)) {
307
+ await fs.copyFile(repoClaudePath, path.join(workflowRoot, '.ai', 'original-task-CLAUDE.md'))
619
308
  }
620
-
621
- const projectMetadataPath = path.join(taskRoot, 'metadata.json')
622
- await ensureProjectMetadata(projectMetadataPath)
309
+ await fs.copyFile(claudeTemplate, repoClaudePath)
623
310
 
624
311
  const workflowMetadataPath = path.join(workflowRoot, '.ai', 'metadata.json')
625
312
  if (!(await pathExists(workflowMetadataPath))) {
626
313
  log('Creating .ai/metadata.json')
627
314
  await fs.writeFile(workflowMetadataPath, `${JSON.stringify({
628
- run_id: randomUUID(),
315
+ run_id: taskId,
629
316
  current_phase: initialPhase,
630
317
  awaiting_human: false,
631
318
  evaluation_prompt_kind: null,
632
319
  active_evaluator_session_id: null,
633
- task_root: 'task',
634
- evaluation_reports_root: 'task/.tmp',
320
+ task_root: taskId,
321
+ evaluation_reports_root: `${taskId}/.tmp`,
635
322
  developer_sessions: [],
636
323
  developer_rulebook_file: developerRulebookFile,
637
324
  current_developer_lane: null,
@@ -642,40 +329,13 @@ async function createRepoStructure(workflowRoot, taskRoot, runtimeAssetRoot, age
642
329
  next_bugfix_session_number: 1,
643
330
  packaging_completed: false,
644
331
  claude_live_root: '.ai/claude-live',
645
- bootstrap_mode: options.adoptExisting ? 'adopt' : 'new',
332
+ bootstrap_mode: 'github-clone',
333
+ github_url: options.githubUrl,
646
334
  requested_start_phase: options.requestedStartPhase,
647
335
  }, null, 2)}\n`, 'utf8')
648
336
  }
649
337
 
650
- await createInitialPhaseArtifacts(taskRoot, workflowRoot, runtimeAssetRoot, options)
651
- }
652
-
653
- async function createInitialCommit(targetPath) {
654
- log('Creating initial git checkpoint')
655
- const existingInitialCommitPaths = []
656
- for (const relativePath of INITIAL_COMMIT_PATHS) {
657
- if (await pathExists(path.join(targetPath, relativePath))) {
658
- existingInitialCommitPaths.push(relativePath)
659
- }
660
- }
661
- const addResult = await runCommand('git', ['-C', targetPath, 'add', '--', ...existingInitialCommitPaths], { stdio: 'inherit' })
662
- if (addResult.code !== 0) {
663
- throw new Error('Initial git add failed')
664
- }
665
-
666
- const commitResult = await runCommand('git', ['-C', targetPath, 'commit', '-m', 'init'], { stdio: 'inherit' })
667
- if (commitResult.code !== 0) {
668
- throw new Error('Initial git commit failed. Configure git user.name/user.email or inspect repository state and retry.')
669
- }
670
-
671
- const statusResult = await runCommand('git', ['-C', targetPath, 'status', '--short'])
672
- if (statusResult.code !== 0) {
673
- throw new Error('Unable to verify the git worktree after bootstrap commit.')
674
- }
675
-
676
- if (statusResult.stdout.trim()) {
677
- throw new Error(`Bootstrap left the repository dirty after the initial commit:\n${statusResult.stdout.trim()}`)
678
- }
338
+ await createOwnerPrivateArtifacts(workflowRoot, options)
679
339
  }
680
340
 
681
341
  async function maybeOpenOpencode(taskRoot, openAfterInit) {
@@ -683,7 +343,9 @@ async function maybeOpenOpencode(taskRoot, openAfterInit) {
683
343
  return
684
344
  }
685
345
 
686
- log('Opening OpenCode in task/')
346
+ const taskDirName = path.basename(taskRoot)
347
+
348
+ log(`Opening OpenCode in ${taskDirName}/`)
687
349
  let result
688
350
 
689
351
  if (process.platform === 'win32') {
@@ -697,7 +359,7 @@ async function maybeOpenOpencode(taskRoot, openAfterInit) {
697
359
  : await resolveCommand('zsh') || await resolveCommand('bash') || await resolveCommand('sh')
698
360
 
699
361
  if (!shellPath) {
700
- warn('No usable shell was found to launch OpenCode automatically. Launch OpenCode manually inside task/.')
362
+ warn(`No usable shell was found to launch OpenCode automatically. Launch OpenCode manually inside ${taskDirName}/.`)
701
363
  return
702
364
  }
703
365
 
@@ -708,7 +370,7 @@ async function maybeOpenOpencode(taskRoot, openAfterInit) {
708
370
  }
709
371
 
710
372
  if (result.code !== 0) {
711
- warn(`Failed to launch OpenCode automatically (${result.stderr || `exit code ${result.code}`}). Launch it manually inside task/.`)
373
+ warn(`Failed to launch OpenCode automatically (${result.stderr || `exit code ${result.code}`}). Launch it manually inside ${taskDirName}/.`)
712
374
  }
713
375
  }
714
376
 
@@ -716,53 +378,27 @@ export async function runInit(args = []) {
716
378
  assertSupportedPlatform()
717
379
 
718
380
  const paths = buildPaths()
719
- const { openAfterInit, targetInput, adoptExisting, continueFromExisting, requestedStartPhase: rawRequestedStartPhase, developerRulebookFile } = parseInitArgs(args)
381
+ const { openAfterInit, githubUrl, requestedStartPhase: rawRequestedStartPhase, developerRulebookFile } = parseInitArgs(args)
720
382
  const requestedStartPhase = normalizeRequestedStartPhase(rawRequestedStartPhase)
721
- if (requestedStartPhase && requestedStartPhase !== 'P1' && !adoptExisting && !continueFromExisting) {
722
- throw new Error(`Later start phase '${requestedStartPhase}' requires --adopt or --continue-from because later-phase entry is only valid for existing-project recovery.`)
723
- }
724
383
 
725
- const { runtimeAssetRoot, trackerScript, agentsTemplate, claudeTemplate } = await assertRequiredFiles(paths)
726
- const initialTargetPath = await resolveTarget(targetInput)
727
- const workflowRoot = resolveWorkflowRootForInit(initialTargetPath, { continueFromExisting, targetInput })
728
- const taskRoot = path.join(workflowRoot, 'task')
384
+ const { trackerScript, claudeTemplate } = await assertRequiredFiles(paths)
385
+ const workflowRoot = process.cwd()
386
+ const taskId = deriveTaskIdFromGitHubUrl(githubUrl)
387
+ const taskRoot = path.join(workflowRoot, taskId)
729
388
 
389
+ log(`Task id: ${taskId}`)
390
+ log(`GitHub URL: ${githubUrl}`)
730
391
  log(`Workflow root: ${workflowRoot}`)
731
392
  log(`Task root: ${taskRoot}`)
732
393
 
733
- if (workflowRoot !== initialTargetPath) {
734
- log(`Detected existing task/repo working directory at ${initialTargetPath}; using ${workflowRoot} as the workflow root`)
735
- }
736
-
737
- if (adoptExisting) {
738
- const adoptionSummary = await prepareExistingProjectForAdoption(workflowRoot, taskRoot)
739
- if (adoptionSummary.movedEntries.length > 0) {
740
- log(`Adopted existing project into repo/: ${adoptionSummary.movedEntries.join(', ')}`)
741
- } else {
742
- log('Adoption mode enabled: no project files needed to be moved into repo/')
743
- }
744
- if (adoptionSummary.adoptedGitignore) {
745
- log('Moved the existing project .gitignore into repo/.gitignore')
746
- }
747
- } else {
748
- await assertBootstrapTargetIsEmpty(workflowRoot)
749
- }
394
+ await assertBootstrapTargetIsEmpty(workflowRoot)
395
+ await cloneTaskRepository(githubUrl, taskRoot)
396
+ await assertClonedTaskStructure(taskRoot)
750
397
 
751
398
  log('Ensuring .ai/artifacts exists')
752
399
  await ensureDir(path.join(workflowRoot, '.ai', 'artifacts'))
753
- await ensureDir(taskRoot)
754
-
755
- await ensureGitRepo(taskRoot)
756
- log('Ensuring .gitignore defaults')
757
- await ensureGitignore(taskRoot)
758
400
  await runWorkflowBootstrap(paths, workflowRoot, trackerScript, { requestedStartPhase })
759
- await createRepoStructure(workflowRoot, taskRoot, runtimeAssetRoot, agentsTemplate, claudeTemplate, { adoptExisting, requestedStartPhase, developerRulebookFile })
760
-
761
- if (!adoptExisting) {
762
- await createInitialCommit(taskRoot)
763
- } else {
764
- log('Skipping automatic bootstrap commit because this workspace adopted an existing project')
765
- }
401
+ await createWorkflowStructure(workflowRoot, taskRoot, claudeTemplate, { githubUrl, requestedStartPhase, developerRulebookFile, taskId })
766
402
 
767
403
  await maybeOpenOpencode(taskRoot, openAfterInit)
768
404
 
package/src/install.js CHANGED
@@ -150,7 +150,6 @@ async function writeOpencodeConfig(filePath, value) {
150
150
  const LEGACY_SUFFIX_PATTERN = /-(v2|v3)(\.md)?$/
151
151
  const OBSOLETE_PACKAGE_ASSET_FILES = [
152
152
  '01-phase-1-design-prompt.md',
153
- '02-phase-1-design-template.md',
154
153
  '03-phase-2-execution-planning-prompt.md',
155
154
  '04-phase-2-plan-template.md',
156
155
  '06-owner-verification-checklist.md',
@@ -1532,7 +1531,7 @@ export async function runInstall() {
1532
1531
  console.log('\nNext steps')
1533
1532
  console.log('- Review any warnings above for skipped files or missing external dependencies.')
1534
1533
  console.log('- If Docker was reported as stopped, start Docker before using theslopmachine on a real project.')
1535
- console.log('- Run `slopmachine init` inside a project directory to bootstrap a new theslopmachine workspace.')
1534
+ console.log('- Run `slopmachine init <github-url>` inside an empty workflow root to clone and bootstrap a task workspace.')
1536
1535
  }
1537
1536
 
1538
1537
  export async function runCleanup(args = []) {
package/src/send-data.js CHANGED
@@ -119,12 +119,18 @@ async function resolveWorkflowPaths() {
119
119
  }
120
120
  }
121
121
 
122
- const taskDir = path.join(cwd, 'task')
123
- if (await pathExists(path.join(taskDir, 'metadata.json')) && await pathExists(path.join(cwd, '.ai', 'metadata.json'))) {
124
- return { workflowRoot: cwd, taskRoot: taskDir, repoPath: path.join(taskDir, 'repo') }
122
+ const cwdWorkflowMetadata = path.join(cwd, '.ai', 'metadata.json')
123
+ if (await pathExists(cwdWorkflowMetadata)) {
124
+ const workflowMetadata = await readJsonIfExists(cwdWorkflowMetadata)
125
+ if (workflowMetadata && typeof workflowMetadata.task_root === 'string') {
126
+ const taskDir = path.join(cwd, workflowMetadata.task_root)
127
+ if (await pathExists(path.join(taskDir, 'metadata.json'))) {
128
+ return { workflowRoot: cwd, taskRoot: taskDir, repoPath: path.join(taskDir, 'repo') }
129
+ }
130
+ }
125
131
  }
126
132
 
127
- throw new Error('slopmachine send-data must be run from task/, task/repo/, or the workflow root containing task/')
133
+ throw new Error('slopmachine send-data could not find the task root. Run from a task root directory (containing metadata.json and repo/), or from a workflow root (containing .ai/metadata.json).')
128
134
  }
129
135
 
130
136
  async function loadWorkflowMetadata(workflowRoot) {