forge-orkes 0.79.0 → 0.80.0
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/package.json +1 -1
- package/template/.claude/hooks/forge-context-migrate.sh +297 -0
- package/template/.claude/hooks/forge-size-gate.sh +175 -0
- package/template/.claude/hooks/forge-state-rollup.sh +135 -2
- package/template/.claude/hooks/skill-gate-tiers.txt +6 -0
- package/template/.claude/hooks/tests/forge-context-migrate.test.sh +166 -0
- package/template/.claude/hooks/tests/forge-size-gate.test.sh +132 -0
- package/template/.claude/settings.json +5 -1
- package/template/.claude/skills/discussing/SKILL.md +30 -31
- package/template/.claude/skills/executing/SKILL.md +3 -3
- package/template/.claude/skills/forge/SKILL.md +112 -170
- package/template/.claude/skills/forge/references/manual-fallback-procedures.md +54 -0
- package/template/.claude/skills/planning/SKILL.md +11 -9
- package/template/.claude/skills/researching/SKILL.md +2 -0
- package/template/.claude/skills/verifying/SKILL.md +2 -2
- package/template/.forge/FORGE.md +79 -91
- package/template/.forge/checks/forge-jarvis-awareness.sh +46 -2
- package/template/.forge/checks/forge-jarvis-relay.sh +64 -16
- package/template/.forge/checks/tests/forge-jarvis-awareness.test.sh +58 -0
- package/template/.forge/checks/tests/forge-jarvis-relay.test.sh +50 -0
- package/template/.forge/migrations/0.80.0-context-md-sharding.md +158 -0
- package/template/.forge/migrations/0.80.0-size-gate-wiring.md +145 -0
- package/template/.forge/templates/constitution.md +1 -1
- package/template/.forge/templates/context-milestone.md +30 -0
- package/template/.forge/templates/slice-runner/config.yml +7 -1
|
@@ -31,20 +31,22 @@ If you find yourself writing a plan that only touches `src/models/`, `src/db/`,
|
|
|
31
31
|
|
|
32
32
|
## Step 1: Resolution Gate
|
|
33
33
|
|
|
34
|
-
Read `.forge/context.md` **Needs Resolution
|
|
34
|
+
Read `.forge/context-log.md` **Needs Resolution** (Needs Resolution is not milestone-scoped — it lives in the log, not a per-milestone file). If unchecked `- [ ]` items:
|
|
35
35
|
*"{N} items need input: [list]. For each: lock, defer, fix, or drop?"*
|
|
36
36
|
|
|
37
|
-
Load `.forge/context.md` as the active decision set
|
|
37
|
+
Load `.forge/context/{id}.md` as the active decision set for milestone `{id}`. Consult
|
|
38
38
|
`.forge/context-archive.md` only when the current milestone, stream, or
|
|
39
39
|
requirement cites an older milestone decision (for example M9 e2e policy or M14
|
|
40
|
-
backlog lifecycle).
|
|
40
|
+
backlog lifecycle) — check `.forge/context.md` (the derived index) first; if the
|
|
41
|
+
cited milestone has a row there, read its `context/{id}.md` directly instead of
|
|
42
|
+
the archive. Do not load archived decision blocks wholesale.
|
|
41
43
|
|
|
42
44
|
| Choice | Action |
|
|
43
45
|
|--------|--------|
|
|
44
46
|
| Lock | Record in Locked Decisions |
|
|
45
47
|
| Defer | Move to Deferred Ideas + revisit date |
|
|
46
48
|
| Fix | Add as FR-xxx in `.forge/requirements/m{N}.yml` (current milestone) |
|
|
47
|
-
| Drop | Note in Amendment Log |
|
|
49
|
+
| Drop | Note in Amendment Log (`.forge/context-log.md`) |
|
|
48
50
|
|
|
49
51
|
Mark resolved `- [x]`. Target: 2-5 min.
|
|
50
52
|
Scan **Carried Forward** -- items affecting current phase get same triage.
|
|
@@ -60,17 +62,17 @@ Record results in plan frontmatter.
|
|
|
60
62
|
|
|
61
63
|
## Step 3: Lock Decisions
|
|
62
64
|
|
|
63
|
-
If missing, create `.forge/context.md` from
|
|
65
|
+
If missing, create `.forge/context/{id}.md` from `.forge/templates/context-milestone.md`:
|
|
64
66
|
1. Ask user key decisions (framework, constraints, preferences)
|
|
65
67
|
2. **Locked Decisions** (contracts)
|
|
66
68
|
3. **Deferred Ideas** (out of scope)
|
|
67
69
|
4. **Discretion Areas** (agent picks)
|
|
68
70
|
|
|
69
|
-
Must complete BEFORE plans. Plans reference context.md.
|
|
71
|
+
Must complete BEFORE plans. Plans reference context/{id}.md.
|
|
70
72
|
|
|
71
73
|
If a plan depends on an archived decision, cite the archive section in the plan
|
|
72
74
|
or active context summary; do not copy the historical block back into
|
|
73
|
-
`.forge/context.md`.
|
|
75
|
+
`.forge/context/{id}.md`.
|
|
74
76
|
|
|
75
77
|
## Step 4: Structure Requirements
|
|
76
78
|
|
|
@@ -396,7 +398,7 @@ Prompt pattern:
|
|
|
396
398
|
> *"UI work detected. Invoke `testing` skill for e2e/integration coverage? (yes/no/later)"*
|
|
397
399
|
|
|
398
400
|
- **yes** — defer to `testing` after planning completes; note in plan frontmatter
|
|
399
|
-
- **no** — document rationale in `context.md` Discretion Areas
|
|
401
|
+
- **no** — document rationale in `context/{id}.md` Discretion Areas (or `context/_shared.md` if cross-cutting)
|
|
400
402
|
- **later** — rides on the verifying **Interface Testing Gate**: when `interface` is declared in `project.yml`, that gate already BLOCKS at verifying if UI tests are still missing (no separate planning hook needed)
|
|
401
403
|
|
|
402
404
|
Decision captured once, pre-code. Does not block planning.
|
|
@@ -472,7 +474,7 @@ Done when approved.
|
|
|
472
474
|
|
|
473
475
|
## Handoff
|
|
474
476
|
|
|
475
|
-
1. **Persist** -- plans `.forge/phases/`, reqs `.forge/requirements/m{N}.yml`, roadmap `.forge/roadmap.yml`, context `.forge/context.md`
|
|
477
|
+
1. **Persist** -- plans `.forge/phases/`, reqs `.forge/requirements/m{N}.yml`, roadmap `.forge/roadmap.yml`, context `.forge/context/{id}.md`
|
|
476
478
|
2. **Reserve version (if delivery bumps the version)** -- if any plan in this milestone will bump `package.json`/the project version: pull first, derive `version` = highest reserved `max()` bumped by this change's semver level, then **claim it in the ledger BEFORE editing releases.yml**: `.claude/hooks/forge-reserve.sh version --value <X.Y.Z> --milestone m-{N}` — a non-zero exit names the sibling milestone already holding that number (its reservation may be worktree-only and invisible in any file you can read): re-read `max()` counting the ledger's version claims and bump again (ADR-029). Then append ONE entry to `.forge/releases.yml` (Version Reservation Protocol, FORGE.md): `{milestone, version, bump, reserved_at, summary}`. **Never edit prior entries.** No version bump in scope → skip. Surface the reserved number to the user.
|
|
477
479
|
3. **State** -- `current.status` = `executing` in `.forge/state/milestone-{id}.yml`
|
|
478
480
|
4. **State-sync commit** (State Commit Protocol): `git -C {worktree_path} add .forge/` then `git -C {worktree_path} commit -m "chore(forge): sync state after planning — m{N} {phase-name}"` (worktree form — recorded `lifecycle.worktree_path` is authoritative over cwd; see FORGE.md State Commit Protocol. Scoped; never `git add .`). The `releases.yml` reservation rides in this commit — **push it** so a parallel session sees the number taken before they reserve.
|
|
@@ -9,6 +9,8 @@ Gather context before planning. Bad research leads to bad plans.
|
|
|
9
9
|
|
|
10
10
|
> Entered via a worktree already, for new work (R10, `forge/SKILL.md` Step 3) — research writes `.forge/research/` state, so if this skill is somehow invoked directly on the main checkout for new work, enter one now before writing anything.
|
|
11
11
|
|
|
12
|
+
If resuming research on an existing milestone, skim `.forge/context/{id}.md` first (if present) — decisions already locked there are out of scope for research now; don't re-investigate what's already settled.
|
|
13
|
+
|
|
12
14
|
## Research Types
|
|
13
15
|
|
|
14
16
|
### 1. Codebase Research
|
|
@@ -19,7 +19,7 @@ After `/clear`, load with fresh eyes — don't carry the executor's assumptions:
|
|
|
19
19
|
Read: .forge/state/milestone-{id}.yml → current phase, plans completed
|
|
20
20
|
Read: .forge/project.yml → tech stack (for running tests)
|
|
21
21
|
Read: .forge/phases/milestone-{id}/{phase}-{name}/plan-{NN}.md → must_haves (truths, artifacts, key_links)
|
|
22
|
-
Read: .forge/context.md → locked decisions
|
|
22
|
+
Read: .forge/context/{id}.md → locked decisions for this milestone
|
|
23
23
|
Read: .forge/requirements/m{N}.yml → requirement IDs for coverage check (current milestone, resolved from state)
|
|
24
24
|
Read: .forge/deferred-issues/*.md → known pre-existing failures (glob the dir; else legacy .forge/deferred-issues.md; advisory)
|
|
25
25
|
```
|
|
@@ -295,7 +295,7 @@ After verification completes (PASSED or GAPS FOUND), run a quick retrospective o
|
|
|
295
295
|
|
|
296
296
|
**6. User corrections**: User correct the same thing multiple times? Implicit rules that should become explicit.
|
|
297
297
|
|
|
298
|
-
**Set `scope` on each observation** (see ADR-012): `framework` when the fix targets Forge's own skills/templates (tier heuristics, a skill's step, a template); `project` when it targets user-owned files (`constitution.md`, `design-system.md`, `context.md`). Record `suggestion_target` when known. This classifies the signal at write time so review can route `framework` signals upstream. Tier-override signals (#2) and the "constitution needs a new article" deviation case (#1) are usually `framework` and `project` respectively — judge by the file the fix touches, not the type.
|
|
298
|
+
**Set `scope` on each observation** (see ADR-012): `framework` when the fix targets Forge's own skills/templates (tier heuristics, a skill's step, a template); `project` when it targets user-owned files (`constitution.md`, `design-system.md`, `context/{id}.md`). Record `suggestion_target` when known. This classifies the signal at write time so review can route `framework` signals upstream. Tier-override signals (#2) and the "constitution needs a new article" deviation case (#1) are usually `framework` and `project` respectively — judge by the file the fix touches, not the type.
|
|
299
299
|
|
|
300
300
|
**Surfacing is owned by `forge` boot — not here** (single review owner, ADR-012). `verifying` only *records* observations; it does not surface recommendations, prompt for fixes, or archive. The 3+ aggregation, the type→evolution suggestion table, the decline-ledger, and upstream routing all live in `forge` Step 1.2. Write the observation files (with `scope`) and move on — the next `forge` boot reviews them.
|
|
301
301
|
|
package/template/.forge/FORGE.md
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# Forge
|
|
2
2
|
|
|
3
|
-
Lean meta-prompting framework. Context engineering + constitutional governance on agent-native primitives. This file is the always-loaded **routing/index layer**: tables, invariants,
|
|
3
|
+
Lean meta-prompting framework. Context engineering + constitutional governance on agent-native primitives. This file is the always-loaded **routing/index layer**: tables, invariants, pointers. Procedures live in the skills that execute them; rationale lives in ADRs — both load on demand only.
|
|
4
4
|
|
|
5
5
|
## Critical: No Native Plan Mode
|
|
6
6
|
|
|
7
|
-
**NEVER use `EnterPlanMode` when Forge active.** Forge writes plans to `.forge/phases/` — native plan mode conflicts.
|
|
8
|
-
|
|
9
|
-
All phases: **invoke via `Skill` tool**, never native behavior. `planning` → `Skill(planning)`, not `EnterPlanMode`.
|
|
7
|
+
**NEVER use `EnterPlanMode` when Forge active.** Forge writes plans to `.forge/phases/` — native plan mode conflicts. All phases: invoke via `Skill` tool, e.g. `planning` → `Skill(planning)`, not `EnterPlanMode`.
|
|
10
8
|
|
|
11
9
|
## Core Principles
|
|
12
10
|
|
|
13
11
|
1. **Lean default, powerful when needed.** Quick → skip ceremony. Complex → full governance.
|
|
14
|
-
2. **Adapter-native.** Use each platform's built-ins through adapters
|
|
12
|
+
2. **Adapter-native.** Use each platform's built-ins through adapters; avoid custom runtime unless the substrate needs it.
|
|
15
13
|
3. **Context is sacred.** Size-gate artifacts, lazy-load skills, fresh agents for isolated work.
|
|
16
14
|
4. **Decisions are contracts.** Lock before building. Honor or flag — never silently override.
|
|
17
15
|
5. **Verify goals, not tasks.** "Does it work?" > "Did we finish checklist?"
|
|
@@ -21,7 +19,7 @@ All phases: **invoke via `Skill` tool**, never native behavior. `planning` → `
|
|
|
21
19
|
|
|
22
20
|
## Core Protocol And Adapters
|
|
23
21
|
|
|
24
|
-
**Core protocol** lives in `.forge/`: project/constitution state, milestones, requirements, roadmap, context, streams, work packages, plans, verification, audits,
|
|
22
|
+
**Core protocol** lives in `.forge/`: project/constitution state, milestones, requirements, roadmap, context, streams, work packages, plans, verification, audits, state ownership rules — durable behavior, not one platform's tool names. **Platform adapters** translate the protocol into a runtime (Claude Code skills/hooks, Codex/AGENTS behavior, manual handoffs) and stay out of core requirements.
|
|
25
23
|
|
|
26
24
|
## Project Streams
|
|
27
25
|
|
|
@@ -33,18 +31,16 @@ Three runtime coordination layers: Project, Stream, Work Package.
|
|
|
33
31
|
| **Stream** | One active line of work: goal, branch/worktree, state, blockers, next action | `.forge/streams/{stream}.yml` + `brief.md` |
|
|
34
32
|
| **Work Package** | Delegated bounded task inside a stream | `.forge/streams/{stream}/packages/{id}.yml` |
|
|
35
33
|
|
|
36
|
-
Ordinary Quick/Standard/Full tiers run inside a stream
|
|
34
|
+
Ordinary Quick/Standard/Full tiers run inside a stream; Project Chief / Chief of Staff coordinates multiple active streams or pivots without dropping context. Workers report to the stream or project chief, never laterally. M10 worktrees are an optional isolation backend, not the primary UX.
|
|
37
35
|
|
|
38
|
-
**Merge often and early
|
|
36
|
+
**Merge often and early** — integrate ready work as soon as it is ready, not at milestone end (long-lived branches drift, merges grow riskier). Realized producer-side (checkpoint publishing, below) + project-side (the Chief's Merge Cadence Check). Forge never force-pushes, auto-resolves a conflict, or auto-rebases.
|
|
39
37
|
|
|
40
38
|
### Stream Integration Checkpoints
|
|
41
39
|
|
|
42
|
-
Event-driven continuous integration
|
|
40
|
+
Event-driven continuous integration ([ADR-027](../docs/decisions/ADR-027-integration-checkpoints-declaration-split.md)). Producer: `verifying` (Integration Checkpoint Publish). Consumer: `forge` boot (Step 1 preflight).
|
|
43
41
|
|
|
44
|
-
- **
|
|
45
|
-
- **
|
|
46
|
-
- **Intake (declaration split, B3'):** a new milestone/stream's **first** worktree commit is a declaration — milestone id (+ reservation), one-line intent, stream registration with `ownership` claims — ff-pushed to main immediately; content stays worktree-only until the milestone's own checkpoint. One-breath rule: main knows THAT work exists; the worktree knows WHAT it is.
|
|
47
|
-
- **Consumer:** boot reads the flag (absent or already-seen → skip; no fetch, no scan). Clean fast-forwards run automatically in worktrees **and** the primary main checkout; any divergence surfaces a prompt — never an auto-rebase. Cross-machine, the flag doesn't exist — the opt-in `forge.worktree_rebase_check` / periodic fetch covers it, eventually.
|
|
42
|
+
- **Producer:** plan-marked checkpoints (`integration_checkpoint: true`, operator-confirmed) fast-forward-push on a worktree's verified PASS, strand-guarded (push only if local `main` is an ancestor of HEAD; stranded → "integrate through local main first", forge#13), then set the machine-local integration flag. A stream's first worktree commit is a lighter declaration-only push (id + intent) so main knows work exists before content lands.
|
|
43
|
+
- **Consumer:** boot reads the flag (absent/seen ⇒ skip, no fetch); clean fast-forwards run automatically, any divergence prompts — never auto-rebase. Cross-machine: opt-in `forge.worktree_rebase_check`.
|
|
48
44
|
|
|
49
45
|
### Worktree Convention (base)
|
|
50
46
|
|
|
@@ -68,9 +64,9 @@ Where worktrees live and what they're named — single source of truth, base con
|
|
|
68
64
|
Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
69
65
|
|
|
70
66
|
### Prototyping (minutes–hours, disposable)
|
|
71
|
-
**Triggers:** "mock up"
|
|
67
|
+
**Triggers:** disposable in-app visual exploration ("mock up", "sketch", "prototype", "explore how X could look") behind an alpha/feature flag, no requirements locked yet
|
|
72
68
|
**Flow:** `prototyping` — establish flag → iterate ⟲ (render → react → adjust) → resolve (graduate→milestone | park | discard)
|
|
73
|
-
**No verify/review gate by design** —
|
|
69
|
+
**No verify/review gate by design** — a thing to look at and react to, not shippable code. Real UI work with known requirements is Standard + `designing` (which *does* gate on quality). See [ADR-022](../docs/decisions/ADR-022-prototyping-tier.md).
|
|
74
70
|
|
|
75
71
|
### Quick (minutes)
|
|
76
72
|
**Triggers:** bug fix, typo, config, dep bump, <50 lines
|
|
@@ -91,29 +87,27 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
91
87
|
|
|
92
88
|
## Skill Routing
|
|
93
89
|
|
|
94
|
-
| Need to... | Skill |
|
|
95
|
-
|
|
96
|
-
| Start any task | `forge` |
|
|
97
|
-
|
|
|
98
|
-
| Investigate
|
|
99
|
-
| Talk through
|
|
100
|
-
| Architectural decisions | `architecting` |
|
|
101
|
-
| Break work into tasks
|
|
102
|
-
| Build with deviation rules + atomic commits | `executing` |
|
|
103
|
-
| Prove
|
|
104
|
-
|
|
|
105
|
-
| Small scoped fix | `quick-tasking` |
|
|
106
|
-
|
|
|
107
|
-
| UI with design system | `designing` |
|
|
108
|
-
| Security review | `securing` |
|
|
109
|
-
| E2E/integration tests + suite audit (+ M9 author-mode gate) | `testing` |
|
|
110
|
-
| Systematic debugging | `debugging` |
|
|
111
|
-
| Upgrade Forge files
|
|
112
|
-
| Cross-session memory | `beads-integration` |
|
|
113
|
-
| Project/read Forge work in Notion | `notion-integration` |
|
|
114
|
-
| Multi-agent backend (experimental) | `orchestrating` |
|
|
115
|
-
|
|
116
|
-
> Experimental skills require opt-in install — see `packages/create-forge/experimental/m10/README.md`.
|
|
90
|
+
| Need to... | Skill |
|
|
91
|
+
|------------|-------|
|
|
92
|
+
| Start any task | `forge` |
|
|
93
|
+
| First-run project setup | `initializing` |
|
|
94
|
+
| Investigate before building | `researching` |
|
|
95
|
+
| Talk through trade-offs | `discussing` |
|
|
96
|
+
| Architectural decisions | `architecting` |
|
|
97
|
+
| Break work into gated tasks | `planning` |
|
|
98
|
+
| Build with deviation rules + atomic commits | `executing` |
|
|
99
|
+
| Prove goals delivered (+ M9 e2e gate; see Human Verification Gate) | `verifying` |
|
|
100
|
+
| Health/security/refactor gate + close-the-loop | `reviewing` |
|
|
101
|
+
| Small scoped fix | `quick-tasking` |
|
|
102
|
+
| Disposable UI mockup behind an alpha flag | `prototyping` |
|
|
103
|
+
| UI with design system | `designing` |
|
|
104
|
+
| Security review | `securing` |
|
|
105
|
+
| E2E/integration tests + suite audit (+ M9 author-mode gate) | `testing` |
|
|
106
|
+
| Systematic debugging | `debugging` |
|
|
107
|
+
| Upgrade Forge files (registry default; `/upgrading dev` for local sync) | `upgrading` |
|
|
108
|
+
| Cross-session memory | `beads-integration` |
|
|
109
|
+
| Project/read Forge work in Notion | `notion-integration` |
|
|
110
|
+
| Multi-agent backend (experimental — see `packages/create-forge/experimental/m10/README.md`) | `orchestrating` |
|
|
117
111
|
|
|
118
112
|
## Context Engineering
|
|
119
113
|
|
|
@@ -125,7 +119,7 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
125
119
|
| `requirements/m{N}.yml` | 50 KB/file | Prevents scope creep |
|
|
126
120
|
| `plan.md` | 30 KB | Keeps executor context <50% |
|
|
127
121
|
| `constitution.md` | 10 KB | Gates must be scannable |
|
|
128
|
-
| `context.md` | 12 KB |
|
|
122
|
+
| `context.md` | 12 KB | Derived index, rendered fresh every boot — one row per milestone, pointing at `context/{id}.md` (full decisions live there, single-owner-mutable) |
|
|
129
123
|
| `refactor-backlog.yml` | 150 KB | Terminal items archive to `refactor-backlog-archive.yml` (advisory) |
|
|
130
124
|
| `streams/active.yml` | 20 KB | Traffic map must stay cheap to load |
|
|
131
125
|
| `streams/{stream}.yml` | 15 KB | Stream state stays resumable without becoming history |
|
|
@@ -136,90 +130,84 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
136
130
|
|
|
137
131
|
### Accumulating Artifacts
|
|
138
132
|
|
|
139
|
-
Every new accumulating artifact declares
|
|
133
|
+
Every new accumulating artifact declares owner, size gate, archive/compaction rule, `derived` vs source-of-truth status, migration behavior. `roadmap.yml`, `requirements/*.yml`, `releases.yml`, `reservations.yml` are source-of-truth — load scoped slices, not whole history. `phases/`, `audits/`, `research/`, `archive/`, `context-archive.md`, `reservations-archive.yml` are historical — load only by milestone/stream/package/version (R104: `reservations-archive.yml` holds every row `compact` dropped; the working file keeps each kind's floor). `prototypes/{slug}.md` is single-owner while `exploring|parked`; terminal → `prototypes/archive/`. Runtime/generated files (`.mcp-server/*.db*`, logs, spike DBs, `.git/forge/*`) are excluded unless debugging. Board (ADR-025): `.forge/notion/map.yml` is derived; config is `board:` in `project.yml` (absent ⇒ inert). Template copies sync mechanically.
|
|
140
134
|
|
|
141
135
|
### Fresh Agent Pattern
|
|
142
|
-
|
|
136
|
+
20+ files or a complex subsystem → spawn a fresh executor with isolated context. Prevents context rot.
|
|
143
137
|
|
|
144
138
|
### Context Handoff
|
|
145
|
-
Each phase writes outputs to `.forge/` before completing
|
|
139
|
+
Each phase writes outputs to `.forge/` before completing; at boundaries recommend `/clear`, next phase loads from disk. Advisory — skip under 40% context.
|
|
146
140
|
|
|
147
141
|
### Lazy Loading
|
|
148
|
-
Skills load only when invoked.
|
|
142
|
+
Skills load only when invoked. `.forge/context.md` is a derived index (id/name/status/path per milestone) — consult it for orientation, then read the specific `context/{id}.md` when a milestone's actual decisions are needed. `context-archive.md` predates this model and is superseded (its content lives in `context/{id}.md` now); consult it only for pre-0.80.0 history not yet folded in.
|
|
149
143
|
|
|
150
144
|
### Rules Layer (`.claude/rules/`)
|
|
151
|
-
Three policy weights, lightest-first (ADR-018):
|
|
145
|
+
Three policy weights, lightest-first (ADR-018): `constitution.md` (always-loaded hard gates, 10 KB) → `.claude/rules/` (ambient guidance — always-on, or path-scoped via `paths:` glob at zero cost until a matching file is touched) → skills (heavy, opt-in). Core ships one always-on rule, `agent-discipline.md`; stack-specific rules are opt-in (`experimental/conventions/`). Format + authoring: `.claude/rules/README.md`.
|
|
152
146
|
|
|
153
147
|
## Model Routing
|
|
154
148
|
|
|
155
|
-
Configured in `project.yml` under `models:` — `default`, `parent_session` (advisory), `by_complexity.{trivial|standard|complex}` (per-task
|
|
149
|
+
Configured in `project.yml` under `models:` — `default`, `parent_session` (advisory), `by_complexity.{trivial|standard|complex}` (per-task), `skills.{name}` (per-skill).
|
|
156
150
|
|
|
157
|
-
**Precedence:** `by_complexity.{task.complexity}` → `skills.X` → `default` → parent model. **Complexity overrides skill** (LOCKED, context.md § M24)
|
|
151
|
+
**Precedence:** `by_complexity.{task.complexity}` → `skills.X` → `default` → parent model. **Complexity overrides skill** (LOCKED, `context.md` § M24) — a task with no complexity resolves via the unchanged chain, zero behavior change untagged.
|
|
158
152
|
|
|
159
|
-
**All advisory** — forge displays the expected model at each transition
|
|
153
|
+
**All advisory** — forge displays the expected model at each transition, suggests `/model` on mismatch; the review gate logs the model used. Forge cannot auto-switch models.
|
|
160
154
|
|
|
161
|
-
**Subagent inheritance.** A skill spawning subagents MUST pass the resolved `model` param explicitly — subagents do NOT inherit skill-level routing
|
|
155
|
+
**Subagent inheritance.** A skill spawning subagents MUST pass the resolved `model` param explicitly — subagents do NOT inherit skill-level routing. Resolve per task where it declares `complexity`, else the skill chain; surface *"Spawning {role} with model: {model} (from {source})"*. An inline task inherits the session model.
|
|
162
156
|
|
|
163
|
-
**Spawn gate — predicate A (LOCKED, context.md § M24; refined m-33).** Executing's mandatory spawn on a complexity-tagged task fires
|
|
157
|
+
**Spawn gate — predicate A (LOCKED, `context.md` § M24; refined m-33).** Executing's mandatory spawn on a complexity-tagged task fires only when the resolved model differs from the live session model — resolved == live (always true with no `models:` block) makes the spawn a no-op, so the tag becomes a context signal only.
|
|
164
158
|
|
|
165
159
|
## Agents
|
|
166
160
|
|
|
167
161
|
| Agent | Role | Tools | When |
|
|
168
162
|
|-------|------|-------|------|
|
|
169
|
-
| `researcher` | Investigation | Read-only
|
|
170
|
-
| `planner` | Planning + constitutional gates | Read + Write (
|
|
163
|
+
| `researcher` | Investigation | Read-only | Research |
|
|
164
|
+
| `planner` | Planning + constitutional gates | Read + Write (plans) | Planning |
|
|
171
165
|
| `executor` | Building + deviation rules | All dev tools | Execution |
|
|
172
166
|
| `verifier` | Goal-backward verification | Read + Bash (tests) | Verification |
|
|
173
|
-
| `reviewer` | Security
|
|
174
|
-
| `tester` | E2E/integration authoring + suite analysis |
|
|
175
|
-
| `security-reviewer` |
|
|
176
|
-
| `performance-reviewer` | Real bottlenecks only (
|
|
177
|
-
| `doc-reviewer` | Docs-vs-source accuracy (≥8; Blocker/Major/Minor) | Read, Grep, Glob, Bash |
|
|
167
|
+
| `reviewer` | Security/architecture/refactoring (breadth, gates the health report) | Read, Bash, Grep, Glob | Reviewing |
|
|
168
|
+
| `tester` | E2E/integration authoring + suite analysis | Author (Write/Edit/Bash/git) or read-only | Testing skill |
|
|
169
|
+
| `security-reviewer` | Security depth (≥8, exploit-scenario required) | Read, Grep, Glob, Bash | Deep-dive |
|
|
170
|
+
| `performance-reviewer` | Real bottlenecks only (frequency × cost; ≥8 + ≥Medium) | Read, Grep, Glob, Bash | Deep-dive |
|
|
171
|
+
| `doc-reviewer` | Docs-vs-source accuracy (≥8; Blocker/Major/Minor) | Read, Grep, Glob, Bash | Deep-dive |
|
|
178
172
|
|
|
179
|
-
The three
|
|
173
|
+
The three specialists complement `reviewer` — single-axis, read-only, pulled in deliberately. `reviewer`'s 3-mode pass remains the breadth gate on the milestone health report.
|
|
180
174
|
|
|
181
175
|
## Project Init (First Run)
|
|
182
176
|
|
|
183
|
-
No `.forge/project.yml` → auto-detect project type:
|
|
184
|
-
|
|
185
|
-
**Brownfield** (has package.json/src/.git): detect frameworks → absorb → verify docs vs code → scan stack → detect design system → analyze patterns → infer constitution → user confirms.
|
|
186
|
-
|
|
187
|
-
**Greenfield**: project basics → design system → constitution → state init.
|
|
188
|
-
|
|
189
|
-
Quick tier skips init.
|
|
177
|
+
No `.forge/project.yml` → auto-detect project type. **Brownfield** (has package.json/src/.git): frameworks → absorb → verify docs vs code → scan stack → design system → patterns → infer constitution → user confirms. **Greenfield**: project basics → design system → constitution → state init. Quick tier skips init.
|
|
190
178
|
|
|
191
179
|
## State Management
|
|
192
180
|
|
|
193
181
|
State lives in `.forge/`. One line per artifact; protocol detail lives in the named ADRs and skills:
|
|
194
182
|
|
|
195
|
-
- `project.yml` — vision, stack, design system, verification, constraints (<5 KB). Optional `jarvis.dev_lane_cmd` (m-48)
|
|
183
|
+
- `project.yml` — vision, stack, design system, verification, constraints (<5 KB). Optional `jarvis.dev_lane_cmd` (m-48) seams Jarvis's dev-server spin-up for UAT; absent ⇒ manual start (`docs/jarvis.md`).
|
|
196
184
|
- `constitution.md` — active architectural gates
|
|
197
185
|
- `design-system.md` — component mapping table
|
|
198
|
-
- `requirements/m{N}.yml` — per-milestone structured requirements
|
|
186
|
+
- `requirements/m{N}.yml` — per-milestone structured requirements, `[NEEDS CLARIFICATION]` markers. **FR/DEF/NFR ids globally unique** — reserve first. M9 e2e gate fields lazy-migrate; absent ⇒ `false`.
|
|
199
187
|
- `roadmap.yml` — phases, milestones, dependencies
|
|
200
|
-
- `state/index.yml` — DERIVED milestone registry,
|
|
201
|
-
- **Derived `release_state`** ([ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md)) — `{unmerged, merged, validated}
|
|
188
|
+
- `state/index.yml` — DERIVED milestone registry, git-ignored render-on-read cache (0.53.0), regenerated at boot by `forge-state-rollup.sh` (issue #22; read-only for skills); never committed; absent on a fresh clone (sentinel `project.yml`). Rows carry derived `release_state`.
|
|
189
|
+
- **Derived `release_state`** ([ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md)) — `{unmerged, merged, validated}`, computed at rollup (`forge-release-fold.sh`, git-only, offline), never stored. Binding via `forge.validation_event`: `in_session_signoff` (default) or `promotion_approval` (CI-signed tag); inert until opted in.
|
|
202
190
|
- `state/milestone-{id}.yml` — per-milestone cursor (**single source of truth**): position, decisions, blockers. One owner at a time.
|
|
203
|
-
- `state/desire-paths/` — append-only
|
|
204
|
-
- `context.md` —
|
|
205
|
-
- `streams/active.yml` — DERIVED
|
|
206
|
-
- `streams/{stream}.yml` (+ `brief.md`, `packages/{id}.yml`) — per-stream **source of truth**:
|
|
191
|
+
- `state/desire-paths/` — append-only usage observations, `scope: project|framework` (absent ⇒ project); counts derived by globbing. `forge` boot is the single review owner — surfaces groups at 3+, persists declines, routes `framework`-scope upstream ([ADR-012](../docs/decisions/ADR-012-upstream-desire-path-feedback-channel.md)); `verifying` captures, never surfaces. Issue-sourced entries carry `resolves_issue: N`.
|
|
192
|
+
- `context/{id}.md` (+ derived `context.md` index) — locked decisions + deferred ideas per milestone; history archives to `context-archive.md`
|
|
193
|
+
- `streams/active.yml` — DERIVED traffic map, git-ignored render-on-read cache, same hook — see Stream Rollup ([ADR-015](../docs/decisions/ADR-015-derived-stream-registry.md))
|
|
194
|
+
- `streams/{stream}.yml` (+ `brief.md`, `packages/{id}.yml`) — per-stream **source of truth**: lifecycle, ownership, surfaces, blockers, merge readiness, optional `stream.milestone` link (rollup reads phase from the milestone)
|
|
207
195
|
- `research/milestone-{id}.md` — dated immutable findings snapshot
|
|
208
196
|
- `phases/milestone-{id}/{phase}-{name}/plan-{NN}.md` — task plans with must_haves frontmatter (`{id}`=milestone, `{phase}`=phase# verbatim, `{name}`=kebab, `{NN}`=seq)
|
|
209
|
-
- `refactor-backlog.yml` —
|
|
197
|
+
- `refactor-backlog.yml` — quick-tasking catalog; vocab `pending|in_progress|done|dismissed|deferred`; terminal items auto-archive
|
|
210
198
|
- `releases.yml` — append-only version-reservation registry (Version Reservation Protocol)
|
|
211
|
-
- `reservations.yml` — append-only id-reservation audit trail + cross-machine floor
|
|
212
|
-
- `state/issue-loop/declined/{N}.yml` —
|
|
199
|
+
- `reservations.yml` — append-only id-reservation audit trail + cross-machine floor; `forge-reserve compact` (R104) moves dropped rows to `reservations-archive.yml`, keeping each kind's max + a 14-day tail
|
|
200
|
+
- `state/issue-loop/declined/{N}.yml` — close-the-loop decline markers (no re-nag) from `reviewing`; inert once the issue closes
|
|
213
201
|
- `archive/milestone-{id}/` — archived milestone artifacts (archive-delete)
|
|
214
|
-
- `prototypes/{slug}.md` —
|
|
202
|
+
- `prototypes/{slug}.md` — disposable-mockup state (`exploring|parked|graduated|discarded`); terminal → `prototypes/archive/`. Single-owner. See `Skill(prototyping)`.
|
|
215
203
|
|
|
216
|
-
**Milestones** group phases into concurrent streams — own state file, no conflicts
|
|
204
|
+
**Milestones** group phases into concurrent streams — own state file, no cross-session conflicts; deferred (frozen) or archive-deleted. Status vocab: `not_started | active | deferred | complete`. **`current.status` is authoritative** — 100% tasks ≠ done (verifying + reviewing + the recorded human sign-off still gate).
|
|
217
205
|
|
|
218
206
|
**Format:** YAML for machine state, Markdown for human content.
|
|
219
207
|
|
|
220
208
|
### Stream Rollup
|
|
221
209
|
|
|
222
|
-
`active.yml` is a
|
|
210
|
+
`active.yml` is a deterministic **join**: per-stream files contribute coordination state; active milestones contribute `phase` (stream-file-less active milestone → derived `implicit` row); `merge_queue` derives from `merge.readiness: ready`. A **step-0 auto-close sweep** closes milestone-backed streams whose milestone is `complete`, not `closed`, with no live worktree. Rendered by the same hook at boot and at `chief-of-staff` Show/Sync/CRUD; Rollup 1.0 runs first, sweep confined to main. Numbered procedure: the ADR-015 addendum — each field has one source, so drift cannot occur.
|
|
223
211
|
|
|
224
212
|
### State Commit Protocol
|
|
225
213
|
|
|
@@ -230,7 +218,7 @@ git add .forge/ # scoped — respects .gitignore; never `git add .`
|
|
|
230
218
|
git commit -m "chore(forge): sync state after {phase} — m{N} {phase-name}"
|
|
231
219
|
```
|
|
232
220
|
|
|
233
|
-
**In a worktree session, pin with the recorded path** — `git -C {worktree_path} add/commit` (
|
|
221
|
+
**In a worktree session, pin with the recorded path** — `git -C {worktree_path} add/commit` (cwd can silently reset to the launch checkout across turns; a wrong-cwd op can even exit 0). Guard: compare `git rev-parse --show-toplevel` to the recorded path before the first write — full discipline in `executing`/`verifying`. State-sync commits are separate from per-task code commits.
|
|
234
222
|
|
|
235
223
|
### State Ownership (multi-worktree safety)
|
|
236
224
|
|
|
@@ -238,12 +226,12 @@ git commit -m "chore(forge): sync state after {phase} — m{N} {phase-name}"
|
|
|
238
226
|
|
|
239
227
|
| Class | Files | Write rule |
|
|
240
228
|
|---|---|---|
|
|
241
|
-
| **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md` | Exactly one writer at a time — the checkout currently driving that milestone. Other worktrees never touch it (not even read-then-write; pull from main instead). |
|
|
229
|
+
| **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md`, `context/{id}.md` | Exactly one writer at a time — the checkout currently driving that milestone. Other worktrees never touch it (not even read-then-write; pull from main instead). |
|
|
242
230
|
| **Single-owner mutable (per stream)** | `streams/{stream}.yml`, `streams/{stream}/brief.md`, `streams/{stream}/packages/*.yml` | The stream's current driver writes them; distinct streams own distinct files — no cross-stream contention. |
|
|
243
|
-
| **Derived (git-ignored render-on-read cache)** | `state/index.yml`, `streams/active.yml`, the rendered `release_state` column | Never hand-edited, **never committed** — regenerated by rollup from sources at every boot. Any session may render its own copy; absence on a fresh clone is normal (render-then-read; the sentinel is `project.yml`). |
|
|
231
|
+
| **Derived (git-ignored render-on-read cache)** | `state/index.yml`, `streams/active.yml`, `context.md`, the rendered `release_state` column | Never hand-edited, **never committed** — regenerated by rollup from sources at every boot. Any session may render its own copy; absence on a fresh clone is normal (render-then-read; the sentinel is `project.yml`). `context.md` specifically joins `context/{id}.md` files with `state/index.yml` (ADR-033). |
|
|
244
232
|
| **Append-only shared** | `releases.yml`, `reservations.yml`, `state/desire-paths/*`, `deferred-issues/*` | Many writers OK; structure prevents collision (append-only entries / distinct filenames). |
|
|
245
233
|
| **Machine-local runtime** | `.git/forge/id-reservations`, `.git/forge/integration-pending` | Git common dir — shared across a machine's worktrees, never git-tracked, excluded from framework context. |
|
|
246
|
-
| **Shared mutable** | `
|
|
234
|
+
| **Shared mutable** | `refactor-backlog.yml`, `requirements/m{N}.yml` | Write only your milestone/stream block; within a block, append-only — strike through instead of rewriting. |
|
|
247
235
|
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading` (registry default — the npm bin is the sync engine; local dev sync only via explicit `/upgrading dev`). Canonical on main; worktrees lag until they rebase. An upgrade touches only its own checkout — `upgrading` Step 8 offers live-worktree rebases (never auto); opt-in `forge.worktree_rebase_check` is the boot-time net. Gitignored carve-outs (`.mcp.json`, experimental hooks) propagate via the experimental installer, not git. |
|
|
248
236
|
|
|
249
237
|
Ownership rules (quick reference):
|
|
@@ -255,11 +243,11 @@ Ownership rules (quick reference):
|
|
|
255
243
|
|
|
256
244
|
### Version Reservation Protocol
|
|
257
245
|
|
|
258
|
-
The
|
|
246
|
+
The version + CHANGELOG slot are shared — `.forge/releases.yml` (append-only). **Reserve at planning**: derive `max() + bump`, claim in the ledger first (`forge-reserve version --value <X.Y.Z>` — conflict names the sibling milestone holding it), append ONE `{milestone, version, bump, reserved_at, summary}` entry, **commit + push before editing the version file**. Never edit prior entries; never invent a number at delivery — no reservation found → reserve then, same steps. Push race → rebase onto the file, re-read `max()`. Bump criteria + race narrative: `planning`'s Reserve-version step + ADR-029.
|
|
259
247
|
|
|
260
248
|
### ID Reservation Protocol
|
|
261
249
|
|
|
262
|
-
Sequential ids
|
|
250
|
+
Sequential ids (`ADR-NNN`, `DEF-NNN`, `FR-`/`NFR-NNN`, milestone `M-NN`, refactor `R0NN`, roadmap phase/wave) are shared cross-worktree resources — scan-and-increment collides silently until merge. **Reserve before create**: `forge-reserve <kind> --milestone <id> [--summary <text>]` (`.claude/hooks/forge-reserve.sh`, kinds `adr|def|fr|nfr|milestone|refactor|phase|wave|version`). Next id = **`max(ledger ∪ in-tree ∪ main:reservations.yml) + 1`** per kind; residual collision → older milestone keeps the id, newer renumbers. Reserve points: `architecting` (adr), `planning` (fr/nfr/def, phase/wave, version), `forge` Rollup/`discussing`/`prototyping` (milestone), `reviewing` (refactor). Deferred issues are counter-free — nothing to collide on. Full mechanics (ledger + lock, id-format table, cross-machine floor, lazy migration): the helper's header comment + [ADR-021](../docs/decisions/ADR-021-id-reservation-ledger-git-common-dir.md) (supersedes ADR-016) + ADR-023 + ADR-029.
|
|
263
251
|
|
|
264
252
|
## Deviation Rules
|
|
265
253
|
|
|
@@ -284,16 +272,16 @@ verification:
|
|
|
284
272
|
- cmd: "npm run lint"
|
|
285
273
|
- cmd: "npm test"
|
|
286
274
|
- cmd: "npx tsc --noEmit"
|
|
287
|
-
advisory: true
|
|
288
|
-
auto_fix: true
|
|
289
|
-
max_retries: 2
|
|
275
|
+
advisory: true # pre-existing failures — warn only
|
|
276
|
+
auto_fix: true # fix and retry on failure
|
|
277
|
+
max_retries: 2 # max attempts per command
|
|
290
278
|
```
|
|
291
279
|
|
|
292
|
-
Auto-detected from `package.json` at init. Advisory mode warns, never blocks. Auto-fix loop: read output → fix → amend → re-run (≤ `max_retries`; retries count toward the 3-strike
|
|
280
|
+
Auto-detected from `package.json` at init. Advisory mode warns, never blocks. Auto-fix loop: read output → fix → amend → re-run (≤ `max_retries`; retries count toward the 3-strike limit). Empty commands = opt-out. `verification.e2e_soft_cap` (default 10) — advisory per-milestone cap on `e2e:true` stories, surfaced by `reviewing`, never blocks.
|
|
293
281
|
|
|
294
282
|
### Truth checks (executable must_haves)
|
|
295
283
|
|
|
296
|
-
Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exit 0 = pass; authored goal-backward at planning, before code exists
|
|
284
|
+
Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exit 0 = pass; authored goal-backward at planning, before code exists). `executing` runs declared checks once at plan completion (early fix-loop signal, never a verdict); `verifying` re-executes, applying the **executed-evidence rule**: VERIFIED only with a recorded command + exit code + output excerpt — no evidence → UNCERTAIN or human-route. Legacy bare-string truths stay valid.
|
|
297
285
|
|
|
298
286
|
### Human Verification Gate (close precondition)
|
|
299
287
|
|
|
@@ -308,8 +296,8 @@ Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exi
|
|
|
308
296
|
|
|
309
297
|
## Beads Integration (Optional)
|
|
310
298
|
|
|
311
|
-
With Beads
|
|
299
|
+
With Beads: `bd prime` (session context), `bd ready` (unblocked tasks), `bd complete` (update deps), `bd compact` (summarize old). Without it, `.forge/state/` + Session Memory suffice.
|
|
312
300
|
|
|
313
301
|
## Atomic Commits
|
|
314
302
|
|
|
315
|
-
One commit per task. Format: `{type}({scope}): {description}` — types `feat fix test refactor chore docs`. Never `git add
|
|
303
|
+
One commit per task. Format: `{type}({scope}): {description}` — types `feat fix test refactor chore docs`. Never `git add .`/`-A` — stage individually. Phase handoffs additionally emit one scoped `chore(forge): sync state …` commit (State Commit Protocol) so `.forge/` state never drifts out of git.
|
|
@@ -69,6 +69,43 @@ fold_state() { # fold_state <milestone-id>
|
|
|
69
69
|
[ -n "$_rs" ] && printf '%s' "$_rs" || printf 'unknown'
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
# ── milestone name lookup (issue #34 — bare ids are useless with 40+ milestones in flight).
|
|
73
|
+
# Reads milestone.name (nested under the top-level `milestone:` key) from the worktree's own
|
|
74
|
+
# state file — a naive `grep -m1 '^name:'` returns empty since the key is indented under
|
|
75
|
+
# `milestone:`, not top-level. Same nested-key awk pattern as yget() in
|
|
76
|
+
# forge-board-render.sh (parent/child scan), specialized to milestone/name. Degrades to empty
|
|
77
|
+
# on any miss (absent file, absent key) — callers degrade to the bare id, never crash. ────────
|
|
78
|
+
milestone_name() { # milestone_name <milestone-id> <worktree-path>
|
|
79
|
+
_mid="${1:-}"; _wt="${2:-}"
|
|
80
|
+
[ -n "$_mid" ] && [ -n "$_wt" ] || { printf ''; return 0; }
|
|
81
|
+
_id="${_mid#m-}"
|
|
82
|
+
_f="$_wt/.forge/state/milestone-$_id.yml"
|
|
83
|
+
[ -f "$_f" ] || { printf ''; return 0; }
|
|
84
|
+
awk '
|
|
85
|
+
/^milestone:/ { inp=1; next }
|
|
86
|
+
inp && /^[A-Za-z]/ { inp=0 }
|
|
87
|
+
inp && /^[[:space:]]+name:/ {
|
|
88
|
+
sub(/^[[:space:]]*[^:]+:[[:space:]]*/, "")
|
|
89
|
+
sub(/[[:space:]]*#.*/, "")
|
|
90
|
+
gsub(/^["'"'"']|["'"'"']$/, "")
|
|
91
|
+
print; exit
|
|
92
|
+
}
|
|
93
|
+
' "$_f"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# ── "m-<id> — <name>", truncated ~60 chars so one slice-list row stays one line; degrades to
|
|
97
|
+
# the bare id (never a blank "m- — " prefix) when the name can't be resolved. ────────────────
|
|
98
|
+
named_milestone() { # named_milestone <milestone-id> <worktree-path>
|
|
99
|
+
_mid="${1:-}"; _wt="${2:-}"
|
|
100
|
+
[ -n "$_mid" ] || { printf ''; return 0; }
|
|
101
|
+
_nm="$(milestone_name "$_mid" "$_wt")"
|
|
102
|
+
if [ -n "$_nm" ]; then
|
|
103
|
+
printf '%s' "$_mid — $_nm" | cut -c1-60
|
|
104
|
+
else
|
|
105
|
+
printf '%s' "$_mid"
|
|
106
|
+
fi
|
|
107
|
+
}
|
|
108
|
+
|
|
72
109
|
# ── milestone id derivation for a matched branch (issue #25, bare-branch loosening). A
|
|
73
110
|
# forge/m-* branch keeps its original textual derivation unchanged (strip forge/, strip the
|
|
74
111
|
# 8-hex session suffix). A bare branch (m-<id>-slug | m<digits>-slug) derives the id from the
|
|
@@ -143,7 +180,8 @@ _slices="$(list_slices)"
|
|
|
143
180
|
if [ -n "$_slices" ]; then
|
|
144
181
|
printf '%s\n' "$_slices" | while IFS="$TAB" read -r _m _br _pt; do
|
|
145
182
|
if [ "$DRY_RUN" -eq 1 ]; then _rs='(dry-run)'; else _rs="$(fold_state "$_m")"; fi
|
|
146
|
-
|
|
183
|
+
_disp="$(named_milestone "$_m" "$_pt")"
|
|
184
|
+
printf ' %-40s %-26s release_state=%-9s %s\n' "$_disp" "$_br" "$_rs" "$_pt"
|
|
147
185
|
done
|
|
148
186
|
else
|
|
149
187
|
printf ' (none on this machine)\n'
|
|
@@ -165,7 +203,13 @@ elif [ -f "$BOARD" ]; then
|
|
|
165
203
|
_id="$(printf '%s' "$_ln" | sed -n 's/.*"forge_id":[[:space:]]*"\([^"]*\)".*/\1/p')"
|
|
166
204
|
_st="$(printf '%s' "$_ln" | sed -n 's/.*"status":[[:space:]]*"\([^"]*\)".*/\1/p')"
|
|
167
205
|
_rs="$(printf '%s' "$_ln" | sed -n 's/.*"release_state":[[:space:]]*"\([^"]*\)".*/\1/p')"
|
|
168
|
-
printf '
|
|
206
|
+
_nm="$(printf '%s' "$_ln" | sed -n 's/.*"name":[[:space:]]*"\([^"]*\)".*/\1/p')"
|
|
207
|
+
if [ -n "$_nm" ]; then
|
|
208
|
+
_disp="$(printf '%s' "${_id:-?} — $_nm" | cut -c1-60)"
|
|
209
|
+
else
|
|
210
|
+
_disp="${_id:-?}"
|
|
211
|
+
fi
|
|
212
|
+
printf ' %s status=%s release_state=%s\n' "$_disp" "${_st:-?}" "${_rs:-?}"
|
|
169
213
|
done
|
|
170
214
|
else
|
|
171
215
|
printf ' (all board units complete — nothing in flight)\n'
|