| name | imm-spec-agent |
| description | Use EVERY TIME someone wants a spec sheet, research document, or freight plan for a used plastic injection molding machine. Trigger on brand+model (KraussMaffei CX 160, Engel Victory, Haitian Mars, Arburg Allrounder), an equipt.com/exapro.com/machinepoint URL, a photo of a machine, or phrases like "build me a spec sheet", "research this IMM", "how do I ship this machine", "step deck or RGN", "how many trucks", "create a one-pager for this used injection molder". Produces a premium dark-theme PDF (matching La Crown's GEO report aesthetic) white-labeled with the user's brand colors pulled from their website on first run. Includes hero photo + multi-photo gallery, hyperlinked listing button on cover, asking price, full technical specs in metric AND imperial, freight logistics with trailer/permit/escort/rate recommendations, blueprint links, and source citations. OEM-first, reseller fallback. All embedded photos auto-strip metadata silently. |
IMM Spec Agent (Premium White-Label)
End-to-end research agent for used plastic injection molding machines. Output is a branded PDF spec sheet matching the La Crown GEO report aesthetic — dark theme, Playfair Display serif headlines, two-tone accent words, gold/orange critical numbers. Brand identity is pulled from the user's website on first run.
When this fires
- Brand + model: "KraussMaffei CX 160", "Engel victory 200/120", "Haitian Mars II 250"
- A listing URL: equipt.com, exapro.com, machinepoint.com, surplusrecord.com
- A photo of a machine (read nameplate or visual ID)
- Phrases: "build me a spec sheet", "research this IMM", "give me the freight plan", "how do I ship this"
First-run flow (every invocation)
-
Check for cached brand at /mnt/user-data/uploads/.imm_brand.json. If exists, load and skip to step 3.
-
No cached brand → ask for the user's website ONCE:
"Before I build the spec sheet — what's your company website? I'll pull your brand colors and contact info so the PDF is white-labeled. (Or paste 'skip' for generic branding.)"
When given a URL:
- Run
python3 scripts/brand_extractor.py <URL> /mnt/user-data/uploads/.imm_brand.json
- Confirm the extracted colors with the user before saving.
- Save final brand to cache.
On "skip" → use generic default (gold/orange on dark theme).
-
Proceed to spec sheet workflow below.
What to ask before building (or during)
The agent uses what's provided and prompts for the rest at the end — never blocks the spec sheet to demand inputs.
| Input | When to ask | Goes where |
|---|
| Hero photo | At end if missing | Cover page |
| Additional photos (nameplate, control panel, injection unit, etc.) | At end if missing — encourage nameplate especially | "Machine Gallery" page |
| Listing URL on reseller's site | At end if missing | Gold "View Live Listing →" button on cover |
| Asking price | At end if missing | Italic Playfair price on cover (next to listing button) |
| Production hours | At end if missing — this is the #1 used-IMM buyer question | Cover stat chip + Identification table |
| Condition rating | Fallback if hours unknown (Excellent / Good / Fair / As-Is) | Cover stat chip (if no hours) + Identification table |
| Inventory ID / stock number | Optional | Footer ribbon if provided |
Closing prompt (if any are missing)
After delivering the first draft, ALWAYS end with something like:
"To upgrade this from research draft to customer-ready, drop me:
• A nameplate close-up (upgrades all the LOW-confidence fields to HIGH)
• 2-3 more shots — control panel, injection unit, power pack
• Production hours (or condition rating if hours aren't logged)
• The listing URL on your site if you have one
• Asking price (or 'price on request')
Send any combo and I'll regenerate."
Photo handling — ALWAYS auto-scrub
Every photo embedded in the PDF gets metadata-stripped automatically before embedding. Use prep_photos.py:
from prep_photos import prep_photos
raw = ["/mnt/user-data/uploads/hero.jpg",
"/mnt/user-data/uploads/nameplate.jpg",
"/mnt/user-data/uploads/control.jpg"]
clean = prep_photos(raw, "/tmp/spec_build/clean")
spec["photo_paths"] = [str(p) for p in clean]
spec["photo_captions"] = {
str(clean[1]): "Nameplate Close-up",
str(clean[2]): "Operator Side / Control",
}
The first photo in photo_paths is the hero (cover page). Everything after becomes the gallery. Captions are optional dict mapping path → label.
No telling the user it's happening. The privacy line ("metadata-stripped") on the gallery page is the only visible signal.
Spec workflow
Step 1 — Identify the machine
- URL given →
web_fetch it
- Brand + model → start here
- Photo → read nameplate / visual ID. Customer-applied asset tags (e.g. "A60") are NOT OEM models.
Step 2 — Pull OEM data first
web_search: "<Brand> <model> specifications dimensions weight"
web_search: "<Brand> <series> brochure filetype:pdf site:<OEM domain>"
See references/data-sources.md for OEM domains.
Step 3 — Cross-reference with reseller listings
Equipt, Exapro, Maszyneria, MachinePoint, Surplus Record.
Step 4 — Run conversions + freight engine
from convert import format_full_spec
from logistics import recommend_freight
formatted = format_full_spec(raw)
plan = recommend_freight(machine_l_mm=..., machine_w_mm=...,
machine_h_mm=..., net_weight_kg=...)
Step 5 — Build the branded PDF
import json
from build_pdf import build_spec_pdf
with open('/mnt/user-data/uploads/.imm_brand.json') as f:
brand = json.load(f)
spec = {
"type": "Plastic Injection Molding Machine",
"manufacturer": "Krauss-Maffei",
"model": "C-Series · 300 Ton",
"year": "2003",
"serial": "12345",
"production_hours": 42500,
"condition": "Good — Working Condition",
"description": "...HTML allowed for <b>bold</b> + <br/>...",
"specs_formatted": format_full_spec(raw),
"logistics": plan.to_dict(),
"photo_paths": clean_photo_paths,
"photo_captions": {path: caption, ...},
"listing_url": "https://reseller.com/listing/12345",
"asking_price": "$48,500",
"blueprint_links": [...],
"sources": [...],
"confidence_notes": "...",
}
build_spec_pdf(spec, "/mnt/user-data/outputs/<brand>_<model>_spec.pdf",
brand=brand)
Critical rules
- First run always asks for the website. Don't skip. Don't guess colors.
- Brand is cached in
/mnt/user-data/uploads/.imm_brand.json — subsequent runs use it without re-asking.
- OEM data first, reseller second. When they conflict, prefer OEM.
- Both unit systems on every numeric field. Never just metric, never just imperial.
- Mark confidence honestly. HIGH / MEDIUM / LOW per field.
- Run web_search every time. Used-IMM specs you "remember" may be wrong revision.
- Don't invent serials, years, or hours. "n/a" or "TBC from nameplate".
- Photos are optional. Build whatever you have. Prompt for more at the end.
- All embedded photos are auto-scrubbed. No exceptions.
- The PDF is always the deliverable, even for quick questions.
Resetting / overriding the brand
"reset brand" or "change my brand colors" → delete .imm_brand.json and re-run first-run flow.
"build this for [Other Company]" → temporarily override company_name for one-time use without touching the cache.
File map
scripts/brand_extractor.py — pulls company name, logo, colors, contact from a website
scripts/prep_photos.py — strips metadata from photos (used silently before embedding)
scripts/convert.py — unit conversions (metric ↔ imperial)
scripts/logistics.py — trailer/permit/escort/rate engine
scripts/build_pdf.py — HTML + WeasyPrint PDF generator (premium dark theme)
references/data-sources.md — OEM domains + reseller aggregators by brand
references/logistics-rules.md — freight rules, trailer types, brand-specific shipping
Anti-patterns
- ❌ Asking for photos upfront and refusing to build without them → build with whatever's provided, prompt at end
- ❌ Including raw photos with GPS/timestamps in the PDF → always run
prep_photos first
- ❌ Hardcoding any reseller's branding into the default → use generic gold/dark when no brand is set
- ❌ Skipping the listing URL when one was provided → always render the gold button on the cover
- ❌ Skipping the brand confirmation step → always show extracted colors before caching
- ❌ Reusing a Premier-branded sample for other resellers → samples are always GENERIC unless a specific brand is requested