ai-startup-skills
创业公司做 AI 产品的 7 步 Agent Skill 合集:验证 → BP → 政策 → 路演 → 获客 → 定价 → 注册。
Translation pending
Every call to Aangan Studio, beautifully handled.
Translation pending
OtherTypeScript · CSSGitHub @wholikescaramel-blipOnlineOwner 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 ↗A Vaani voice agent answers every inbound call. After the call, Gemini judges whether the caller is a lead worth a designer's time, using the studio's own rubric. Every call is logged in HubSpot. Real leads become deals and are posted to a Telegram group with one I'll take it button. A Cal.com booking moves the deal forward.
Metrics:
flowchart LR
caller([Caller]) -->|phone, any hour| vaani[Vaani agent<br/>prompt v2]
vaani -->|end-of-call webhook| wh[/api/webhooks/vaani/]
wh -->|store once, 200 fast| neon[(Neon Postgres)]
wh -.after().-> q[Gemini qualification<br/>rules + services, never pricing]
q --> neon
q --> hs[HubSpot<br/>contact + call, deal if lead]
q -->|qualified / needs review| tg[Telegram group<br/>card + claim button]
tg -->|first tap wins| twh[/api/webhooks/telegram/]
twh --> neon
twh -->|assigned designer, stage DESIGNER_CONTACTED| hs
designer([Designer]) -->|calls back, sends Cal.com link| cal[Cal.com]
cal -->|BOOKING_CREATED / CANCELLED| cwh[/api/webhooks/calcom/]
cwh -->|stage CONSULT_BOOKED, meeting| hs
cwh --> tg
gha[GitHub Actions hourly] --> cron[/api/cron/sync/]
cron -->|deal stages, won values| neon
cron -->|retry failed calls| q
neon --> dash[/dashboard/]
Everything after the Vaani adapter works on a channel-agnostic Enquiry (lib/enquiry.ts), so
WhatsApp or a web form can be added later as new adapters.
| Path | What it does |
|---|---|
config/qualification_rules.md | The approved rubric (v1, with a decision log). Fed to Gemini. |
agent/vaani_prompt_v2.md | The voice agent's prompt (current). v1 is kept for comparison. |
agent/vaani_config_notes.md | Settings to enter in the Vaani dashboard |
knowledge/ | services.md, qualified.md, pricing.md (internal; never sent to any model or message), September transcripts |
lib/ | vaani adapter, pipeline, qualify (Gemini), hubspot, telegram, calcom, claim, price guard |
app/api/webhooks/{vaani,telegram,calcom} | Webhooks |
app/api/cron/sync | Hourly HubSpot stage sync and retry of failed calls |
app/dashboard | Dashboard (metrics, recent calls) and per-call transcript pages. Public by studio decision, hidden from search engines. |
migrations/ | SQL migrations (npm run migrate) |
tests/ | Unit tests, call simulations, 40-transcript qualification run |
APPROVED_PRICE_BAND_TEXT is empty by studio
decision). AI summaries are sanitised. Every Telegram message passes assertNoPrice or isn't sent.
The caller's own budget is stored in Neon but shown in Telegram only as "mentioned / not mentioned".(channel, external_id) key is unique, and each step stores its ids before moving on.robots.txt + noindex). Re-adding a login later is a small change.DRY_RUN=true (the default) skips HubSpot writes and sends Telegram cards only to the admin chat.| Service | What you need |
|---|---|
| Gemini | API key from Google AI Studio |
| Neon | A project (Singapore/Mumbai region) and its pooled connection string |
| HubSpot | Free CRM, super-admin user, a private app (see below) |
| Telegram | A bot from @BotFather, the designers' group with the bot added, your private chat with the bot |
| Cal.com | An event type with a required phone number question, and its public link |
| GitHub + Vercel | A private repo and a Vercel Hobby project importing it |
Copy .env.example to .env and fill it in. Set the same values in Vercel (Project → Settings →
Environment Variables; you can paste the whole file).
| Variable | Notes |
|---|---|
GEMINI_API_KEY, GEMINI_MODEL | Default model gemini-3.8-flash (2.5-flash isn't offered to new keys) |
GEMINI_FALLBACK_MODELS | Tried in order when the free daily quota of the main model runs out |
GEMINI_INPUT_PRICE, GEMINI_OUTPUT_PRICE | USD per 1M tokens, for the cost panel (0 on the free tier) |
CALLBACK_WINDOW_BUSINESS_HOURS / _AFTER_HOURS | within an hour / by eleven a.m. on the next working day |
APPROVED_PRICE_BAND_TEXT(_OFFICE) | Keep empty (no figures) |
VAANI_API_KEY, VAANI_WEBHOOK_SECRET, VAANI_COST_PER_MIN | Secret goes in the webhook URL or header |
DATABASE_URL | Neon pooled connection string |
HUBSPOT_TOKEN, HUBSPOT_PORTAL_ID, HUBSPOT_PIPELINE_ID, HUBSPOT_STAGE_* | npm run hubspot-setup prints these |
TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_ADMIN_CHAT_ID, TELEGRAM_WEBHOOK_SECRET, SEND_NEEDS_REVIEW | npm run telegram-setup -- chats lists chat ids |
CALCOM_WEBHOOK_SECRET, CALCOM_LINK | Secret is pasted into Cal.com's webhook form |
APP_BASE_URL | e.g. https://aangan-intake.vercel.app |
CRON_SECRET | Protects the hourly job endpoint |
FIXED_MONTHLY_COSTS_JSON | e.g. {"vaani_plan": 1500} (INR) |
DRY_RUN | true until you've tested end to end |
npm install
npm run migrate
crm.objects.contacts.read/writecrm.objects.deals.read/writecrm.schemas.contacts.read/writecrm.schemas.deals.read/writenpm run hubspot-setup. It checks the scopes, creates the 6 custom deal properties (the free
CRM allows 10 in total), and prints the HUBSPOT_* values for .env.knowledge/ holds internal pricing).APP_BASE_URL to the deployment URL and redeploy.APP_BASE_URL and CRON_SECRET. This enables
.github/workflows/hourly-sync.yml. Vercel Hobby cron can only run daily, so GitHub Actions runs it instead.npm run telegram-setup -- chats and put the group id in TELEGRAM_CHAT_ID and your private
chat id in TELEGRAM_ADMIN_CHAT_ID.npm run telegram-setup -- webhook. After this, typing /chatid in any chat shows its id.Follow agent/vaani_config_notes.md. In short:
npm run render-prompt.https://<app>/api/webhooks/vaani?token=<VAANI_WEBHOOK_SECRET>.https://<app>/api/webhooks/calcomCALCOM_WEBHOOK_SECRETCALCOM_LINK. It appears on every Telegram card.(The brief named Calendly, but Calendly webhooks need a paid plan. Cal.com's free plan includes signed webhooks, so no registration script is needed: the webhook is created in the Cal.com UI above.)
| Command | What |
|---|---|
npm test | Unit tests: phone normalisation, after-hours, idempotency and claim race (against Neon), HubSpot dedupe, Telegram formatting, Cal.com signature and matching, no-rupee assertion |
npm run simulate | Gemini plays 32 callers (17 from real phone transcripts, plus edge cases) against the agent prompt. An LLM judge scores each against the checklist. Report: tests/output/simulations/report_v2.md. Resumable across days on the free tier. |
npm run qualify-all | Runs all 40 September enquiries through qualification and writes tests/output/qualification_results.csv |
DRY_RUN=true./dashboard with its transcript.DRY_RUN=false in Vercel and redeploy. Cards then go to the group and
HubSpot gets written.handoffs WHERE claimed_at IS NULL AND posted_at < now() - interval '15 minutes',
posting reminders and DMing the owner. /api/cron/sync already runs hourly and is the place for it,
or run it more often from the same GitHub Action.claimed_by (with an audit row)
and re-posts.designers table (areas, project types, load), plus a function between
qualification and ensureTelegramPost that picks a designer and mentions them on the card.Enquiry. Everything
downstream already works per channel (calls.channel).