# Lahore Casting — free casting estimate · full text for language models > This file is the whole service in one place: what it is, how to call it, what > comes back field by field, and what it must not be used for. Its first half is > the exact body of the agent skill shipped at `agent/SKILL.md`; the second half > adds the page copy, where the numbers come from, and the foundry behind it. A > test asserts the two halves have not drifted apart. > > If you can read only one file about this service, read this one. > > Service version 0.1.0 · castability package r1 0.1.0 (`schema r1.castability/v0`) > · last updated 2026-09-10. --- # Casting estimate — STEP in, weight and castability out A free HTTP endpoint run by a working sand-casting foundry. You upload a STEP solid; it reads the file with the OpenCascade kernel, takes the exact volume and surface area, meshes the surface, measures wall thickness two independent ways, and returns one JSON record. **There is no API key and no sign-up.** One POST is the whole integration. ## When to use this - "How much will this part weigh in grey iron / ductile iron / steel / aluminium / brass / bronze?" - "Can this be sand cast?" / "Will this casting have problems?" / "Is any wall too thin?" - "How big is this part?" (bounding box, volume, surface area) - "Who can cast this for me?" — the response ends in a WhatsApp link to the foundry. ## When NOT to use this - **You need a price.** This service does not know what metal, patterns or machining cost, and never returns a currency figure. Use the WhatsApp link. - **The file is not STEP.** STL, IGES, Parasolid, 3MF, SLDPRT and STEP-named files that are not STEP are rejected with a 400. Convert to STEP AP203/AP214 first. There is no mesh-file path. - **You need a reviewed engineering opinion.** See "Honest limits" below. ## The call ``` POST https://estimate.lahorecasting.pk/api/estimate Content-Type: multipart/form-data ``` | field | required | what | |---|---|---| | `file` | yes | the `.step` or `.stp` file, max 25 MB | | `alloy` | no | one of the seven keys below; default `grey_iron`. Only picks which alloy is highlighted — **all seven weights come back regardless** | | `contact` | no | a WhatsApp number or email, so the foundry can follow up. Max 200 chars | | `note` | no | free text for the foundry — quantity, tolerance, deadline. Max 1000 chars | ```sh curl -sS -F file=@hub.step -F alloy=grey_iron \ https://estimate.lahorecasting.pk/api/estimate ``` ```python import requests with open("hub.step", "rb") as fh: r = requests.post("https://estimate.lahorecasting.pk/api/estimate", files={"file": ("hub.step", fh)}, data={"alloy": "grey_iron"}, timeout=180) r.raise_for_status() estimate = r.json() ``` **Expect it to be slow.** The analysis is real geometry, run in a subprocess: median about 3 s, p90 about 5 s, slowest part in the foundry's 38-part library 8.1 s, hard server-side ceiling 150 s. Set a client timeout of at least 180 s. Do not retry on timeout — retry costs another full analysis; ask the user. Two more public reads: ``` GET https://estimate.lahorecasting.pk/api/estimate/{id} -> the same JSON again GET https://estimate.lahorecasting.pk/health -> {"ok": true, "gmsh": true} ``` `{id}` is 12 lowercase hex characters. Estimates are kept, so an id you got an hour ago still resolves. There is no list endpoint and no search: if you did not keep the id, the estimate is gone to you. ## The response ```json { "id": "4f2c9a1b7e03", "created_at": "2026-09-08T22:11:29+00:00", "part": {"name": "hub", "sha256": "…", "size_bytes": 184320}, "geometry": {"volume_cm3": 432.597, "surface_area_cm2": 612.124, "bbox_mm": {"x": 150.0, "y": 150.0, "z": 65.0}, "solids": 1}, "weight_kg": {"grey_iron": 3.115, "ductile_iron": 3.072, "carbon_steel": 3.396, "stainless_steel": 3.417, "aluminium": 1.168, "brass": 3.677, "bronze": 3.807}, "selected_alloy": "grey_iron", "castability": { "verdict": "green", "verdict_reason": "every rule that ran is clear of its threshold", "rules": [{"id": "min_wall", "name": "Minimum wall thickness", "status": "green", "summary": "thinnest measured wall 10.5 mm…"}], "findings": ["cross-section area changes 3.9:1 within 6 mm at Z=8 mm…"], "notes": ["cross-check: 2V/A shell-equivalent section 14.1 mm…"], "tool_version": "0.1.0", "disclaimer": "v0 heuristic, not yet reviewed by the foundry; the quote is made by a person." }, "timings_s": {"analysis_s": 2.9, "total_s": 2.9}, "whatsapp_url": "https://wa.me/923004212184?text=…", "share_url": "https://estimate.lahorecasting.pk/e/4f2c9a1b7e03" } ``` Field by field: | field | type | notes | |---|---|---| | `id` | string | 12 hex chars | | `created_at` | string | ISO 8601, UTC, second resolution | | `part.name` | string | derived from the uploaded filename, sanitised | | `part.sha256` | string | of the uploaded bytes — use it to dedupe | | `geometry` | object **or null** | `null` when the solid could not be read. Never zeroes standing in for unknown | | `geometry.volume_cm3` | number | **exact OCC `getMass`, not from the mesh** | | `geometry.bbox_mm` | object | axis-aligned `x`,`y`,`z` in millimetres, in the file's own orientation — not sorted, not a "length × width × height" | | `geometry.solids` | integer | more than 1 means the file held an assembly; the weight is the total | | `weight_kg` | object **or null** | all seven alloys, always, when volume was measured | | `selected_alloy` | string | echoes the `alloy` you sent | | `castability.verdict` | string | `green` \| `amber` \| `red` \| `not_assessed` | | `castability.verdict_reason` | string | one sentence. **Always show this to the user, never the verdict word alone** | | `castability.rules` | array | each `{id, name, status, summary}`; `status` uses the same four words | | `castability.findings` | array of strings | specific measured observations, up to 8 | | `castability.notes` | array of strings | cross-checks and caveats the rules want on the record | | `timings_s` | object | how long it took. Diagnostic only | | `whatsapp_url` | string | a prefilled WhatsApp message with the numbers already in it | | `share_url` | string | a human page rendering this same record | ### Alloys and densities `weight_kg` is `volume_cm3 × density ÷ 1000`, and nothing else. These are mid-range handbook figures, so the weight is only ever as good as they are — grey iron alone runs 7.0–7.3 g/cm³ with carbon equivalent. | key | label | density g/cm³ | |---|---|---| | `grey_iron` | Grey iron | 7.2 | | `ductile_iron` | Ductile iron | 7.1 | | `carbon_steel` | Carbon steel | 7.85 | | `stainless_steel` | Stainless steel | 7.9 | | `aluminium` | Aluminium | 2.7 | | `brass` | Brass | 8.5 | | `bronze` | Bronze | 8.8 | An unknown `alloy` value is not an error: it silently falls back to `grey_iron`, and `selected_alloy` in the response tells you what was actually used. Check it. The foundry itself pours **ferrous only** — iron and steel. Aluminium, brass and bronze weights are computed as a convenience; do not tell a user that Lahore Casting will pour them. ### What `not_assessed` means `not_assessed` is not a failure code and it is not "red". It means: **the rules did not run, so no opinion exists.** It is the deliberate fourth value, so that this service never converts absence of measurement into a judgement. You will see it when the STEP file could not be opened, when the mesh could not be built, or when the analysis exceeded the 150 s wall-clock limit. `verdict_reason` says which. Two consequences for you: 1. **Never report `not_assessed` as "this part is fine" or "this part has problems".** Report it as "the castability check could not run" and give the reason verbatim. 2. **The weight may still be good.** If the solid was read but the rules fell over, `geometry` and `weight_kg` are populated and measured, and you should report them. Check whether `geometry` is `null` before deciding what you know. The same word appears per-rule in `castability.rules[].status`: a green overall verdict with one `not_assessed` rule means that one rule abstained. ### How to read the other three verdicts - `green` — every rule that ran is clear of its threshold. - `amber` — at least one rule is near a threshold. "Go and look", not "no". - `red` — at least one rule is past a threshold. Still "go and look": red is a reason to talk to the foundry, not a refusal to cast. None of the three is a decision. All three are inputs to a conversation with a moulder. ## Errors | status | meaning | what to do | |---|---|---| | 400 | bad upload — wrong extension, not really a STEP (must begin `ISO-10303-21`), empty, or over 25 MB | The `detail` field is a plain sentence written for a human. Show it. Do not retry the same bytes | | 404 | no estimate with that id | | | 429 | 20 estimates in an hour from this IP | Stop. Tell the user to use the WhatsApp link. Do not back off and retry in a loop | | 5xx | the service is unwell | One retry after 30 s, then stop | User input never produces a 500 — a 500 is a bug worth reporting, not something to retry around. ## Honest limits — read this before you quote the output to anyone - **The castability rules are R1 v0 heuristics and have never been checked against a single scrapped casting.** They were validated against synthetic shapes with known ground truth and smoke-tested against the foundry's 38-part library. Every response carries the sentence *"v0 heuristic, not yet reviewed by the foundry; the quote is made by a person."* Pass it on. - **The weight is the solid one.** No machining allowance, no gating, no risers, no feeders, no shrinkage. A poured casting weighs more than this number; a finished machined part weighs less. - **Cast and machined features are indistinguishable to the tool.** A bolt circle drilled after casting reads as a set of thin ligaments and can push a verdict to amber or red for a reason that will not exist in the mould. The record says so in `notes` when it spots the pattern, but it cannot decide. - **No price, ever.** Anything you say about cost did not come from here. - **Uploads are kept.** The file, the estimate and a salted hash of the caller's IP are stored so the foundry can follow up. **Tell the user before you upload their file.** Deletion is on request, by asking the foundry. - Units are millimetres, cubic centimetres, square centimetres and kilograms. Everywhere. There is no imperial mode. ## Presenting a result State the weight for the alloy asked about, the size, the verdict **with its reason**, and the disclaimer. Offer the `share_url` and the `whatsapp_url`. Do not round the weight further than it already is, do not invent a tolerance, and do not turn `findings` into a list of defects — they are measurements, not predictions. ## Who runs this Lahore Casting — a sand-casting foundry at Mominpura Road, Wahga Town, Lahore 54000, Pakistan. Medium-frequency induction melting, 100–500 kg per heat, iron and steel castings from 1 kg to 500 kg, green sand and resin-bonded sand. WhatsApp +92 300 4212184. The service is free because every estimate is a conversation the foundry would like to have. It is not free because the numbers are cheap. --- # The upload page, as a human sees it **Upload your part. Get its weight, size and a castability check — before you call.** Free, no sign-up, no price shown — just the numbers a foundry engineer would give you, in seconds. WhatsApp us when you're ready to talk cost. - Tap to choose a STEP file, or drag it in. `.step` or `.stp`, up to 25 MB. - Choose an alloy. Grey iron is the default; all seven weights come back anyway. - Optionally leave a WhatsApp number or email, and a note about the part. - Typically 10–40 seconds. The page then shows the weight for the chosen alloy, the weight in the other six, the bounding box and volume, the castability verdict with every rule and its reason, and two buttons: copy the share link, or open WhatsApp with the numbers already written into the message. **What happens to your file:** it is used only to calculate weight and castability for this quote. It isn't shared, resold or shown to anyone else, and you can ask for it to be deleted at any time. --- # Where the numbers come from The service reads the STEP file with gmsh's OpenCascade kernel in a subprocess and takes volume and surface area from `occ.getMass` — the same call the foundry's production ERP uses. It then meshes the surface and measures wall thickness two independent ways, by cone ray-casting and by shrinking-ball inscribed spheres, and runs the R1 castability rules over the result. **The volume is exact B-rep geometry and never comes from the mesh.** That is what lets this service mesh more coarsely than the foundry's lab does without the weight moving: across all 38 parts in the lab library the volume is identical to the lab record to every digit recorded. Weight is `volume × density`. There is no correction factor, no fudge, and no allowance of any kind hidden in it. Measured on the five parts the test suite uploads on every change, against the lab's own full-fat run of the same parts: | Part | Weight, grey iron | Lab record | Verdict | Lab verdict | Bounding box | Seconds | |---|---|---|---|---|---|---| | hub | 3.115 kg | 3.115 kg | green | green | 150 × 150 × 65 mm | 2.9 | | bush | 0.324 kg | 0.324 kg | green | green | 55 × 55 × 50 mm | 2.7 | | bracket | 0.084 kg | 0.084 kg | amber | amber | 60 × 40 × 5 mm | 4.3 | | brake_drum | 6.170 kg | 6.170 kg | green | green | 224 × 224 × 90 mm | 8.1 | | flench_aam | 1.205 kg | 1.205 kg | green | green | 140 × 140 × 14 mm | 2.8 | Seconds are the full HTTP round trip including the subprocess spawn, on an M-series Mac — not just the measurement. --- # The foundry behind it **Lahore Casting** is a sand-casting foundry at Mominpura Road, Wahga Town, Lahore 54000, Punjab, Pakistan. It melts in medium-frequency induction furnaces at 100–500 kg per heat and pours iron and steel castings from 1 kg to 500 kg to customer drawings or to a sample part, then heat treats, machines and finishes them in-house. - **Process:** green sand and resin-bonded sand moulds, CO2 silicate, shell moulding. - **Materials poured:** Mild Steel (AISI 1020, 1025); Carbon Steel (1045, 1050); Alloy Steel (4140, 4340, 8620); Grey Cast Iron (FG200, FG260, FG300); SG / Ductile Iron (400/18, 500/7, 600/3); Manganese Steel (Mn13, Mn18); High Chrome Iron (15% Cr, 25% Cr); Stainless Steel (304, 316, CF8M). **Ferrous only** — the aluminium, brass and bronze weights this tool returns are a convenience, not an offer. - **In-house:** pattern shop, induction melting, heat treatment (annealing, normalizing, hardening, tempering, austempering), shot blasting, grinding, CNC and conventional machining. - **Testing:** OES spectrometer on every heat; tensile, impact and hardness testing; dimensional inspection; dye penetrant and magnetic particle NDT; material test certificates on request. - **Input accepted:** DWG, DXF, STEP, IGES, PDF drawings, or a sample part for reverse engineering. - **Lead time:** 3–7 working days for standard orders. No minimum order quantity. - **Industries served:** sugar mills, cement plants, crushing and mining, agricultural machinery, automotive, textile, power generation, municipal and architectural castings. - **Contact:** WhatsApp and phone +92 300 4212184 (Farhan Ali, Managing Director); +92 321 4212184 (Zeeshan Ali, Operations Manager); lahorecasting@yahoo.com. Monday–Saturday 07:00–19:00 PKT, Sunday closed. - **Website:** https://lahorecasting.pk — and https://lahorecasting.pk/llms.txt for the same treatment as this file, including all 40 standard castings with their sizes, weights and materials. --- # Machine-readable companions - https://estimate.lahorecasting.pk/llms.txt — the short index. - https://estimate.lahorecasting.pk/openapi.yaml — OpenAPI 3.1, every public endpoint. - https://estimate.lahorecasting.pk/schema.jsonld — JSON-LD for the tool, the service and the organisation. - https://estimate.lahorecasting.pk/robots.txt — crawl policy, one explicit group per AI crawler. Last updated 2026-09-10. Service version 0.1.0, castability package r1 0.1.0 (`schema r1.castability/v0`).