@floless/app 0.51.0 → 0.53.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.
@@ -52856,7 +52856,7 @@ function appVersion() {
52856
52856
  return resolveVersion({
52857
52857
  isSea: isSea2(),
52858
52858
  sqVersionXml: readSqVersionXml(),
52859
- define: true ? "0.51.0" : void 0,
52859
+ define: true ? "0.53.0" : void 0,
52860
52860
  pkgVersion: readPkgVersion()
52861
52861
  });
52862
52862
  }
@@ -52866,7 +52866,7 @@ function resolveChannel(s) {
52866
52866
  return "dev";
52867
52867
  }
52868
52868
  function appChannel() {
52869
- return resolveChannel({ isSea: isSea2(), define: true ? "0.51.0" : void 0 });
52869
+ return resolveChannel({ isSea: isSea2(), define: true ? "0.53.0" : void 0 });
52870
52870
  }
52871
52871
 
52872
52872
  // workflow-update.ts
@@ -53893,7 +53893,7 @@ function contractToScene(contractInput) {
53893
53893
  color: pickColor(profile, i, contract)
53894
53894
  }));
53895
53895
  return {
53896
- scene: { meta: { name: contract.title || "Steel takeoff", units: "mm", up: "z" }, groups, elements },
53896
+ scene: { meta: { name: contract.title || "Steel Model", units: "mm", up: "z" }, groups, elements },
53897
53897
  skipped
53898
53898
  };
53899
53899
  }
@@ -60631,14 +60631,18 @@ var PRODUCT_SKILLS = [
60631
60631
  // file a diagnosed bug/idea/question to the private log via the floless.io relay
60632
60632
  "floless-app-routines",
60633
60633
  // author event-driven ("on trigger") routines
60634
+ "floless-app-steel-model",
60635
+ // front-door guide: orchestrate a steel drawing SET into a model (project → knowledge → agents → confirm-gated reads via the reader)
60634
60636
  "floless-app-steel-takeoff",
60635
60637
  // read a steel drawing into an editable steel.takeoff/v1 contract (the Steel Takeoff reader)
60636
60638
  "floless-app-tweak-contract",
60637
- // handle a tweak-contract request from the steel-takeoff contract editor (Slice 2 AI round-trip)
60639
+ // handle a tweak-contract request from the Steel Model contract editor (Slice 2 AI round-trip)
60638
60640
  "floless-app-ui",
60639
60641
  // compose Custom Panels (~/.floless/ui/extensions.json) for the Dashboard
60640
- "floless-app-workflows"
60642
+ "floless-app-workflows",
60641
60643
  // author/run .flo workflows
60644
+ "reading-structural-drawings"
60645
+ // the drawing-set reading discipline (non-namespace) the steel guide + reader lean on; shipped so users get it too
60642
60646
  ];
60643
60647
  function selectShippedSkillNames(names) {
60644
60648
  const present = new Set(names);
@@ -40,7 +40,7 @@ documented in `floless-app-bridge`; the five types map to:
40
40
  |---|---|---|
41
41
  | `tweak` | "Tweak node **`<nodeId>`** in **`<appId>`** — *<instruction>*" | `floless-app-workflows` |
42
42
  | `use-template` | "Add template **<template.name>** to **`<appId>`**" | `floless-app-workflows` |
43
- | `tweak-contract` | "Edit the steel-takeoff contract for **`<appId>`** — *<instruction>* (+N screenshot(s))" | `floless-app-tweak-contract` |
43
+ | `tweak-contract` | "Edit the Steel Model contract for **`<appId>`** — *<instruction>* (+N screenshot(s))" | `floless-app-tweak-contract` |
44
44
  | `ui-customize` | "Customize the Dashboard (optionally `panel <panelId>`) — *<instruction>*" | `floless-app-ui` |
45
45
  | `rebake` | "Re-read the **<inputName>** drawing (<sourceName>) in **`<appId>`** — *<instruction>*" | `floless-app-rebake` |
46
46
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: floless-app-report-issue
3
- description: File a diagnosed bug / idea / question from floless.app into the PRIVATE product log via the floless.io relay. Use when the user invokes /floless-app-report-issue, clicks "Report an issue" in the floless.app UI (a queued report or a copied prompt), or says "report this", "file a bug", "something broke in floless", "send feedback / a feature idea". It READS the live run evidence first (latest run trace, failing node + error, the .flo, exec code), offers a workaround when one exists, then composes a maintainer-ready report and sends it — always showing the exact text and confirming first. Read-only: it never re-runs a workflow node.
3
+ description: File a diagnosed bug / idea / question from floless.app into the PRIVATE product log via the floless.io relay. Use when the user invokes /floless-app-report-issue, clicks "Report an issue" in the floless.app UI (a queued report or a copied prompt), or says "report this", "file a bug", "something broke in floless", "send feedback / a feature idea". It READS the live run evidence first (latest run trace, failing node + error, the .flo, exec code), offers a workaround when one exists, then composes a maintainer-ready report and sends it — always showing the exact text and confirming first. Read-only it never re-runs a workflow node.
4
4
  metadata:
5
5
  version: 0.1.0
6
6
  ---
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: floless-app-steel-model
3
+ description: The front-door guide for turning a structural steel drawing SET into an editable model in floless.app — the "Steel Model" flow. This skill orchestrates the whole pipeline — set up a project folder, learn the set into plain-English knowledge files, provision the right AWARE agents (region-specific steel detailer plus any bake targets), confirm which sheets are plans / elevations / details, then hand off to the Steel Takeoff reader to read each plan into a steel.takeoff/v1 contract — with explicit confirm gates between stages. Use it when a user wants to model steel from a drawing SET or asks things like "model this steel job from the drawings", "take off this whole set", "start a steel takeoff project", "turn these structural drawings into a model", "I have a PDF set of framing plans", or "/floless-app-steel-model". It is re-runnable — resume at any stage. For a single already-isolated framing plan the Steel Takeoff reader (floless-app-steel-takeoff) can be used directly; this guide is for driving a real job end to end.
4
+ metadata:
5
+ version: 0.1.0
6
+ ---
7
+
8
+ # Steel Model — guide a steel drawing set into an editable model
9
+
10
+ ## What this is
11
+
12
+ The **front door** to floless.app's steel pipeline. A real steel job arrives as a *set* of PDFs
13
+ (framing plans, elevations, sections, details, schedules) plus firm conventions — not a single
14
+ clean plan. This guide drives that whole job: project setup → learn the set → provision agents →
15
+ classify the sheets → read each framing plan into an editable **steel.takeoff/v1 contract**, then
16
+ point the user at the on-canvas tools (filter, 3D, IFC/Tekla export, BOM, the connection library,
17
+ clickable callouts).
18
+
19
+ It is the **orchestration layer ABOVE** the readers and the editor. The actual drawing reading is
20
+ done by **`floless-app-steel-takeoff`** (the Steel Takeoff reader) — this guide gets the project to
21
+ the point where that read is reliable, and hands off. The host AI is the brain (the FloLess thin-UI
22
+ contract): reading happens at COMPOSE time with the terminal AI's own vision; there is no model in
23
+ the run path and no API key.
24
+
25
+ **Re-runnable + interactive.** Each stage ends with an explicit **confirm gate** — show the user
26
+ what was found and get an OK before spending effort on the next stage. Resume at any stage on
27
+ re-invoke ("we already set up the folder, provision the agents").
28
+
29
+ > Companion skills (both ship with floless.app — invoke them, don't duplicate them):
30
+ > - **`reading-structural-drawings`** — the reading *discipline* (massing + coordinate frame FIRST,
31
+ > members LAST, cross-validate every view). Follow it whenever skimming or classifying the set
32
+ > (stages 2 and 5) — it stops the classic failures (two buildings read as one, a sloped roof read
33
+ > as flat, grids conflated across sheets).
34
+ > - **`floless-app-steel-takeoff`** — reads one framing plan into the contract (the heavy vision
35
+ > pipeline, the filter pre-stage, the AISC/EN/BS lookup, the contract write + editor hand-off).
36
+
37
+ ---
38
+
39
+ ## The flow
40
+
41
+ Work the stages in order. Announce the stage, do the work, then **stop at the confirm gate** and
42
+ wait for the user's OK before the next stage.
43
+
44
+ ### 1. Project folder
45
+
46
+ A steel job has many files and derived artifacts — keep them together. Ask the user to pick or
47
+ create a **dedicated project folder** (e.g. `~/projects/<job-name>/`). Everything lives there: the
48
+ drawing PDF(s), the knowledge files (stage 2), and any exported contracts / IFC / BOM. If they
49
+ already have one, use it. Record the absolute path for the rest of the run.
50
+
51
+ **Gate:** confirm the folder path and that the drawing set (PDF) is in it (or get its path).
52
+
53
+ ### 2. Learn the set → plain-English knowledge files
54
+
55
+ Before reading geometry, skim the set and capture what matters into a few short Markdown files in
56
+ the project folder (a few files, **not** a framework):
57
+
58
+ - **`set-index.md`** — one line per sheet: number, title, and what it is (framing plan / elevation /
59
+ section / detail / schedule). This is the map the later stages classify against.
60
+ - **`general-notes.md`** — the General Notes that bind the whole job: design spec, default
61
+ connection type, bolt/weld standard, material grades, anything that overrides a single sheet.
62
+ - **`company-rules.md`** *(ask first)* — **ask whether the firm has company-specific standards**
63
+ (e.g. "moment → detail 50S504 → Tekla component 146"). If yes, capture them here. This file feeds
64
+ the connection-library pre-fill in stage 6 (the editor's Connections panel reads these as
65
+ `source:"company-rules"`). If the firm has none, skip the file — don't invent rules.
66
+
67
+ Read the set with the terminal AI's own vision, following the **`reading-structural-drawings`**
68
+ discipline while skimming (massing + coordinate frame first — it's what makes the sheet
69
+ classification reliable).
70
+
71
+ **Gate:** show `set-index.md` (the sheet map) and confirm the classification looks right — the user
72
+ knows their set better than any read.
73
+
74
+ ### 3. Provision the AWARE agents
75
+
76
+ The reader leans on a **region-specific steel detailer** agent (AISC vs EN vs BS section tables) and,
77
+ if the user will bake later, the host bridges.
78
+
79
+ 1. **Check what's installed:** `aware agent list --json`.
80
+ 2. **Steel detailer — ask the region**, then install the match: `steel-detailer-us` (AISC /
81
+ imperial), `steel-detailer-eu` (EN), or `steel-detailer-uk` (BS). Install with
82
+ `aware agent install <id>`. **Verify it's live** with a known-section lookup before relying on it
83
+ (a section that should resolve — e.g. a W-shape for US — returns a weight).
84
+ 3. **Bake targets (optional, only if they'll export later):** offer `tekla`, `rhino`, `revit`,
85
+ `sketchup` — install the ones they want. (3D and IFC export need no host; Tekla bake needs Tekla
86
+ open with a model.)
87
+ 4. **Discover more:** `aware agent catalog` / `aware agent search <capability>` lists agents that
88
+ are *available but not installed*. Scan it and suggest any genuinely useful one for steel work;
89
+ don't install without asking.
90
+
91
+ If `aware agent catalog` is unsupported (older AWARE), say so and offer to update AWARE (the footer
92
+ ↑ Upgrade pill / `floless-app-onboarding` covers this); fall back to `aware agent list`.
93
+
94
+ **Gate:** confirm the detailer (right region, verified live) and any bake agents are installed.
95
+
96
+ ### 4. Read method — PyMuPDF + hide the title block
97
+
98
+ The read method is settled: a deterministic **PyMuPDF** pass enumerates the drawing elements (no
99
+ LLM, no API key) and the framing area is rastered for the vision read. The **title block is
100
+ excluded** from what's read and rastered (it carries client/project/firm identity — see
101
+ Confidentiality). This is handled inside the Steel Takeoff reader and the filter pre-stage; surface
102
+ it to the user as "your title block stays out of the read," and confirm the crop excludes it on the
103
+ first sheet.
104
+
105
+ **Gate:** on the first framing plan, confirm the framing area is captured and the title block is
106
+ out of frame.
107
+
108
+ ### 5. Classify the sheets + confirm, view by view
109
+
110
+ The set has many sheets; only the **framing plans** become takeoff contracts. Walk the user through,
111
+ with an explicit OK at each kind (this is the interactive heart — never one-shot a whole set):
112
+
113
+ - **Framing plans** — the sheets that get read into members. Confirm the list before reading.
114
+ - **Elevations / sections** — used for member heights (TOS/BOS), moment-frame schedules, and as
115
+ jump targets for clickable callouts (stage 6). Confirm which sheets these are.
116
+ - **Details** — the connection details the callouts point to. Confirm the detail sheets.
117
+ - **A sample line + profile** — on the first plan, read ONE member (its segment + profile label)
118
+ and show it back; get an OK that the geometry + size mapping is right before reading the rest.
119
+
120
+ **Gate:** explicit OK on the framing-plan list and the sample read before the full read.
121
+
122
+ ### 6. Hand off to the reader + the on-canvas tools
123
+
124
+ With the project, knowledge, agents, and classification confirmed, drive the actual reads and point
125
+ the user at the editor:
126
+
127
+ - **Read each framing plan** via **`floless-app-steel-takeoff`** — it runs the filter pre-stage
128
+ (isolate the steel linework by layer/thickness/colour), the vision read, the AISC/EN/BS lookup
129
+ via the detailer, honors `target_confidence`, writes the `steel.takeoff/v1` contract, and opens
130
+ the overlay editor. One contract per `steel-model` app; multi-sheet sets ride the filter's
131
+ `sheets[]` + the editor's plan switcher.
132
+ - **Pre-fill the connection library** from `company-rules.md` (stage 2): emit the firm's rows into
133
+ the contract's `connections[]` with `source:"company-rules"`; the user reviews/assigns them per
134
+ member end in the editor's **Connections** panel (the per-end picker + confidence card).
135
+ - **Point at the rest of the canvas:** the **filter** view (refine the kept linework), **Approve**
136
+ (bake the lock — the determinism gate), **3D** model, **IFC** / **Tekla** export, the **BOM**, the
137
+ **confidence report**, and the **callout bubbles** (click a section/elevation/detail mark on a
138
+ plan to jump to the referenced sheet).
139
+
140
+ **Done** when each framing plan has an approved, editor-reviewed contract and the user knows which
141
+ on-canvas tool does what. The exports (3D/IFC/Tekla/BOM) are on-demand from the editor.
142
+
143
+ ---
144
+
145
+ ## Guardrails
146
+
147
+ - **The host AI is the brain; the run is deterministic.** Reading is a compose-time act; never put
148
+ an LLM or heavy compute in the run path or the server.
149
+ - **Confidentiality (hard rule).** Never commit or echo `raster_b64` / `bg_b64` page rasters or any
150
+ client / project / firm names. The title block is excluded from the read for this reason. Keep job
151
+ files in the user's project folder, not the repo.
152
+ - **Confirm gates are not optional.** A steel set is easy to misread (two buildings on one sheet, a
153
+ sloped roof, grids that differ across sheets). Show findings and get an OK at each stage — the
154
+ user catches what a read misses.
155
+ - **Don't duplicate the companions.** Hand the actual drawing read to `floless-app-steel-takeoff`;
156
+ follow `reading-structural-drawings` for the reading discipline. This guide owns the orchestration
157
+ and the gates, not the pixel-level read.
158
+ - **Tekla (or any platform) component INSERTION at bake is deferred** — the connection library +
159
+ per-end references + scoring are editor-verifiable today; native component placement is a later,
160
+ Tekla-gated step. Don't promise it.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: floless-app-steel-takeoff
3
- description: Read a structural steel drawing into an editable steel.takeoff/v1 contract in floless.app — the "Steel Takeoff" reader. Triggers on a pending floless `rebake` request for the `steel-takeoff` app (queued from its "Re-read & re-bake ▸" button), or asks like "read this framing plan into a takeoff", "turn this structural drawing into a takeoff", "bake my drawing into steel-takeoff", "extract members from this PDF". Teaches the host AI to READ a steel drawing (PDF/image) with its own vision at COMPOSE time, build a steel.takeoff/v1 contract (members + profiles + elevations + weights from AISC lookup), write it to the contract store, and hand control to the editor — no model in the run path, no API key.
3
+ description: Read a structural steel drawing into an editable steel.takeoff/v1 contract in floless.app — the "Steel Takeoff" reader. Triggers on a pending floless `rebake` request for the `steel-model` app (queued from its "Re-read & re-bake ▸" button), or asks like "read this framing plan into a takeoff", "turn this structural drawing into a takeoff", "bake my drawing into steel-model", "extract members from this PDF". Teaches the host AI to READ a steel drawing (PDF/image) with its own vision at COMPOSE time, build a steel.takeoff/v1 contract (members + profiles + elevations + weights from AISC lookup), write it to the contract store, and hand control to the editor — no model in the run path, no API key.
4
4
  metadata:
5
5
  version: 0.1.0
6
6
  ---
@@ -9,7 +9,7 @@ metadata:
9
9
 
10
10
  ## What this is
11
11
 
12
- `steel-takeoff` is a FloLess app that turns a structural steel drawing into an editable
12
+ `steel-model` is a FloLess app that turns a structural steel drawing into an editable
13
13
  **takeoff contract** — members, profiles, AISC weights, T.O. elevations, connection detail refs
14
14
  — rendered in the overlay editor, then baked at Approve into the app's `read` node.
15
15
 
@@ -34,7 +34,7 @@ but do not attempt them here.
34
34
  ### 1. Find the drawing
35
35
 
36
36
  From a `rebake` request: `GET http://localhost:<port>/api/requests` → the entry with
37
- `type:"rebake"` and `appId:"steel-takeoff"` carries `snapshots: ["<abs path>"]` (the drawing
37
+ `type:"rebake"` and `appId:"steel-model"` carries `snapshots: ["<abs path>"]` (the drawing
38
38
  file) and optionally `sourceName` (the original filename — use it for the `source.name`
39
39
  provenance field). If the user just attaches or points at a drawing in prose, skip the lookup
40
40
  and proceed from that path.
@@ -72,7 +72,7 @@ native/display coords):
72
72
  `*BEAM*STEL*`, `*COL*`, `*BRACE*`, `*JOIST*`) → default **on**; others off. Mark
73
73
  `drawable: false` on pure text/dimension/title-block layers.
74
74
  5. Set `filter.mode: "layer"`, `filter.active: 0`. **PUT** the contract
75
- (`PUT /api/contract/steel-takeoff`). On a re-read, preserve any existing per-facet `on` flags.
75
+ (`PUT /api/contract/steel-model`). On a re-read, preserve any existing per-facet `on` flags.
76
76
 
77
77
  Then tell the user to open the **Filter** node, flip through the sheets, narrow to the steel, and
78
78
  **Save**. The saved `on` flags + `mode` are what step 2 reads — **per sheet** (each sheet's elements
@@ -180,7 +180,7 @@ excluded from the average and counted separately as the headline drag).
180
180
  **The score endpoint is your gauge — call it, don't guess:**
181
181
 
182
182
  ```
183
- POST http://localhost:<port>/api/contract/steel-takeoff/score
183
+ POST http://localhost:<port>/api/contract/steel-model/score
184
184
  Content-Type: application/json
185
185
  { "contract": <your draft contract>, "target": <target_confidence, e.g. 70> }
186
186
  ```
@@ -309,7 +309,7 @@ Key field rules:
309
309
  ### 5. Write to the contract store
310
310
 
311
311
  ```
312
- PUT http://localhost:<port>/api/contract/steel-takeoff
312
+ PUT http://localhost:<port>/api/contract/steel-model
313
313
  Content-Type: application/json
314
314
 
315
315
  <contract JSON body>
@@ -317,7 +317,7 @@ Content-Type: application/json
317
317
 
318
318
  The server schema-validates the body. If it responds with `400`, read the error, fix the
319
319
  offending fields, and re-PUT. You can read back the current contract with
320
- `GET /api/contract/steel-takeoff`.
320
+ `GET /api/contract/steel-model`.
321
321
 
322
322
  ### 6. Hand off to the user
323
323
 
@@ -347,7 +347,7 @@ DELETE http://localhost:<port>/api/requests/<id>
347
347
 
348
348
  Never write client, firm, or project identifiers into files, commits, or responses. The
349
349
  contract carries the source path in `source.path` and an embedded raster in `raster_b64` — both
350
- are machine-local (stored under `~/.floless/contracts/steel-takeoff.json` by the server and
350
+ are machine-local (stored under `~/.floless/contracts/steel-model.json` by the server and
351
351
  never committed). Clip title blocks from any embedded preview.
352
352
 
353
353
  ---
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: floless-app-tweak-contract
3
- description: This skill should be used when there is a pending floless `tweak-contract` request — the user typed an instruction in the steel-takeoff contract editor and clicked Send (Ask AI). Also triggers on asks like "edit the steel takeoff contract via AI", "adjust the steel takeoff in the contract editor", "the user asked me to change the steel contract", "pick up my tweak-contract request", "update the member profile in the contract". It teaches the host AI to read the request, fetch the current steel.takeoff/v1 contract, apply the instruction (and any pasted screenshots), PUT the updated contract back, and resolve the request.
3
+ description: This skill should be used when there is a pending floless `tweak-contract` request — the user typed an instruction in the Steel Model contract editor and clicked Send (Ask AI). Also triggers on asks like "edit the steel takeoff contract via AI", "adjust the steel takeoff in the contract editor", "the user asked me to change the steel contract", "pick up my tweak-contract request", "update the member profile in the contract". It teaches the host AI to read the request, fetch the current steel.takeoff/v1 contract, apply the instruction (and any pasted screenshots), PUT the updated contract back, and resolve the request.
4
4
  metadata:
5
5
  version: 0.1.0
6
6
  ---
@@ -9,7 +9,7 @@ metadata:
9
9
 
10
10
  ## What this is
11
11
 
12
- The floless.app steel-takeoff contract editor surfaces an **Ask AI** panel: the user types
12
+ The floless.app Steel Model contract editor surfaces an **Ask AI** panel: the user types
13
13
  an instruction ("change all W12X26 to W14X30", "add a new beam on sheet S-202", "mark this
14
14
  member as moment-frame") and optionally pastes screenshots, then clicks **Send**. That records
15
15
  a `tweak-contract` request in the reverse channel. You pick it up here, edit the contract
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: reading-structural-drawings
3
+ description: This skill should be used BEFORE modelling anything from a structural/architectural drawing SET (PDF). Use it whenever turning drawings into a 3D frame, takeoff, IFC, or Tekla model — it is the prerequisite reading discipline for the `floless-app-steel-takeoff` reader (and the `floless-app-steel-model` guide that orchestrates the full flow). Triggers on "read this drawing set", "model this structure from the PDF", "take off this steel", "build a model from these drawings", or any pure-PDF → structure task. It encodes the method that stops the classic failures (missing that a set is TWO buildings, missing a curved/sloped roof, conflating grids across sheets, tracing dimension lines as members) — establish MASSING + COORDINATE FRAME first (from the index + elevations + sections), members LAST; deterministic geometry feeds the reasoning; cross-validate every view; verify before presenting.
4
+ metadata:
5
+ version: 0.1.2
6
+ ---
7
+
8
+ # Reading a structural drawing set — the discipline (do this BEFORE you model anything)
9
+
10
+ ## Why this exists (the lesson, in one line)
11
+
12
+ A frontier vision model is **document-literate, not drawing-literate** — free-reading a multi-sheet
13
+ set and counting members "by eye" fails *by default* (symbol-grounded geometry ≈ 0.4–0.55 accuracy,
14
+ AECV-Bench 2026). Getting a building wrong (two buildings read as one, a curved roof read as flat,
15
+ a skewed grid read straight) is **not an OCR problem — it is a topology / cross-sheet-fusion
16
+ problem.** The fix is order and validation, not "look harder". This skill is that order.
17
+
18
+ > **Hard rule:** establish the **massing** (how many buildings, roof shape) and the **coordinate
19
+ > frame** (grids + levels) FIRST. Members come LAST. If you are reading member sizes before you can
20
+ > state the building count and roof geometry, STOP — you are about to be confidently wrong.
21
+
22
+ ## The one mistake to never repeat
23
+
24
+ Plans cannot show the third dimension. **Building count, roof shape, and storey heights live in the
25
+ ELEVATIONS and SECTIONS — read those before the framing plans.** (A real failure this skill came
26
+ from: a set was modelled as one straight box from the plans; it was actually two separate buildings,
27
+ one with a curved roof — both obvious in the elevations, invisible in the plan.)
28
+
29
+ ## Tools — use the deterministic layer; the AI interprets, never measures
30
+
31
+ - **Render/extract with PyMuPDF (`fitz`)** — prefer it over `pdftoppm` (which may not be installed).
32
+ `page.get_text("words")` gives positioned text (grid bubbles, sizes) **losslessly** on vector PDFs;
33
+ `page.get_drawings()` gives every line with real coordinates. Read vectors before you OCR pixels.
34
+ - **AWARE `vision` agent** (`aware agent describe vision`) — image/PDF → **fixed-schema** structured
35
+ JSON via a model. Use it for the structured extraction passes below; the FIXED schema is the point
36
+ (it constrains hallucination). The terminal AI / `vision` *interprets and assembles*; AWARE's
37
+ deterministic nodes own measurement and the `.lock` (the floless contract).
38
+ - **Ask for DXF/DWG first.** If the source CAD exists, `ezdxf` (layers → grids/members/dims directly,
39
+ ARCs → curved roof for free) collapses ~80% of this. AWARE also ships CAD agents
40
+ (`autocad-2025/26`, `tekla`, `tsd-25/26`, `allplan`, `archicad`) if a real model file is available —
41
+ reading the model beats reverse-engineering the drawing.
42
+
43
+ ## The method — ordered passes (do not start a pass until the prior one is done)
44
+
45
+ ### Pass 0 — Inventory & sheet classification
46
+ Read the **cover / drawing index** and **general notes** first. Build a sheet list classified by
47
+ type (index, notes, foundation plan, framing plans per level, frame elevations, sections, details,
48
+ **schedules**). Confirm the set is complete + current revision. Grab the legend, datum, material
49
+ defaults, and the **abbreviations** (FC/MF/BF/(E)/(N)/matchline symbols). Trust PyMuPDF page_count over
50
+ any external count.
51
+
52
+ ### Pass 1 — MASSING (how many buildings, what shape) — from elevations/sections, not plans
53
+ - **Count the buildings.** Look for separate grid-label namespaces, **expansion/seismic joints**
54
+ (a double grid line / gap = two *structurally independent* buildings — members never frame across),
55
+ matchlines, building-name labels, and **disjoint grid clusters** (cluster the long grid lines from
56
+ `get_drawings()` — separate clusters = separate buildings).
57
+ - **Roof + heights** from the **frame elevations and sections**: flat / sloped / hipped / **curved**;
58
+ ridge/eave elevations; storey heights; mezzanines. State each building's roof type explicitly.
59
+ - Output a massing statement BEFORE going further, e.g. *"2 buildings: West (grids F–K.1 × 0.5–5.2),
60
+ 2-storey, curved roof; East (grids A–F × 0.5–6), 2-storey, ~flat roof; separated by a seismic joint."*
61
+
62
+ ### Pass 2 — COORDINATE FRAME (grid + levels) per building
63
+ - **Grid:** grid-bubble label positions are usually real text (`get_text("words")`). Per building,
64
+ per axis, build `(label, position, real_offset)`. **Calibrate scale from a real dimension string**
65
+ (e.g. a "16'-7¾"" between two bubbles) — NOT the title-block "1:100" (PDFs get re-scaled on plot).
66
+ A 2-point fit gives `real = A·pixel + b`. Check the grid is orthogonal / skewed / radial — don't
67
+ assume 90°. **Each sheet may have its own origin/orientation — re-anchor per sheet; never carry one
68
+ sheet's grid onto another** (this conflation is a top failure).
69
+ - **Levels:** OCR the level/T.O.STEEL tags from an elevation/section into a datum table
70
+ (L1 +0'-0", L2 +16'-6", Roof …). Members snap to these.
71
+
72
+ ### Pass 3 — MEMBERS (now, and only now), per building, per level
73
+ - Tile big sheets: **always include a low-DPI full-sheet overview alongside overlapping high-DPI
74
+ tiles** (≥200 DPI; overlap ≥ the largest label). A 3×3 of tiles with **no** overview destroys
75
+ coherence — that is the "wrong shape" failure. Tile only as fine as needed to make the smallest
76
+ label ~20 px.
77
+ - Place each member by the **grid lines it spans** + its level. Read its size label; **confirm size
78
+ against the schedule** (column schedule = authoritative per tier/splice; beam schedule maps marks).
79
+ Map W18×35 = wide-flange, 18" nominal depth, 35 lb/ft, etc.
80
+ - **Use a structured schema that enforces the order** (vision agent or your own): fill
81
+ `coordinate_system → buildings(+roof) → grids_per_building → members`, every value carrying
82
+ `source_view`, `evidence_bbox`, `confidence`, plus mandatory `unreadable[]` and `contradictions[]`.
83
+ A nullable/`unreadable` escape on every field is required — forcing a value the sheet doesn't show
84
+ *causes* fabrication.
85
+
86
+ ### Pass 4 — CROSS-VALIDATE (no single view is trusted)
87
+ Plan ↔ elevation ↔ section ↔ schedule must agree. Confirm every member in ≥2 views; confirm
88
+ sloped/spliced members in section/elevation. Disagreement → record in `contradictions[]` as an RFI
89
+ candidate; **do not silently pick one.**
90
+
91
+ ### Pass 5 — VERIFY before presenting (definition of done)
92
+ Before building/baking ANY model, self-check against the elevations/sections/3D:
93
+ - building count, roof shape, storey heights, footprint — do they match what the elevations show?
94
+ - did any member cross a seismic joint or matchline? (bug)
95
+ - is the grid the right one for *this* building (not another sheet's)?
96
+ Only then build the scene / overlay / IFC. If unsure, present the **massing + grid** for confirmation
97
+ *before* spending effort on members.
98
+
99
+ ## Pitfalls checklist (the traps that cause wrong models)
100
+ - [ ] Multiple independent buildings on one set (count first).
101
+ - [ ] Seismic / expansion joint read as one structure.
102
+ - [ ] Skewed / rotated / radial grid assumed orthogonal.
103
+ - [ ] Curved / sloped roof read as flat (read the elevation!).
104
+ - [ ] Grid from sheet A used on sheet B (per-sheet origins).
105
+ - [ ] Dimension lines / grid lines / leaders traced as members (auto-extraction noise).
106
+ - [ ] `(E)` existing vs `(N)` new vs demo merged (read the legend / line-weight / colour).
107
+ - [ ] Member crossing a matchline read as terminating or double-counted.
108
+ - [ ] Mezzanine / intermediate level missed (only sections show it).
109
+ - [ ] Sizes scaled off the PDF instead of read from dimensions/schedule.
110
+
111
+ ## Companion skills
112
+ - After this reading produces a verified structure, hand to the **`floless-app-steel-takeoff`** reader
113
+ to produce the editable `steel.takeoff/v1` contract (which then exports 3D + IFC + Tekla + BOM). This
114
+ skill is the *reading discipline*; that one is the *reader*. The **`floless-app-steel-model`** guide
115
+ (the front-door orchestrator) wraps the whole flow and references this discipline at the
116
+ classify-and-verify gates rather than re-deriving it.
117
+ - There is no off-the-shelf OSS tool that does the whole drawing→model job — floorplan vectorisers
118
+ (e.g. CubiCasa5k) are residential-trained and won't read steel framing — which is why the order +
119
+ validation discipline above, not a single tool, is the method.
120
+
121
+ ## References (researched 2026-06-16)
122
+ - AECV-Bench — VLMs are document- not drawing-literate; human-in-the-loop for geometry. arXiv 2601.04819.
123
+ - Multi-stage hybrid VLM for multi-view drawings (arXiv 2510.21862); CAD2Program 2D→3D (arXiv 2412.11892).
124
+ - "From Drawings to Decisions" detect-then-read (YOLO-OBB + small VLM), arXiv 2506.17374.
125
+ - Image-tiling needs a global overview (arXiv 2512.11167); Claude vision limits (≤1568 px, images-before-text).
126
+ - AISC 303 Code of Standard Practice (drawings show size/grade/location + work points); steel-detailing read-order guides.
127
+ - Tooling: PyMuPDF, PaddleOCR/Surya, OpenCV/ELSED, ezdxf, IfcOpenShell.
@@ -1,6 +1,6 @@
1
- app: steel-takeoff
1
+ app: steel-model
2
2
  version: 0.2.0
3
- display-name: Steel Takeoff
3
+ display-name: Steel Model
4
4
  publisher: floless
5
5
  module: steel-detailer
6
6
  description: |
package/dist/web/aware.js CHANGED
@@ -2880,7 +2880,7 @@
2880
2880
  }
2881
2881
 
2882
2882
  // ── Workflow update (module-shaped) ─────────────────────────────────────────────
2883
- // A FloLess-published workflow (e.g. steel-takeoff) has a newer bundled template. Poll GET
2883
+ // A FloLess-published workflow (e.g. steel-model) has a newer bundled template. Poll GET
2884
2884
  // /api/workflows/updates; when the OPEN app has one, show a pill → modal with the changelog →
2885
2885
  // "Back up & update" POSTs /api/workflows/:id/update (backup → swap structure → re-bake the user's
2886
2886
  // data from the contract store → recompile) → reload the app. No auto-update. `_wfUpdates` + the
@@ -1,5 +1,5 @@
1
1
  /*
2
- * steel-3d-view.js — the 3D render/interaction layer for the steel-takeoff editor's 3D mode.
2
+ * steel-3d-view.js — the 3D render/interaction layer for the steel-model editor's 3D mode.
3
3
  *
4
4
  * Three.js lives ONLY here (the rest of the editor is import-free). It renders the SAME scene the
5
5
  * IFC/Tekla bake uses (fetched from /api/contract/:id/scene → contractToScene), so the editable 3D
@@ -1,5 +1,5 @@
1
1
  <!doctype html><html><head><meta charset=utf-8>
2
- <title>Steel takeoff — editor</title>
2
+ <title>Steel Model — editor</title>
3
3
  <style>
4
4
  :root{--bg:#0f172a;--panel:#1e293b;--line:#334155;--text:#e2e8f0;--mut:#94a3b8;--brand:#3b82f6}
5
5
  /* Theme EVERY scrollbar — no native white default may leak (applies to the canvas, panels, and every modal list). */
@@ -204,7 +204,7 @@
204
204
  <script type="module" src="./steel-3d-view.js"></script>
205
205
  </head><body>
206
206
  <header>
207
- <b>Steel takeoff</b>
207
+ <b>Steel Model</b>
208
208
  <div id=viewToggle role=group aria-label="Canvas view"><button id=vt2d class="seg on" aria-pressed=true title="Plan view (2D overlay)">2D</button><button id=vt3d class=seg aria-pressed=false title="3D model view">3D</button></div>
209
209
  <select id=planSel title="Switch plan view"></select>
210
210
  <span class=stat>Members <b id=mc>0</b></span><span class=stat>Weight <b id=wt>0</b> tons · <b id=wtlb>0</b> lb</span>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floless/app",
3
- "version": "0.51.0",
3
+ "version": "0.53.0",
4
4
  "type": "module",
5
5
  "description": "Thin localhost host for floless.app — serves web/ and shells the aware CLI. No engine, no LLM.",
6
6
  "bin": {