simcon-toolkit 0.1.0__py3-none-any.whl

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 (97) hide show
  1. simcon_toolkit/__init__.py +40 -0
  2. simcon_toolkit/__main__.py +7 -0
  3. simcon_toolkit/_kit/LICENSE +202 -0
  4. simcon_toolkit/_kit/NOTICE +37 -0
  5. simcon_toolkit/_kit/assets/parts/clip_frame.stl +0 -0
  6. simcon_toolkit/_kit/assets/parts/simple_plate.stl +0 -0
  7. simcon_toolkit/_kit/packages/.ruff.toml +10 -0
  8. simcon_toolkit/_kit/packages/cadmould_cloud/__init__.py +8 -0
  9. simcon_toolkit/_kit/packages/cadmould_cloud/auth.py +681 -0
  10. simcon_toolkit/_kit/packages/cadmould_cloud/client.py +235 -0
  11. simcon_toolkit/_kit/packages/cadmould_geometry/__init__.py +5 -0
  12. simcon_toolkit/_kit/packages/cadmould_geometry/mesh.py +210 -0
  13. simcon_toolkit/_kit/packages/cadmould_geometry/stl.py +168 -0
  14. simcon_toolkit/_kit/packages/cadmould_results/__init__.py +30 -0
  15. simcon_toolkit/_kit/packages/cadmould_results/loader.py +288 -0
  16. simcon_toolkit/_kit/packages/cadmould_scoring/__init__.py +7 -0
  17. simcon_toolkit/_kit/packages/cadmould_scoring/metrics.py +519 -0
  18. simcon_toolkit/_kit/pyproject.toml +232 -0
  19. simcon_toolkit/_kit/templates/_shared/AGENTS.base.md +101 -0
  20. simcon_toolkit/_kit/templates/gate-study/.gitignore +18 -0
  21. simcon_toolkit/_kit/templates/gate-study/AGENTS.md +46 -0
  22. simcon_toolkit/_kit/templates/gate-study/GATING_STUDY_PLAYBOOK.md +219 -0
  23. simcon_toolkit/_kit/templates/gate-study/INITIAL_PROMPT.md +26 -0
  24. simcon_toolkit/_kit/templates/gate-study/README.md +137 -0
  25. simcon_toolkit/_kit/templates/gate-study/main.py +344 -0
  26. simcon_toolkit/_kit/templates/gate-study/pipeline.py +281 -0
  27. simcon_toolkit/_kit/templates/process-window/.gitignore +20 -0
  28. simcon_toolkit/_kit/templates/process-window/AGENTS.md +49 -0
  29. simcon_toolkit/_kit/templates/process-window/METHOD.md +155 -0
  30. simcon_toolkit/_kit/templates/process-window/README.md +176 -0
  31. simcon_toolkit/_kit/templates/process-window/configs/simple-plate.yaml +116 -0
  32. simcon_toolkit/_kit/templates/process-window/doe_spec.schema.md +249 -0
  33. simcon_toolkit/_kit/templates/process-window/main.py +82 -0
  34. simcon_toolkit/_kit/templates/process-window/process_window/__init__.py +5 -0
  35. simcon_toolkit/_kit/templates/process-window/process_window/centre.py +298 -0
  36. simcon_toolkit/_kit/templates/process-window/process_window/design.py +144 -0
  37. simcon_toolkit/_kit/templates/process-window/process_window/economics.py +367 -0
  38. simcon_toolkit/_kit/templates/process-window/process_window/emit.py +591 -0
  39. simcon_toolkit/_kit/templates/process-window/process_window/guardrails.py +153 -0
  40. simcon_toolkit/_kit/templates/process-window/process_window/harness.py +360 -0
  41. simcon_toolkit/_kit/templates/process-window/process_window/identity.py +92 -0
  42. simcon_toolkit/_kit/templates/process-window/process_window/inspect_part.py +184 -0
  43. simcon_toolkit/_kit/templates/process-window/process_window/kpis.py +355 -0
  44. simcon_toolkit/_kit/templates/process-window/process_window/material_card.py +163 -0
  45. simcon_toolkit/_kit/templates/process-window/process_window/probe_proxy.py +169 -0
  46. simcon_toolkit/_kit/templates/process-window/process_window/run_confirm.py +403 -0
  47. simcon_toolkit/_kit/templates/process-window/process_window/run_epsilon_floor.py +198 -0
  48. simcon_toolkit/_kit/templates/process-window/process_window/run_feedback.py +322 -0
  49. simcon_toolkit/_kit/templates/process-window/process_window/run_refine.py +279 -0
  50. simcon_toolkit/_kit/templates/process-window/process_window/run_screening.py +370 -0
  51. simcon_toolkit/_kit/templates/process-window/process_window/run_sweep.py +166 -0
  52. simcon_toolkit/_kit/templates/process-window/process_window/setup_campaign.py +312 -0
  53. simcon_toolkit/_kit/templates/process-window/process_window/surrogate.py +201 -0
  54. simcon_toolkit/_kit/templates/process-window/process_window/test_centre.py +169 -0
  55. simcon_toolkit/_kit/templates/process-window/process_window/test_design.py +113 -0
  56. simcon_toolkit/_kit/templates/process-window/process_window/test_guardrails.py +157 -0
  57. simcon_toolkit/_kit/templates/process-window/process_window/test_surrogate.py +127 -0
  58. simcon_toolkit/_kit/templates/process-window/process_window/units.py +152 -0
  59. simcon_toolkit/_kit/templates/quoting/.gitignore +24 -0
  60. simcon_toolkit/_kit/templates/quoting/AGENTS.md +58 -0
  61. simcon_toolkit/_kit/templates/quoting/INTERVIEW.md +147 -0
  62. simcon_toolkit/_kit/templates/quoting/METHOD.md +256 -0
  63. simcon_toolkit/_kit/templates/quoting/PROMPT.md +46 -0
  64. simcon_toolkit/_kit/templates/quoting/QUOTING_PLAYBOOK.md +245 -0
  65. simcon_toolkit/_kit/templates/quoting/README.md +158 -0
  66. simcon_toolkit/_kit/templates/quoting/main.py +484 -0
  67. simcon_toolkit/_kit/templates/quoting/parts/.gitkeep +0 -0
  68. simcon_toolkit/_kit/templates/quoting/quoting/__init__.py +11 -0
  69. simcon_toolkit/_kit/templates/quoting/quoting/costing.py +725 -0
  70. simcon_toolkit/_kit/templates/quoting/quoting/geometry.py +398 -0
  71. simcon_toolkit/_kit/templates/quoting/quoting/shop.py +193 -0
  72. simcon_toolkit/_kit/templates/quoting/quoting/state.py +260 -0
  73. simcon_toolkit/_kit/templates/quoting/quoting/study.py +577 -0
  74. simcon_toolkit/_kit/templates/quoting/quoting/toolkit.py +50 -0
  75. simcon_toolkit/_kit/templates/quoting/shop/README.md +43 -0
  76. simcon_toolkit/_kit/templates/quoting/shop/commercial.md +86 -0
  77. simcon_toolkit/_kit/templates/quoting/shop/lessons.md +94 -0
  78. simcon_toolkit/_kit/templates/quoting/shop/machines.md +68 -0
  79. simcon_toolkit/_kit/templates/quoting/shop/materials.md +92 -0
  80. simcon_toolkit/_kit/templates/quoting/shop/shop-profile.md +87 -0
  81. simcon_toolkit/_kit/templates/quoting/shop/tooling.md +145 -0
  82. simcon_toolkit/_kit/templates/run-one-simulation/.gitignore +16 -0
  83. simcon_toolkit/_kit/templates/run-one-simulation/AGENTS.md +41 -0
  84. simcon_toolkit/_kit/templates/run-one-simulation/README.md +133 -0
  85. simcon_toolkit/_kit/templates/run-one-simulation/main.py +216 -0
  86. simcon_toolkit/_kit/templates.toml +83 -0
  87. simcon_toolkit/choices.py +11 -0
  88. simcon_toolkit/cli.py +381 -0
  89. simcon_toolkit/generate.py +590 -0
  90. simcon_toolkit/instructions.py +152 -0
  91. simcon_toolkit/manifest.py +86 -0
  92. simcon_toolkit/project.py +356 -0
  93. simcon_toolkit/wizard.py +160 -0
  94. simcon_toolkit-0.1.0.dist-info/METADATA +48 -0
  95. simcon_toolkit-0.1.0.dist-info/RECORD +97 -0
  96. simcon_toolkit-0.1.0.dist-info/WHEEL +4 -0
  97. simcon_toolkit-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,245 @@
1
+ # Quoting playbook — the method, the cost model, and every gotcha
2
+
3
+ How this example turns a geometry and a cavity count into a defensible tool price and piece price,
4
+ what each number rests on, and what breaks. Read this before adapting it to your own shop.
5
+
6
+ > TL;DR: read the shop context → derive the cost drivers from the geometry (projected area, wall,
7
+ > undercuts) → simulate the gating options on the cloud → price each one end to end → pick on total
8
+ > cost of ownership → write the quote → take the estimator's corrections back into `shop/lessons.md`.
9
+
10
+ ---
11
+
12
+ ## 0. Why a quote needs a simulation at all
13
+
14
+ A moldmaker's quote is decided long before anyone runs a mold-flow analysis, and three of the
15
+ decisions that set the price are exactly the ones a filling simulation answers:
16
+
17
+ | Decision | What it costs | Who normally decides it | When |
18
+ |---|---|---|---|
19
+ | **Gate count** | one hot-runner nozzle **per cavity**, plus a weld line each | the mold designer | after the order |
20
+ | **Cavity pressure** | clamp force → press class → hourly rate for the tool's whole life | a rule of thumb | at quotation |
21
+ | **Fill time** | the fill share of the cycle; the shear ceiling | a guess | at quotation |
22
+
23
+ The second one is the expensive one. Press class is a decision you live with for 500k shots, and
24
+ it is normally taken from a number somebody remembered. A filling run costs about nine seconds.
25
+
26
+ The point of this example is not that the simulation is more accurate than the estimator — on
27
+ absolute pressure it demonstrably is not (§5.2). It is that the *ranking* it provides is sound, and
28
+ ranking is what a gate-count decision needs.
29
+
30
+ ---
31
+
32
+ ## 1. What the geometry alone decides (`quoting/geometry.py`)
33
+
34
+ All offline, all free, all in seconds.
35
+
36
+ | Quantity | How | Feeds |
37
+ |---|---|---|
38
+ | **Projected area** | summed \|projected\| facet area / 2 (exact for a closed surface) | clamp force |
39
+ | **Draw direction** | the axis with the largest shadow | projected area, undercuts |
40
+ | **Wall thickness** | largest sphere that fits inside the material, touching each sampled facet | cooling time, complexity |
41
+ | **Undercuts** | facets that release in neither draw direction, clustered | slides / lifters |
42
+ | **Shape factor** | part surface ÷ bounding-box surface | cavity machining complexity |
43
+ | **Volume** | closed-surface volume | shot size, material, barrel fit |
44
+
45
+ Three of those have a non-obvious implementation, each because the obvious one is wrong:
46
+
47
+ - **Sampling is area-weighted, not per-facet.** An STL's rim is meshed with many tiny triangles.
48
+ Sampling facets uniformly puts most rays on the rim, and a ray cast inward from the 1.5 mm edge
49
+ of a plate measures the plate's 150 mm *span*. Weighting by area also happens to be the quantity
50
+ you want: "how much of the surface is thin", not "how many triangles are thin".
51
+ - **Thickness is the largest inscribed sphere**, not a ray cast inward. A single inward ray
52
+ over-reads at every rim, where it measures the plate's *span* rather than its wall; the
53
+ inscribed sphere reads 1.5 mm from the face and from the rim alike. The p95 wall sets the
54
+ cooling time, so that error would go straight into the cycle and the price.
55
+
56
+ ⚠️ **This replaced a bundle of tilted rays cast through a VTK OBB tree, and the reason is
57
+ worth keeping.** That tree was rebuilt non-deterministically: the same file measured between
58
+ 1 and 461 usable samples run to run, aborting outright below 10, and it reported a 31 mm
59
+ median wall on a part 21.9 mm deep. The measurement now comes from trimesh and is identical
60
+ on every run of the same file. If anyone proposes going back to ray casting for speed, this
61
+ is what they are buying back.
62
+ - **Complexity uses the shape factor, not surface-to-volume.** Surface-to-volume looks like a
63
+ complexity measure and is mostly a thinness measure: a plain 1.5 mm plate scores 15 cm⁻¹ and
64
+ would be priced like a ribbed housing (it was, in the first run of this example — the tool came
65
+ out 28 % too expensive). Shape factor is ≈1 for a flat part and climbs with real features.
66
+
67
+ **Known limits.** Wall thickness under-reads at edges and corners, where a genuinely smaller
68
+ sphere fits — read the median as the nominal wall, not the p05. The undercut count is geometric:
69
+ it cannot know that a feature will be moulded with a hand-loaded insert instead of a slide. If
70
+ the cadmould mesher's own thickness/w2w data becomes reachable from the SDK, prefer it over this
71
+ geometric estimate. ⚠️ **The numbers have not been validated against a part of known wall
72
+ thickness** — they are physically plausible and reproducible, which is not the same as correct.
73
+
74
+ ---
75
+
76
+ ## 2. The simulations (`quoting/study.py`)
77
+
78
+ One cloud project per quote, one group per batch, a project note per decision. The part is meshed
79
+ and uploaded once.
80
+
81
+ **Batch Q1 — gate count.** One run per gate count at a fixed nominal process. This is the batch
82
+ that pays for itself.
83
+
84
+ **Batch Q2 — process window (optional).** A flow-rate sweep at the chosen gating. Worth it when
85
+ fill time is a real share of the cycle; on a thick-walled part cooling dominates and the sweep
86
+ tells you nothing you will use.
87
+
88
+ **Nominal flow rate** comes from the SDK's own `estimate_fill_time`, which accounts for wall
89
+ thickness and the material's rheology. Do not derive it from a guessed fill time — a hand-picked
90
+ "fill it in 1 s" has been measured 3.5× wrong on a thin part, which moves the entire process
91
+ window and everything downstream of it.
92
+
93
+ **The material lookup is worth more than it looks.** `GET /material-versions/{id}` carries not just
94
+ the recommended melt and mould temperatures but the thermal data the cooling model needs —
95
+ `lambda_W_mK`, `cp_J_kgK`, `melt_density_kg_m3`, `no_flow_temperature_K`,
96
+ `ejection_temperature_K`. So the cycle-time estimate is built from *this grade's* physics rather
97
+ than a textbook constant. If the payload lacks them, `FAMILY_THERMAL` supplies family defaults and
98
+ the material is marked `family-default`.
99
+
100
+ ---
101
+
102
+ ## 3. The cost model (`quoting/costing.py`)
103
+
104
+ ### 3.1 Clamp force
105
+
106
+ ```
107
+ F[kN] = p_mean[bar] × A_projected[cm²] / 100 (1 bar = 0.1 N/mm²)
108
+ p_mean = max(p_peak_simulated × sim_peak_to_mean, material rule of thumb)
109
+ F_required = F × clamp_safety_factor
110
+ ```
111
+
112
+ Both factors live in `shop/lessons.md`. The `max()` is the important part and §5.2 is why. On a
113
+ cold-runner tool the runner's own projected area is added (15 % of the cavity area); on a hot
114
+ runner it is not, because the melt channel is inside the manifold rather than in the parting line.
115
+
116
+ ### 3.2 Press selection
117
+
118
+ Smallest press clearing **clamp** (≤ 80 % utilisation), **tie-bar opening**, and the **shot window**
119
+ (20–80 % of barrel). The three are not equally hard, and treating them as if they were produces
120
+ "nothing fits" on ordinary parts. Clamp and tie-bar are hard constraints — too little tonnage is
121
+ flash, and a mold that does not fit does not fit. The shot window is soft: a small shot is a melt
122
+ residence problem to be managed, not a reason to refuse the job. So the search relaxes the shot
123
+ window last and names the constraint it bent.
124
+
125
+ ### 3.3 Cycle time
126
+
127
+ ```
128
+ cycle = fill + max(hold, cool) + handling
129
+ cool = h²/(π²α) · ln[ (4/π) · (T_melt − T_mould)/(T_eject − T_mould) ] · cooling_time_factor
130
+ ```
131
+
132
+ with `h` the half **governing** wall (p95 — the slowest-cooling section governs ejection) and
133
+ `α = λ/(ρ·c_p)` from the grade's own data. Holding time is `pack_time_s_per_mm_wall × nominal`
134
+ wall, because gate freeze follows the wall the melt flows through, not the thickest section.
135
+ Holding and cooling run concurrently, hence the `max()`.
136
+
137
+ **This is an analytic estimate, not a cooling simulation** — the filling solver has no cooling
138
+ phase. Its virtue is that a process engineer can redo it on paper from a datasheet, and an estimate
139
+ the customer can check beats a black box. Its known weakness is ribs and bosses, which is exactly
140
+ what `cooling_time_factor` exists to absorb (see L-001 in `lessons.md`).
141
+
142
+ ### 3.4 The tool
143
+
144
+ Base + cavities × complexity + side actions + feed system + cooling + ejection + finish +
145
+ engineering + sampling, then project management, risk and margin. Every rate is in
146
+ `shop/tooling.md`. The gate count enters as `cavities × gates_per_cavity` hot-runner nozzles.
147
+
148
+ ### 3.5 The piece price
149
+
150
+ ```
151
+ material + machine + labour + secondary + setup → manufacturing
152
+ + overhead (on material and labour ONLY) + margin → price
153
+ ```
154
+
155
+ **Overhead is not applied to the machine line.** The machine rates in `shop/machines.md` are loaded
156
+ rates that already recover fixed cost; applying overhead again is the classic double count.
157
+
158
+ Only two things move along the volume ladder: **setup amortisation** (capped by the minimum
159
+ economic batch — nobody sets up twelve times a year for 800-part runs) and the **material price
160
+ break** on annual tonnage. A ladder that comes out nearly flat between two rungs is therefore a
161
+ correct answer, not a missing discount.
162
+
163
+ ### 3.6 Choosing the gating
164
+
165
+ `compare_options()` prices every gating option end to end and ranks by **tool + piece × volume** at
166
+ the reference volume. That is the whole reason the study runs before the quote. If the winner is
167
+ within a couple of percent of the runner-up, the model cannot tell them apart — say so.
168
+
169
+ ---
170
+
171
+ ## 4. The quote document
172
+
173
+ `python main.py cost` writes `quote.json` — the chosen option, every option it was chosen against,
174
+ the machine and cycle basis, and the reference volumes. That file is the deliverable.
175
+
176
+ Turning it into a document is your assistant's job, and the format should be yours rather than
177
+ ours. What the document must carry, however it looks:
178
+
179
+ **The basis, stated plainly** — surrogate solver, one cavity, no runner, analytic cooling,
180
+ geometric weld-visibility. That is not decoration: it is what makes the quote defensible when the
181
+ first article disagrees with it.
182
+
183
+ **Honest comparisons.** If the winner is within a couple of percent of the runner-up, the model
184
+ cannot tell them apart and the document must say so. One measure per chart; never one chart with
185
+ two y-scales.
186
+
187
+ ---
188
+
189
+ ## 5. Things to know (each cost a real mistake)
190
+
191
+ ### 5.1 The offline path is not a quote
192
+ `--offline` exists so the flow can be demonstrated and tested without credentials. Everything it
193
+ produces is marked `estimated` through to `quote.json`. Do not send it.
194
+
195
+ ### 5.2 Never size the clamp from the simulation alone
196
+ The AI model is **one cavity with no runner system** and under-reads absolute pressure on
197
+ multi-gate parts. Cavity pressure at the end of *pack* — which is what actually opens a tool — is
198
+ not modelled at all, because the solver models filling only. The rule-of-thumb floor per material
199
+ family in `shop/materials.md` is what keeps a tool from flashing at trial. Use the simulation to
200
+ rank gating options; use the rule of thumb to size the press. `quote.json` records which governed.
201
+
202
+ ### 5.3 The endpoint sheds load
203
+ `max_workers=2` with retry and backoff. Everything timing out means the model went cold — one lone
204
+ request warms it. Never run a second batch concurrently with a running one.
205
+
206
+ ### 5.4 Determinism
207
+ Identical configuration → identical result. Re-running for confidence buys nothing; spend every run
208
+ on a new configuration.
209
+
210
+ ### 5.5 Weld lines are located, not judged
211
+ The detector finds where flow fronts meet. Whether that position is acceptable depends on the
212
+ part's functional and visible faces, which are on a drawing you were probably not given. It goes on
213
+ the assumptions slide as a flag, never as a silent pass.
214
+
215
+ ### 5.6 Result-file details
216
+ Handled by the reused `metrics.py`, but worth knowing: `Degree_of_filling` is a sharp 0→1 front
217
+ (arrival = first crossing of 0.5, *not* `isfinite`); `Pressure` honours a `unit` attribute (Pa now,
218
+ bar in older files); the `geometry3DF` group name has a trailing space; the result mesh is
219
+ re-centred on the origin while your gate coordinates are not.
220
+
221
+ ---
222
+
223
+ ## 6. Adapting it to your shop
224
+
225
+ 1. **Replace `shop/` wholesale.** Keep the file names and the fenced JSON block names; change
226
+ everything else. The prose is read by the agent and matters as much as the numbers.
227
+ 2. **Re-derive the tooling rates** against your last ten tools. The shipped numbers are invented.
228
+ 3. **Set the calibration block to neutral** (`1.00` everywhere, `clamp_safety_factor` to whatever
229
+ you use today) and let it move only through `learn`. Starting from someone else's corrections
230
+ is how you inherit someone else's mistakes.
231
+ 4. **Quote three parts you already know the answer to**, and run `learn` on each. Three corrections
232
+ is roughly where the cycle-time and tool-price factors stop moving much.
233
+ 5. **Check the side-action count** on every one of those three. It is the estimate most likely to
234
+ be wrong and the most expensive when it is.
235
+
236
+ ## 7. Limitations
237
+
238
+ - Filling only. No packing, cooling or warpage simulation — cooling is analytic, packing is a rate
239
+ per mm of wall.
240
+ - One cavity is simulated; cavity-to-cavity imbalance on a multi-cavity tool is not represented
241
+ even in principle.
242
+ - Undercut detection is geometric and cannot distinguish a slide from a hand-loaded insert.
243
+ - The tool model covers a 2-plate mould with a hot or cold runner. Unscrewing cores, 2K tools and
244
+ conformal cooling are explicitly out and are flagged rather than priced.
245
+ - Tolerances are not modelled at all. Nothing here guarantees a dimension.
@@ -0,0 +1,158 @@
1
+ # Template · Agentic quoting (`quoting`)
2
+
3
+ Give an agent **a geometry and a cavity count** — nothing else — and get back a **quotation**: a
4
+ tool price, a piece price at a volume ladder, a press and a cycle time, written out as a
5
+ `quote.json` your own assistant turns into the document your customer expects. The decisions that drive that price and have to be taken early — **how many gates**,
6
+ **what cavity pressure**, **how fast it fills** — are settled by running filling simulations on the
7
+ Simcon cloud, not by a rule of thumb.
8
+
9
+ Two things make it more than a calculator:
10
+
11
+ - **The agent has its own context.** `shop/` describes a specific shop: its presses, its material
12
+ bias, how it estimates a mould, what it declines. The agent quotes as *that* shop. It ships
13
+ filled in with a **fictional** shop, so the first thing to do is the 20-minute interview in
14
+ [`INTERVIEW.md`](INTERVIEW.md) — until then every quote is watermarked as example data, because
15
+ a precise price built on someone else's invented rates is worse than no price.
16
+ - **It is meant to be corrected.** Every quote ends with a review. The estimator says what is
17
+ wrong and *why*; the agent writes the reason into `shop/lessons.md` and the number into that
18
+ file's `calibration` block, which the cost model reads on the next quote. Expect the first
19
+ handful of quotes to be mostly learning — that is the design.
20
+
21
+ ## Run it
22
+
23
+ <!-- simcon-toolkit:setup -->
24
+ **Python 3.12 or newer**, and a virtual environment created *with that interpreter* — a venv
25
+ isolates packages, not the interpreter.
26
+
27
+ **Three sign-ins, each in your browser, and each does a different job.**
28
+
29
+ 1. **The package index**, once, in the steps below: `cadmould-sdk-auth` lets pip install the
30
+ licensed `cadmould` wheel from SIMCON's private index. Your company's email domain has to be
31
+ enabled for it: if you can sign in but the browser tab then says `Access denied: your email
32
+ domain is not authorized for this API`, ask SIMCON support.
33
+ 2. **Your licence**, the first time the code opens a licence session. It first checks the
34
+ Thales Sentinel run-time on your machine, and prints `License init failed: HASP driver
35
+ version too old` or `... runtime version too old` when that needs installing or updating.
36
+ 3. **The cloud**, the first time the code calls it.
37
+
38
+ ⚠️ A failed licence sign-in does not stop the script. It prints `License init failed: ...` or
39
+ `License acquisition failed.` to the terminal and carries on, so the error you meet later is `Cadmould API licence (LICENCE_API)
40
+ required`. When you see that one, scroll up to the first.
41
+
42
+ **macOS / Linux (bash):**
43
+
44
+ ```bash
45
+ python3.12 -m venv .venv
46
+ source .venv/bin/activate
47
+ pip install --upgrade pip cadmould-sdk-auth
48
+ cadmould-sdk-auth # opens a browser; sign in with your Simcon account
49
+ pip install . # installs cadmould and everything the quoting flow needs
50
+ ```
51
+
52
+ **Windows (PowerShell):**
53
+
54
+ ```powershell
55
+ py -3.12 -m venv .venv
56
+ .\.venv\Scripts\python.exe -m pip install --upgrade pip cadmould-sdk-auth
57
+ $env:VIRTUAL_ENV = "$PWD\.venv" # tell the login CLI which venv to configure
58
+ .\.venv\Scripts\cadmould-sdk-auth.exe # opens a browser; sign in with your Simcon account
59
+ .\.venv\Scripts\python.exe -m pip install .
60
+ ```
61
+
62
+ The Windows route never activates the environment. `Activate.ps1` is blocked by the default
63
+ execution policy on many machines; naming the interpreter outright avoids it.
64
+ <!-- /simcon-toolkit:setup -->
65
+
66
+ Only the `study` stage needs the licensed wheel; `intake`, `cost` and `learn` run offline. No
67
+ graphics stack is involved: the geometry measurements are trimesh's, and the only dependency
68
+ beyond the shared ones is `rtree`, the ~2 MB spatial index behind them.
69
+
70
+ Then, from the project folder:
71
+
72
+ ```powershell
73
+ # 0. ONCE: make shop/ describe YOUR shop, not the shipped fictional one
74
+ python main.py setup
75
+
76
+ # 1. what the geometry alone decides (offline, seconds)
77
+ python main.py intake --cavities 4 # uses the bundled sample/
78
+ python main.py intake --part my.stl --cavities 4
79
+
80
+ # 2. the simulations that settle the cost drivers (cloud; --offline to skip)
81
+ python main.py study --gate-counts 1,2,3
82
+
83
+ # 3. price every gating option, choose on total cost
84
+ python main.py cost
85
+
86
+ # 4. the review: apply the estimator's corrections to the shop context
87
+ python main.py learn --quote <key>
88
+ ```
89
+
90
+ Every stage takes the same `--part`, defaulting to the bundled sample. The last one takes
91
+ `--quote` instead: it corrects a quote that already exists and never opens the geometry.
92
+
93
+ **A quote is keyed on the part's contents, not its file name.** `intake` prints a key such as
94
+ `clip_frame-655b895fd2b5` and every later stage derives the same key from the same file — so
95
+ re-exporting a part starts a new quote rather than silently pricing the new shape against the
96
+ old one's mesh, uploaded geometry and decisions.
97
+
98
+ Bookkeeping lands in `cache/<key>/` (`state.json`, `decisions.md`); the quote itself lands in
99
+ `output/<key>/quote.json`. Both are safe to delete, and only the cache costs time.
100
+
101
+ **No cloud access?** Add `--offline` to step 2: gating comes from a rule of thumb instead of the
102
+ solver and every artefact is marked `estimated`. The other three stages need neither a licence
103
+ nor a token.
104
+
105
+ ## But mostly: point an agent at it
106
+
107
+ The commands above are what the agent runs. The way this is meant to be used is
108
+ [`PROMPT.md`](PROMPT.md) — one plain-English ask, in a session opened in this folder. The
109
+ assistant reads the method from [`METHOD.md`](METHOD.md); there is no skill to load.
110
+
111
+ ## What's here
112
+
113
+ ```
114
+ quoting/
115
+ ├── PROMPT.md # the prompt to give the agent
116
+ ├── INTERVIEW.md # the 20-min setup interview that builds YOUR shop context
117
+ ├── QUOTING_PLAYBOOK.md # the method, the cost model, every gotcha (read before adapting)
118
+ ├── AGENTS.md # how an assistant drives this template
119
+ ├── METHOD.md # the quoting procedure, stage by stage
120
+ ├── shop/ # THE AGENT'S OWN CONTEXT - replace with your shop
121
+ │ ├── shop-profile.md # what we sell, what we do in-house, house quoting rules
122
+ │ ├── machines.md # the press list + how to pick one
123
+ │ ├── materials.md # house grades, prices, the material bias
124
+ │ ├── tooling.md # how a mould is estimated here
125
+ │ ├── commercial.md # rates, scrap, overhead, margin, the ladder
126
+ │ └── lessons.md # corrections from real quotes + the calibration block
127
+ ├── quoting/ # the code
128
+ │ ├── geometry.py # projected area, wall thickness, undercuts (offline)
129
+ │ ├── study.py # the cloud filling study
130
+ │ ├── costing.py # clamp, press, cycle, tool price, piece price
131
+ │ ├── shop.py / state.py # context loader; quote state, decision log, the learn loop
132
+ │ └── toolkit.py # reuses the kit's shared REST client + result metrics
133
+ ├── main.py # the five stages
134
+ ├── sample/ # the default geometry (written when the project is generated)
135
+ └── parts/ # drop your own geometries here
136
+ ```
137
+
138
+ ## Making the method discoverable
139
+
140
+ The procedure lives in [`METHOD.md`](METHOD.md) as a plain file, so every assistant can read it
141
+ rather than only the one that loads skills. [`AGENTS.md`](AGENTS.md) points at it, and opening a
142
+ session **in this folder** is enough for a tool that reads either file.
143
+
144
+ ## How it relates to the other templates
145
+
146
+ This is the **gate-study one layer up**: that template answers *how should this part be gated*, this
147
+ one answers *what should we charge for it*, and uses the gating study as one input among several.
148
+ It reuses the kit's shared REST client and result metrics directly (`quoting/toolkit.py`) rather
149
+ than copying them, so both stay in step.
150
+
151
+ Prerequisites are the setup and the three sign-ins at the top of this file — and only for the
152
+ `study` stage.
153
+
154
+ ## Read before adapting it
155
+
156
+ [`QUOTING_PLAYBOOK.md`](QUOTING_PLAYBOOK.md) — what every number rests on, the three geometry
157
+ estimators that are non-obvious for good reasons, why the clamp force is never taken from the
158
+ simulation alone, and §6 on repointing it at your own shop.