Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
e753ef9
feat(snapshot): PROB-060 identity triple + structured /api/snapshot e…
explosivebit May 8, 2026
984f567
chore(release): back-merge v0.2.4 into develop (#150)
fedorovvvv May 25, 2026
1da8c21
Merge remote-tracking branch 'origin/develop' into feat/prob-060-snap…
explosivebit Jun 23, 2026
0101560
fix(snapshot): forward error_code/stderr_excerpt to Timeline
explosivebit Jun 23, 2026
a4116c6
docs(guides): add FORGEPLAN-GITIGNORE remediation guide
explosivebit Jun 23, 2026
47b5de1
feat(snapshot): PROB-060 web identity adaptation + structured /api/sn…
explosivebit Jun 30, 2026
bb04d8c
chore(forgeplan): record EVID-040 + link to RFC-015/PRD-016
explosivebit Jun 30, 2026
f3bfa99
chore(forgeplan): record EVID-040 + RFC-015/PRD-016 identity-contract…
explosivebit Jun 30, 2026
115248d
chore(forgeplan): activate shipped version-footer + template-hardening
explosivebit Jun 30, 2026
cdc08a4
feat(update-banner): per-session dismiss (PRD-013 FR-011)
explosivebit Jun 30, 2026
a71e95f
chore(forgeplan): activate shipped version-footer + template-hardenin…
explosivebit Jun 30, 2026
34eab40
Merge branch 'develop' into feat/update-banner-session-dismiss
explosivebit Jun 30, 2026
758b8e1
feat(update-banner): per-session dismiss (PRD-013 FR-011) + activate …
explosivebit Jun 30, 2026
cd13dd1
feat(risk-overlay): glow at-risk graph nodes + risk anatomy (PRD-009)
explosivebit Jun 30, 2026
43d6f37
chore(forgeplan): activate risk-overlay (PRD-009/RFC-008) + EVID-041
explosivebit Jun 30, 2026
a7ccaa3
feat(risk-overlay): glow at-risk graph nodes + risk anatomy (PRD-009)…
explosivebit Jun 30, 2026
07e851d
feat(stats-pulse): workspace pulse dashboard + health score (PRD-010)
explosivebit Jun 30, 2026
f6b8303
chore(forgeplan): activate stats-pulse (PRD-010/RFC-009) + EVID-042 +…
explosivebit Jun 30, 2026
6e5b71f
feat(stats-pulse): workspace pulse dashboard + health score (PRD-010)…
explosivebit Jun 30, 2026
b471f26
feat(hints-engine): proactive workspace hints (PRD-011)
explosivebit Jun 30, 2026
cff2b3d
chore(forgeplan): activate hints-engine (PRD-011/RFC-010) + EVID-043
explosivebit Jun 30, 2026
5f76a41
feat(hints-engine): proactive workspace hints (PRD-011) (#157)
explosivebit Jun 30, 2026
364c5e1
docs(rules): rule-22 covers git-reconstruction endpoints + OPTIONS/CORS
explosivebit Jun 30, 2026
6125390
docs(rules): rule-22 covers git-reconstruction endpoints + OPTIONS/CO…
explosivebit Jun 30, 2026
dd97616
chore(rules): harden claim hygiene + activate ADR-002 (dispatch proto…
explosivebit Jun 30, 2026
b527bd0
chore(rules): harden claim hygiene + activate ADR-002 (dispatch proto…
explosivebit Jun 30, 2026
5120ccf
docs: forgeplan insights + upstream findings index
explosivebit Jun 30, 2026
ae1324f
docs: forgeplan insights + upstream findings index (#160)
explosivebit Jun 30, 2026
5997d58
docs: add marketplace#168 (AGENT-AUTHORING-GUIDE addendum) to upstrea…
explosivebit Jun 30, 2026
54a905c
docs: add marketplace#168 to upstream issue index (#161)
explosivebit Jun 30, 2026
1d7546c
refactor(tier): lift tier vocabulary to shared/lib/tier
explosivebit Jul 1, 2026
251a977
feat(idef0): add shared TADD decomposition core
explosivebit Jul 1, 2026
ae21370
docs(forgeplan): EPIC-001 IDEF0 keystone artifacts + evidence
explosivebit Jul 1, 2026
fbe0da9
fix(idef0): JSON-encode composite keys to prevent boundary collisions
explosivebit Jul 1, 2026
68a50cb
fix(idef0): sort enumerated diagram/forest outputs for order-invariance
explosivebit Jul 1, 2026
4b03b46
docs(forgeplan): T2 SHAPE — PRD-034 + SPEC-005 idef0 view + design ev…
explosivebit Jul 1, 2026
2abf473
docs(forgeplan): T2 ARCHITECT — RFC-029 idef0 view host-renderer + C4
explosivebit Jul 1, 2026
080d6d9
feat(idef0): T2 idef0 view — first host renderer over the TADD core
explosivebit Jul 1, 2026
44c0d57
fix(idef0): T2 view a11y — Fitts targets + WCAG AA contrast + afforda…
explosivebit Jul 1, 2026
2afe90e
fix(idef0): T2 view code-review — pagination peek + dead-label TODO +…
explosivebit Jul 1, 2026
084896a
test(idef0): SPEC-005 render-surface DOM harness — AC-4 12/12
explosivebit Jul 2, 2026
e396b85
fix(stats): stale-while-error poller + honest Stats degradation
explosivebit Jul 2, 2026
7f8d610
fix(graph): defer hover clear past Svelte teardown (state_unsafe_muta…
explosivebit Jul 2, 2026
89e814c
docs(forgeplan): T2 GATE-A PASS — activate PRD-034/SPEC-005/RFC-029 +…
explosivebit Jul 2, 2026
6247450
feat(idef0): design-excellence pass — kind colors, band identity, ada…
explosivebit Jul 2, 2026
9f1d84f
fix(idef0): center canvas via margin-inline auto (flexbox overflow-cl…
explosivebit Jul 2, 2026
b29066b
feat(idef0): PRD-035 gate PASS — a11y follow-ups + evidence chain
explosivebit Jul 2, 2026
e2538c4
fix(stats): server-side last-good cache + stale seed + 60s score poll
explosivebit Jul 2, 2026
573bf70
feat(idef0): P1 utility package — R_eff tone, band aggregates, M:N ba…
explosivebit Jul 2, 2026
8a511da
docs(forgeplan): EVID-074/075 P1 utility verification chain (active)
explosivebit Jul 2, 2026
6f85604
docs(map): add PROJECT-MAP-SPEC — composed-map master spec (T4 source…
explosivebit Jul 2, 2026
b6396d6
docs(forgeplan): ARC C SHAPE — PRD-036/SPEC-006/ADR-008(draft)/RFC-03…
explosivebit Jul 2, 2026
c374beb
feat(idef0): wave-2 UX — band wrap, clickable cards, visible edges, d…
explosivebit Jul 2, 2026
c307932
docs(forgeplan): EVID-079/080 wave-2 verification (BLOCKER root-cause…
explosivebit Jul 2, 2026
be2cc8e
docs(forgeplan): ARC C fix-loop — time-travel invariant, spike-grid a…
explosivebit Jul 2, 2026
4c59cda
docs(forgeplan): ARC C GATE C2 PASS — activate PRD-036/SPEC-006/RFC-0…
explosivebit Jul 2, 2026
b64fd09
feat(idef0): composed-map Phase-1 core — entity, validator, layout, API
explosivebit Jul 3, 2026
ee46772
feat(idef0): composed-map registration — 9th view + isLive + tokens
explosivebit Jul 3, 2026
450b9f0
feat(idef0): composed-map ZoneSlab + named accent tokens
explosivebit Jul 3, 2026
93d1397
feat(idef0): composed-map NodeCard + EdgeLayer + FlowChips
explosivebit Jul 3, 2026
39a93ab
feat(idef0): composed-map ComposedMapView — render-proof complete
explosivebit Jul 3, 2026
31a828c
fix(idef0): composed-map error/loading discriminant + layout coverage
explosivebit Jul 3, 2026
f451568
docs(forgeplan): ARC C wave-3 verification — EVID-082/083 CONCERNS, E…
explosivebit Jul 3, 2026
a0a8958
docs(forgeplan): EVID-085 — composed-map data-flow verified, visual p…
explosivebit Jul 3, 2026
7df8052
docs(forgeplan): EVID-086 — guardian gate CONCERNS, open PR with disc…
explosivebit Jul 3, 2026
a40dd92
docs(forgeplan): trailing whitespace normalization on RFC-030 (reinde…
explosivebit Jul 3, 2026
1c143e8
fix(idef0): composed-map zoom-to-fit microtask reading torn-down derived
explosivebit Jul 3, 2026
264f1b3
docs(forgeplan): EVID-087 — visual render-proof captured, closes guar…
explosivebit Jul 3, 2026
5c30dda
fix(idef0): composed-map edges hidden under zone-slab backgrounds
explosivebit Jul 3, 2026
8440d16
docs(forgeplan): EVID-088 — z-order fix verified, flow-chip mechanism…
explosivebit Jul 3, 2026
79e5a0c
docs(map): add forgeplan-map-pack build brief for ForgePlanMarketplace
explosivebit Jul 3, 2026
80c9015
docs(map): EVID-089 compliance audit + brief/spec amendments
explosivebit Jul 3, 2026
ff17ce1
fix(idef0): composed-map Esc-reset clears selection + flow-highlight …
explosivebit Jul 3, 2026
f2d8dc9
test(idef0): add NodeCard dimming coverage for EVID-090's last open item
explosivebit Jul 3, 2026
a0a40e5
docs(forgeplan): EVID-090/091 fix-loop trail + NOTE-002 filled
explosivebit Jul 3, 2026
8ffd387
Merge pull request #162 from ForgePlan/feat/idef0-decomposition-surfaces
explosivebit Jul 3, 2026
dd47f3c
Merge pull request #163 from ForgePlan/feat/idef0-view-t2
explosivebit Jul 3, 2026
47b37c3
chore(forgeplan): re-render RFC-030 projection (trailing whitespace o…
explosivebit Jul 3, 2026
3931f28
chore(idef0): merge develop (T1+T2 landed) into feat/idef0-composed-map
explosivebit Jul 3, 2026
9218b84
Merge pull request #164 from ForgePlan/feat/idef0-composed-map
explosivebit Jul 3, 2026
527a67f
fix(stats): Stats tab stuck on eternal loading spinner
explosivebit Jul 4, 2026
a8d9ac0
feat(idef0): actionable composed-map empty-state with map-build guidance
explosivebit Jul 4, 2026
07a4dc8
feat(idef0): composed-map layout polish — text clip + spike flow expe…
explosivebit Jul 4, 2026
5bac5a8
docs(map): map-pack output-quality findings vs spike (O-1/O-2/O-3)
explosivebit Jul 4, 2026
ccbb232
docs(map): session handoff — composed-map renderer polish + map-pack …
explosivebit Jul 5, 2026
3213607
fix(idef0): composed-map collapses mega-node children instead of doub…
explosivebit Jul 5, 2026
eae268f
feat(home): merge Filters + InsightsRail into one collapsible left rail
explosivebit Jul 5, 2026
60456b0
feat(home): filters to top toolbar, insights-only left rail, logo col…
explosivebit Jul 5, 2026
4cc2132
fix(home): keep InsightsRail mounted on collapse (hide, don't unmount)
explosivebit Jul 5, 2026
d9a2ab8
docs(idef0): shape recursive drill-down — PRD-037 + RFC-031 + ADR-009
explosivebit Jul 5, 2026
acd68cc
feat(idef0): drill-down pure core — deriveSubDocument + hit-test + dr…
explosivebit Jul 5, 2026
dcce8d1
feat(idef0): drill-down view wiring + LevelBreadcrumb
explosivebit Jul 5, 2026
112fc47
feat(idef0): mega card click descends (un-collapse) + drillable affor…
explosivebit Jul 5, 2026
0bea900
docs(idef0): activate drill-down arc — RFC-031/PRD-037/ADR-009 + EVID…
explosivebit Jul 5, 2026
b68893e
feat(idef0): composed-map zone-hover detail + flow-highlight polish
explosivebit Jul 5, 2026
da47c5e
fix(idef0): move zone-detail card to top-right, clear of minimap
explosivebit Jul 5, 2026
c7c421f
docs(map): understanding-map enhancement brief for map-pack (E1-E4)
explosivebit Jul 5, 2026
694b708
feat(idef0): C4 edge rollup onto collapsed megas + flow highlight lif…
explosivebit Jul 5, 2026
c83b165
feat(idef0): sticky interactive zone detail card (scroll, descend but…
explosivebit Jul 6, 2026
952e7f0
docs(map): project onboarding narrative — textual twin of the compose…
explosivebit Jul 6, 2026
e620829
fix(idef0): audit fixes — rollup NUL-key + self-loop drop + flow-rese…
explosivebit Jul 6, 2026
8bf1a77
docs(map): cascade dogfood findings — F-ARR + F-REF emitter bugs
explosivebit Jul 6, 2026
e9c21b5
feat(idef0): E3 seam — render map-pack generated layers on descend
explosivebit Jul 6, 2026
d33b5fb
feat(idef0): thin edges + small arrowheads + roomy card spacing
explosivebit Jul 6, 2026
fddacb9
feat(idef0): node-detail tab — code-module cards open in the right tabs
explosivebit Jul 6, 2026
fb624a5
fix(idef0): node tab shows node label, not raw node:<id>
explosivebit Jul 6, 2026
860c1b8
fix(idef0): truncate long flow chips + gentler adaptive roomyCanvas
explosivebit Jul 6, 2026
aa924c7
docs(idef0): activate RFC-032 E3 seam + backing artifacts for PR #165
explosivebit Jul 6, 2026
02fea89
feat(idef0): recursive composed-map drill-down + sidebar ergonomics (…
explosivebit Jul 6, 2026
9553faf
fix(idef0): carry parent flows into deriveSubDocument for deeper-leve…
explosivebit Jul 6, 2026
d34f4db
docs(idef0): EVID-094 — deeper-level flow-carry checkpoint (informs R…
explosivebit Jul 6, 2026
b0f34f3
docs(map): consolidated marketplace findings brief (25 findings, per-…
explosivebit Jul 6, 2026
693f566
feat(idef0): onboarding tour (Pillar B) — /onboard + zone-walk camera
explosivebit Jul 6, 2026
a1ef133
fix(idef0): deeper composed-map levels show flow chips (carry filtere…
explosivebit Jul 6, 2026
3939813
Merge remote-tracking branch 'origin/develop' into feat/idef0-onboard…
explosivebit Jul 6, 2026
630fc38
feat(idef0): onboarding tour (Pillar B) — /onboard + zone-walk camera…
explosivebit Jul 6, 2026
e762cb5
feat(idef0): Pillar C Phase 1 — camera-bus seam + Tier-0 chat (RFC-034)
explosivebit Jul 6, 2026
f7726f5
feat(idef0): Pillar C daemon + Tier-1 — live onboarding agent (RFC-03…
explosivebit Jul 6, 2026
02229ee
docs(idef0): activate Pillar C — RFC-034 + ADR-010 + EVID-096 (live a…
explosivebit Jul 6, 2026
9fadc9c
fix(idef0): Tier-1 chat — buffer WS sends issued before the socket opens
explosivebit Jul 6, 2026
6093923
feat(idef0): full assistant chat — markdown, sessions, scroll, our style
explosivebit Jul 6, 2026
2ea9337
fix(idef0): chat is AI-only (drop Tier-0) + daemon streams token-by-t…
explosivebit Jul 6, 2026
a3212f4
feat(idef0): chat Phase-4 — cancel/Stop, live-continue sessions, prob…
explosivebit Jul 6, 2026
b68cf95
fix(idef0): revert chat daemon probe to WebSocket — fetch /health is …
explosivebit Jul 6, 2026
2538a0e
docs(playground): showcase ScrollArea primitive (rule 24)
explosivebit Jul 6, 2026
e42040e
fix(idef0): stop onboard-agent from leaking a Claude Code subprocess …
explosivebit Jul 7, 2026
286ced8
feat(idef0): chat panel v2 — floatable/dockable/resizable window + Ch…
explosivebit Jul 7, 2026
1cb6edb
feat(idef0): chat Info tab live data (token usage + instance discover…
explosivebit Jul 7, 2026
18bf9f8
feat(idef0): populate chat Info tab on open — carry instance data on …
explosivebit Jul 7, 2026
60ae14a
feat(idef0): magic "✨ Ask" launcher in onboard header (off the map)
explosivebit Jul 7, 2026
2be797f
feat(idef0): chat launcher is a ✨ sparkle in the chips toolbar (extra…
explosivebit Jul 7, 2026
67ee436
fix(idef0): zone detail card — dwell delay + fixed bottom-left corner
explosivebit Jul 7, 2026
f0ffeb7
fix(idef0): close 9 adversarially-confirmed Pillar C / RFC-035 web bugs
explosivebit Jul 7, 2026
c703308
feat(idef0): Pillar C — live onboarding agent (daemon + Agent SDK + c…
explosivebit Jul 8, 2026
6a92feb
feat(idef0): 3D isometric exploded-pyramid spike (Threlte) + R1 geometry
explosivebit Jul 7, 2026
f8a4e2b
wip(idef0): SOLID decomposition of iso view + material/relayer/hover …
explosivebit Jul 7, 2026
373c77f
wip(idef0): iso minimap — thin sheets, element hover, root-anchored d…
explosivebit Jul 7, 2026
c13b290
wip(idef0): iso minimap — click-to-explode + visible corner dashes + …
explosivebit Jul 7, 2026
67038b7
fix(idef0): descend auto-grows depthWindow so the entered layer alway…
explosivebit Jul 7, 2026
332ceee
wip(idef0): iso minimap — focus-relative depth dimming + wider plane gap
explosivebit Jul 7, 2026
602de75
wip(idef0): iso minimap declutter — ancestor planes show frames only
explosivebit Jul 7, 2026
6698d62
refactor(idef0): graduate iso view routes/iso-spike -> widgets/iso-map
explosivebit Jul 7, 2026
882054c
feat(idef0): mount 3D iso as Map-view corner minimap (lazy-loaded)
explosivebit Jul 7, 2026
5b1c3a4
perf(idef0): iso bundle surgery — 6.0M -> 3.29M dist
explosivebit Jul 7, 2026
be8d5c0
build(idef0): raise dist cap 3M -> 3.5M for lazy 3D Map minimap
explosivebit Jul 7, 2026
4d71cd0
chore(idef0): drop throwaway /iso-spike route — corner minimap is the…
explosivebit Jul 8, 2026
e342cd8
feat(idef0): bidirectional 3D<->2D drill sync via shared drill-bus + …
explosivebit Jul 8, 2026
56ee61f
docs(idef0): resolve TODO(iso-adr) — cap amendment recorded in ADR-011
explosivebit Jul 8, 2026
92b26b6
fix(idef0): close EVID-100 review findings — sync-retry, WebGL bounda…
explosivebit Jul 8, 2026
9808640
test(idef0): shared-drill-bus + iso-view-state sync tests (closes EVI…
explosivebit Jul 8, 2026
f1d16e4
docs(idef0): activate 3D iso-map chain PRD-039/RFC-036/ADR-011
explosivebit Jul 8, 2026
e29a005
feat(idef0): 3D isometric layered-overview minimap in the Map-view co…
explosivebit Jul 8, 2026
630f4d4
chore(forgeplan): reconcile markdown status + tidy pre-release worktree
explosivebit Jul 9, 2026
d1518e8
chore(forgeplan): reconcile markdown status + tidy pre-release worktr…
explosivebit Jul 9, 2026
3aae2c1
chore(release): bump version to 0.3.0
explosivebit Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
27 changes: 27 additions & 0 deletions .claude/rules/12-forgeplan-agent-dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ forgeplan_dispatch → forgeplan_claim → (sub-agent работает) → forg

Перед запуском параллельных sub-агентов:

0. **`forgeplan_claims`** — СНАЧАЛА посмотреть, что уже занято и кем.
Никогда не клеймить артефакт, на котором уже висит активный claim
другого агента; направь нового агента на свободную работу или дождись
release. Это и есть «следующий смотрит, что уже взято и кто над этим
работает» — без этой проверки два агента возьмут один артефакт.
1. **`forgeplan_dispatch agents=N status=<status>`** — получить план
(bucket'ы по агентам + serial queue для остатка). Read-only вызов;
re-dispatch при изменении claim-set'а.
Expand All @@ -32,6 +37,28 @@ forgeplan_dispatch → forgeplan_claim → (sub-agent работает) → forg
При crash sub-агента или зависании claim'а: `forgeplan_release <id>
--force` — orchestrator escape hatch.

## Claim hygiene — no висяки (orchestrator MUST)

Висяк = claim, оставшийся после того как агент закончил/упал. Он вводит в
заблуждение таб Agents / `forgeplan_health` и блокирует следующего агента до
TTL-expiry. Чтобы их не было:

1. **Sweep после каждого sprint'а / workflow'а.** Как только пачка
параллельных агентов отработала (или workflow завершился/упал):
`forgeplan_claims` → для каждого оставшегося claim этой пачки
`forgeplan_release <id> --force`. Терминальное состояние —
`active_claim_count == 0` (см. Verification).
2. **Release on crash/timeout — сразу, не по TTL.** Если sub-агент упал,
завис, или workflow-агент не отработал (например, schema/StructuredOutput
retry-cap) — `forgeplan_release <id> --force` немедленно.
3. **Read-only ревьюеры тоже подметай.** Им claim не нужен (см. ниже), но
если агент-фреймворк поставил claim от их имени — orchestrator снимает его
тем же sweep'ом. (Наблюдалось: конформанс-аудит оставил 3 висяка на
RFC-008/009/010 после падения architect-reviewer'ов на schema.)
4. **/smith и /autorun** перед рекомендацией следующего шага сверяются с
`forgeplan_claims` — не предлагать работу, которая уже claimed другим
агентом, и сообщать пользователю кто над чем работает.

## Required (sub-agent-side)

Если sub-агент получил инструкцию редактировать файлы в рамках
Expand Down
153 changes: 149 additions & 4 deletions .claude/rules/22-readonly-proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Constraints (every one of these is enforceable from the diff):
- Headers: `accept: application/json` and a static `user-agent`. No cookies,
no credentials.
- Response shape mirrors the standard envelope: `{ ok, data: { current,
latest, hasUpdate }, cmd, error? }` with `current = __FORGEPLAN_WEB_VERSION__`.
latest, hasUpdate }, cmd, error? }` with `current = __FORGEPLAN_WEB_VERSION__`.
- Network failures (timeout, non-2xx, JSON parse error) MUST fall back to
`{ ok: false, error, data: { ..., hasUpdate: false } }` — never throw.

Expand Down Expand Up @@ -75,17 +75,142 @@ Constraints (every one of these is enforceable from the diff):
inflight promise) inside
`template/src/shared/server/registry.ts#readInstances`.
- Response shape mirrors the standard envelope: `{ ok, data: { instances },
cmd: "registry:read", error? }`. `instances` MUST conform to the
cmd: "registry:read", error? }`. `instances` MUST conform to the
SPEC-003 v1 row shape (id / host / port / pid / scope / workspaceRoot /
projectName / startedAt / heartbeatAt / webVersion / forgeplanCli);
malformed rows are silently dropped from the live view.
- Errors (file read, JSON parse) MUST fall back to `{ ok: false, error,
data: { instances: [] } }` — never throw.
data: { instances: [] } }` — never throw.

Any additional non-forgeplan endpoint (whether it hits npm, GitHub,
crates.io, the local filesystem outside the registry, or anything else)
requires a new Forgeplan artifact and a fresh amendment to this rule.

## Allow-list extension: `/api/map` (non-forgeplan; PRD-036 / SPEC-006 / RFC-030)

`/api/map` is a read-only mirror of the composed-map document at
`<workspaceRoot>/.forgeplan/map/map.json` (SPEC-006 C5), backing the
composed-map view (the 9th graph view, Phase-1 render-proof).

Constraints (every one of these is enforceable from the diff):

- Method: `GET` only.
- File path: `path.join(workspaceRoot(), ".forgeplan", "map", "map.json")` —
**no interpolation, no env override beyond the standard `workspaceRoot()`
resolution, no user input** on the path.
- **No spawn, no Forgeplan invocation, no network.** The endpoint reads via
`node:fs.readFileSync` only, inside
`template/src/shared/server/map.ts#readMapFile`. The file's content is
mirrored **verbatim** — the endpoint performs NO structural validation.
Validation (`validateMapDocument`) is the web client's job (SPEC-006 C4);
the server is the third of the three validation call sites (§20) and is
deliberately a "dumb honest mirror" — forking the rule list between
server and client would hide errors from the error-surface UX.
- Response shape mirrors the standard envelope: `{ ok, data, cmd: "map:read",
error? }`. HTTP 200 in every handled case.
- File present, parseable JSON → `{ ok: true, data: <file content
verbatim> }`.
- File missing (ENOENT) → `{ ok: true, data: {} }` — a NORMAL state
("no map yet"), never an error.
- Unreadable / unparseable → `{ ok: false, data: {}, error }` — never a
thrown exception.

Any additional non-forgeplan endpoint requires a new Forgeplan artifact and
a fresh amendment to this rule.

## Allow-list extension: `/api/map/layers/<zone>` (non-forgeplan; PRD-038 FR-002)

`/api/map/layers/<zone>` is a read-only mirror of a **map-pack-emitted
per-zone layer** document at
`<workspaceRoot>/.forgeplan/map/layers/<zone>.json` (PRD-038 FR-002), backing
the composed-map's "prefer emitted layer, fall back to client-derived"
descend seam (FD-6, RFC-031's `deriveSubDocument` seam). This is a distinct,
**read-only** amendment — categorically separate from ADR-008's later,
human-gated **write** amendment for the append/deeper-scan loop (PRD-038
Non-Goals).

Constraints (every one of these is enforceable from the diff):

- Method: `GET` only.
- Route param: `zone` (single dynamic segment, `routes/api/map/layers/[zone]/+server.ts`).
Validated against `^[a-zA-Z0-9._-]+$` **and** rejected if it contains `..`
— no interpolation of unvalidated input into the filesystem path. The
charset excludes `/` outright (no path-traversal via a raw slash); the
explicit `..` rejection closes the two-adjacent-dots gap the charset alone
would allow.
- File path: `path.join(workspaceRoot(), ".forgeplan", "map", "layers",
\`${zone}.json\`)`— the validated`zone` is the only interpolated segment.
- **No spawn, no Forgeplan invocation, no network.** The endpoint reads via
`node:fs.readFileSync` only, inside
`template/src/shared/server/map.ts#readMapLayerFile`. The file's content
is mirrored **verbatim** — the endpoint performs NO structural validation
(validation is the web client's job, SPEC-006 C4, same division of labour
as `/api/map`).
- Response shape mirrors the standard envelope: `{ ok, data, cmd:
"map:layer:read", error? }`.
- File present, parseable JSON → `{ ok: true, data: <file content
verbatim> }`.
- File missing (ENOENT) → `{ ok: true, data: {} }` — a NORMAL state ("no
emitted layer for this zone yet"), never an error.
- Unreadable / unparseable → `{ ok: false, data: {}, error }` — never a
thrown exception.
- Invalid `zone` param → HTTP 400 (`error(400, ...)`), the only non-GET-2xx
response this endpoint returns.
- **MVP scope**: single-segment top-level zone ids only. A nested
`<ancestor>/<zone>` layer path is a follow-up — out of scope for this
amendment, rejected by the same `zone` validation (no `/` in the charset).

Any additional non-forgeplan endpoint requires a new Forgeplan artifact and
a fresh amendment to this rule.

## Allow-list extension: git-reconstruction endpoints (`/api/snapshot`, `/api/timeline-events`)

Time-travel (PRD-008 / RFC-007) and snapshot identity (PRD-016 / RFC-015) need
the workspace's _history_, which the `forgeplan` CLI does not expose read-only.
Two endpoints therefore spawn **`git`** (not `forgeplan`) in read-only mode:

- `/api/timeline-events` — `git log` over `.forgeplan/` to list create / activate
/ supersede / score events for the scrubber.
- `/api/snapshot` — reconstructs a past workspace state: `git rev-list` (resolve
the commit at/before an ISO timestamp), `git cat-file -e` (reachability),
`git worktree add --detach <tmp> <sha>` into an OS tmpdir, then runs
`forgeplan reindex` **inside that ephemeral throwaway worktree** plus
`forgeplan list/graph --json` against it, then `git worktree remove --force`.

Constraints (every one enforceable from the diff):

- Method: `GET` only.
- Every `git` / `forgeplan` invocation goes through `child_process.spawn` with an
**argv array** — never a shell-string. The only interpolated values are the
SHA (validated `^[0-9a-f]{40}$`) and the `at` timestamp (validated against an
ISO-8601 regex); no raw user input reaches argv.
- `git` runs are scoped to the repo root (`git rev-parse --show-toplevel`) with
the pathspec restricted to `.forgeplan/`; every spawn carries a timeout.
- **The `forgeplan reindex` here is the documented exception to the "forbidden
reindex" rule below.** It writes the Lance index of a _disposable_ git worktree
under `tmpdir`, never the host `.forgeplan/lance/`; the host workspace is never
mutated, and the worktree is always removed in a `finally`.
- No network; no host filesystem write outside the OS-tmpdir worktree.

These are the only places `git` is spawned from `/api/*`, and the only place
`reindex` runs (ephemeral-worktree-scoped). Any new git-spawning or
history-reconstruction endpoint requires an updating Forgeplan artifact and a
revision of this rule. See PRD-008 / RFC-007 and PRD-016 / RFC-015.

## OPTIONS preflight + CORS carve-out (`/api/instance-status`)

`/api/instance-status` (issue #134) reports a single instance's live status using
only the allow-listed `health` + `claims` subcommands — fully compliant with the
forgeplan allow-list above. Because the instance switcher fetches _other_
forgeplan-web instances **cross-origin** (different port = different origin), this
endpoint is the one permitted exception to the strict "GET only" shape: it also
exports an `OPTIONS` handler returning `204` with `Access-Control-Allow-Origin: *`

- `Access-Control-Allow-Methods: GET` for the browser preflight. The `OPTIONS`
handler is side-effect-free (no spawn, no body); `GET` stays the only data path.
No other `/api/*` route may export a non-GET handler or set CORS headers without
an updating artifact.

## Forbidden `forgeplan` subcommands from any `/api/*` endpoint

Any subcommand that mutates the workspace:
Expand Down Expand Up @@ -122,8 +247,13 @@ browser invalidates that.

- `grep -RIn "forgeplan" template/src/routes/api/` must show only commands
from the allow-list above.
- `grep -RIn "spawn\|execFile" template/src/routes/api/ template/src/shared/server/`
may show `git` spawns ONLY in the snapshot / timeline-events reconstruction
path (see git-reconstruction extension above); every such spawn is argv-based
with validated SHA / ISO inputs.
- Every route file is `+server.ts` exporting `GET` only (no `POST`, `PUT`,
`PATCH`, `DELETE`).
`PATCH`, `DELETE`) — the sole exception is the side-effect-free `OPTIONS`
preflight on `/api/instance-status` (CORS carve-out above).
- `runForgeplan` in `template/src/shared/server/forgeplan.ts` MUST check
`args[0] ∈ READ_ONLY_SUBCOMMANDS` before spawning, and the constant MUST
match this allow-list (see rule above). The check is the runtime backstop
Expand All @@ -136,3 +266,18 @@ browser invalidates that.
call (read-only constraint above). The reader
`template/src/shared/server/registry.ts` MAY only call
`existsSync` + `readFileSync` against `~/.forgeplan-web/instances.json`.
- `template/src/routes/api/map/+server.ts` MUST NOT contain any `spawn`,
`execFile`, `writeFileSync`, `renameSync`, or `mkdirSync` call, and MUST
NOT call `validateMapDocument` (validation stays client-side per SPEC-006
C4/C5). The reader `template/src/shared/server/map.ts#readMapFile` MAY
only call `existsSync` + `readFileSync` against
`<workspaceRoot>/.forgeplan/map/map.json`.
- `template/src/routes/api/map/layers/[zone]/+server.ts` MUST NOT contain
any `spawn`, `execFile`, `writeFileSync`, `renameSync`, or `mkdirSync`
call, and MUST NOT call `validateMapDocument` (validation stays
client-side, same as `/api/map`). It MUST validate `params.zone` via
`isValidZoneId` and respond `400` before calling `readMapLayerFile` on an
invalid id. The reader
`template/src/shared/server/map.ts#readMapLayerFile` MAY only call
`existsSync` + `readFileSync` against
`<workspaceRoot>/.forgeplan/map/layers/<zone>.json`.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ id: ADR-002
kind: adr
last_modified_at: 2026-05-04T13:50:41.701061+00:00
last_modified_by: claude-code/2.1.126
status: draft
status: active
title: Sub-agent dispatch must go through forgeplan_dispatch + forgeplan_claim
---

Expand Down Expand Up @@ -198,3 +198,5 @@ markdown-правки + status-flip.
| RFC-003 | RFC | informs (наблюдение симптомов на нём триггернуло этот ADR) |
| ADR-001 | ADR | based_on (host isolation contract — близкий по духу) |



Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,4 @@ windows CI), брать MAX как worst-case; если worst-case <100ms — CL




Loading
Loading