A step‑by‑step guide to running the full Echo stack locally: the Convex backend, the operator dashboard, the widget, and (optionally) the embed loader.
For a conceptual overview first, read architecture.md. For production, see deployment.md.
- Prerequisites
- Step 1 — Clone & install
- Step 2 — Convex
- Step 3 — Clerk
- Step 4 — Google Gemini
- Step 5 — Environment variables
- Step 6 — Optional: Vapi + AWS (voice)
- Step 7 — Optional: Sentry
- Step 8 — Run everything
- Step 9 — First‑run walkthrough
- Troubleshooting
| Tool | Version |
|---|---|
| Node.js | >= 20 |
| pnpm | >= 10.33 (repo pins pnpm@10.33.4) |
| Git | latest |
Accounts (free tiers work): Convex, Clerk, Google AI Studio. Optional: Vapi, AWS, Sentry.
git clone https://github.com/RISHII7/echo.git
cd echo
pnpm installConvex is the backend and database. Provision a dev deployment:
pnpm --filter backend devOn first run this logs you in, creates a project, and prints your deployment URL (https://<name>.convex.cloud). Keep this terminal running — it hot‑reloads functions. Note the URL for NEXT_PUBLIC_CONVEX_URL.
Backend secrets are set on the Convex dashboard (Settings → Environment Variables) or via npx convex env set KEY value — not just in .env.local, because functions run on Convex's servers.
- Create a Clerk application and enable Organizations (Organizations → Settings).
- Create a JWT template named
convex(JWT Templates → New → Convex). Copy its Issuer URL. - From API Keys, copy your Publishable key (
pk_test_…) and Secret key (sk_test_…). - (For billing) enable Billing and create a plan with the key
pro. - (For the webhook, optional locally) create a webhook endpoint pointing at
<convex-site>/clerk-webhooksubscribed tosubscription.updated, and copy its signing secret.
Set in the Convex dashboard:
CLERK_JWT_ISSUER_DOMAIN= theconvextemplate's Issuer URLCLERK_SECRET_KEY=sk_test_…CLERK_WEBHOOK_SECRET= the webhook signing secret (if using billing)
- Get an API key from Google AI Studio.
- Set it in the Convex dashboard:
GOOGLE_GENERATIVE_AI_API_KEY.
This powers the chat agent (gemini-2.5-flash), text extraction, and embeddings (gemini-embedding-001).
apps/web/.env.local
NEXT_PUBLIC_CONVEX_URL=https://<your-deployment>.convex.cloud
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...apps/widget/.env.local
NEXT_PUBLIC_CONVEX_URL=https://<your-deployment>.convex.cloudConvex dashboard (backend): CLERK_JWT_ISSUER_DOMAIN, CLERK_SECRET_KEY, CLERK_WEBHOOK_SECRET, GOOGLE_GENERATIVE_AI_API_KEY, and (for voice) AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY.
Voice is a Pro plugin. To enable it:
- AWS — create an IAM user with a policy allowing
secretsmanager:CreateSecret,secretsmanager:PutSecretValue, andsecretsmanager:GetSecretValueonarn:aws:secretsmanager:*:*:secret:tenant/*. SetAWS_REGION,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEYin the Convex dashboard. - Vapi — create an assistant and copy your public and private API keys from the Vapi dashboard.
- In Echo, go to Plugins → Vapi, connect the keys, then pick the assistant/number in Widget Customization.
See voice.md for the full flow and security model.
For source‑map upload on build, create apps/web/.env.sentry-build-plugin:
SENTRY_AUTH_TOKEN=...The Sentry org/project are configured in apps/web/next.config.ts.
# All apps + Convex via Turborepo
pnpm devor individually:
pnpm --filter backend dev # Convex functions (keep running)
pnpm --filter web dev # Dashboard → http://localhost:3000
pnpm --filter widget dev # Widget → http://localhost:3001
pnpm --filter embed dev # Embed demo → http://localhost:3002/demo.htmlflowchart LR
a["Sign in at :3000"] --> b["Create an organization"]
b --> c["Upgrade to Pro<br/>(billing page)"]
c --> d["Upload a doc<br/>(Knowledge Base)"]
d --> e["Customize greeting"]
e --> f["Open widget with your org ID"]
style f fill:#f0fff4,stroke:#3FB62F
-
Visit
http://localhost:3000, sign in, and create an organization. -
Copy your organization ID from the Integrations page (
org_…). -
(For AI) subscribe to Pro on the billing page so AI features unlock.
-
Under Knowledge Base, upload a PDF/TXT so the agent has something to answer from.
-
Under Widget Customization, set a greeting and suggestions.
-
Open the widget with your org ID:
http://localhost:3001/?organizationId=org_XXXXXXXXXXXXXXXXXXXX -
Start a chat and ask a question your uploaded doc answers.
| Symptom | Likely cause | Fix |
|---|---|---|
| Widget shows the error screen | Org ID invalid or organizations.validate failing |
Check the ?organizationId= value; ensure CLERK_SECRET_KEY is set in the Convex dashboard |
| Widget stuck on loading | Missing NEXT_PUBLIC_CONVEX_URL in the widget |
Add it to apps/widget/.env.local |
| AI never responds | No active subscription, or conversation escalated/resolved | Subscribe to Pro; check conversation status |
| File upload fails | Not on Pro, or Gemini key missing | Subscribe; set GOOGLE_GENERATIVE_AI_API_KEY in Convex |
| Embedding errors on upload | Wrong embedding model/dimension | Uses gemini-embedding-001 at 1536‑dim by design |
| Voice option missing | No Vapi plugin / assistant configured | Connect Vapi and pick an assistant in Customization |
AccessDenied from AWS |
IAM policy missing GetSecretValue |
Add the Secrets Manager permissions above |
| Convex function has stale env | Secret only in .env.local |
Set it in the Convex dashboard (npx convex env set) |
| Editor shows phantom type errors after installs | Stale TS server / .next cache |
Restart the TS server; delete apps/web/.next if needed |
Next: Deployment Guide · Embedding the Widget