Done Chasing
An SMS-native follow-up system for trades contractors. Log a quote in 30 seconds, let the system handle all customer outreach automatically. Claude does two things. Everything else is deterministic.
Solo contractors and small crews doing 10–20 bids a month are physically on job sites 8–10 hours a day. The follow-up call that converts a quote never happens because there's no desk, no CRM open, and no reminder. Contractors who follow up within 48 hours win 60–70% of competitive bids. Most don't follow up at all — not because they don't want to, but because no lightweight tool has made it easier than ignoring it.
Remove the app entirely. The owner texts a quote summary from wherever they are and the system handles everything after. Claude does exactly two things: parse a freeform SMS into five structured fields at intake, and classify a customer reply when one arrives. A daily Vercel Cron handles all outbound follow-up using templates with no AI in the hot path. Objection responses are staged for owner approval and never auto-sent.
- Intake — owner texts a quote summary; Claude Haiku parses freeform SMS into {customer_name, customer_phone, job_type, amount, quote_date}; Zod validates before any DB write
- Idempotency — twilio_message_sid is a UNIQUE constraint; duplicate webhook deliveries are no-ops before parsing begins
- Daily cron — cursor-paginated batch at 14:00 UTC; pre-send gate checks opt-outs and enforces a 9am–8pm local safe-hours window; templates only, no Claude
- Reply handling — customer inbound hits /api/reply; Claude Haiku classifies {category, confidence}; confidence below 0.70 escalates the raw message to the owner with no suggestion
- Approval loop — objection responses are staged and sent to the owner via SMS for explicit approval before anything reaches the customer
- Failure recovery — every outbound SMS is pre-logged to the DB before the Twilio call; cron crash recovery via followup_cursor.last_quote_id so the next run resumes from the same position
Next.js · App Router · Vercel
Supabase — Postgres, RLS
Twilio Programmable Messaging · A2P 10DLC
Claude Haiku — freeform SMS → structured fields, JSON schema mode
Claude Haiku — customer SMS → {category, confidence}, 0.70 threshold
Vercel Cron — daily batch at 14:00 UTC, cursor-paginated
Zod — schema validation on all Claude output before DB write
Keeping Claude out of the daily cron was a deliberate constraint, not a cost cut. Template substitution is auditable, predictable, and fast — a contractor's follow-up message should never vary based on what a model felt like generating at 2pm UTC. The interesting engineering problems are elsewhere: prompt injection defense (all customer SMS is XML-wrapped before touching Claude's context, with an explicit system instruction to classify only), a confidence threshold that routes between a staged response and a raw escalation, and an approval loop that ensures no negotiation message ever goes out on the owner's behalf without their sign-off. A bad price objection response sent automatically is a business liability, not a UX bug.
Done Chasing is a study in knowing where AI earns its cost. Two calls at intake — one to parse, one to validate. One conditional call on customer reply when classification beats pattern-matching. Zero calls in the cron hot path where templates do the job exactly. The product works because the AI is scoped tightly, not because it's everywhere. That boundary is the design.