Lalabase
Tickets, Doku, Zeiterfassung und Kundengespräche an einem Ort, durchsuchbar per KI. Für Softwarefirmen mit Kundenprojekten. Open Source: auf deinem eigenen Server oder in unserer Cloud in Deutschland.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗An inbound-call agent for Aangan Studio. It answers every call, day or night, runs Nikhil's qualifying conversation, books a consultation for qualified callers during the call, and sends the designer a note with everything already asked. Every call is logged with its outcome and its cost.
Scope: incoming phone calls only. WhatsApp and the web form are not built (see Extending to other channels).
Be precise about this when asked.
| Piece | Status |
|---|---|
| Qualification logic, scripts, pricing guard, handoff note | Built and tested (95 automated tests, all pass; npm test) |
| All 20 phone transcripts (T01-T20) | Run through the logic, 20/20 agree with expected verdicts (see Testing). This tests the decisions given facts, not speech understanding |
| Booking after the call | Verified live with every real service. The agent asks the caller which day and time suits them; after the call the server books exactly that time in Cal.com if it is free. If the caller named no time, or it is taken, or it is a Sunday or outside 9am-6pm, nothing is booked and the Telegram note lists free slots for the designer to offer. A caller who declines is never booked. Live test: "Tuesday at 11 in the morning" became Tue 13 Oct 11:00 IST, booked, then cancelled with its test deal and contact. AUTO_BOOK=0 switches it off |
| Booking | Verified live through production: a test consultation was booked via the tool, read back from Cal.com, then cancelled. Found and fixed a bug on the way: Cal.com rejects made-up attendee email domains, so bookings now use a "+" alias of a real inbox (CALCOM_EMAIL_FALLBACK) |
| Vercel deployment | Live at https://aangan-phone-agent.vercel.app (dashboard at /, needs the password). Every endpoint is checked from outside: wrong or missing credentials get 401, and a forged webhook is rejected. A real round trip through production reached Neon and Cal.com (two real slots). Test rows removed |
| Call log, cost ledger, dashboard | Call log and cost ledger verified on the real Neon database (schema applied; a test call written, read back through the dashboard query, then deleted). Dashboard viewed locally with sample data. Not yet run on Vercel |
| Gemini (speech to facts) | Verified live. The real T01-T20 conversations, read turn by turn by gemini-3.5-flash-lite as a live call would, give 19/19 matching verdicts (npm run live:extract). Caveat: I tuned the instructions against these same 19 calls, so this shows the approach works, not how it does on unseen calls |
| Telegram | Verified live. A test handoff note (sample data, labelled TEST) was sent to the designers' group through the real adapter |
| Cal.com | Verified live for reading: the "Design consultation" event type exists and the slots endpoint returns real availability in the shape the code expects. No booking has been made yet. Default availability starts at 9am, so set the working hours to Aangan's in Cal.com |
| HubSpot | Verified live. A labelled test deal and contact were created through the real adapter, linked to each other, landed in the default pipeline at "Lead Captured" with no amount set, and were then deleted. The account's pipeline uses custom stage names, so the stage id is set in .env |
| After-call pipeline (Vaani webhook, judge, script audit, handoff, deal) | Verified live with real Gemini: the real T01-T20 conversations replayed as webhooks give 19/19 matching verdicts, twice (npm run live:webhook). Telegram/CRM/calendar were mocked in that run. The webhook receiver matches Vaani's documented call_postprocessing format and verifies each call with Vaani's API; no real Vaani event has reached it yet |
| Vaani (voice agent, app.vaanivoice.ai) | Set up and tested in text chat. The agent "Aangan Studio Phone Desk" is configured with the generated instructions (OpenAI gpt-4o, temperature 0). In chat it asks the right questions, uses the decline line word for word, and the price line word for word apart from "you'd" becoming "you would". Not yet tested by voice or on a real call. Vaani's "call finished" notification does not fire for chat tests, so the after-call pipeline has not yet received a real Vaani event |
Nothing here has taken a real call yet.
| What breaks today | Evidence from the brief | What fixes it |
|---|---|---|
| Nobody answers outside 10am-7pm. About a third of enquiries (~66 of ~200 a month) arrive then. | "~33% arrive outside 10am-7pm" | The agent answers every call, any hour. The dashboard shows after-hours calls separately, and the answer time per call (it targets seconds, against Nikhil's five-minute bar) |
| Half of enquiries get no reply within 48 hours, and a reply within 1 hour converts at 4x. | "~48% get no response in 48 hrs"; "4x conversion" | Same fix: the first response is on the call itself. A call is never "missed", only handled or hung up on, and both are logged |
| Leads get lost between people. T16 and T08 in the transcripts: a call logged days late, a missed call never followed up. | T08, T16 | The call row is created the moment the call is answered. If the voice platform reports a call our server never saw, the webhook logs it anyway. Nothing is silent |
| Designers get a forwarded message with no context and spend their first call re-asking. | "first call is spent asking questions the front desk already asked" | A structured handoff note (name, phone, project, area, state of the space, timeline, budget signal, who decides, uncertainty flags, booking) goes to Telegram. The consultation is already booked, and the deal is already in HubSpot |
| Nikhil pulls his own numbers by hand. | "pulled his own numbers last month" | The dashboard: enquiries, after-hours share, answer time, outcome split, consultations booked, and the cost of the system itself |
| Unqualified calls waste designer time, but declining wrongly loses a ₹8-14 lakh project. | "Average project value ₹8-14 lakh" | Nikhil's five-criteria rubric, implemented exactly. When unsure the lead goes forward with the uncertainty flagged, not dropped |
Nikhil asked for the system to "quote our standard per-square-foot pricing". It does not, and never will on its own. pricing.md says no number, range or per-sq-ft figure may be given, because the real price depends on site, materials and scope (a standard-vs-premium kitchen alone can differ 3x). So the agent says the exact scripted line every time, however the caller rephrases:
"Pricing depends on the site, the materials you choose, and the scope — your designer will walk you through it in detail at the consultation. I can book that for you right now if you'd like."
Because Vaani's own AI does the speaking, my code cannot rewrite its words, so the rule is enforced in four ways: (1) the exact line and the "never state a number" rule are in the agent's instructions; (2) the qualify_enquiry tool returns the exact words for decline, deferral and escalation; (3) after every call, an audit checks the transcript for any rupee figure, "lakh" or per-sq-ft figure the agent said, and for whether the scripted line was used when price came up. A breach is stored on the call, shown on the dashboard, and sent to the senior Telegram channel at once; (4) the dashboard shows a script-compliance count. This catches breaches after the fact. It cannot prevent them mid-call. Asking the price never disqualifies a caller.
| Component | Role | Why this one |
|---|---|---|
| Claude Code | Builds and maintains the project | The brief's requirement. Every step is a git commit |
| Vaani Labs | Answers calls and speaks (including Indian languages and accents) | Built for India. Hinglish shows up in the enquiries (W03, a WhatsApp thread), so callers may mix languages. Its AI runs the conversation from written instructions, calls my tools for rules and booking, and sends a call-completed notification afterwards |
Gemini Flash (gemini-3.5-flash-lite) | Reads what the caller said into structured facts; routes general questions | Cheap and fast (about $0.30/$2.50 per million tokens in/out), so it adds well under ₹1 per call. It only reads: every decision is plain code, so verdicts are testable and the scripts can't be reworded |
| Neon (Postgres) | Call log, state, cost ledger | Serverless Postgres, free tier, works from Vercel functions. A call's in-progress state lives here, so any server can take the next turn. (Supabase also works: the code supports both) |
| Cal.com | Books the consultation inside the call | Free, has an API, books in seconds so there is no separate follow-up step. Needs an attendee email, which phone callers rarely give, so a placeholder is used (see limitations) |
| Telegram | Sends the designer handoff | See the next section |
| HubSpot | CRM | Qualified calls become deals automatically on the free tier. No deal amount is set, because the agent never estimates value |
| Vercel | Hosts the dashboard (and the call endpoints) | Free tier, deploys from GitHub, no server to manage |
| GitHub | Version control | Progress saved between sessions |
I chose Telegram because the handoff only works if a designer sees it in the next few minutes, and designers live on their phones, on site, not in an inbox: a Telegram message buzzes a phone and gets read in seconds, while an email waits for a desk and competes with every other message, which brings back exactly the next-day delay Nikhil is trying to remove. A shared designers' group also lets the whole team see a new lead at once and one person reply "taking this", something a forwarded email can't do. It costs nothing and the message is plain text, so a caller's words can't break or inject formatting. The trade-offs are real and I'd say them out loud: it only works if designers actually use Telegram (to confirm with the team), the group holds phone numbers so membership must be controlled, and it isn't a durable record, which is why every note is also stored in the database and HubSpot deal. Email through Resend would be the fallback if the team won't use Telegram, and it would be a small adapter to add.
Caller -> Vaani (answers, speaks; its AI follows the instructions in docs/vaani-agent-instructions.md)
|-- calls qualify_enquiry -> my rules: verdict + exact words to say (existing client: senior team alerted at once)
|-- calls check_availability / book_consultation -> Cal.com, booked inside the call
`-- when the call ends: "call.completed" webhook with the transcript
|
v my server (Vercel)
judge the transcript turn by turn (Gemini reads the facts, plain code decides)
audit what the agent said (price quoted? scripted lines used?)
qualified -> Telegram handoff note + HubSpot deal
everything -> call row + cost rows (Neon); breaches -> senior Telegram alert
Dashboard (Vercel) reads the call log.
The decision engine is the same code in every path. What changed is who speaks: Vaani's AI, guided by instructions and my tools, instead of my server writing each line.
The real platform is app.vaanivoice.ai (docs at docs.vaanivoice.ai). What is set up there:
docs/vaani-agent-instructions.md (regenerate with npm run vaani:docs), OpenAI gpt-4o at temperature 0, greeting left blank so it follows the instructions.https://aangan-phone-agent.vercel.app/api/webhooks/vaani. Vaani's webhooks have no documented signature, so the server verifies each event by asking Vaani's API (call_details) whether that call exists and fetching the transcript from there. A forged call id gets a 404 and does nothing.aangan_desk is created in Vaani (rules, availability, booking) and the server side is built and tested, but it is switched off. In testing, Vaani's AI never called it and instead read the tool's name aloud. It stays off until a voice test shows tool calls working.Consequences, stated plainly: the agent cannot book during the call. It tells the caller the designer will phone to confirm a time. After the call the server books the time the caller chose, if it is free (see above), and the designer is told to phone and confirm. A call that captured nothing about the project is logged as dropped, not as a lead.
The qualification logic knows nothing about phones: it takes extracted facts and returns a verdict and the next thing to say. That's the part that carries over.
turn handler, keyed by the sender's number; the reply is sent as text. The same engine, scripts, booking, handoff and CRM steps apply. After-hours WhatsApp messages (like W01 and W05 in the transcripts, left unanswered until the next working day) would be answered at once.channel column exists; it's constrained to phone today).Vercel does not bundle the shared code the functions import, so each function in api-src/ is bundled into one file in api/ by esbuild. After changing any code run:
npm run build:api # api-src/*.ts -> api/*.js (commit the result)
vercel deploy --prod
Environment variables live in Vercel's production settings (secrets marked sensitive). Never commit .env.
Requires Node 22.18+ (or 24). No dependencies to install.
npm test # 95 tests
npm run test:transcripts # T01-T20 table
npm run simulate # talk to the old turn-by-turn brain in the terminal (mock services)
npm run vaani:docs # regenerate the text to paste into Vaani (docs/)
npm run live:webhook # replay T01-T20 through the real after-call pipeline with live Gemini
npm run dashboard:dev # dashboard with SAMPLE data on :8788, password "demo"
npm run serve # local call endpoints on :8787
Without keys everything runs on mocks. Each service switches to the real one as soon as its keys are in .env (copy .env.example). Database setup: put DATABASE_URL in .env and run npm run db:migrate (applies db/migrations/*.sql once each). npm run db:smoke writes and deletes one test call to check the connection.
src/core/ rules: config, scripts, qualification, pricing guard, FAQ, costs, handoff
src/session/ the live call (resumable from the database)
src/integrations/ Gemini, Cal.com, Telegram, HubSpot (+ mocks)
src/voice/ brain endpoints and the Vaani webhook receiver
src/db/ repositories, recorder, summaries, dashboard data
src/fixtures/ T01-T20 as facts, harness, sample-data seed
public/, api/ dashboard page and Vercel functions
db/migrations/ SQL
test/ 95 tests