Synaplan
Open-source AI platform for companies: self-hosted AI agents, GDPR-compliant chatbot widget, RAG knowledge base, WhatsApp and Outlook AI, MCP, multi-model routing. Docker, Kubernetes or hosted in Germ
Aangan Studio phone enquiry agent
Translation pending
BusinessTypeScript · CSSGitHub @alaiserikki-cellOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Every phone enquiry goes to a voice agent (Vaani Labs) at any hour. The agent qualifies the caller against Nikhil's rules and books a consultation on the call (Cal.com). After the call, Gemini Flash classifies the transcript. Qualified leads become HubSpot deals, and the designer gets a brief by email (Resend) within two minutes. Nikhil follows it all on a mobile dashboard.
Next.js 16 (App Router, TypeScript) on Vercel · Neon Postgres · HubSpot free CRM · Resend · Cal.com · Gemini.
| Part | State |
|---|---|
| Database schema + seed | ✅ db/0001_init.sql, db/seed.sql (every app query checked against real Postgres) |
| Replay test | ✅ npm run replay -- --stub passes. Real-Gemini run needs the 12 transcripts in tests/fixtures/transcripts/ |
| Classification (Gemini) | ✅ written, not yet run against real transcripts |
| Routing + emails | ✅ written, not yet run against live Neon/Resend |
| Cal.com tools | ✅ live: Consultation event 7422764 (Mon–Sat 10:00–19:00 IST, 12 h notice, 30 min buffer), slots verified 10 Oct 2026 |
| Vaani adapter | ⏳ stub: src/lib/vaani/adapter.ts returns 501 until written against Vaani's API docs |
| HubSpot | ✅ written, not yet run live |
| Dashboard | ✅ |
| Crons | ✅ (see the cron note below) |
Caller ─▶ Vaani agent ──(mid-call)──▶ POST /api/tools/availability ─▶ Cal.com slots for the assigned designer
└─(mid-call)──▶ POST /api/tools/book ─▶ Cal.com booking (or "a designer will call within 2 hours")
call ends ──▶ POST /api/webhooks/vaani
1. verify signature 2. store raw payload 3. 200 OK
4. after(): Gemini classify → validate → confidence gate → route
qualified → designer email (+ack button) → HubSpot contact + deal
existing_client → [URGENT] email to Nikhil + escalation address
needs_review → email Nikhil (+ "pending review" brief to the designer if already booked)
declined/not_a_lead/dropped → log only (dropped with a number → call-back list)
agent said a price → compliance incident + email Nikhil
Crons: ack-check every 15 min (escalate after 2h, retry failed processing) · HubSpot sync hourly · digest 08:45 IST
Only src/lib/vaani/ knows Vaani's payload shapes. Everything else uses NormalizedInteraction / NormalizedToolCall (src/lib/types.ts). The calls table has a channel column, so WhatsApp or a web form can come in later as another adapter with no schema change.
db/0001_init.sql, then db/seed.sql. From a terminal, psql "$DATABASE_URL" -f db/0001_init.sql does the same.areas (Pune localities they prefer), and calcom_event_type_id (step 3).DATABASE_URL. The app talks to Neon over HTTPS with @neondatabase/serverless, which suits Vercel functions: there's no connection pool to manage.DATABASE_URL for you.Only the server holds DATABASE_URL. The browser never talks to the database.
Copy .env.example → .env.local for local dev, and set the same keys in Vercel. EMAIL_TEST_MODE defaults to true: every email goes to EMAIL_TEST_RECIPIENT with a [TEST → real recipient] prefix. Set it to false only when going live.
designers.calcom_event_type_id. Designers without an ID are never offered to callers during a call.CALCOM_API_KEY.CALCOM_FALLBACK_ATTENDEE_EMAIL.Qualified calls become a HubSpot contact plus a deal in the Consultation booked stage, and the dashboard's pipeline panel syncs hourly.
crm.objects.contacts.read/write, crm.objects.deals.read/write and crm.schemas.deals.read/write. Put the token in .env.local and Vercel as HUBSPOT_ACCESS_TOKEN.npm run hubspot:setup. It checks the token, creates a test pipeline "Aangan enquiries (test)" (or, on the free plan's single pipeline, adds a Consultation booked stage to it) and prints HUBSPOT_PIPELINE_ID and HUBSPOT_STAGE_CONSULTATION_BOOKED. Set both in .env.local and Vercel, then redeploy.Deals never get an amount from this system. The dashboard's "won value" only sums amounts a person typed into HubSpot on won deals.
Verify your sending domain, create an API key → RESEND_API_KEY, and set RESEND_FROM.
Pending API docs. Once the adapter is written:
agent/vaani-system-prompt.md into the agent. Apply the platform settings and run the red-team test script in agent/README.md before go-live and after every prompt change.check_availability → POST <APP_URL>/api/tools/availability. Args: location (string), consultation_mode (home | studio).book_consultation → POST <APP_URL>/api/tools/book. Args: slot (ISO start time returned by check_availability), caller_name, phone, location, consultation_mode.POST <APP_URL>/api/webhooks/vaani with VAANI_WEBHOOK_SECRET.APP_URL to the production URL.vercel.json schedules the daily digest at 15 3 * * * (03:15 UTC = 08:45 IST)..github/workflows/crons.yml). Add the repo secrets APP_URL and CRON_SECRET. GitHub can start scheduled runs a few minutes late, which is fine for these jobs. On Vercel Pro you can move both into vercel.json and delete the workflow.Authorization: Bearer $CRON_SECRET.npm run replay -- --stub # no network: gate, routing plan, email rendering, price guard
npm run replay # real Gemini over tests/fixtures/transcripts/T*.txt (needs GEMINI_API_KEY)
npm run replay -- T07 T10 # selected cases
Hard failures: outcome, decline_reason, pricing_requested, price_mentioned_by_agent (must be false), routing (T09 must never create a deal or handoff), and any price figure in a rendered email or deal. Flags are free text, so they are printed side by side but never fail the run.
src/lib/price-guard.ts). Caller-derived text is redacted before rendering. Every email and deal description is scanned again before sending, and a hit blocks the send and logs an incident. A volunteered budget shows as "Mentioned by caller (amount withheld)". The dashboard transcript view hides amounts too.incidents row + immediate email to Nikhil.src/lib/log.ts strips them from logs.(provider, external_id). Processing claims the row atomically, reuses an existing classification, and every side effect has its own dedupe record (handoffs, hubspot_sync, incidents, emails.dedupe_key).needs_review: the designer still gets the brief, marked "pending review", so the slot isn't missed. Nikhil gets the review email. No HubSpot deal is created until Nikhil decides.areas match the caller's location. The pointer moves only when a booking is made, or when a handoff is assigned post-call.