specrails-core 4.8.2 → 4.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/bin/specrails-core.mjs +5 -1
  2. package/dist/installer/cli.js +46 -6
  3. package/dist/installer/cli.js.map +1 -1
  4. package/dist/installer/commands/doctor.js +14 -5
  5. package/dist/installer/commands/doctor.js.map +1 -1
  6. package/dist/installer/commands/framework.js +134 -0
  7. package/dist/installer/commands/framework.js.map +1 -0
  8. package/dist/installer/commands/init.js +107 -32
  9. package/dist/installer/commands/init.js.map +1 -1
  10. package/dist/installer/commands/update.js +75 -35
  11. package/dist/installer/commands/update.js.map +1 -1
  12. package/dist/installer/phases/scaffold.js +493 -73
  13. package/dist/installer/phases/scaffold.js.map +1 -1
  14. package/dist/installer/util/fs.js +143 -1
  15. package/dist/installer/util/fs.js.map +1 -1
  16. package/dist/installer/util/registry.js +339 -0
  17. package/dist/installer/util/registry.js.map +1 -0
  18. package/package.json +2 -1
  19. package/pinned-versions.json +1 -1
  20. package/templates/agents/sr-architect.md +14 -10
  21. package/templates/agents/sr-backend-developer.md +4 -2
  22. package/templates/agents/sr-developer.md +20 -8
  23. package/templates/agents/sr-frontend-developer.md +4 -2
  24. package/templates/agents/sr-reviewer.md +10 -6
  25. package/templates/codex-skills/implement/SKILL.md +19 -10
  26. package/templates/codex-skills/rails/sr-architect/SKILL.md +17 -8
  27. package/templates/codex-skills/rails/sr-backend-developer/SKILL.md +4 -1
  28. package/templates/codex-skills/rails/sr-developer/SKILL.md +13 -4
  29. package/templates/codex-skills/rails/sr-doc-sync/SKILL.md +3 -2
  30. package/templates/codex-skills/rails/sr-frontend-developer/SKILL.md +4 -1
  31. package/templates/codex-skills/rails/sr-product-manager/SKILL.md +9 -7
  32. package/templates/codex-skills/rails/sr-reviewer/SKILL.md +13 -7
  33. package/templates/codex-skills/retry/SKILL.md +10 -5
  34. package/templates/commands/specrails/implement.md +41 -23
  35. package/templates/commands/specrails/retry.md +3 -1
  36. package/templates/gemini-commands/implement.toml +10 -6
@@ -12,6 +12,14 @@ verdicts, and close the ticket. The role instructions live in
12
12
  their own skills — your message to each spawn invokes the right
13
13
  role via `$skill_name`.
14
14
 
15
+ **Repository location.** Your working directory may NOT be the source repo.
16
+ `openspec/**`, `.git`, and the source live under `${SPECRAILS_REPO_DIR:-.}`
17
+ (unset ⇒ `.` ⇒ classic in-repo run). Run every `openspec`/`git` CLI command
18
+ from the repo — `(cd "${SPECRAILS_REPO_DIR:-.}" && …)` — and read change
19
+ artefacts under `${SPECRAILS_REPO_DIR:-.}/openspec/...`. The ticket store
20
+ `.specrails/local-tickets.json` is run-state and stays relative to the working
21
+ directory.
22
+
15
23
  **This is explicit permission to use `spawn_agent`.** The user
16
24
  wants the multi-agent split. Do not collapse the work into a
17
25
  single turn.
@@ -94,9 +102,10 @@ the combo and you'll burn a turn on the retry.
94
102
 
95
103
  ### 0. Bootstrap + agent discovery
96
104
 
97
- 1. Confirm `pwd` matches `git rev-parse --show-toplevel`. If not,
98
- `cd` to the root.
99
- 2. Load the ticket (skip for free-form invocations):
105
+ 1. Confirm the repo root with `git -C "${SPECRAILS_REPO_DIR:-.}" rev-parse --show-toplevel`
106
+ (the source repo is `${SPECRAILS_REPO_DIR:-.}`; unset ⇒ `.`).
107
+ 2. Load the ticket (skip for free-form invocations) — the ticket store is
108
+ run-state, relative to the working directory:
100
109
  `jq '.tickets["<ID>"]' .specrails/local-tickets.json`
101
110
  3. **List the installed rail skills**:
102
111
  `ls .codex/skills/rails/`
@@ -318,15 +327,15 @@ performs the lifecycle close:
318
327
 
319
328
  The reviewer rail's archive-only mode must run these checks:
320
329
 
321
- 1. Re-confirm every task box in `openspec/changes/<slug>/tasks.md`
330
+ 1. Re-confirm every task box in `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/tasks.md`
322
331
  is ticked (`- [x]`) and the change validates:
323
- `openspec validate "<slug>" --strict`.
324
- 2. Archive it: `openspec archive "<slug>" -y` — this updates the
325
- main specs and moves the change to `openspec/changes/archive/`.
332
+ `(cd "${SPECRAILS_REPO_DIR:-.}" && openspec validate "<slug>" --strict)`.
333
+ 2. Archive it: `(cd "${SPECRAILS_REPO_DIR:-.}" && openspec archive "<slug>" -y)` — this updates the
334
+ main specs and moves the change to `${SPECRAILS_REPO_DIR:-.}/openspec/changes/archive/`.
326
335
  3. **Verify the archive landed — do NOT assume success.** Confirm
327
- `openspec/changes/archive/` now contains the slug
328
- (`ls -d openspec/changes/archive/*<slug>* 2>/dev/null`) AND that
329
- `openspec/changes/<slug>/` is gone. If the archive directory is
336
+ `${SPECRAILS_REPO_DIR:-.}/openspec/changes/archive/` now contains the slug
337
+ (`ls -d "${SPECRAILS_REPO_DIR:-.}"/openspec/changes/archive/*<slug>* 2>/dev/null`) AND that
338
+ `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/` is gone. If the archive directory is
330
339
  absent, archiving FAILED.
331
340
  4. If `openspec validate`, `openspec archive`, or the step-3
332
341
  verification fails: do NOT mark the ticket `done`. Treat the run
@@ -10,10 +10,17 @@ orchestrator already loaded the ticket and surveyed the repo before
10
10
  spawning you. Your turn is short, focused, and ends with TWO
11
11
  written artefacts: an OpenSpec change package and a plan artefact.
12
12
 
13
+ **Repository location.** `openspec/**`, `.git`, and the source live under
14
+ `${SPECRAILS_REPO_DIR:-.}` (unset ⇒ `.` ⇒ classic in-repo run). Run every
15
+ `openspec` CLI command from the repo — `(cd "${SPECRAILS_REPO_DIR:-.}" && openspec …)`
16
+ — and read/write change artefacts under `${SPECRAILS_REPO_DIR:-.}/openspec/...`.
17
+ Your plan artefact under `.specrails/agent-memory/` is run-state and stays
18
+ relative to the working directory.
19
+
13
20
  ## Your scope
14
21
 
15
22
  You **plan**. You do not write production code. You do not edit
16
- source files outside `openspec/` and `.specrails/agent-memory/`.
23
+ source files outside `${SPECRAILS_REPO_DIR:-.}/openspec/` and `.specrails/agent-memory/`.
17
24
 
18
25
  ## What you produce
19
26
 
@@ -25,15 +32,15 @@ scaffolding so the change is registered with a workflow schema and
25
32
  stays trackable by `openspec status`. Run:
26
33
 
27
34
  ```
28
- openspec new change "<slug>" --schema spec-driven
35
+ (cd "${SPECRAILS_REPO_DIR:-.}" && openspec new change "<slug>" --schema spec-driven)
29
36
  ```
30
37
 
31
38
  where `<slug>` is a kebab-case derivation of the ticket title
32
39
  (e.g. ticket "Build a Playable Tetris Game" → `add-tetris-game`).
33
- This creates `openspec/changes/<slug>/.openspec.yaml`.
40
+ This creates `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/.openspec.yaml`.
34
41
 
35
42
  - If the command fails because OpenSpec isn't initialised in this
36
- repo, run `openspec init . --tools codex --force` once, then
43
+ repo, run `(cd "${SPECRAILS_REPO_DIR:-.}" && openspec init . --tools codex --force)` once, then
37
44
  re-run `openspec new change …`.
38
45
  - If the change directory already exists from a prior run,
39
46
  **reuse** it (idempotent) — skip the `new change` call.
@@ -44,10 +51,10 @@ tasks). Check the order and what's still outstanding at any time
44
51
  with:
45
52
 
46
53
  ```
47
- openspec status --change "<slug>" --json
54
+ (cd "${SPECRAILS_REPO_DIR:-.}" && openspec status --change "<slug>" --json)
48
55
  ```
49
56
 
50
- Write these four artefacts into `openspec/changes/<slug>/`:
57
+ Write these four artefacts into `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/`:
51
58
 
52
59
  **`proposal.md`** — the change's executive summary:
53
60
 
@@ -256,9 +263,11 @@ on the touched files as a fallback.>
256
263
  When BOTH the OpenSpec change package and the plan artefact are
257
264
  written:
258
265
 
259
- 1. **Validate the change with the OpenSpec CLI** (mandatory):
266
+ 1. **Validate the change with the OpenSpec CLI** (mandatory). The
267
+ OpenSpec project root is `${SPECRAILS_REPO_DIR:-.}` (the repo),
268
+ NOT the workspace cwd — so run it scoped to the repo:
260
269
  ```
261
- openspec validate "<slug>"
270
+ (cd "${SPECRAILS_REPO_DIR:-.}" && openspec validate "<slug>")
262
271
  ```
263
272
  If validation reports structural errors, fix the offending
264
273
  artefact and re-run until it passes. Do not hand off a change
@@ -15,8 +15,11 @@ for changes that are neither, `$sr-developer`.
15
15
  ## Your scope
16
16
 
17
17
  Same TDD contract as `$sr-developer` — read the architect's
18
- plan, walk `openspec/changes/<slug>/tasks.md` in order, write
18
+ plan, walk `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/tasks.md` in order, write
19
19
  the failing test first, then production code, re-run, tick.
20
+ (openspec + the source files named in `tasks.md` live under
21
+ `${SPECRAILS_REPO_DIR:-.}` — unset ⇒ `.` ⇒ classic in-repo run; edit each
22
+ source file as `${SPECRAILS_REPO_DIR:-.}/<path>`.)
20
23
 
21
24
  What's different: you bias the test surface toward integration
22
25
  and contract correctness, not isolated unit happy paths.
@@ -5,6 +5,15 @@ license: MIT
5
5
  compatibility: "Codex-native. Designed to run as a full-history sub-agent fork of the implement orchestrator."
6
6
  ---
7
7
 
8
+ **Repository location.** Your working directory may NOT be the source
9
+ repo. `openspec/**` and the source files named in `tasks.md` (repo-relative
10
+ paths like `src/foo.ts`) live under `${SPECRAILS_REPO_DIR:-.}` — unset ⇒ `.`
11
+ ⇒ byte-identical to a classic in-repo run. Read openspec from
12
+ `${SPECRAILS_REPO_DIR:-.}/openspec/...` and edit every source file as
13
+ `${SPECRAILS_REPO_DIR:-.}/<path>`. Run-state you write (`.specrails/agent-memory/`)
14
+ stays relative to the working directory; `.specrails/local-tickets.json` is
15
+ likewise relative (and owned by the orchestrator — you never write it).
16
+
8
17
  You are the **developer** in the specrails implement pipeline. The
9
18
  architect produced an OpenSpec change package (proposal + design +
10
19
  tasks + spec deltas) and a plan artefact. Your job is to **apply**
@@ -27,14 +36,14 @@ note it in your reply — do not block on the architect.
27
36
  1. **Read the inputs**, in this order:
28
37
  - `<plan-path>` (the architect's plan artefact under
29
38
  `.specrails/agent-memory/explanations/`).
30
- - `openspec/changes/<slug>/proposal.md` — the why + what.
31
- - `openspec/changes/<slug>/design.md` — the deep design.
39
+ - `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/proposal.md` — the why + what.
40
+ - `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/design.md` — the deep design.
32
41
  Read **every section**, especially "Architecture", "Data
33
42
  shapes", "State & lifecycle", "Public API / surface",
34
43
  "Trade-offs" (so you know what NOT to revisit), and "Open
35
44
  questions".
36
- - `openspec/changes/<slug>/tasks.md` — your execution checklist.
37
- - `openspec/changes/<slug>/specs/<cap>/spec.md` — the
45
+ - `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/tasks.md` — your execution checklist.
46
+ - `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/specs/<cap>/spec.md` — the
38
47
  behavioural contracts the tests must encode.
39
48
 
40
49
  **About design.md's "Open questions" section** — if the
@@ -29,8 +29,9 @@ Two ways:
29
29
  specrails-managed:start -->` … `<!--
30
30
  specrails-managed:end -->` block. Outside that block
31
31
  is user-authored; don't touch it.
32
- - `docs/` (any markdown files).
33
- - `openspec/specs/<capability>/spec.md` (capabilities
32
+ - `${SPECRAILS_REPO_DIR:-.}/docs/` (any markdown files; repo-resident — unset
33
+ `SPECRAILS_REPO_DIR` ⇒ `.` ⇒ classic in-repo run).
34
+ - `${SPECRAILS_REPO_DIR:-.}/openspec/specs/<capability>/spec.md` (capabilities
34
35
  documentation — drift here is the most serious; this
35
36
  is the contract).
36
37
  - Inline JSDoc / TSDoc / Python docstrings on exported
@@ -15,9 +15,12 @@ instead.
15
15
  ## Your scope
16
16
 
17
17
  Same TDD contract as `$sr-developer` — read the architect's
18
- plan, walk `openspec/changes/<slug>/tasks.md` in order, write
18
+ plan, walk `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/tasks.md` in order, write
19
19
  the failing test first, then the production code, then re-run.
20
20
  Tick boxes only after observing the expected runner state.
21
+ (openspec + the source files named in `tasks.md` live under
22
+ `${SPECRAILS_REPO_DIR:-.}` — unset ⇒ `.` ⇒ classic in-repo run; edit each
23
+ source file as `${SPECRAILS_REPO_DIR:-.}/<path>`.)
21
24
 
22
25
  What's different: you bias the test surface toward UI.
23
26
 
@@ -25,14 +25,16 @@ Two ways:
25
25
 
26
26
  ### 1. Read the existing artefacts
27
27
 
28
- - `README.md` (project intent and surface).
29
- - `openspec/specs/` (existing specs — what the product
28
+ (Repo-resident reads live under `${SPECRAILS_REPO_DIR:-.}` unset `.` ⇒
29
+ classic in-repo run.)
30
+ - `${SPECRAILS_REPO_DIR:-.}/README.md` (project intent and surface).
31
+ - `${SPECRAILS_REPO_DIR:-.}/openspec/specs/` (existing specs — what the product
30
32
  contract is today).
31
- - `.specrails/local-tickets.json` (existing backlog —
32
- don't propose duplicates).
33
- - A representative slice of the source code (5-10 files,
34
- drawn from the relevant theme).
35
- - The desktop app's own `openspec/specs/` if relevant
33
+ - `.specrails/local-tickets.json` (existing backlog — run-state, relative to
34
+ the working directory — don't propose duplicates).
35
+ - A representative slice of the source code (5-10 files under
36
+ `${SPECRAILS_REPO_DIR:-.}`, drawn from the relevant theme).
37
+ - The desktop app's own `${SPECRAILS_REPO_DIR:-.}/openspec/specs/` if relevant
36
38
  (cross-component changes).
37
39
 
38
40
  ### 2. Identify gaps
@@ -11,6 +11,12 @@ implemented it. Your job is to validate the **whole** implementation
11
11
  against ALL the artefacts the architect left, not just spot-check
12
12
  the code. You emit a structured verdict and never touch the code.
13
13
 
14
+ **Repository location.** `openspec/**`, `.git`, and the source live under
15
+ `${SPECRAILS_REPO_DIR:-.}` (unset ⇒ `.` ⇒ classic in-repo run). Read change
16
+ artefacts from `${SPECRAILS_REPO_DIR:-.}/openspec/...`, and run every `openspec`
17
+ CLI, `git`, build, and test command from the repo —
18
+ `(cd "${SPECRAILS_REPO_DIR:-.}" && …)`.
19
+
14
20
  ## Your scope
15
21
 
16
22
  You **validate**. You read every artefact, you re-run every check,
@@ -23,12 +29,12 @@ the completed OpenSpec change with the `openspec` CLI.
23
29
 
24
30
  ### 1. Validate the OpenSpec change package
25
31
 
26
- Load `openspec/changes/<slug>/` (the orchestrator gave you the
32
+ Load `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/` (the orchestrator gave you the
27
33
  slug). **Run the OpenSpec validator first** — it is the canonical
28
34
  structural check and is mandatory:
29
35
 
30
36
  ```
31
- openspec validate "<slug>" --strict --json
37
+ (cd "${SPECRAILS_REPO_DIR:-.}" && openspec validate "<slug>" --strict --json)
32
38
  ```
33
39
 
34
40
  A non-empty error list is a blocker finding: record each under
@@ -200,13 +206,13 @@ orchestrator has aggregated all reviewer verdicts. Therefore:
200
206
  When archiving is authorized and the verdict is clean, run these exact
201
207
  checks in order:
202
208
 
203
- 1. Re-run `openspec validate "<slug>" --strict`.
204
- 2. Read `openspec/changes/<slug>/tasks.md` and search for unchecked
209
+ 1. Re-run `(cd "${SPECRAILS_REPO_DIR:-.}" && openspec validate "<slug>" --strict)`.
210
+ 2. Read `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/tasks.md` and search for unchecked
205
211
  tasks (`- [ ]`). If any remain, do not archive; change the verdict to
206
212
  `fix needed: OpenSpec tasks remain unchecked`.
207
- 3. Run `openspec archive "<slug>" -y`.
208
- 4. Verify the archive landed: confirm `openspec/changes/<slug>/` is gone
209
- and `openspec/changes/archive/` contains a directory whose name
213
+ 3. Run `(cd "${SPECRAILS_REPO_DIR:-.}" && openspec archive "<slug>" -y)`.
214
+ 4. Verify the archive landed: confirm `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/` is gone
215
+ and `${SPECRAILS_REPO_DIR:-.}/openspec/changes/archive/` contains a directory whose name
210
216
  includes `<slug>`.
211
217
 
212
218
  If validation, archive, or verification fails, do not report `clean`.
@@ -13,9 +13,14 @@ You are NOT a separate pipeline. You inspect what `$implement`
13
13
  left behind, summarise the current state, and re-invoke
14
14
  `$implement` with a hint about what's already in place. The
15
15
  implement skill is idempotent — architect reuses an existing
16
- `openspec/changes/<slug>/`, developer detects ticked tasks and
16
+ `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/`, developer detects ticked tasks and
17
17
  already-correct files, reviewer re-validates from scratch.
18
18
 
19
+ **Repository location.** `openspec/**` and `.git` live under
20
+ `${SPECRAILS_REPO_DIR:-.}` (unset ⇒ `.` ⇒ classic in-repo run); inspect change
21
+ artefacts there. The ticket store and `.specrails/agent-memory/` are run-state,
22
+ relative to the working directory.
23
+
19
24
  ## How the user invokes you
20
25
 
21
26
  - `$retry #N` — retry the implement run for ticket `N`.
@@ -25,8 +30,8 @@ already-correct files, reviewer re-validates from scratch.
25
30
 
26
31
  ### 0. Locate the prior run's artefacts
27
32
 
28
- 1. Confirm `pwd` matches the git root.
29
- 2. Load the ticket:
33
+ 1. Confirm the repo root with `git -C "${SPECRAILS_REPO_DIR:-.}" rev-parse --show-toplevel`.
34
+ 2. Load the ticket (run-state, relative to the working directory):
30
35
  `jq '.tickets["<ID>"]' .specrails/local-tickets.json`. If
31
36
  the ticket doesn't exist, stop and report.
32
37
  3. Inspect what's already on disk for this ticket:
@@ -34,11 +39,11 @@ already-correct files, reviewer re-validates from scratch.
34
39
  `.specrails/agent-memory/explanations/` named
35
40
  `*-architect-ticket-<ID>.md`. List the latest.
36
41
  - **OpenSpec change package**: any
37
- `openspec/changes/<slug>/` whose proposal.md mentions
42
+ `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/` whose proposal.md mentions
38
43
  the ticket title or whose tasks.md has tasks scoped to
39
44
  the ticket. Find the slug.
40
45
  - **tasks.md progress**: count `[x]` vs `[ ]` boxes in
41
- `openspec/changes/<slug>/tasks.md`.
46
+ `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<slug>/tasks.md`.
42
47
  - **Reviewer verdict**: latest matching
43
48
  `*-reviewer-ticket-<ID>.confidence-score.json`. Read
44
49
  the issues list and overall score.
@@ -14,6 +14,20 @@ Full OpenSpec lifecycle with specialized agents: architect designs, developer im
14
14
 
15
15
  ---
16
16
 
17
+ ## Repository location (read first)
18
+
19
+ Your working directory may NOT be the user's source repository. **Repo-resident** things — the source code, `openspec/**`, `.git`, and the GitHub remote — live under **`${SPECRAILS_REPO_DIR:-.}`**. The spawner sets `SPECRAILS_REPO_DIR` to the repo path; **when it is unset it defaults to `.` (the current directory), making every command below byte-identical to a classic in-repo run.**
20
+
21
+ Rules used throughout this pipeline:
22
+ - **openspec reads/writes** → `${SPECRAILS_REPO_DIR:-.}/openspec/...`
23
+ - **git commands** → `git -C "${SPECRAILS_REPO_DIR:-.}" ...`
24
+ - **`gh` commands** (issue/PR — they need the repo's remote) → run them from the repo: `(cd "${SPECRAILS_REPO_DIR:-.}" && gh ...)`
25
+ - **worktree merge-back** → the merge *target* side (the main working tree) is `${SPECRAILS_REPO_DIR:-.}/<file>`
26
+
27
+ **Run-state stays with the working directory** (NOT the repo): `.claude/pipeline-state/`, `.claude/agent-memory/`, `.claude/backlog-cache.json`, and the dry-run cache `.claude/.dry-run/` are all written relative to the current directory. **Profile/agent files** (`.claude/agents/sr-*.md`) are likewise resolved relative to the current directory — do NOT prefix them with `${SPECRAILS_REPO_DIR:-.}`.
28
+
29
+ ---
30
+
17
31
  ## Phase -1: Environment Setup (cloud pre-flight)
18
32
 
19
33
  **This phase runs BEFORE anything else.** Detect if we're in a cloud/remote environment and ensure all required tools are available.
@@ -353,7 +367,7 @@ If the write fails: print `[backlog-cache] Warning: could not write cache. Confl
353
367
  For each resolved issue number, run:
354
368
 
355
369
  ```bash
356
- gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt
370
+ (cd "${SPECRAILS_REPO_DIR:-.}" && gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt)
357
371
  ```
358
372
 
359
373
  Build a snapshot object for each issue:
@@ -502,7 +516,7 @@ Otherwise, re-fetch each issue in scope and diff against the Phase 0 snapshot:
502
516
  **If `BACKLOG_PROVIDER=github`:** For each issue number in `ISSUE_REFS`:
503
517
 
504
518
  ```bash
505
- gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt
519
+ (cd "${SPECRAILS_REPO_DIR:-.}" && gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt)
506
520
  ```
507
521
 
508
522
  If the `gh` command returns non-zero (issue deleted or inaccessible): treat as a CRITICAL conflict — field `"state"`, was `<cached state>`, now `"deleted"`.
@@ -558,7 +572,7 @@ For `body_sha` rows in the table, display only the first 8 characters of each SH
558
572
 
559
573
  For each chosen idea, launch an **sr-architect** agent (`subagent_type: sr-architect`, `run_in_background: true`).
560
574
 
561
- Each architect creates OpenSpec artifacts in `openspec/changes/<name>/`.
575
+ Each architect creates OpenSpec artifacts in `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<name>/`.
562
576
 
563
577
  Each agent's prompt should include:
564
578
  - Description of the feature
@@ -574,7 +588,7 @@ After all architect agents complete, before launching any developer agent:
574
588
 
575
589
  #### Step 1: Extract file references
576
590
 
577
- For each `openspec/changes/<name>/tasks.md`, extract all paths listed under `**Files:**` entries (both `Create:` and `Modify:` lines). Normalize paths: strip leading `./`.
591
+ For each `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<name>/tasks.md`, extract all paths listed under `**Files:**` entries (both `Create:` and `Modify:` lines). Normalize paths: strip leading `./`.
578
592
 
579
593
  #### Step 2: Build the shared-file registry
580
594
 
@@ -653,7 +667,7 @@ Before launching any developer agent, run a trivial Bash command to confirm Bash
653
667
 
654
668
  #### Choosing the right developer agent
655
669
 
656
- For each feature, read `openspec/changes/<name>/tasks.md` and classify every task by its layer tags and file references.
670
+ For each feature, read `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<name>/tasks.md` and classify every task by its layer tags and file references.
657
671
 
658
672
  **Step 1 — Classify tasks into layers:**
659
673
 
@@ -857,6 +871,8 @@ If a doc-sync agent fails or times out:
857
871
 
858
872
  #### Merge Algorithm
859
873
 
874
+ The merge **target** (the main repo working tree where merged files land) is `<target>` = **`${SPECRAILS_REPO_DIR:-.}`**. Every `<target>/<file>` below therefore resolves to `${SPECRAILS_REPO_DIR:-.}/<file>` so merged code lands in the real repo, not the working directory. (`<worktree-path>` is an absolute git-worktree path supplied by the runtime; `git -C <worktree-path>` already targets it directly.)
875
+
860
876
  Process features in `MERGE_ORDER` sequence. For each feature:
861
877
 
862
878
  **Step 1: Identify changed files**
@@ -871,7 +887,7 @@ Split into `exclusive_files` (only this feature modifies them) and `shared_files
871
887
 
872
888
  Copy directly from worktree to target:
873
889
  ```bash
874
- cp <worktree-path>/<file> <target>/<file>
890
+ cp <worktree-path>/<file> "${SPECRAILS_REPO_DIR:-.}"/<file>
875
891
  ```
876
892
  Log: `Copied (exclusive): <file>`
877
893
 
@@ -880,7 +896,7 @@ Log: `Copied (exclusive): <file>`
880
896
  For each shared file, choose strategy by file type:
881
897
 
882
898
  **Strategy A — Markdown section-aware merge** (`.md` files):
883
- 1. Read base: current content of `<target>/<file>`.
899
+ 1. Read base: current content of `${SPECRAILS_REPO_DIR:-.}/<file>` (the merge target).
884
900
  2. Read incoming: `<worktree-path>/<file>`.
885
901
  3. Parse both into sections using `##` heading boundaries (heading line + all content until next `##` or EOF).
886
902
  4. Build section maps: `{heading_text: content}` for base and incoming.
@@ -897,7 +913,7 @@ For each shared file, choose strategy by file type:
897
913
  >>>>>>> base
898
914
  ```
899
915
  Log: `CONFLICT: <file> — section "<heading>" requires manual resolution.`
900
- 6. Write merged result to `<target>/<file>`.
916
+ 6. Write merged result to `${SPECRAILS_REPO_DIR:-.}/<file>` (the merge target).
901
917
 
902
918
  **Strategy B — Unified diff sequential apply** (all other file types):
903
919
  1. Generate incoming diff against original `main`:
@@ -906,7 +922,7 @@ For each shared file, choose strategy by file type:
906
922
  ```
907
923
  2. Apply to current target:
908
924
  ```bash
909
- patch --forward --fuzz=3 <target>/<file> < <diff>
925
+ patch --forward --fuzz=3 "${SPECRAILS_REPO_DIR:-.}"/<file> < <diff>
910
926
  ```
911
927
  3. If `patch` succeeds: log `Merged (diff-apply): <file>`.
912
928
  4. If `patch` fails: insert conflict markers around rejected hunks. Log: `CONFLICT: <file> — N hunks rejected.`
@@ -949,7 +965,7 @@ If `MERGE_REPORT.requires_resolution` is non-empty:
949
965
 
950
966
  Build `CONTEXT_BUNDLES` from the features in `MERGE_ORDER`:
951
967
  ```
952
- { "<feature-a>": "openspec/changes/<feature-a>/context-bundle.md", "<feature-b>": "openspec/changes/<feature-b>/context-bundle.md" }
968
+ { "<feature-a>": "${SPECRAILS_REPO_DIR:-.}/openspec/changes/<feature-a>/context-bundle.md", "<feature-b>": "${SPECRAILS_REPO_DIR:-.}/openspec/changes/<feature-b>/context-bundle.md" }
953
969
  ```
954
970
 
955
971
  Load merge resolver config from `.claude/merge-resolver-config.json` if it exists. Extract `confidence_threshold` (default: 70) and `mode` (default: `auto`).
@@ -959,7 +975,7 @@ Construct the `sr-merge-resolver` agent prompt with:
959
975
  - `CONTEXT_BUNDLES`: the map above
960
976
  - `CONFIDENCE_THRESHOLD`: from config or default (70)
961
977
  - `RESOLUTION_MODE`: from config or default (`auto`)
962
- - `REPORT_PATH`: `openspec/changes/<first-feature-in-MERGE_ORDER>/merge-resolution-report.md`
978
+ - `REPORT_PATH`: `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<first-feature-in-MERGE_ORDER>/merge-resolution-report.md`
963
979
 
964
980
  Launch the **sr-merge-resolver** agent (`subagent_type: sr-merge-resolver`, foreground, `run_in_background: false`). Wait for it to complete.
965
981
 
@@ -1107,7 +1123,7 @@ After the generalist reviewer agent completes, evaluate the confidence score bef
1107
1123
 
1108
1124
  #### Step 1 — Read score file
1109
1125
 
1110
- Path: `openspec/changes/<name>/confidence-score.json`
1126
+ Path: `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<name>/confidence-score.json`
1111
1127
 
1112
1128
  - If the file does not exist:
1113
1129
  - Set `CONFIDENCE_STATUS=MISSING`
@@ -1213,7 +1229,7 @@ Re-fetch each issue in `ISSUE_REFS` and diff against `.claude/backlog-cache.json
1213
1229
 
1214
1230
  **If `BACKLOG_PROVIDER=github`:**
1215
1231
  ```bash
1216
- gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt
1232
+ (cd "${SPECRAILS_REPO_DIR:-.}" && gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt)
1217
1233
  ```
1218
1234
 
1219
1235
  If the cache file is missing or malformed JSON at this point: log `[conflict-check] Warning: cache file missing or unreadable. Skipping diff for this run.` and proceed to Phase 4c (treat as clean).
@@ -1270,13 +1286,15 @@ This phase respects the `GIT_AUTO` and `BACKLOG_WRITE` settings from configurati
1270
1286
 
1271
1287
  #### If `GIT_AUTO=true` (automatic shipping)
1272
1288
 
1273
- 1. Create branch from `main`: `git checkout -b feat/<descriptive-name>`
1274
- 2. One commit per feature with descriptive messages
1275
- 3. If the reviewer modified files, create an additional commit: `fix: resolve CI issues (reviewer)`
1276
- 4. Push with `-u` flag: `git push -u origin <branch-name>`
1277
- 5. Create PR (if GitHub CLI is available):
1289
+ All git operations run against the repo via `git -C "${SPECRAILS_REPO_DIR:-.}"`, and `gh` runs from inside the repo so it can detect the remote.
1290
+
1291
+ 1. Create branch from `main`: `git -C "${SPECRAILS_REPO_DIR:-.}" checkout -b feat/<descriptive-name>`
1292
+ 2. One commit per feature with descriptive messages (`git -C "${SPECRAILS_REPO_DIR:-.}" add … && git -C "${SPECRAILS_REPO_DIR:-.}" commit -m …`)
1293
+ 3. If the reviewer modified files, create an additional commit: `git -C "${SPECRAILS_REPO_DIR:-.}" commit -m "fix: resolve CI issues (reviewer)"`
1294
+ 4. Push with `-u` flag: `git -C "${SPECRAILS_REPO_DIR:-.}" push -u origin <branch-name>`
1295
+ 5. Create PR (if GitHub CLI is available), running it from the repo:
1278
1296
  ```bash
1279
- {{PR_CREATE_CMD}}
1297
+ (cd "${SPECRAILS_REPO_DIR:-.}" && {{PR_CREATE_CMD}})
1280
1298
  ```
1281
1299
  If `gh` is not authenticated, print a compare URL for manual PR creation.
1282
1300
 
@@ -1293,9 +1311,9 @@ All implementation is complete and CI checks pass.
1293
1311
  - [list all modified/created files per feature]
1294
1312
 
1295
1313
  ### Suggested Next Steps
1296
- 1. Review the changes: `git diff`
1297
- 2. Create a branch: `git checkout -b feat/<name>`
1298
- 3. Stage and commit: `git add <files> && git commit -m "feat: ..."`
1314
+ 1. Review the changes: `git -C "${SPECRAILS_REPO_DIR:-.}" diff`
1315
+ 2. Create a branch: `git -C "${SPECRAILS_REPO_DIR:-.}" checkout -b feat/<name>`
1316
+ 3. Stage and commit: `git -C "${SPECRAILS_REPO_DIR:-.}" add <files> && git -C "${SPECRAILS_REPO_DIR:-.}" commit -m "feat: ..."`
1299
1317
  4. Push and create PR manually
1300
1318
  ```
1301
1319
 
@@ -1307,7 +1325,7 @@ All implementation is complete and CI checks pass.
1307
1325
  {{BACKLOG_COMMENT_CMD}}
1308
1326
  ```
1309
1327
  - **Local:** Update the ticket status to `"done"` using `{{BACKLOG_UPDATE_CMD}}` and add a comment: `"Implemented in PR #XX. All acceptance criteria met."` via `{{BACKLOG_COMMENT_CMD}}`. Local tickets are closed directly — there is no auto-close-on-merge mechanism.
1310
- - **GitHub:** `gh issue comment {number} --body "Implemented in PR #XX. All acceptance criteria met."` — do NOT close the issue explicitly. Use `Closes #N` in the PR body so GitHub auto-closes on merge.
1328
+ - **GitHub:** `(cd "${SPECRAILS_REPO_DIR:-.}" && gh issue comment {number} --body "Implemented in PR #XX. All acceptance criteria met.")` — do NOT close the issue explicitly. Use `Closes #N` in the PR body so GitHub auto-closes on merge.
1311
1329
  - **JIRA:** `jira issue comment {key} --message "Implemented in PR #XX. All acceptance criteria met."`
1312
1330
  - For GitHub/JIRA: ensure the PR body includes `Closes #N` for each fully resolved issue (auto-closes on merge)
1313
1331
  - For partially resolved issues/tickets: add a comment noting progress:
@@ -19,6 +19,8 @@ Resume a failed `/specrails:implement` run for **{{PROJECT_NAME}}**. Reads pipel
19
19
 
20
20
  **MANDATORY: Follow this pipeline exactly. Do NOT skip phases or re-run phases that already succeeded. Read all context from the pipeline state file — do not rely on memory. Do not re-implement anything yourself; delegate to the same agents used by `/specrails:implement`.**
21
21
 
22
+ **Repository location.** Your working directory may NOT be the user's source repository. Repo-resident things — `openspec/**`, source, `.git`, the GitHub remote — live under **`${SPECRAILS_REPO_DIR:-.}`** (set by the spawner; unset ⇒ `.` ⇒ byte-identical to a classic in-repo run). The pipeline-state file itself is **run-state**, read from `.claude/pipeline-state/` relative to the working directory — do NOT prefix it. The `openspec_artifacts` value stored in that file is a repo-relative path (`openspec/changes/<name>/`); prefix it with `${SPECRAILS_REPO_DIR:-.}/` when you read those files on disk. All git/PR operations are delegated to `/specrails:implement` Phase 4c, which already runs them against the repo.
23
+
22
24
  **Input:** $ARGUMENTS — accepted forms:
23
25
 
24
26
  1. `<feature-name>` — kebab-case feature name matching a `.claude/pipeline-state/<feature-name>.json` file
@@ -214,7 +216,7 @@ Wait for all architects to complete.
214
216
  Before launching, verify architect artifacts exist:
215
217
 
216
218
  ```bash
217
- ls <OPENSPEC_ARTIFACTS>tasks.md <OPENSPEC_ARTIFACTS>context-bundle.md
219
+ ls "${SPECRAILS_REPO_DIR:-.}/<OPENSPEC_ARTIFACTS>tasks.md" "${SPECRAILS_REPO_DIR:-.}/<OPENSPEC_ARTIFACTS>context-bundle.md"
218
220
  ```
219
221
 
220
222
  If missing and `RESUME_PHASE=developer`: print:
@@ -58,14 +58,18 @@ The change is archived BY THE REVIEWER as part of a passing review — never by
58
58
 
59
59
  ## Pipeline
60
60
 
61
- 0. **Bootstrap.** Confirm `pwd` is the git repo root and load the ticket from
62
- `.specrails/local-tickets.json` (or use the free-form description). Then go
63
- STRAIGHT to phase 1 do not analyse, design, scaffold, or write anything
64
- yourself; the architect does that.
61
+ 0. **Bootstrap.** The source repo (with `openspec/**` and `.git`) lives at
62
+ `${SPECRAILS_REPO_DIR:-.}` when `SPECRAILS_REPO_DIR` is unset it defaults to
63
+ `.`, i.e. your current directory is the repo (classic behaviour). Confirm the
64
+ repo root with `git -C "${SPECRAILS_REPO_DIR:-.}" rev-parse --show-toplevel`,
65
+ then load the ticket from `.specrails/local-tickets.json` (run-state — relative
66
+ to the working directory, NOT the repo). Then go STRAIGHT to phase 1 — do not
67
+ analyse, design, scaffold, or write anything yourself; the architect does that.
65
68
 
66
69
  1. **DESIGN — `invoke_agent` `sr-architect`.** Pass it the ticket/description.
67
70
  It creates an OpenSpec change (proposal + spec deltas + tasks) under
68
- `openspec/changes/<id>/` and validates it (`openspec validate <id> --strict`).
71
+ `${SPECRAILS_REPO_DIR:-.}/openspec/changes/<id>/` and validates it
72
+ (`openspec validate <id> --strict`).
69
73
  Apply the outcome rules above.
70
74
 
71
75
  2. **APPLY — `invoke_agent` `sr-developer`.** Only after the architect reports
@@ -89,7 +93,7 @@ The change is archived BY THE REVIEWER as part of a passing review — never by
89
93
  or ambiguous review: the reviewer's PASS is the ONLY gate to archive.
90
94
 
91
95
  4. **ARCHIVE (verify only).** Confirm the change moved under
92
- `openspec/changes/archive/`. If the reviewer PASSED but the change was somehow
96
+ `${SPECRAILS_REPO_DIR:-.}/openspec/changes/archive/`. If the reviewer PASSED but the change was somehow
93
97
  not archived, re-`invoke_agent` `sr-reviewer` to complete it. Never archive by
94
98
  hand to substitute for the reviewer.
95
99