@garygentry/feature-forge 0.2.9 → 0.2.11

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 (82) hide show
  1. package/adapters/claude/.feature-forge-bundle.json +1 -1
  2. package/adapters/claude/references/pipeline-state-schema.json +37 -1
  3. package/adapters/claude/references/shared-conventions.md +22 -8
  4. package/adapters/claude/references/stage-exit-protocol.md +18 -0
  5. package/adapters/claude/references/templates/specs-hygiene/AGENTS.md +9 -0
  6. package/adapters/claude/references/templates/specs-hygiene/CLAUDE.md +9 -0
  7. package/adapters/claude/scripts/forge-session.py +41 -0
  8. package/adapters/claude/skills/forge-0-epic/SKILL.md +2 -0
  9. package/adapters/claude/skills/forge-1-prd/SKILL.md +1 -1
  10. package/adapters/claude/skills/forge-2-tech/SKILL.md +2 -0
  11. package/adapters/claude/skills/forge-3-specs/SKILL.md +3 -1
  12. package/adapters/claude/skills/forge-4-backlog/SKILL.md +2 -0
  13. package/adapters/claude/skills/forge-5-loop/SKILL.md +1 -1
  14. package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +22 -2
  15. package/adapters/claude/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +11 -0
  16. package/adapters/claude/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +11 -0
  17. package/adapters/codex/.feature-forge-bundle.json +1 -1
  18. package/adapters/codex/references/pipeline-state-schema.json +37 -1
  19. package/adapters/codex/references/shared-conventions.md +22 -8
  20. package/adapters/codex/references/stage-exit-protocol.md +18 -0
  21. package/adapters/codex/references/templates/specs-hygiene/AGENTS.md +9 -0
  22. package/adapters/codex/references/templates/specs-hygiene/CLAUDE.md +9 -0
  23. package/adapters/codex/scripts/forge-session.py +41 -0
  24. package/adapters/codex/skills/forge-0-epic/SKILL.md +2 -0
  25. package/adapters/codex/skills/forge-1-prd/SKILL.md +1 -1
  26. package/adapters/codex/skills/forge-2-tech/SKILL.md +2 -0
  27. package/adapters/codex/skills/forge-3-specs/SKILL.md +3 -1
  28. package/adapters/codex/skills/forge-4-backlog/SKILL.md +2 -0
  29. package/adapters/codex/skills/forge-5-loop/SKILL.md +1 -1
  30. package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +22 -2
  31. package/adapters/codex/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +11 -0
  32. package/adapters/codex/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +11 -0
  33. package/adapters/copilot/.feature-forge-bundle.json +1 -1
  34. package/adapters/copilot/references/pipeline-state-schema.json +37 -1
  35. package/adapters/copilot/references/shared-conventions.md +22 -8
  36. package/adapters/copilot/references/stage-exit-protocol.md +18 -0
  37. package/adapters/copilot/references/templates/specs-hygiene/AGENTS.md +9 -0
  38. package/adapters/copilot/references/templates/specs-hygiene/CLAUDE.md +9 -0
  39. package/adapters/copilot/scripts/forge-session.py +41 -0
  40. package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +2 -0
  41. package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +1 -1
  42. package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +2 -0
  43. package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +3 -1
  44. package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +2 -0
  45. package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +1 -1
  46. package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +22 -2
  47. package/adapters/copilot/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +11 -0
  48. package/adapters/copilot/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +11 -0
  49. package/adapters/cursor/.feature-forge-bundle.json +1 -1
  50. package/adapters/cursor/references/pipeline-state-schema.json +37 -1
  51. package/adapters/cursor/references/shared-conventions.md +22 -8
  52. package/adapters/cursor/references/stage-exit-protocol.md +18 -0
  53. package/adapters/cursor/references/templates/specs-hygiene/AGENTS.md +9 -0
  54. package/adapters/cursor/references/templates/specs-hygiene/CLAUDE.md +9 -0
  55. package/adapters/cursor/scripts/forge-session.py +41 -0
  56. package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +2 -0
  57. package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +1 -1
  58. package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +2 -0
  59. package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +3 -1
  60. package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +2 -0
  61. package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +1 -1
  62. package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +22 -2
  63. package/adapters/cursor/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +11 -0
  64. package/adapters/cursor/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +11 -0
  65. package/adapters/gemini/.feature-forge-bundle.json +1 -1
  66. package/adapters/gemini/gemini-extension.json +1 -1
  67. package/adapters/gemini/references/pipeline-state-schema.json +37 -1
  68. package/adapters/gemini/references/shared-conventions.md +22 -8
  69. package/adapters/gemini/references/stage-exit-protocol.md +18 -0
  70. package/adapters/gemini/references/templates/specs-hygiene/AGENTS.md +9 -0
  71. package/adapters/gemini/references/templates/specs-hygiene/CLAUDE.md +9 -0
  72. package/adapters/gemini/scripts/forge-session.py +41 -0
  73. package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +2 -0
  74. package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +1 -1
  75. package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +2 -0
  76. package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +3 -1
  77. package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +2 -0
  78. package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +1 -1
  79. package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +22 -2
  80. package/adapters/gemini/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +11 -0
  81. package/adapters/gemini/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +11 -0
  82. package/package.json +1 -1
@@ -19,4 +19,13 @@ traceability matrices, and per-feature `backlog.json` files).
19
19
  skills/agents, configs, docs) should be self-contained and should **not** reference
20
20
  files under `specs/`, which may be archived or deleted after a feature ships.
21
21
 
22
+ ## Tooling feedback
23
+
24
+ Friction with the feature-forge pipeline or the rauf loop — anything confusing, buggy, or
25
+ missing? Help me capture it while fresh and file it (feature-forge →
26
+ https://github.com/garygentry/feature-forge/issues, rauf →
27
+ https://github.com/garygentry/rauf/issues). See the project-root `CLAUDE.md` "Tooling
28
+ feedback" section for the full flow. In an autonomous rauf iteration, note it in
29
+ `progress.md` instead of opening an issue mid-loop.
30
+
22
31
  This file was generated by feature-forge. Edit or remove it to suit your project.
@@ -66,6 +66,7 @@ from __future__ import annotations
66
66
 
67
67
  import argparse
68
68
  import json
69
+ import os
69
70
  import subprocess
70
71
  import sys
71
72
  from datetime import datetime, timezone
@@ -210,6 +211,12 @@ def next_stage(state: dict) -> str | None:
210
211
  status is not ``complete`` (a missing/pending/in-progress/stale stage all
211
212
  count as "not done"). Returns ``None`` when every production stage is
212
213
  complete (nothing left to run).
214
+
215
+ This is the derived "what runs next" value — the single source of truth for
216
+ the next stage. It is intentionally distinct from the stored
217
+ ``currentStage`` field ("where the pipeline IS"; see the schema): the next
218
+ stage is computed from ``stages[].status`` here, never read from
219
+ ``currentStage``.
213
220
  """
214
221
  for stage in PRODUCTION_STAGES:
215
222
  if _stage_status(state, stage) != _DONE_STATUS:
@@ -348,6 +355,9 @@ def build_rows(specs_dir: Path, config: dict | None = None) -> list[FeatureRow]:
348
355
  rows.append({
349
356
  "name": name,
350
357
  "epic": epic,
358
+ # currentStage = "where the pipeline IS" (the recorded field). When a
359
+ # legacy/absent state omits it, fall back to the DERIVED next stage
360
+ # for display only — never conflate the two elsewhere (schema O1).
351
361
  "currentStage": state.get("currentStage") or (nxt or "complete"),
352
362
  "branch": branch if isinstance(branch, str) else None,
353
363
  "updatedAt": updated if isinstance(updated, str) else None,
@@ -710,6 +720,27 @@ def doctor_report(specs_dir: Path, config_path: Path) -> dict:
710
720
  "counts": _counts(specs_dir),
711
721
  "features": features,
712
722
  "invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
723
+ "rootSandbox": _root_sandbox_status(),
724
+ }
725
+
726
+
727
+ def _root_sandbox_status() -> dict:
728
+ """Report the root/sandbox launch condition for forge-5-loop (issue #99).
729
+
730
+ On a hosted remote (e.g. Claude.ai) the loop runs as root, where rauf's
731
+ ``claude --dangerously-skip-permissions`` is refused unless ``IS_SANDBOX``
732
+ is set. forge-5-loop exports ``IS_SANDBOX=${IS_SANDBOX:-1}`` at launch when
733
+ root; this surfaces the same condition as a diagnosable check. ``geteuid``
734
+ is absent on Windows — treat that as non-root.
735
+ """
736
+ geteuid = getattr(os, "geteuid", None)
737
+ is_root = geteuid() == 0 if geteuid is not None else False
738
+ is_sandbox_set = os.environ.get("IS_SANDBOX") not in (None, "")
739
+ return {
740
+ "isRoot": is_root,
741
+ "isSandboxSet": is_sandbox_set,
742
+ # True only when the loop would need to supply the default at launch.
743
+ "loopWillSetSandbox": is_root and not is_sandbox_set,
713
744
  }
714
745
 
715
746
 
@@ -756,6 +787,16 @@ def _print_doctor(report: dict) -> None:
756
787
  invalid = report.get("invalidAutoVerifyKeys") or []
757
788
  if invalid:
758
789
  print(" ! invalid autoVerifyStages keys (ignored): " + ", ".join(invalid))
790
+ rs = report.get("rootSandbox") or {}
791
+ if rs.get("isRoot"):
792
+ if rs.get("isSandboxSet"):
793
+ print("root/sandbox: running as root; IS_SANDBOX already set — loop launch OK")
794
+ else:
795
+ print(
796
+ "root/sandbox: running as root; IS_SANDBOX not set — forge-5-loop will "
797
+ "export IS_SANDBOX=1 at launch so rauf's "
798
+ "--dangerously-skip-permissions is not refused"
799
+ )
759
800
 
760
801
 
761
802
  # --------------------------------------------------------------------------- #
@@ -68,6 +68,8 @@ Resolve the epic subtree path `{specsDir}/{epic}/` and decide which branch to ru
68
68
  - **NEW** (no `epic-manifest.json`) → **Creation branch** (Step C1 onward).
69
69
  - **EXISTS** → **Edit branch** (§ Edit Mode below).
70
70
 
71
+ This manifest-existence dispatch **is** forge-0-epic's stage-entry guard: a re-entry on an existing epic lands in Edit Mode (helper-mutated, re-validated) rather than re-running the creation interview, so the **Stage-Entry Guard** block used by `forge-1-prd`..`forge-4-backlog` does not apply here (an epic has no self `.pipeline-state.json` to stamp — it writes member states).
72
+
71
73
  3. **Pre-flight epic-name uniqueness (creation only).** Before composing anything for a NEW
72
74
  epic, confirm the epic name itself does not collide with any existing feature or epic:
73
75
 
@@ -19,7 +19,7 @@ Invoke the **Branch Setup** block in `references/shared-conventions.md` with `{l
19
19
 
20
20
  Set the working directory by invoking the **Feature Directory Resolution** block in `references/shared-conventions.md`, which yields `{resolvedFeatureDir}`. Note one PRD-specific caveat: at PRD time a brand-new standalone feature may have NO directory yet, so resolution is expected to fail `not-found` for a never-started standalone feature — in that case forge-1 creates `{specsDir}/{feature}/` as today. For an epic member the directory already exists (created empty by forge-0-epic with an `epic` back-pointer), so resolution succeeds and yields the nested path.
21
21
 
22
- If `.pipeline-state.json` exists for this feature and `forge-1-prd` is already marked complete, use the host's question mechanism to warn: "A PRD already exists for '{feature}'. Continuing will create a new version. Proceed?"
22
+ After resolution, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-1-prd`. It classifies re-entry (fresh / interrupted / re-authoring), runs the resume-vs-restart gate and the "create a new version?" warning as applicable, and applies the entry stamp on the authoring paths. For a brand-new standalone feature there is no state file yet, so the guard's **fresh** arm applies with nothing to prompt; the entry stamp lands when the state file is first created in Step 6.
23
23
 
24
24
  ## Step 2: Examine Existing Context
25
25
 
@@ -18,6 +18,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
18
18
 
19
19
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode and `forge-1-prd` is not `complete`, STOP and tell the user: "The PRD for '{feature}' isn't complete yet. Run `/feature-forge:forge-1-prd {feature}` first."
20
20
 
21
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-2-tech` — it detects an interrupted or already-complete tech-spec, runs the resume/restart or new-version gate, and stamps `status: "in-progress"` + `startedAt` + `currentStage` before the research and interview.
22
+
21
23
  Read `{resolvedFeatureDir}/PRD.md` into context. This is your foundation — every technology decision must trace back to a PRD requirement.
22
24
 
23
25
  After reading the PRD, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the research and interview.
@@ -20,6 +20,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
20
20
 
21
21
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, both `forge-1-prd` and `forge-2-tech` must be `complete`. If not, STOP and tell the user which prerequisites are missing.
22
22
 
23
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-3-specs`. Because this stage writes a suite incrementally, the guard's **interrupted** arm uses the `stages.forge-3-specs.artifacts` array (already updated after each spec file — Step 3) to resume from the first unwritten document rather than regenerating the whole suite.
24
+
23
25
  Read both `{resolvedFeatureDir}/PRD.md` and `{resolvedFeatureDir}/tech-spec.md` into context.
24
26
 
25
27
  After reading the PRD and tech spec, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the spec suite is planned.
@@ -55,7 +57,7 @@ Feature-specific:
55
57
 
56
58
  **Then call the host's question mechanism** following the **Decision Support** protocol in `references/shared-conventions.md`: recommend this plan as the default (it's your evidence-backed read of the feature's complexity) and name the trade-off so the user can push back knowingly — more documents means finer separation of concerns but more to keep in sync; fewer means tighter docs but risks one document carrying multiple concerns. Lead with: "I recommend this plan. Add or remove any documents?" Note the guidance below — resist splitting a concern into a sub-50-line document.
57
59
 
58
- **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Crash Recovery").
60
+ **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Stage-Entry Guard").
59
61
 
60
62
  ## Step 4: Write the Spec Suite
61
63
 
@@ -38,6 +38,8 @@ Resolve the **loop runner** from the `loopRunner` block in `forge.config.json`,
38
38
 
39
39
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, stages `forge-1-prd`, `forge-2-tech`, and `forge-3-specs` must all be `complete`. If not, STOP and tell the user which prerequisites are missing.
40
40
 
41
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-4-backlog` — it detects an interrupted or complete `backlog.json`, runs the resume/restart or new-version gate, and stamps entry before Step 2 loads the specs. (The backlog is a single artifact, so "resume" means: reuse the existing `backlog.json` if the previous run wrote it, rather than re-authoring from scratch.)
42
+
41
43
  **Verification check.** Check whether the specs have been verified. If not, use the host's question mechanism to warn with the cost of skipping: "Specs haven't been verified yet. Recommended: run `/feature-forge:forge-verify {feature}` first — unverified specs can carry gaps or contradictions that get baked into backlog items and only surface mid-loop, where they're far more expensive to fix. Continue anyway?" Offer **Verify first (recommended)** · **Continue without verifying**.
42
44
 
43
45
  ## Step 2: Load All Specs
@@ -196,7 +196,7 @@ Then commit this state write before launching (mandatory). The runner refuses to
196
196
 
197
197
  ### 3b. Launch Background Process
198
198
 
199
- Launch the loop **backgrounded** (the host's background-execution mechanism) so it survives session end and does not block the session. For a runner that **persists its own structured event file** (the default — rauf writes `{stateDir}/events.ndjson` natively and rotates it per run), launch the **plain `runCommand`** with **no stdout redirect** and supervise the runner's **native** `events.ndjson` directly; do **not** redirect `--ndjson` into `{stateDir}` (it is redundant and collides with the runner's own writer — see `references/runner-contract.md`). Only a stdout-only runner (no native event file) uses `eventStreamCommand`, redirected to a file **outside** `{stateDir}`. The background task's exit notification is the single authoritative terminal signal (Step 4). Loop runs can take significant time (minutes to hours depending on backlog size). For the exact launch commands (incl. the `mkdir -p` state-dir guard) and the self-persisting vs. stdout-only detail, read `references/runner-contract.md`.
199
+ Launch the loop **backgrounded** (the host's background-execution mechanism) so it survives session end and does not block the session. For a runner that **persists its own structured event file** (the default — rauf writes `{stateDir}/events.ndjson` natively and rotates it per run), launch the **plain `runCommand`** with **no stdout redirect** and supervise the runner's **native** `events.ndjson` directly; do **not** redirect `--ndjson` into `{stateDir}` (it is redundant and collides with the runner's own writer — see `references/runner-contract.md`). Only a stdout-only runner (no native event file) uses `eventStreamCommand`, redirected to a file **outside** `{stateDir}`. The background task's exit notification is the single authoritative terminal signal (Step 4). Loop runs can take significant time (minutes to hours depending on backlog size). For the exact launch commands (incl. the `mkdir -p` state-dir guard and the root→`IS_SANDBOX` sandbox guard) and the self-persisting vs. stdout-only detail, read `references/runner-contract.md`.
200
200
 
201
201
  ### 3c. Inform User
202
202
 
@@ -101,6 +101,13 @@ default / `claude-cli` path skips this guard (the aliases are valid there).
101
101
  > rauf `author-backlog` skill to keep `model` **provider-neutral** by default (or to
102
102
  > document that writing a tier alias binds the backlog to Claude agents). That lives
103
103
  > in the separate rauf plugin/repo, not feature-forge; tracked as a follow-up.
104
+ >
105
+ > **Follow-up (out of scope here — rauf repo).** The durable fix for the root/sandbox
106
+ > refusal (see "Root/sandbox env guard" under Step 3b) is for **rauf itself** to honor
107
+ > `IS_SANDBOX` when it launches `claude --dangerously-skip-permissions` as root (or to
108
+ > detect root+flag-refused and emit a clear error instead of an opaque circuit-break).
109
+ > feature-forge's launch-time export is the mitigation; the upstream fix lives in the
110
+ > rauf plugin/repo. Track as a follow-up.
104
111
 
105
112
  ## Optional flags catalog (Step 2d, rauf)
106
113
 
@@ -131,6 +138,19 @@ session, then supervise it live via the runner's structured event file.
131
138
  > changes after that commit, surface it and let the user commit/stash or pass
132
139
  > `--force`; never auto-pass `--force`.
133
140
 
141
+ > **Root/sandbox env guard.** On a hosted remote (e.g. Claude.ai) the loop often runs
142
+ > **as root**. rauf's default Claude launch is `claude -p --dangerously-skip-permissions
143
+ > …`, which the Claude CLI **refuses under root unless `IS_SANDBOX` is set** — the remote
144
+ > container is a legitimate ephemeral sandbox, but without the flag every spawn exits and
145
+ > rauf circuit-breaks (*"3 consecutive infra failures — halting"*) with no hint of the
146
+ > cause. So when — and only when — the launcher is root (`[ "$(id -u)" = 0 ]`), export
147
+ > `IS_SANDBOX="${IS_SANDBOX:-1}"` in front of the launch (an explicitly-set value is
148
+ > honored; the `:-1` only supplies a default). Non-root/local runs are unaffected — the
149
+ > guard is a no-op. **Surface a one-line note** when you set it — e.g. *"running as root →
150
+ > setting IS_SANDBOX=1 so the sandboxed runner can use --dangerously-skip-permissions"* —
151
+ > so the behavior is never silent. `forge-session.py doctor` also reports this condition.
152
+ > Both launch commands below already carry the guard.
153
+
134
154
  **Do NOT redirect the run's stdout into `{loopRunner.stateDir}`.** rauf **persists
135
155
  its own** `{stateDir}/events.ndjson` (structured) and `{stateDir}/{logFile}` (human)
136
156
  natively, and **rotates** them at the start of every run (the prior run's files are
@@ -150,7 +170,7 @@ rotation timing. So:
150
170
  (Step 3d). Guard the very first run with the state dir:
151
171
 
152
172
  ```
153
- mkdir -p {backlogDir}/{loopRunner.stateDir} && {rendered runCommand}
173
+ mkdir -p {backlogDir}/{loopRunner.stateDir} && { [ "$(id -u)" = 0 ] && export IS_SANDBOX="${IS_SANDBOX:-1}" || true; } && {rendered runCommand}
154
174
  ```
155
175
 
156
176
  (Note: the `--ndjson` stdout stream and `loopRunner.eventStreamCommand` are **not**
@@ -160,7 +180,7 @@ rotation timing. So:
160
180
  collide with any native file or be swept into `archive/`, then Monitor that file:
161
181
 
162
182
  ```
163
- mkdir -p {backlogDir}/{loopRunner.stateDir} && {rendered eventStreamCommand} > {backlogDir}/forge-events.ndjson 2>&1
183
+ mkdir -p {backlogDir}/{loopRunner.stateDir} && { [ "$(id -u)" = 0 ] && export IS_SANDBOX="${IS_SANDBOX:-1}" || true; } && {rendered eventStreamCommand} > {backlogDir}/forge-events.ndjson 2>&1
164
184
  ```
165
185
 
166
186
  The background task's exit notification remains the single authoritative terminal
@@ -22,3 +22,14 @@ This project was scaffolded by forge-bootstrap. To continue development:
22
22
  - Documents under `specs/` (PRDs, tech specs, numbered implementation specs) establish the backlog. They are **not** kept in sync with the code as it evolves.
23
23
  - Do not flag or "fix" divergence between a finalized spec and the implementation — code is the source of truth for behavior.
24
24
  - It's fine for `specs/` artifacts and `backlog.json` to reference specs for provenance, but implementation artifacts (source code, generated skills/agents, configs, docs) must not reference spec files, which may be archived or deleted after a feature ships.
25
+
26
+ ## Tooling feedback (feature-forge / rauf)
27
+
28
+ This project is driven by the feature-forge pipeline and the rauf loop. Help improve those tools by capturing friction as you hit it — papercuts included, not just outright bugs.
29
+
30
+ - **When to flag:** any forge/rauf command, skill, agent, or prompt that is confusing, buggy, missing a capability, forces a workaround, or produces a surprising result.
31
+ - **Where to file** — route by which tool the friction is with:
32
+ - feature-forge (pipeline stages, forge skills/agents): https://github.com/garygentry/feature-forge/issues
33
+ - rauf (the autonomous loop runner, `rauf` CLI): https://github.com/garygentry/rauf/issues
34
+ - **How:** capture it while fresh — *what you ran / what you expected / what actually happened / a fix idea* — then propose a titled issue and file it with `gh issue create` **on the human's go-ahead, not silently.**
35
+ - **In an autonomous rauf iteration:** do **not** open issues mid-loop. Note the friction in `progress.md` for the human to triage later.
@@ -23,3 +23,14 @@ This project was scaffolded by forge-bootstrap. To continue development:
23
23
  - Documents under `specs/` (PRDs, tech specs, numbered implementation specs) establish the backlog. They are **not** kept in sync with the code as it evolves.
24
24
  - Don't flag or "fix" divergence between a finalized spec and the implementation — code is the source of truth for behavior.
25
25
  - It's fine for `specs/` artifacts and `backlog.json` to reference specs for provenance, but implementation artifacts (source code, generated skills/agents, configs, docs) must not reference spec files, which may be archived or deleted after a feature ships.
26
+
27
+ ## Tooling feedback (feature-forge / rauf)
28
+
29
+ I'm driving this project with the feature-forge pipeline and the rauf loop, and I want to keep improving them. When you hit friction with either tool, help me capture it — papercuts included, not just outright bugs.
30
+
31
+ - **When to flag:** any forge/rauf command, skill, agent, or prompt that is confusing, buggy, missing a capability, forces a workaround, or produces a surprising result.
32
+ - **Where to file** — route by which tool the friction is with:
33
+ - feature-forge (pipeline stages, `/feature-forge:*`, forge skills/agents): https://github.com/garygentry/feature-forge/issues
34
+ - rauf (the autonomous loop runner, `rauf` CLI): https://github.com/garygentry/rauf/issues
35
+ - **How:** capture it while fresh — *what you ran / what you expected / what actually happened / a fix idea* — then propose a titled issue and file it with `gh issue create` **once I give the go-ahead, not silently.**
36
+ - **In an autonomous rauf iteration:** don't open issues mid-loop. Note the friction in `progress.md` for me to triage later.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garygentry/feature-forge",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Cross-agent installer for the feature-forge skill suite — installs the canonical forge pipeline into Claude, Codex, Copilot, Cursor, or Gemini.",
5
5
  "license": "MIT",
6
6
  "type": "module",