Inspiration

I'm a prepress operator at a commercial printer. Every day I see the same pattern: a customer emails the front desk with a request like "need 500 business cards on something heavy and glossy, ready Friday" — and a CSR spends 15 minutes translating that into a precise spec, looking up the customer's history, checking stock, picking a press, and writing up a job ticket I can actually run.

Multiply that by 40 emails a day across 6 CSRs and you have a real bottleneck — one that happens to be exactly the kind of fuzzy, multi-step, judgment-requiring task that modern agents are good at. So I built Voomie: a natural-language front door for print shops that does the CSR's first pass automatically.

What it does

Voomie reads a customer email (or web-to-print intake, or MIS handoff) and produces a validated, production-ready job declaration. End-to-end:

  1. Parses the customer's natural-language request
  2. Looks up the customer in MongoDB Atlas — or creates a new record if it's a walk-in
  3. Resolves vague language ("heavy and glossy") to concrete stock and press choices via JSON registries
  4. Generates a structured job declaration in our shop's spec format
  5. Validates the declaration against a parser — and self-corrects on validation errors
  6. Either: returns a ready-for-review job, drafts a clarifying customer reply, or escalates to a human with full context

Every step is logged to MongoDB. A live Streamlit dashboard streams agent phase transitions at 1-second polling, so the CSR can watch Voomie think.

How we built it

Stack: Google Cloud Agent Builder + Vertex AI Gemini 2.5 Pro for reasoning, MongoDB Atlas for state and conversation memory (via the MongoDB MCP server), Python MCP servers for the agent's tool surface, Streamlit for the dashboard, all glued together over MCP stdio.

Architecture: 11 MCP tools across 5 domain modules (parse_shoptalk, registry, mongodb, inspect_pdf, render_preview). The agent invokes them through a single voomie_server.py aggregator. The MongoDB tools are load-bearing — they're how the agent remembers anything between turns: customer records, job history, conversation turns, flag context.

Why MongoDB as source-of-truth: The dashboard reads directly from Mongo, which means its view is always consistent with what the agent thinks happened. There's no separate event log to keep in sync. When Voomie persists a job, the dashboard streams the new row in real time. When the agent appends a conversation turn, it appears live. The agent's memory and the operator's view are the same data.

Demonstrated resilience — 17-run fixture suite

Before recording the demo, I ran a 17-fixture test suite — 5 standard customer scenarios + 12 adversarial scenarios designed to break the agent. Results:

  • 17/17 runs completed without crashing
  • 16/17 resolved through conversational paths — clarification, ready-for-review, or graceful customer reply
  • 1/17 hit the terminal flag_for_human escalation, by design (parser limitation on an unsupported finishing technique)
  • ~8 Gemini parameter typos auto-corrected per run on average — the agent's tool layer transparently fixes malformed parameter names that Gemini occasionally emits
  • 0 malformed conversation turns across the entire suite

The adversarial set included a prompt injection attempt — the agent recognized the attack in its own reasoning, refused, and continued the legitimate request without acknowledging the injection. The reasoning is captured verbatim in the conversation log. It also handled a bilingual customer message by replying in Spanish, unprompted, and caught an internal contradiction in a customer email ("business cards" and "4×6 postcards" in the same message) and asked which they meant.

Challenges

MongoDB as conversation memory, not just storage. Early on I treated MongoDB as a write-only audit log. That worked until I realized the agent needed to read past conversation turns to resolve references like "the postcards we talked about last week." Restructuring the data model so a job's conversation history was queryable, structured, and incremental — without becoming a 10-call mess per turn — was the hardest design problem.

Clarify-first vs flag-first policy. My original spec said "if a stock isn't in the catalog, escalate to a human." The agent kept ignoring it and asking the customer instead. After a 17-fixture audit I realized the agent's behavior was actually better than the spec — escalating to a CSR for things the customer could easily clarify wastes CSR time. So I rewrote the spec to reserve flag_for_human for terminal states only (parser failure, infrastructure error, 3-turn cap exhausted) and embraced the agent's clarify-first instinct.

Gemini parameter typos. Gemini occasionally emits MCP tool calls with slightly malformed parameter names (joba_id instead of job_id). On a busy run it can happen 10+ times. I built a transparent correction layer that fixes them on the way in — averaging ~8 auto-corrections per run with zero downstream effect.

Atlas connection drift. Mid-build, the M0 free-tier cluster started rejecting TLS handshakes from my VPN IP after the network access list got stale. The agent failed gracefully (returned a natural-language deferral to the customer, didn't crash), but the demo couldn't complete. Real production-day risk worth flagging — and a useful reminder that even "infrastructure failures" are now content that needs UX consideration.

What we learned

Agents prefer asking over escalating, and that's correct. The spec-vs-behavior divergence wasn't a bug. It was the model making smarter triage decisions than my flowchart did.

MCP makes the agent's surface auditable. Every capability Voomie has is exposed as one of 11 MCP tools in one file. Adding a new capability doesn't touch the agent loop. The same tools can be reused by Claude Code, Cursor, or any other MCP client — which means the print shop's tooling outlives the agent.

The dashboard is half the product. The agent is invisible. The dashboard is what makes the agent legible to the operator. Building it forced me to figure out exactly which phases mattered, which state transitions deserved visual treatment, and what "watching an agent think" should feel like.

What's next for Voomie

Voomie is the customer-facing layer of a three-part vision:

  • 🗣️ Voomie — the mouth. Natural-language intake.
  • 🧠 shoptalk — the brain. Structured job-spec format that captures what was ordered.
  • 🤲 Printssistant — the hands. PDF production execution. (Already a live, revenue-generating prepress app at printssistant.com.)

Voomie produces a shoptalk declaration. shoptalk is the immutable record of the order. Printssistant consumes the declaration and does the actual prepress work. Together: a print shop that runs on language.

Near-term roadmap:

  • Inbound email integration (IMAP/Gmail ingestion)
  • PDF preflight feedback loop (wire inspect_pdf results back into the conversation)
  • Voice intake (phone-call transcription → agent — the back-end is already shape-compatible)
  • Multi-shop tenancy
  • Direct handoff to Printssistant for production execution

Built solo by a prepress operator, for prepress operators. The thing I see broken every day is now half-fixed.

Built With

Share this project:

Updates