specrails-core 3.5.0 → 3.5.2

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/README.md CHANGED
@@ -196,7 +196,7 @@ AI product discovery using your personas. Evaluates ideas, creates tickets (loca
196
196
 
197
197
  specrails-core ships with a built-in ticket system — no GitHub account or external tools required.
198
198
 
199
- Tickets live in `.claude/local-tickets.json` alongside your code. They're plain JSON and git-friendly.
199
+ Tickets live in `.specrails/local-tickets.json` alongside your code. They're plain JSON and git-friendly.
200
200
 
201
201
  **Local tickets are the default.** The `/specrails:setup` wizard defaults to local tickets and skips GitHub/JIRA credential setup unless you opt in.
202
202
 
package/commands/setup.md CHANGED
@@ -59,7 +59,7 @@ Read the following files to understand the current installation state:
59
59
  Command template files include `implement.md`, `batch-implement.md`, `compat-check.md`, `refactor-recommender.md`, `why.md`, `get-backlog-specs.md`, `auto-propose-backlog-specs.md`.
60
60
  If this directory does not exist, skip command template checking for this update.
61
61
 
62
- 6. Read `$SPECRAILS_DIR/backlog-config.json` if it exists — contains stored provider configuration needed for command placeholder substitution.
62
+ 6. Read `.specrails/backlog-config.json` if it exists — contains stored provider configuration needed for command placeholder substitution.
63
63
 
64
64
  ### Phase U2: Quick Codebase Re-Analysis
65
65
 
@@ -178,7 +178,7 @@ For each command in the "changed commands" list from Phase U3:
178
178
  1. Read the NEW template:
179
179
  - If `cli_provider == "claude"`: from `$SPECRAILS_DIR/setup-templates/commands/specrails/<name>.md`
180
180
  - If `cli_provider == "codex"`: from `$SPECRAILS_DIR/setup-templates/skills/sr-<name>/SKILL.md`
181
- 2. Read stored backlog configuration from `$SPECRAILS_DIR/backlog-config.json` (if it exists) to resolve provider-specific placeholders:
181
+ 2. Read stored backlog configuration from `.specrails/backlog-config.json` (if it exists) to resolve provider-specific placeholders:
182
182
  - `BACKLOG_PROVIDER` → `provider` field (`github`, `jira`, or `none`)
183
183
  - `BACKLOG_WRITE` → `write_access` field
184
184
  - `JIRA_BASE_URL` → `jira_base_url` field
@@ -424,8 +424,8 @@ Core commands (always install if missing):
424
424
  - `auto-propose-backlog-specs.md`
425
425
 
426
426
  **Initialize local ticket storage** (backlog provider defaults to `local`):
427
- 1. Copy `templates/local-tickets-schema.json` to `$SPECRAILS_DIR/local-tickets.json` and set `last_updated` to the current ISO-8601 timestamp. Skip if the file already exists.
428
- 2. Write `$SPECRAILS_DIR/backlog-config.json` (skip if already exists):
427
+ 1. Copy `templates/local-tickets-schema.json` to `.specrails/local-tickets.json` and set `last_updated` to the current ISO-8601 timestamp. Skip if the file already exists.
428
+ 2. Write `.specrails/backlog-config.json` (skip if already exists):
429
429
  ```json
430
430
  {
431
431
  "provider": "local",
@@ -699,7 +699,7 @@ Ask the user how they want to manage their product backlog. Default is local —
699
699
  Use local ticket management or connect an external provider?
700
700
 
701
701
  1. **Local tickets** (default, recommended) — lightweight JSON-based ticket management built into the project.
702
- No external tools or accounts required. Tickets stored in `.claude/local-tickets.json`, version-controlled and diffable.
702
+ No external tools or accounts required. Tickets stored in `.specrails/local-tickets.json`, version-controlled and diffable.
703
703
  2. **External provider** — connect GitHub Issues, JIRA, or disable backlog commands
704
704
  ```
705
705
 
@@ -713,7 +713,7 @@ If the user selects **2**: display the secondary menu:
713
713
  Which external provider?
714
714
 
715
715
  1. **Local tickets** (recommended) — lightweight JSON-based ticket management built into the project.
716
- No external tools required. Tickets stored in `.claude/local-tickets.json`, version-controlled and diffable.
716
+ No external tools required. Tickets stored in `.specrails/local-tickets.json`, version-controlled and diffable.
717
717
  2. **GitHub Issues** — uses `gh` CLI to read/create issues with labels and VPC scores
718
718
  3. **JIRA** — uses JIRA CLI or REST API to read/create tickets in a JIRA project
719
719
  4. **None** — skip backlog commands (you can still use /implement with text descriptions)
@@ -725,10 +725,10 @@ Wait for the user's choice. Set `BACKLOG_PROVIDER` to `local`, `github`, `jira`,
725
725
 
726
726
  No external tools or credentials required. Initialize the storage file:
727
727
 
728
- 1. Copy `templates/local-tickets-schema.json` to `$SPECRAILS_DIR/local-tickets.json`
728
+ 1. Copy `templates/local-tickets-schema.json` to `.specrails/local-tickets.json`
729
729
  2. Set `last_updated` to the current ISO-8601 timestamp
730
730
 
731
- Store configuration in `$SPECRAILS_DIR/backlog-config.json`:
731
+ Store configuration in `.specrails/backlog-config.json`:
732
732
  ```json
733
733
  {
734
734
  "provider": "local",
@@ -774,13 +774,13 @@ Local tickets are always read-write — there is no "read only" mode since the f
774
774
 
775
775
  The `revision` counter in the JSON root enables optimistic concurrency — increment it on **every** write. The lock file prevents concurrent corruption:
776
776
 
777
- 1. **Acquire lock:** Check for `$SPECRAILS_DIR/local-tickets.json.lock`
777
+ 1. **Acquire lock:** Check for `.specrails/local-tickets.json.lock`
778
778
  - If the file exists and its `timestamp` is less than 30 seconds old: wait 500ms and retry (max 5 attempts before aborting with an error)
779
779
  - If the file exists and its `timestamp` is 30+ seconds old (stale): delete it and proceed
780
780
  - If no lock file exists: proceed immediately
781
- 2. **Create lock file:** Write `{"agent": "<agent-name-or-process>", "timestamp": "<ISO-8601>"}` to `$SPECRAILS_DIR/local-tickets.json.lock`
781
+ 2. **Create lock file:** Write `{"agent": "<agent-name-or-process>", "timestamp": "<ISO-8601>"}` to `.specrails/local-tickets.json.lock`
782
782
  3. **Minimal lock window:** Read the JSON → modify in memory → write back → release
783
- 4. **Release lock:** Delete `$SPECRAILS_DIR/local-tickets.json.lock`
783
+ 4. **Release lock:** Delete `.specrails/local-tickets.json.lock`
784
784
  5. **Always increment `revision`** by 1 and update `last_updated` on every successful write
785
785
 
786
786
  The hub server uses `proper-lockfile` (or equivalent) to honor the same protocol via the `.lock` file path.
@@ -895,7 +895,7 @@ Ask:
895
895
 
896
896
  Set `EPIC_LINK_FIELD` to `parent` or `customfield_10014`. Default: `parent`.
897
897
 
898
- Store the full configuration in `.claude/backlog-config.json`:
898
+ Store the full configuration in `.specrails/backlog-config.json`:
899
899
  ```json
900
900
  {
901
901
  "provider": "jira",
@@ -1147,22 +1147,22 @@ When adapting `auto-propose-backlog-specs.md` and `get-backlog-specs.md`, substi
1147
1147
 
1148
1148
  #### Local Tickets (`BACKLOG_PROVIDER=local`)
1149
1149
 
1150
- For the local provider, backlog placeholders resolve to **inline file-operation instructions** embedded in the generated command markdown — not shell commands. Agents execute these by reading/writing `$SPECRAILS_DIR/local-tickets.json` directly using their file tools.
1150
+ For the local provider, backlog placeholders resolve to **inline file-operation instructions** embedded in the generated command markdown — not shell commands. Agents execute these by reading/writing `.specrails/local-tickets.json` directly using their file tools.
1151
1151
 
1152
1152
  All write operations must follow the **advisory file locking protocol** defined in Phase 3.2. Always increment `revision` and update `last_updated` on every write.
1153
1153
 
1154
1154
  | Placeholder | Substituted value |
1155
1155
  |-------------|-------------------|
1156
1156
  | `{{BACKLOG_PROVIDER_NAME}}` | `Local Tickets` |
1157
- | `{{BACKLOG_PREFLIGHT}}` | `[[ -f "$SPECRAILS_DIR/local-tickets.json" ]] && echo "Local tickets storage: OK" \|\| echo "WARNING: $SPECRAILS_DIR/local-tickets.json not found — run /specrails:setup to initialize"` |
1158
- | `{{BACKLOG_FETCH_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"todo"` or `"in_progress"`. |
1159
- | `{{BACKLOG_FETCH_ALL_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse the `tickets` map and return all entries regardless of status. |
1160
- | `{{BACKLOG_FETCH_CLOSED_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"done"` or `"cancelled"`. |
1161
- | `{{BACKLOG_VIEW_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse JSON and return the full ticket object at `tickets["{id}"]`, or an error if not found. |
1162
- | `{{BACKLOG_CREATE_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → set `id = next_id`, increment `next_id`, set all ticket fields, set `created_at` and `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1163
- | `{{BACKLOG_UPDATE_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → update fields in `tickets["{id}"]`, set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1164
- | `{{BACKLOG_DELETE_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → delete `tickets["{id}"]`, bump `revision`, update `last_updated` → write → release lock. |
1165
- | `{{BACKLOG_COMMENT_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → append `{"author": "<agent-name>", "body": "<comment>", "created_at": "<ISO-8601>"}` to `tickets["{id}"].comments` (create the array if absent), set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1157
+ | `{{BACKLOG_PREFLIGHT}}` | `[[ -f ".specrails/local-tickets.json" ]] && echo "Local tickets storage: OK" \|\| echo "WARNING: .specrails/local-tickets.json not found — run /specrails:setup to initialize"` |
1158
+ | `{{BACKLOG_FETCH_CMD}}` | Read `.specrails/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"todo"` or `"in_progress"`. |
1159
+ | `{{BACKLOG_FETCH_ALL_CMD}}` | Read `.specrails/local-tickets.json`. Parse the `tickets` map and return all entries regardless of status. |
1160
+ | `{{BACKLOG_FETCH_CLOSED_CMD}}` | Read `.specrails/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"done"` or `"cancelled"`. |
1161
+ | `{{BACKLOG_VIEW_CMD}}` | Read `.specrails/local-tickets.json`. Parse JSON and return the full ticket object at `tickets["{id}"]`, or an error if not found. |
1162
+ | `{{BACKLOG_CREATE_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → set `id = next_id`, increment `next_id`, set all ticket fields, set `created_at` and `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1163
+ | `{{BACKLOG_UPDATE_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → update fields in `tickets["{id}"]`, set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1164
+ | `{{BACKLOG_DELETE_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → delete `tickets["{id}"]`, bump `revision`, update `last_updated` → write → release lock. |
1165
+ | `{{BACKLOG_COMMENT_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → append `{"author": "<agent-name>", "body": "<comment>", "created_at": "<ISO-8601>"}` to `tickets["{id}"].comments` (create the array if absent), set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1166
1166
  | `{{BACKLOG_PARTIAL_COMMENT_CMD}}` | Same as `{{BACKLOG_COMMENT_CMD}}` but append `{"author": "<agent-name>", "body": "<comment>", "type": "progress", "created_at": "<ISO-8601>"}`. |
1167
1167
  | `{{BACKLOG_INIT_LABELS_CMD}}` | No label initialization required. Local tickets use freeform label strings. Standard label conventions: `area:frontend`, `area:backend`, `area:api`, `effort:low`, `effort:medium`, `effort:high`. |
1168
1168
 
@@ -1183,7 +1183,7 @@ All write operations must follow the **advisory file locking protocol** defined
1183
1183
  - Issue view: `jira issue view {key}` or REST API
1184
1184
  - VPC scores stored in the issue description body (same markdown format, parsed from description)
1185
1185
  - Pre-flight check: `jira me` or test API connectivity
1186
- - Store JIRA config in `$SPECRAILS_DIR/backlog-config.json`:
1186
+ - Store JIRA config in `.specrails/backlog-config.json`:
1187
1187
  ```json
1188
1188
  {
1189
1189
  "provider": "jira",
@@ -231,7 +231,7 @@ The quick path — three questions, sensible defaults, done in under a minute.
231
231
  |------|--------|
232
232
  | Core agents | sr-architect, sr-developer, sr-reviewer, sr-product-manager |
233
233
  | All workflow commands | `/specrails:implement`, `/specrails:get-backlog-specs`, and 14 more |
234
- | Backlog storage | Local tickets (`.claude/local-tickets.json`) — no GitHub or JIRA required |
234
+ | Backlog storage | Local tickets (`.specrails/local-tickets.json`) — no GitHub or JIRA required |
235
235
  | CLAUDE.md | Project-level context for agents |
236
236
 
237
237
  You can run the full wizard later to deepen configuration: personas, stack analysis, layer-specific conventions.
@@ -6,7 +6,7 @@ specrails-core ships with a built-in, file-based ticket management system. It is
6
6
 
7
7
  ## Overview
8
8
 
9
- Tickets live in `.claude/local-tickets.json` at your project root. Because it's a plain JSON file, tickets are:
9
+ Tickets live in `.specrails/local-tickets.json` at your project root. Because it's a plain JSON file, tickets are:
10
10
 
11
11
  - **Version-controlled** — tracked by git, diffable in PRs
12
12
  - **Offline-first** — no network calls, no rate limits
@@ -18,7 +18,7 @@ The file is read and written by specrails-core during command execution.
18
18
 
19
19
  ## Storage format
20
20
 
21
- `.claude/local-tickets.json`:
21
+ `.specrails/local-tickets.json`:
22
22
 
23
23
  ```json
24
24
  {
@@ -99,7 +99,7 @@ Use local ticket management or connect an external provider?
99
99
  2. External provider — connect GitHub Issues, JIRA, or disable backlog commands
100
100
  ```
101
101
 
102
- Pressing **Enter** or selecting **1** initializes `.claude/local-tickets.json` with an empty ticket store and writes `.claude/backlog-config.json`:
102
+ Pressing **Enter** or selecting **1** initializes `.specrails/local-tickets.json` with an empty ticket store and writes `.specrails/backlog-config.json`:
103
103
 
104
104
  ```json
105
105
  {
@@ -123,7 +123,7 @@ Multiple agents can modify `local-tickets.json` simultaneously. The system uses
123
123
 
124
124
  ### Advisory file lock
125
125
 
126
- Before every write, the agent creates `.claude/local-tickets.json.lock`:
126
+ Before every write, the agent creates `.specrails/local-tickets.json.lock`:
127
127
 
128
128
  ```json
129
129
  {
@@ -22,7 +22,7 @@ Switching is optional. GitHub Issues and JIRA remain fully supported. Local tick
22
22
 
23
23
  ## Step 1: Switch the provider
24
24
 
25
- Edit `.claude/backlog-config.json` in your project root:
25
+ Edit `.specrails/backlog-config.json` in your project root:
26
26
 
27
27
  ```json
28
28
  {
@@ -42,7 +42,7 @@ Then initialize the ticket store if it doesn't exist yet:
42
42
  Or create the file manually:
43
43
 
44
44
  ```bash
45
- cat > .claude/local-tickets.json << 'EOF'
45
+ cat > .specrails/local-tickets.json << 'EOF'
46
46
  {
47
47
  "schema_version": "1.0",
48
48
  "revision": 0,
@@ -93,7 +93,7 @@ To do a dry run (preview without writing):
93
93
 
94
94
  ### From JIRA
95
95
 
96
- Use the `sr:migrate-from-jira` command (requires `jira` CLI or REST API credentials in `.claude/backlog-config.json`):
96
+ Use the `sr:migrate-from-jira` command (requires `jira` CLI or REST API credentials in `.specrails/backlog-config.json`):
97
97
 
98
98
  ```bash
99
99
  # Inside Claude Code
@@ -133,7 +133,7 @@ The `--update` flag regenerates only the backlog commands (`get-backlog-specs`,
133
133
 
134
134
  To revert to GitHub Issues:
135
135
 
136
- 1. Edit `.specrails/config.yaml` (or `.claude/backlog-config.json` for scaffold installs) and set `provider: github`
136
+ 1. Edit `.specrails/config.yaml` (or `.specrails/backlog-config.json` for scaffold installs) and set `provider: github`
137
137
  2. Re-run `/specrails:setup --update` to regenerate commands
138
138
  3. Your `local-tickets.json` is preserved — switch back any time
139
139
 
package/docs/workflows.md CHANGED
@@ -126,7 +126,7 @@ View your prioritized product backlog, ranked by VPC fit and effort.
126
126
 
127
127
  ### What it shows
128
128
 
129
- The Product Analyst reads your backlog (local tickets in `.claude/local-tickets.json` by default, or GitHub Issues labeled `product-driven-backlog` if configured) and produces:
129
+ The Product Analyst reads your backlog (local tickets in `.specrails/local-tickets.json` by default, or GitHub Issues labeled `product-driven-backlog` if configured) and produces:
130
130
 
131
131
  - **Backlog table** per area — sorted by Total Persona Score
132
132
  - **Top 3 recommendations** — ranked by VPC score / effort ratio, filtered to Wave 1 of the safe implementation order
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specrails-core",
3
- "version": "3.5.0",
3
+ "version": "3.5.2",
4
4
  "description": "AI agent workflow system for Claude Code — installs 12 specialized agents, orchestration commands, and persona-driven product discovery into any repository",
5
5
  "bin": {
6
6
  "specrails-core": "bin/specrails-core.js"
@@ -67,7 +67,7 @@ After the Explore agent completes:
67
67
 
68
68
  1. **Display** results to the user.
69
69
 
70
- 2. Read `.claude/backlog-config.json` and extract:
70
+ 2. Read `.specrails/backlog-config.json` and extract:
71
71
  - `BACKLOG_PROVIDER` (`local`, `github`, `jira`, or `none`)
72
72
  - `BACKLOG_WRITE` (from `write_access`)
73
73
 
@@ -100,7 +100,7 @@ After the Explore agent completes:
100
100
 
101
101
  ### If provider=local — Sync to Local Tickets
102
102
 
103
- Local tickets are always read-write. Sync directly to `$SPECRAILS_DIR/local-tickets.json`.
103
+ Local tickets are always read-write. Sync directly to `.specrails/local-tickets.json`.
104
104
 
105
105
  3. **Fetch existing local tickets** to avoid duplicates:
106
106
  ```
@@ -196,7 +196,7 @@ Local tickets are always read-write. Sync directly to `$SPECRAILS_DIR/local-tick
196
196
 
197
197
  ### If provider=jira and BACKLOG_WRITE=true — Sync to JIRA
198
198
 
199
- Read from `.claude/backlog-config.json`:
199
+ Read from `.specrails/backlog-config.json`:
200
200
  - `JIRA_BASE_URL`, `JIRA_PROJECT_KEY`, `AUTH_METHOD`
201
201
  - `PROJECT_LABEL` (may be empty string)
202
202
  - `EPIC_MAPPING` (object mapping area name → JIRA epic key)
@@ -262,7 +262,7 @@ For each unique area:
262
262
  If `PROJECT_LABEL` is non-empty, add it to the `labels` array.
263
263
  Set `EPIC_MAPPING[area] = <returned key>`.
264
264
 
265
- After all areas are processed: write the updated `EPIC_MAPPING` back to `.claude/backlog-config.json`.
265
+ After all areas are processed: write the updated `EPIC_MAPPING` back to `.specrails/backlog-config.json`.
266
266
 
267
267
  #### Step E: Create Story tickets
268
268
 
@@ -163,7 +163,7 @@ The product-analyst receives this prompt:
163
163
 
164
164
  #### If provider=local — Cache from Local Tickets
165
165
 
166
- Read `$SPECRAILS_DIR/local-tickets.json` and parse the `tickets` map. For each ticket with `"product-driven-backlog"` in its `labels` array and `status` not `"cancelled"`, build a snapshot object:
166
+ Read `.specrails/local-tickets.json` and parse the `tickets` map. For each ticket with `"product-driven-backlog"` in its `labels` array and `status` not `"cancelled"`, build a snapshot object:
167
167
  - `number`: ticket `id` (integer)
168
168
  - `title`: ticket `title` string
169
169
  - `state`: map ticket `status` — `"done"` or `"cancelled"` → `"closed"`, otherwise → `"open"`
@@ -26,11 +26,11 @@ Check the environment variable `CLAUDE_CODE_ENTRYPOINT`. If it contains `remote_
26
26
 
27
27
  #### 1. Backlog provider availability
28
28
 
29
- Read `.claude/backlog-config.json` and extract `BACKLOG_PROVIDER`.
29
+ Read `.specrails/backlog-config.json` and extract `BACKLOG_PROVIDER`.
30
30
 
31
31
  **If `BACKLOG_PROVIDER=local`:**
32
32
  ```bash
33
- [[ -f "$SPECRAILS_DIR/local-tickets.json" ]] && echo "Local tickets storage: OK" || echo "WARNING: local-tickets.json not found"
33
+ [[ -f ".specrails/local-tickets.json" ]] && echo "Local tickets storage: OK" || echo "WARNING: local-tickets.json not found"
34
34
  ```
35
35
  - Set `LOCAL_TICKETS_AVAILABLE=true/false` based on file existence.
36
36
  - Set `GH_AVAILABLE=false` (GitHub CLI not needed for local provider).
@@ -132,7 +132,7 @@ After fetching issue refs, capture a baseline snapshot for conflict detection.
132
132
 
133
133
  ##### If `BACKLOG_PROVIDER=local` and input mode was issue numbers:
134
134
 
135
- For each resolved ticket ID, read `$SPECRAILS_DIR/local-tickets.json` and extract the ticket object at `tickets["{id}"]`.
135
+ For each resolved ticket ID, read `.specrails/local-tickets.json` and extract the ticket object at `tickets["{id}"]`.
136
136
 
137
137
  Build a snapshot object for each ticket:
138
138
  - `number`: ticket `id` (integer)
@@ -314,7 +314,7 @@ Pick the single idea with the best impact/effort ratio from each exploration. Pr
314
314
 
315
315
  Otherwise, re-fetch each issue in scope and diff against the Phase 0 snapshot:
316
316
 
317
- **If `BACKLOG_PROVIDER=local`:** For each ticket ID in `ISSUE_REFS`, read `$SPECRAILS_DIR/local-tickets.json` and extract the ticket at `tickets["{id}"]`. If the ticket does not exist (deleted): treat as a CRITICAL conflict — field `"state"`, was `<cached state>`, now `"deleted"`. Otherwise, reconstruct a current snapshot using the same mapping as the Phase 0 local snapshot.
317
+ **If `BACKLOG_PROVIDER=local`:** For each ticket ID in `ISSUE_REFS`, read `.specrails/local-tickets.json` and extract the ticket at `tickets["{id}"]`. If the ticket does not exist (deleted): treat as a CRITICAL conflict — field `"state"`, was `<cached state>`, now `"deleted"`. Otherwise, reconstruct a current snapshot using the same mapping as the Phase 0 local snapshot.
318
318
 
319
319
  **If `BACKLOG_PROVIDER=github`:** For each issue number in `ISSUE_REFS`:
320
320
 
@@ -897,7 +897,7 @@ This check is independent of Phase 3a.0. Even if the user chose to continue thro
897
897
 
898
898
  Re-fetch each issue in `ISSUE_REFS` and diff against `.claude/backlog-cache.json` using the same algorithm as Phase 3a.0:
899
899
 
900
- **If `BACKLOG_PROVIDER=local`:** Read `$SPECRAILS_DIR/local-tickets.json` and extract each ticket by ID.
900
+ **If `BACKLOG_PROVIDER=local`:** Read `.specrails/local-tickets.json` and extract each ticket by ID.
901
901
 
902
902
  **If `BACKLOG_PROVIDER=github`:**
903
903
  ```bash
@@ -47,7 +47,7 @@ Output ONLY the following structured markdown. Do not add any preamble or explan
47
47
 
48
48
  ## Backlog Sync
49
49
 
50
- After generating the proposal, read `.claude/backlog-config.json` to determine `BACKLOG_PROVIDER` and `BACKLOG_WRITE`.
50
+ After generating the proposal, read `.specrails/backlog-config.json` to determine `BACKLOG_PROVIDER` and `BACKLOG_WRITE`.
51
51
 
52
52
  ### If provider=local — Create Local Ticket
53
53
 
@@ -59,7 +59,7 @@ Read the following files to understand the current installation state:
59
59
  Command template files include `implement.md`, `batch-implement.md`, `compat-check.md`, `refactor-recommender.md`, `why.md`, `get-backlog-specs.md`, `auto-propose-backlog-specs.md`.
60
60
  If this directory does not exist, skip command template checking for this update.
61
61
 
62
- 6. Read `$SPECRAILS_DIR/backlog-config.json` if it exists — contains stored provider configuration needed for command placeholder substitution.
62
+ 6. Read `.specrails/backlog-config.json` if it exists — contains stored provider configuration needed for command placeholder substitution.
63
63
 
64
64
  ### Phase U2: Quick Codebase Re-Analysis
65
65
 
@@ -178,7 +178,7 @@ For each command in the "changed commands" list from Phase U3:
178
178
  1. Read the NEW template:
179
179
  - If `cli_provider == "claude"`: from `$SPECRAILS_DIR/setup-templates/commands/specrails/<name>.md`
180
180
  - If `cli_provider == "codex"`: from `$SPECRAILS_DIR/setup-templates/skills/sr-<name>/SKILL.md`
181
- 2. Read stored backlog configuration from `$SPECRAILS_DIR/backlog-config.json` (if it exists) to resolve provider-specific placeholders:
181
+ 2. Read stored backlog configuration from `.specrails/backlog-config.json` (if it exists) to resolve provider-specific placeholders:
182
182
  - `BACKLOG_PROVIDER` → `provider` field (`github`, `jira`, or `none`)
183
183
  - `BACKLOG_WRITE` → `write_access` field
184
184
  - `JIRA_BASE_URL` → `jira_base_url` field
@@ -424,8 +424,8 @@ Core commands (always install if missing):
424
424
  - `auto-propose-backlog-specs.md`
425
425
 
426
426
  **Initialize local ticket storage** (backlog provider defaults to `local`):
427
- 1. Copy `templates/local-tickets-schema.json` to `$SPECRAILS_DIR/local-tickets.json` and set `last_updated` to the current ISO-8601 timestamp. Skip if the file already exists.
428
- 2. Write `$SPECRAILS_DIR/backlog-config.json` (skip if already exists):
427
+ 1. Copy `templates/local-tickets-schema.json` to `.specrails/local-tickets.json` and set `last_updated` to the current ISO-8601 timestamp. Skip if the file already exists.
428
+ 2. Write `.specrails/backlog-config.json` (skip if already exists):
429
429
  ```json
430
430
  {
431
431
  "provider": "local",
@@ -699,7 +699,7 @@ Ask the user how they want to manage their product backlog. Default is local —
699
699
  Use local ticket management or connect an external provider?
700
700
 
701
701
  1. **Local tickets** (default, recommended) — lightweight JSON-based ticket management built into the project.
702
- No external tools or accounts required. Tickets stored in `.claude/local-tickets.json`, version-controlled and diffable.
702
+ No external tools or accounts required. Tickets stored in `.specrails/local-tickets.json`, version-controlled and diffable.
703
703
  2. **External provider** — connect GitHub Issues, JIRA, or disable backlog commands
704
704
  ```
705
705
 
@@ -713,7 +713,7 @@ If the user selects **2**: display the secondary menu:
713
713
  Which external provider?
714
714
 
715
715
  1. **Local tickets** (recommended) — lightweight JSON-based ticket management built into the project.
716
- No external tools required. Tickets stored in `.claude/local-tickets.json`, version-controlled and diffable.
716
+ No external tools required. Tickets stored in `.specrails/local-tickets.json`, version-controlled and diffable.
717
717
  2. **GitHub Issues** — uses `gh` CLI to read/create issues with labels and VPC scores
718
718
  3. **JIRA** — uses JIRA CLI or REST API to read/create tickets in a JIRA project
719
719
  4. **None** — skip backlog commands (you can still use /implement with text descriptions)
@@ -725,10 +725,10 @@ Wait for the user's choice. Set `BACKLOG_PROVIDER` to `local`, `github`, `jira`,
725
725
 
726
726
  No external tools or credentials required. Initialize the storage file:
727
727
 
728
- 1. Copy `templates/local-tickets-schema.json` to `$SPECRAILS_DIR/local-tickets.json`
728
+ 1. Copy `templates/local-tickets-schema.json` to `.specrails/local-tickets.json`
729
729
  2. Set `last_updated` to the current ISO-8601 timestamp
730
730
 
731
- Store configuration in `$SPECRAILS_DIR/backlog-config.json`:
731
+ Store configuration in `.specrails/backlog-config.json`:
732
732
  ```json
733
733
  {
734
734
  "provider": "local",
@@ -774,13 +774,13 @@ Local tickets are always read-write — there is no "read only" mode since the f
774
774
 
775
775
  The `revision` counter in the JSON root enables optimistic concurrency — increment it on **every** write. The lock file prevents concurrent corruption:
776
776
 
777
- 1. **Acquire lock:** Check for `$SPECRAILS_DIR/local-tickets.json.lock`
777
+ 1. **Acquire lock:** Check for `.specrails/local-tickets.json.lock`
778
778
  - If the file exists and its `timestamp` is less than 30 seconds old: wait 500ms and retry (max 5 attempts before aborting with an error)
779
779
  - If the file exists and its `timestamp` is 30+ seconds old (stale): delete it and proceed
780
780
  - If no lock file exists: proceed immediately
781
- 2. **Create lock file:** Write `{"agent": "<agent-name-or-process>", "timestamp": "<ISO-8601>"}` to `$SPECRAILS_DIR/local-tickets.json.lock`
781
+ 2. **Create lock file:** Write `{"agent": "<agent-name-or-process>", "timestamp": "<ISO-8601>"}` to `.specrails/local-tickets.json.lock`
782
782
  3. **Minimal lock window:** Read the JSON → modify in memory → write back → release
783
- 4. **Release lock:** Delete `$SPECRAILS_DIR/local-tickets.json.lock`
783
+ 4. **Release lock:** Delete `.specrails/local-tickets.json.lock`
784
784
  5. **Always increment `revision`** by 1 and update `last_updated` on every successful write
785
785
 
786
786
  The hub server uses `proper-lockfile` (or equivalent) to honor the same protocol via the `.lock` file path.
@@ -895,7 +895,7 @@ Ask:
895
895
 
896
896
  Set `EPIC_LINK_FIELD` to `parent` or `customfield_10014`. Default: `parent`.
897
897
 
898
- Store the full configuration in `.claude/backlog-config.json`:
898
+ Store the full configuration in `.specrails/backlog-config.json`:
899
899
  ```json
900
900
  {
901
901
  "provider": "jira",
@@ -1147,22 +1147,22 @@ When adapting `auto-propose-backlog-specs.md` and `get-backlog-specs.md`, substi
1147
1147
 
1148
1148
  #### Local Tickets (`BACKLOG_PROVIDER=local`)
1149
1149
 
1150
- For the local provider, backlog placeholders resolve to **inline file-operation instructions** embedded in the generated command markdown — not shell commands. Agents execute these by reading/writing `$SPECRAILS_DIR/local-tickets.json` directly using their file tools.
1150
+ For the local provider, backlog placeholders resolve to **inline file-operation instructions** embedded in the generated command markdown — not shell commands. Agents execute these by reading/writing `.specrails/local-tickets.json` directly using their file tools.
1151
1151
 
1152
1152
  All write operations must follow the **advisory file locking protocol** defined in Phase 3.2. Always increment `revision` and update `last_updated` on every write.
1153
1153
 
1154
1154
  | Placeholder | Substituted value |
1155
1155
  |-------------|-------------------|
1156
1156
  | `{{BACKLOG_PROVIDER_NAME}}` | `Local Tickets` |
1157
- | `{{BACKLOG_PREFLIGHT}}` | `[[ -f "$SPECRAILS_DIR/local-tickets.json" ]] && echo "Local tickets storage: OK" \|\| echo "WARNING: $SPECRAILS_DIR/local-tickets.json not found — run /specrails:setup to initialize"` |
1158
- | `{{BACKLOG_FETCH_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"todo"` or `"in_progress"`. |
1159
- | `{{BACKLOG_FETCH_ALL_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse the `tickets` map and return all entries regardless of status. |
1160
- | `{{BACKLOG_FETCH_CLOSED_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"done"` or `"cancelled"`. |
1161
- | `{{BACKLOG_VIEW_CMD}}` | Read `$SPECRAILS_DIR/local-tickets.json`. Parse JSON and return the full ticket object at `tickets["{id}"]`, or an error if not found. |
1162
- | `{{BACKLOG_CREATE_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → set `id = next_id`, increment `next_id`, set all ticket fields, set `created_at` and `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1163
- | `{{BACKLOG_UPDATE_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → update fields in `tickets["{id}"]`, set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1164
- | `{{BACKLOG_DELETE_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → delete `tickets["{id}"]`, bump `revision`, update `last_updated` → write → release lock. |
1165
- | `{{BACKLOG_COMMENT_CMD}}` | Write to `$SPECRAILS_DIR/local-tickets.json` using the advisory locking protocol: acquire lock → read file → append `{"author": "<agent-name>", "body": "<comment>", "created_at": "<ISO-8601>"}` to `tickets["{id}"].comments` (create the array if absent), set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1157
+ | `{{BACKLOG_PREFLIGHT}}` | `[[ -f ".specrails/local-tickets.json" ]] && echo "Local tickets storage: OK" \|\| echo "WARNING: .specrails/local-tickets.json not found — run /specrails:setup to initialize"` |
1158
+ | `{{BACKLOG_FETCH_CMD}}` | Read `.specrails/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"todo"` or `"in_progress"`. |
1159
+ | `{{BACKLOG_FETCH_ALL_CMD}}` | Read `.specrails/local-tickets.json`. Parse the `tickets` map and return all entries regardless of status. |
1160
+ | `{{BACKLOG_FETCH_CLOSED_CMD}}` | Read `.specrails/local-tickets.json`. Parse the `tickets` map and return all entries where `status` is `"done"` or `"cancelled"`. |
1161
+ | `{{BACKLOG_VIEW_CMD}}` | Read `.specrails/local-tickets.json`. Parse JSON and return the full ticket object at `tickets["{id}"]`, or an error if not found. |
1162
+ | `{{BACKLOG_CREATE_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → set `id = next_id`, increment `next_id`, set all ticket fields, set `created_at` and `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1163
+ | `{{BACKLOG_UPDATE_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → update fields in `tickets["{id}"]`, set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1164
+ | `{{BACKLOG_DELETE_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → delete `tickets["{id}"]`, bump `revision`, update `last_updated` → write → release lock. |
1165
+ | `{{BACKLOG_COMMENT_CMD}}` | Write to `.specrails/local-tickets.json` using the advisory locking protocol: acquire lock → read file → append `{"author": "<agent-name>", "body": "<comment>", "created_at": "<ISO-8601>"}` to `tickets["{id}"].comments` (create the array if absent), set `updated_at` to now, bump `revision`, update `last_updated` → write → release lock. |
1166
1166
  | `{{BACKLOG_PARTIAL_COMMENT_CMD}}` | Same as `{{BACKLOG_COMMENT_CMD}}` but append `{"author": "<agent-name>", "body": "<comment>", "type": "progress", "created_at": "<ISO-8601>"}`. |
1167
1167
  | `{{BACKLOG_INIT_LABELS_CMD}}` | No label initialization required. Local tickets use freeform label strings. Standard label conventions: `area:frontend`, `area:backend`, `area:api`, `effort:low`, `effort:medium`, `effort:high`. |
1168
1168
 
@@ -1183,7 +1183,7 @@ All write operations must follow the **advisory file locking protocol** defined
1183
1183
  - Issue view: `jira issue view {key}` or REST API
1184
1184
  - VPC scores stored in the issue description body (same markdown format, parsed from description)
1185
1185
  - Pre-flight check: `jira me` or test API connectivity
1186
- - Store JIRA config in `$SPECRAILS_DIR/backlog-config.json`:
1186
+ - Store JIRA config in `.specrails/backlog-config.json`:
1187
1187
  ```json
1188
1188
  {
1189
1189
  "provider": "jira",
@@ -70,7 +70,7 @@ After the Explore agent completes:
70
70
 
71
71
  1. **Display** results to the user.
72
72
 
73
- 2. Read `.claude/backlog-config.json` and extract:
73
+ 2. Read `.specrails/backlog-config.json` and extract:
74
74
  - `BACKLOG_PROVIDER` (`github`, `jira`, or `none`)
75
75
  - `BACKLOG_WRITE` (from `write_access`)
76
76
 
@@ -159,7 +159,7 @@ After the Explore agent completes:
159
159
 
160
160
  ### If provider=jira and BACKLOG_WRITE=true — Sync to JIRA
161
161
 
162
- Read from `.claude/backlog-config.json`:
162
+ Read from `.specrails/backlog-config.json`:
163
163
  - `JIRA_BASE_URL`, `JIRA_PROJECT_KEY`, `AUTH_METHOD`
164
164
  - `PROJECT_LABEL` (may be empty string)
165
165
  - `EPIC_MAPPING` (object mapping area name → JIRA epic key)
@@ -225,7 +225,7 @@ For each unique area:
225
225
  If `PROJECT_LABEL` is non-empty, add it to the `labels` array.
226
226
  Set `EPIC_MAPPING[area] = <returned key>`.
227
227
 
228
- After all areas are processed: write the updated `EPIC_MAPPING` back to `.claude/backlog-config.json`.
228
+ After all areas are processed: write the updated `EPIC_MAPPING` back to `.specrails/backlog-config.json`.
229
229
 
230
230
  #### Step E: Create Story tickets
231
231