@giamme/forge 0.0.0-stage → 0.8.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1854 -2
  4. package/SKILL.md +122 -0
  5. package/VERSION +1 -0
  6. package/forge +74 -0
  7. package/package.json +26 -4
  8. package/references/dataset.md +329 -0
  9. package/references/decompose.md +667 -0
  10. package/references/fractal-dashboard.md +21 -0
  11. package/references/fractal.md +307 -0
  12. package/references/harnesses.md +353 -0
  13. package/references/jev.md +865 -0
  14. package/references/memory.md +228 -0
  15. package/references/planning.md +42 -0
  16. package/references/ripwire.md +47 -0
  17. package/references/runtime.md +64 -0
  18. package/references/solo.md +113 -0
  19. package/references/ui.md +112 -0
  20. package/registry.tsv +81 -0
  21. package/scripts/forge-artifact.sh +78 -0
  22. package/scripts/forge-contract.py +430 -0
  23. package/scripts/forge-dataset.py +6 -0
  24. package/scripts/forge-dispatch.sh +665 -0
  25. package/scripts/forge-fail-first.py +195 -0
  26. package/scripts/forge-fractal-dispatch.sh +4 -0
  27. package/scripts/forge-fractal-options.sh +54 -0
  28. package/scripts/forge-fractal.py +6 -0
  29. package/scripts/forge-guard.py +266 -0
  30. package/scripts/forge-install-fractal.sh +4 -0
  31. package/scripts/forge-install-ripwire.sh +52 -0
  32. package/scripts/forge-install.sh +135 -0
  33. package/scripts/forge-jev-options.sh +259 -0
  34. package/scripts/forge-jev.py +6 -0
  35. package/scripts/forge-lib-plans.sh +785 -0
  36. package/scripts/forge-lib-review.sh +494 -0
  37. package/scripts/forge-lib-task.sh +302 -0
  38. package/scripts/forge-lib-verify.sh +30 -0
  39. package/scripts/forge-memory.sh +575 -0
  40. package/scripts/forge-metrics.sh +39 -0
  41. package/scripts/forge-parallel-options.sh +76 -0
  42. package/scripts/forge-parallel.sh +1717 -0
  43. package/scripts/forge-plan-check.py +118 -0
  44. package/scripts/forge-prompt.py +45 -0
  45. package/scripts/forge-ripwire.py +136 -0
  46. package/scripts/forge-route.py +344 -0
  47. package/scripts/forge-runtime.py +533 -0
  48. package/scripts/forge-schedule.py +312 -0
  49. package/scripts/forge-shadow.py +305 -0
  50. package/scripts/forge-solo.sh +347 -0
  51. package/scripts/forge-ui-options.sh +42 -0
  52. package/scripts/forge-ui.py +435 -0
  53. package/scripts/forge-update.sh +71 -0
  54. package/scripts/forge-verify-coverage.py +956 -0
  55. package/scripts/forge-version.py +198 -0
  56. package/scripts/forge_dataset/__init__.py +439 -0
  57. package/scripts/forge_dataset/capture.py +330 -0
  58. package/scripts/forge_dataset/checks.py +109 -0
  59. package/scripts/forge_dataset/cli.py +233 -0
  60. package/scripts/forge_dataset/export.py +1009 -0
  61. package/scripts/forge_dataset/harvest.py +716 -0
  62. package/scripts/forge_dataset/importer.py +412 -0
  63. package/scripts/forge_dataset/outcomes.py +275 -0
  64. package/scripts/forge_dataset/routing.py +278 -0
  65. package/scripts/forge_fractal/__init__.py +83 -0
  66. package/scripts/forge_fractal/bridge.py +46 -0
  67. package/scripts/forge_fractal/cli.py +202 -0
  68. package/scripts/forge_fractal/dashboard.css +138 -0
  69. package/scripts/forge_fractal/dashboard.html +41 -0
  70. package/scripts/forge_fractal/dashboard.js +687 -0
  71. package/scripts/forge_fractal/decomposition.py +262 -0
  72. package/scripts/forge_fractal/execution.py +659 -0
  73. package/scripts/forge_fractal/inspection.py +261 -0
  74. package/scripts/forge_fractal/install.py +158 -0
  75. package/scripts/forge_fractal/invocation.py +94 -0
  76. package/scripts/forge_fractal/pipeline.py +124 -0
  77. package/scripts/forge_fractal/selection.py +179 -0
  78. package/scripts/forge_jev/__init__.py +376 -0
  79. package/scripts/forge_jev/backtest.py +322 -0
  80. package/scripts/forge_jev/cli.py +980 -0
  81. package/scripts/forge_jev/client.py +418 -0
  82. package/scripts/forge_jev/corpus.py +156 -0
  83. package/scripts/forge_jev/coupling.py +244 -0
  84. package/scripts/forge_jev/features.py +24 -0
  85. package/scripts/forge_jev/gates.py +100 -0
  86. package/scripts/forge_jev/memory.py +163 -0
  87. package/scripts/forge_jev/outcome.py +49 -0
  88. package/scripts/forge_jev/predict.py +204 -0
  89. package/scripts/forge_jev/questions.py +661 -0
  90. package/scripts/forge_jev/review.py +73 -0
  91. package/scripts/forge_jev/routing.py +271 -0
  92. package/scripts/forge_jev/subset.py +123 -0
  93. package/scripts/forge_jev/verify.py +453 -0
  94. package/scripts/forge_registry.py +140 -0
  95. package/ui/README.md +287 -0
  96. package/ui/THIRD_PARTY_NOTICES.md +69 -0
  97. package/ui/docs/api.md +888 -0
  98. package/ui/forge_ui/__init__.py +20 -0
  99. package/ui/forge_ui/__main__.py +135 -0
  100. package/ui/forge_ui/diffs.py +454 -0
  101. package/ui/forge_ui/executions.py +436 -0
  102. package/ui/forge_ui/export.py +204 -0
  103. package/ui/forge_ui/findings.py +132 -0
  104. package/ui/forge_ui/fractal.py +583 -0
  105. package/ui/forge_ui/models.py +216 -0
  106. package/ui/forge_ui/reader.py +1336 -0
  107. package/ui/forge_ui/server.py +303 -0
  108. package/ui/forge_ui/static/app.js +924 -0
  109. package/ui/forge_ui/static/cloud3d.js +646 -0
  110. package/ui/forge_ui/static/cloudmodel.js +375 -0
  111. package/ui/forge_ui/static/cloudui.js +394 -0
  112. package/ui/forge_ui/static/diffview.js +216 -0
  113. package/ui/forge_ui/static/favicon.svg +1 -0
  114. package/ui/forge_ui/static/files.js +776 -0
  115. package/ui/forge_ui/static/gantt.js +97 -0
  116. package/ui/forge_ui/static/graph.js +266 -0
  117. package/ui/forge_ui/static/index.html +55 -0
  118. package/ui/forge_ui/static/iso.js +765 -0
  119. package/ui/forge_ui/static/leaderboard.js +315 -0
  120. package/ui/forge_ui/static/map3d.js +45 -0
  121. package/ui/forge_ui/static/modelstats.js +249 -0
  122. package/ui/forge_ui/static/notify.js +179 -0
  123. package/ui/forge_ui/static/panel.js +526 -0
  124. package/ui/forge_ui/static/runmodel.js +651 -0
  125. package/ui/forge_ui/static/scene3d.js +996 -0
  126. package/ui/forge_ui/static/search.js +119 -0
  127. package/ui/forge_ui/static/style.css +618 -0
package/ui/README.md ADDED
@@ -0,0 +1,287 @@
1
+ # forge-ui
2
+
3
+ forge-ui is a small, read-only local web UI for forge runs. It draws them the way
4
+ [archivision](https://github.com/Giamme/archivision) draws a codebase: a 3D isometric map of
5
+ blocks on a plate, with cables between them and lamps that light up as things happen.
6
+
7
+ - **A map of every run**, one district per repo and one block per run, with a lamp per task.
8
+ Filter it by state, repo, kind, model, age or review verdict; what does not match fades
9
+ instead of disappearing.
10
+ - **A run, as planned and as it ran.** *Planned waves* puts each task in its wave, with
11
+ dependency cables, and ends in a *finish* line of three nodes: integration, verification
12
+ and the whole-run **final review**. *Execution* lays the same work out on wall-clock time:
13
+ one block per attempt, in the lane it really ran in, with its dwarf and review inside, the
14
+ attempts that have not started projected by forge-schedule's own rules, and a strip of how
15
+ many slots were busy against `--max-parallel`. Switching between the two moves each task
16
+ from its wave to where it ran.
17
+ - **Click to open.** A task opens to show its attempts, each with its dwarf, its reviewer and
18
+ any shadow reviews, linked; an escalation is a labelled cable between attempts. The
19
+ inspector beside the stage shows what launched each step and what came of it: the exact
20
+ prompt, the model (alias, harness, model, effort, clamping), the timings by phase, tokens,
21
+ the verdict, and every **P0–P3 finding** of every review, the final review included.
22
+ - **Live.** Statuses change in place while a run works (every 2 s while something runs, 5 s
23
+ otherwise); running nodes pulse and show their current phase.
24
+ - **Extras:** replay a run from its recorded times, light its critical path, set block height
25
+ and colour by duration, tokens, attempts or model, and mark shadow reviews that disagreed
26
+ with the primary and how sure Clef was that each task would pass.
27
+ - **Beyond one run:** a full-screen **run cloud** of every run, grouped by project, in five
28
+ layouts with filters and runs you can drag anywhere; **diffs** with each finding under the
29
+ line it names; a **model leaderboard**; a **files heatmap**; **Fractal** child-task trees;
30
+ **quick jump** and **notifications**; and **export** of a run as one HTML file. See
31
+ [What you see](#what-you-see).
32
+
33
+ <p align="center">
34
+ <img src="docs/media/hero.webp" width="860" alt="A decomposed run on its 3D plate: eight tasks in their planned waves, then the same run on wall-clock time, where two first attempts that failed review show in red beside the retries that passed.">
35
+ </p>
36
+
37
+ The 3D view loads three.js from a CDN the first time it is used (see [Privacy](#privacy)).
38
+ Without it (offline, an old browser, no WebGL) the same page shows the 2D dependency graph,
39
+ an execution chart and the same inspector. The server is Python's standard library; there
40
+ is no install or build step.
41
+
42
+ It lives inside forge, in `ui/`, and is forge's companion: runs open it with `--ui`.
43
+
44
+ ## Run it
45
+
46
+ Normally forge launches it. `forge ui open [DIR]` (from the forge checkout) starts or
47
+ reuses one shared detached server and prints the link to a run dir, `forge ui status`
48
+ shows it and `forge ui stop` ends it; see [references/ui.md](../references/ui.md). A run
49
+ starts it itself with `forge-solo.sh --ui` or `forge-parallel.sh plan --ui`.
50
+
51
+ To run the server directly, from `ui/`:
52
+
53
+ ```sh
54
+ python3 -m forge_ui
55
+ ```
56
+
57
+ Open the printed URL (default `http://127.0.0.1:8765/`). Stop with Ctrl-C.
58
+
59
+ - `--plan DIR`: add one plan directory; repeatable, default none.
60
+ - `--root DIR`: scan for plan directories at depth 0–2; repeatable, default none.
61
+ - `--no-registry`: disable the registry, which is read by default.
62
+ - `--registry-dir DIR`: override the registry directory described below.
63
+ - `--port N`: use port N, default `8765`; `0` selects a free port.
64
+ - `--quiet`: suppress request logging; off by default (errors can still be logged).
65
+ - `--open`: open the browser after startup; off by default.
66
+ - `--idle-exit SECONDS`: exit after that many idle seconds; default `0` (never). `forge ui` sets it from `FORGE_UI_IDLE_S`.
67
+ - `--version`: print the version and exit.
68
+ - `-h`, `--help`: print usage and exit.
69
+
70
+ Three examples (replace the example paths with your own):
71
+
72
+ ```sh
73
+ # Registry only
74
+ python3 -m forge_ui
75
+ # One plan directory only
76
+ python3 -m forge_ui --no-registry --plan /path/to/plan
77
+ # A root containing many runs, without registry entries
78
+ python3 -m forge_ui --no-registry --root /path/to/runs
79
+ ```
80
+
81
+ No runs yet? `tools/demo_runs.py` writes made-up ones, the same that fill the pictures here: a
82
+ live run and a few weeks of history across five projects.
83
+
84
+ ```sh
85
+ python3 tools/demo_runs.py /tmp/forge-demo
86
+ python3 -m forge_ui --no-registry --root /tmp/forge-demo --open
87
+ ```
88
+
89
+ ## Where runs come from
90
+
91
+ Sources are checked in this order:
92
+
93
+ 1. Explicit `--plan DIR` directories.
94
+ 2. `--root DIR` itself, its children and grandchildren. Scanning stops when a plan
95
+ directory is found; hidden children and symlinked child directories are skipped.
96
+ 3. Forge's registry: `*.txt` files in `$XDG_CONFIG_HOME/forge/runs/`, defaulting
97
+ to `~/.config/forge/runs/` when XDG_CONFIG_HOME is unset or empty. Each file
98
+ supplies absolute paths, one per line; blank lines and `#` comments are ignored.
99
+ `--registry-dir` replaces this location; `--no-registry` disables it.
100
+
101
+ Plan directories (containing a `tasks.tsv` file) and solo run directories (a `prompt.md`
102
+ and a `repo` file) appear through `--plan` and the registry; `--root` finds plan directories
103
+ only. Stale or invalid paths are skipped. Duplicate real paths appear once,
104
+ with the first source winning. Discovery and disk reads repeat on each API request.
105
+
106
+ ## What you see
107
+
108
+ - **Map (`#/`):** every discovered run, newest first, grouped by repo. By default the last
109
+ 60 runs from the past 14 days; *older runs too* shows the rest. The sidebar list follows
110
+ the same filter.
111
+
112
+ <img src="docs/media/map.png" width="760" alt="The map: one block per run, in a district per repo, green when done, blue while running, red with failures.">
113
+ - **Run cloud (`#/cloud`):** every run at once, full screen, floating in 3D and grouped by project
114
+ (repo). Pick a layout: *Helix* (one spiral per project, oldest at the bottom), *Sphere*,
115
+ *Galaxy* (a disc per project, newest at the centre), *Timeline* (left to right by start time,
116
+ one lane per project) or *Constellation* (pulled together by project and shared models, with
117
+ lines joining each project's nearest runs). Runs are *Blocks* (a lamp per task on the roof) or
118
+ *Orbs* (a ring of task segments); size is the number of tasks, colour the run's state. The
119
+ filter panel narrows the cloud to exactly the runs wanted: projects, state, kind, difficulty
120
+ (has a task of, or mostly), tasks per run, models (any role, implementer or reviewer), recent
121
+ activity, final review, verification, decompose level and text (goals, ids, task titles).
122
+ Orbit, pan and zoom anywhere; drag a run to put it where you want (Shift: nearer or further,
123
+ Alt: up or down). Dropped positions are kept in this browser per layout; *Positions* resets them
124
+ (with undo) or exports and imports them as a JSON file. Click a run for its card, double-click
125
+ to open it; `#/cloud/runs/<key>` and `#/cloud/projects/<id>` link to a selection. Keys:
126
+ arrows orbit, + − zoom, F frames, P steps through projects, [ ] through runs, L changes the
127
+ layout, B the shape, 0 resets the view, Esc steps back. With *2D*, the cloud lists the same
128
+ filtered runs and offers *Load 3D*.
129
+
130
+ <img src="docs/media/cloud.webp" width="760" alt="The run cloud orbited, then laid out as galaxies and as a timeline with one lane per project.">
131
+ - **Run (`#/runs/<key>`):** a header (goal, repo, counts, and *Run details*: settings, request,
132
+ waves, verification output), a toolbar (*Planned waves* / *Execution*, *3D* / *2D*, height
133
+ and colour overlays, *Critical path*, *Review marks*, *Projected*, *Replay*), the stage with
134
+ the inspector beside it, and the task table.
135
+
136
+ <img src="docs/media/run.png" width="49%" alt="Planned waves: a run's tasks on a 3D plate with dependency cables and the finish nodes, beside the run's inspector."> <img src="docs/media/execution.png" width="49%" alt="Execution: one block per attempt on wall-clock time, failed attempts in red, with the timeline and critical path in the inspector.">
137
+ - **Inspector:** for the run, its timeline, critical path, peak concurrency and finish line;
138
+ for a task, its models and routing, escalations, timings (busy, model time, overhead,
139
+ queue wait after its dependencies merged), attempts and their executions, review findings
140
+ with the gate decision, Clef predictions against outcomes, and its prompts; for one
141
+ execution, its model, phases, tokens, exact prompt and final message; for the final
142
+ review, its verdict, findings, report, prompt and history.
143
+ - **Files (the run toolbar's third mode):** a heatmap of files (grouped and collapsible by
144
+ directory) against tasks (grouped by wave): planned files outlined, touched files filled by how
145
+ many attempts changed them, drift hatched, merge conflicts ringed, and a dot where another task
146
+ of the same wave planned or touched the file too. Filter by path, sort by path, most touched or
147
+ most tasks, and hide any kind of mark; a cell selects its task and offers that file's diff.
148
+ Below: overlaps, drift, merge conflicts and deferrals as lists.
149
+
150
+ <img src="docs/media/files.png" width="560" alt="The files heatmap: files by directory against tasks by wave, with planned, touched, drift and same-wave overlap marks.">
151
+ - **Models (`#/models`):** a leaderboard of the models forge used. Implementers: tasks, first-attempt
152
+ pass rate with its 95% Wilson interval, censored attempts, retries, escalations away from the
153
+ model, timeouts, gate and human accepts, median model time and tokens. Reviewers: primary,
154
+ shadow and final reviews, the PASS/FAIL split, findings per review by severity, and how often a
155
+ shadow review agreed with the primary. Filter by project, difficulty, kind and period, or keep
156
+ only exploratory picks; open a difficulty for its own table. Routing is not random, so the
157
+ numbers compare what happened, not what would have: the page says so. A model's name opens the
158
+ run cloud filtered to its runs.
159
+
160
+ <img src="docs/media/models.png" width="760" alt="The implementers table: tasks, first-attempt pass rate with its 95% interval, retries, escalations, timeouts, accepts, median model time and tokens per model.">
161
+ - **Diffs (`…/tasks/<id>/diff[/<source>][/file/<path>]`, `…/final-review/<name>/diff`):** a task's
162
+ `changes.diff`, its previous or committed diff, or exactly the diff one reviewer read (the last
163
+ diff in that review's prompt), picked from a row of sources with each review's verdict; a final
164
+ review's combined diff. Files are listed with their +/− counts and how many findings point
165
+ into them; each finding is shown under the line it names, those on a line outside the changed
166
+ hunks at the top of their file, and those whose file is not in the diff (or that name no
167
+ location) in a section of their own. n and p move between findings, j and k between files.
168
+ Open it from a task, an attempt's review, an execution or the final review in the inspector.
169
+
170
+ <img src="docs/media/diff.png" width="760" alt="The diff a reviewer read, with a P1 finding under the line that compares token digests and a P2 finding under the revoke function.">
171
+ - **Fractal child tasks:** when a run used Fractal, a task's inspector shows the tree it was split
172
+ into (status, difficulty, model, phase, cost, the split decision), and the opened task in 3D
173
+ carries the same tree floating above it. A node (`…/tasks/<id>/fractal/<node>`) shows its goal,
174
+ paths, timings, cost and tokens, its decomposition and the children it admitted, its last
175
+ messages, and its candidate diff. Fractal's state is read under `$XDG_STATE_HOME/forge/fractal`
176
+ (default `~/.local/state`), read-only, without following symlinks.
177
+ - **Export:** *Export…* in a run's header downloads the run as one HTML file that opens in any
178
+ browser without forge-ui, offline included (in 2D; in 3D when cdn.jsdelivr.net is reachable).
179
+ It asks each time: by default prompts, reviewer reports, logs, finding details and diffs are
180
+ left out (each finding's headline stays) and local paths are reduced to their last component.
181
+ The file states what it left out, and fetches nothing but three.js: its own policy allows only
182
+ its inline scripts, by hash.
183
+ - **Quick jump:** Ctrl K (⌘K on a Mac), `/` or *Search* opens one search over every run (goal,
184
+ run id, repo, models), task (id and title), project, model and command. Enter opens the pick;
185
+ Shift+Enter shows a run in the cloud; a model shows its runs in the cloud. With nothing typed,
186
+ recent picks and running runs come first.
187
+ - **Notifications:** the bell lists what changed while the page was open: a run that finished or
188
+ ended with failures, a task that failed (FAIL, ERROR, CONFLICT, TIMEOUT, INVALIDATED,
189
+ INTERRUPTED or BLOCKED; INFRA retries are not failures) and a final review's verdict, each
190
+ linked to it. Unread ones show as a count in the tab title and a dot on its icon. *Enable
191
+ browser notifications* asks the browser once; then changes also show as system notifications
192
+ while the tab is in the background, and a hidden tab checks the run list every 30 seconds
193
+ (browsers may check less often after a while). Open tabs share one log and notify once. Runs
194
+ that have not changed for two hours never notify.
195
+ - **Keys on the stage:** ← → move between tasks, Esc closes, `e` switches plan and
196
+ execution. Drag to orbit, right-drag to pan, scroll to zoom once the stage is clicked.
197
+
198
+ URLs such as `http://127.0.0.1:8765/#/runs/<key>/tasks/<id>` are shareable within the
199
+ machine while this server is running and discovering that run dir. *Live refresh* pauses
200
+ polling; a hidden tab polls only the run list, every 30 seconds, and only with browser
201
+ notifications on. Failed requests keep the last good data and show a banner.
202
+
203
+ ## Layout of the code
204
+
205
+ - `forge_ui/reader.py`: discover runs, parse their files and produce summaries and details.
206
+ - `forge_ui/executions.py`: the per-dispatch records (`attempts/<role>-<uuid>/`), nested and
207
+ matched to attempts, through a cache keyed by each file's identity and mtime.
208
+ - `forge_ui/findings.py`: P0–P3 findings and the gate, parsed by forge's own `scripts/forge-contract.py`.
209
+ - `forge_ui/server.py`: serve the JSON API and static assets, with GET/HEAD only.
210
+ - `forge_ui/__main__.py`: CLI options, local startup and optional browser opening.
211
+ - `forge_ui/__init__.py`: package version and the build id `forge ui` compares to find a stale server.
212
+ - `forge_ui/static/index.html`, `style.css`, `app.js`: the page shell, styles, routes, views and polling.
213
+ - `forge_ui/static/runmodel.js`: the pure run model (layouts, schedule projection, critical path, replay).
214
+ - `forge_ui/static/panel.js`, `gantt.js`, `graph.js`: the inspector, the execution chart and strip, the 2D graph.
215
+ - `forge_ui/static/map3d.js`, `scene3d.js`, `iso.js`: the 3D loader, scenes and engine (ported from archivision).
216
+ - `forge_ui/static/cloudmodel.js`, `cloud3d.js`, `cloudui.js`: the run cloud's pure model (projects,
217
+ filters, layouts, layout files), its scene on the shared stage, and its controls.
218
+ - `forge_ui/static/diffview.js`: the diff viewer, with findings pinned to their lines.
219
+ - `forge_ui/static/files.js`: the files heatmap (`matrix()` is pure and node-tested).
220
+ - `forge_ui/export.py`: a run as one HTML file (the page's scripts and styles inlined, the API
221
+ responses it reads, the 3D stage's modules as one module text, a hash-based policy).
222
+ - `forge_ui/static/modelstats.js`, `leaderboard.js`: the leaderboard's aggregation (outcomes as
223
+ `scripts/forge_dataset/export.py` labels them, the interval of its `routing.py`) and its page.
224
+ - `forge_ui/diffs.py`, `fractal.py`, `models.py`: diff parsing and finding pins, the Fractal state
225
+ reader, and the facts behind the model leaderboard.
226
+ - `forge_ui/static/search.js`, `notify.js`, `favicon.svg`: the quick jump and the notifications
227
+ (ranking and change detection are in `runmodel.js`).
228
+ - `tests/`: reader, executions, endpoints, server, static-script and browser checks; `run_fixture.py`
229
+ builds realistic runs in a temp dir (`python3 tests/run_fixture.py DIR` writes two you can open),
230
+ and `many_fixture.py` many small ones across repos for the cloud (`python3 tests/many_fixture.py DIR 300`).
231
+ - `tools/demo_runs.py`, `tools/readme_media.py`: made-up runs to look around with (one live run
232
+ and five projects of history), and the script that turns them into the READMEs' pictures in
233
+ `docs/media/`.
234
+ - [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md): the licences of the ported and loaded code;
235
+ forge-ui itself is under forge's [MIT License](../LICENSE).
236
+
237
+ [docs/api.md](docs/api.md) is the data contract between the reader, server and page.
238
+
239
+ ### Known differences from docs/api.md
240
+
241
+ - Root discovery stops at a discovered plan and skips symlinked child directories;
242
+ it does not visit every nested plan within depth 2.
243
+ - The reader accepts wave numbers only from 1 to 10,000 and warns about other values.
244
+ - List `updated` timestamps cover the directory and summary inputs; detail timestamps
245
+ additionally cover files read for the task panels and other run details.
246
+ - The server rejects Host headers other than `127.0.0.1` or `localhost` (optional
247
+ port) with `403`; an absent Host is accepted. This also precedes method rejection.
248
+ - Static filenames must contain only letters, digits, `_`, `-` and `.` and must
249
+ not contain `..`; resolved files must be directly inside the static directory.
250
+
251
+ ## Develop
252
+
253
+ Use Python 3.9+ to run the server and tests. Node.js 18+ runs the JavaScript checks; use a
254
+ modern browser for the page (import maps: Chrome 89, Firefox 108, Safari 16.4). No Python or
255
+ Node packages need installing.
256
+
257
+ Run these from `ui/`:
258
+
259
+ ```sh
260
+ python3 -m unittest discover -s tests # includes the syntax checks and node --test
261
+ node --test tests/js/*.test.js # the run and cloud models alone
262
+ ```
263
+
264
+ `tests/test_browser.py` drives the page in Chromium when Python Playwright is installed, and
265
+ skips otherwise. Its 3D tests need three.js: the CDN, or a local copy of the npm package
266
+ (`npm pack three@0.160.0`, unpacked) named by `FORGE_UI_TEST_THREE=<dir>/package`.
267
+
268
+ The pictures in this README and forge's come from `tools/readme_media.py`. After a change you
269
+ can see, run it again: it builds the demo runs, serves them, and captures each view in
270
+ Chromium with Playwright (three.js as for the browser tests; ffmpeg with libwebp and ImageMagick
271
+ to encode the animations and PNGs). `--only cloud diff` retakes some of them.
272
+
273
+ ```sh
274
+ python3 tools/readme_media.py # writes docs/media/
275
+ ```
276
+
277
+ ## Privacy
278
+
279
+ Run dirs can contain prompts, diffs and review text from private repos. The server binds
280
+ only `127.0.0.1`, makes no network requests, and writes nothing to run dirs, repositories or
281
+ forge's config. Anyone with access to the local server can read the runs it discovers, and
282
+ forge now registers every run, so that is every run on the machine.
283
+
284
+ The 3D view loads three.js 0.160.0 from `cdn.jsdelivr.net` the first time it is shown in a
285
+ tab: the browser asks the CDN for those script files and sends nothing about your runs
286
+ (`Referrer-Policy: no-referrer`, and the page's CSP allows only that one package). Choose
287
+ **2D** in the toolbar and the browser remembers it and never contacts the CDN.
@@ -0,0 +1,69 @@
1
+ # Third-party notices
2
+
3
+ forge-ui's 3D view is ported from archivision and draws in the iso-glow style. The served
4
+ copies of that code (`forge_ui/static/iso.js`, `scene3d.js` and `runmodel.js`) carry these
5
+ notices in their head comments; this file keeps them with the source.
6
+
7
+ ## archivision
8
+
9
+ `forge_ui/static/iso.js` and `scene3d.js` port `assets/shell-3d.html` and `assets/figure.js`;
10
+ `forge_ui/static/runmodel.js` ports `lib/layout.js` (https://github.com/Giamme/archivision).
11
+
12
+ ```
13
+ MIT License
14
+
15
+ Copyright (c) 2026 Giamme
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ of this software and associated documentation files (the "Software"), to deal
19
+ in the Software without restriction, including without limitation the rights
20
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ copies of the Software, and to permit persons to whom the Software is
22
+ furnished to do so, subject to the following conditions:
23
+
24
+ The above copyright notice and this permission notice shall be included in all
25
+ copies or substantial portions of the Software.
26
+
27
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
+ SOFTWARE.
34
+ ```
35
+
36
+ ## iso-glow and iso-figure
37
+
38
+ archivision's shell and the drawing style of its figures come from iso-glow, which is based
39
+ on iso-figure. The same code is in `forge_ui/static/iso.js` and `scene3d.js`.
40
+
41
+ ```
42
+ MIT License
43
+
44
+ Copyright (c) 2026 April Zhu (iso-glow: lighting, palettes, gallery shell, examples)
45
+ Copyright (c) 2026 Tolga Cohce (iso-figure, on which iso-glow is based)
46
+
47
+ Permission is hereby granted, free of charge, to any person obtaining a copy
48
+ of this software and associated documentation files (the "Software"), to deal
49
+ in the Software without restriction, including without limitation the rights
50
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51
+ copies of the Software, and to permit persons to whom the Software is
52
+ furnished to do so, subject to the following conditions:
53
+
54
+ The above copyright notice and this permission notice shall be included in all
55
+ copies or substantial portions of the Software.
56
+
57
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
61
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
63
+ SOFTWARE.
64
+ ```
65
+
66
+ ## three.js
67
+
68
+ three.js 0.160.0 (MIT, Copyright © 2010-2023 three.js authors) is not part of forge. The page
69
+ loads it, with its `examples/jsm` add-ons, from `cdn.jsdelivr.net` when the 3D view is used.