Inspiration
A car company's day starts with an inbox full of messages: a supplier's chips are late, a plant floods, a parts lot looks bad, a dealer asks for brochures, someone forwards a rumor. Each real problem fans out across production slots, dealers, loaner cars and owners, and one wrong move (notifying a dealer twice, giving away a loaner the pool doesn't have, acting on a rumor) costs money and trust. We wanted a control tower where an LLM does what it's good at, reading messy text, and everything that touches the business is exact, explainable and impossible to get creatively wrong.
What it does
For each incoming event, the control tower:
- Reads it: Gemini 3.5 Flash-Lite classifies and splits the message (supplier delay, plant outage, quality issue, noise or rumor) and extracts entity references and date phrases.
- Grounds it: code resolves aliases and relative dates ("next Thursday") and walks a typed knowledge graph built from all 16 company tables (16,979 nodes, 28,190 edges) to find exactly which builds, orders, dealers, lots and vehicles are affected.
- Acts on it through one coordinator and three bounded specialists:
- Supply Chain Planner: moves each affected build to the earliest feasible slot at the same plant, or transfers it to a compatible plant.
- Dealer Network / Customer Care: notifies each dealer exactly once with only its affected orders, and assigns loaners by tier (Platinum, then Gold), promised date and order ID, within live pool limits.
- Quality: holds the lot, stops sale of unsold vehicles and contacts owners of sold ones.
- Shows its work: a Streamlit UI shows the graph path, each agent's decisions, the typed handoffs between agents, and every official tool call and response.
Noise makes no calls. Unconfirmed rumors only escalate.
How we built it
- Knowledge graph: NetworkX over all 16 CSV tables, covering 11 entity types, with 814/814 direct-table consistency checks. The ontology is exported as JSON, GraphML and Mermaid.
- LLM extraction: a Gemini adapter that records raw output, text hashes, model version and token usage for every event. For all 15 public events, it used 12,986 input tokens and 1,306 output tokens in total.
- Deterministic policy: handbook rules written as plain Python. A delay blocks the window from the original ETA up to (not including) the new ETA, only at the receiving plant. Outages are inclusive, and the plant restarts the next working day. There are no event-specific answer branches.
- Agent boundaries: each agent acts through a
ScopedClientwith its own tool allowlist. An out-of-scope call is refused before any HTTP request, so it can never become a failed enterprise call. Agents pass typed handoffs (WorkOrder→ProductionChanges→CustomerCareReport;QualityOrder→QualityReport), and Customer Care rejects an inconsistent handoff. The coordinator dispatches only specialists that have work. - Independent audit:
audit_run.pyderives expectations from direct CSV joins and replays our action log through the officialEnterpriseimplementation. It passes 15/15 events against a do-nothing baseline of 3/15, and it caught 6/6 deliberately injected faults. - Testing: 88/88 unit and guardrail tests and 9 UI scenario tests.
Challenges we ran into
- LLM extraction was 12/15 correct at first. The model sometimes dropped a leading article or missed context in a shipment's sender header. We fixed this with general normalization in code, not event-specific patches, and revalidated the same recorded model output at 15/15 without spending more API calls.
- Unwritten tie-breaks: the handbook doesn't say which plant wins when two can take a transfer on the same day. We chose the company's canonical
plants.csvorder (the order the official system loads plants) and documented the decision. - Efficiency: our first run re-read each dealer's loaner pool before every notification and assignment. Reading each pool once, and capping assignments at that live value, cut calls from 1,120 to 900 with zero failures and identical outcomes.
- Never guessing on a write: if a write's outcome is uncertain, the system stops instead of retrying, so a network hiccup can't double-book anything.
Accomplishments that we're proud of
- 15/15 public events pass the independent audit, and 900 official calls produced 0 failures: 766 corrective writes, 132 reads and 2 escalations.
- Real business outcomes in one run: 50 orders moved, 192 dealer notices, 103 loaners assigned, 3 lots held, 236 vehicles stopped from sale and 320 owners contacted.
- Agents that cannot overstep their role, enforced in code rather than by prompt.
- Full reproducibility: the dry run and the clean submission run produced byte-for-byte identical action logs.
What we learned
LLMs are excellent readers and unreliable deciders. Splitting the job (the model extracts facts, code makes decisions) gave us both flexibility on messy text and exact handbook compliance. We also learned that guardrails are worth building as structure, through scoped clients, typed handoffs and fail-closed parsing, instead of hoping a prompt keeps an agent in line. And measuring against a do-nothing baseline kept us honest about what each change actually bought.
What's next for Wacky Wheels Control Tower
- Calibrated uncertainty: have the extractor report confidence, and route low-confidence reads to a human before any write.
- More paraphrase holdouts: stress-test the extraction step on reworded and adversarial messages.
- Live inbox integration: feed real email or ticket streams with human approval for high-impact actions.
- What-if planning: simulate a disruption before it happens and show which customers and dealers would be hit.