Stack
- Runtime: Node.js v18+
- Bot interface: Telegram (via BotFather)
- AI: Claude (Anthropic API)
- Prospecting: Google Places API (New)
- Database: Supabase (PostgreSQL)
- Editor: Cursor IDE + Claude Code
Total setup time: ~35 minutes
This is the complete setup guide for the AI Agency OS — a Telegram bot that runs your prospecting pipeline, manages your client roster, and gives you a command interface for your agency from your phone.
You’ll start from zero accounts and end with a live bot that can find local businesses, test their contact funnels, research them with AI, and store everything in a structured database.
Pre-Flight Checklist
Before you touch the terminal, get these accounts and pieces of software ready. The setup goes faster when you’re not stopping to create accounts mid-way.
Accounts You’ll Need
- Anthropic account — add $10–20 in credits to get started. console.anthropic.com
- Telegram account — you’ll also need the app on your phone. telegram.org
- Google account — needed for Google Voice and the optional Sheets integration.
- Google Cloud account — free to create, needed for the Places API key. console.cloud.google.com
- Supabase account — free tier is sufficient to start. supabase.com
Software to Install
- Node.js v18+ — the runtime that powers the server. nodejs.org
- Cursor IDE — AI-native code editor, recommended for managing the project. cursor.com
- Claude Code — install via terminal after Node.js is ready:
npm install -g @anthropic-ai/claude-code
Things to Prepare
- Google Voice number — claim a free number at voice.google.com. This will be your test lead identity for funnel testing.
- Test name variation — create a believable fake name like “John T” or “Sarah M” for contact form submissions.
- Google Sheet ID (optional) — if you have an existing prospect sheet, grab the ID from the URL.
Phase 1 — Create Your Telegram Bot
5 min — Set up the bot that will be your command interface.
1. Open Telegram and search for @BotFather
This is Telegram’s official bot creation service. Tap Start.
2. Send /newbot and follow the prompts
You’ll choose a display name (e.g. “Agency OS”) and a username ending in _bot (e.g. myagencyos_bot).
3. Copy your API token
BotFather will send you an API token — a long string like 7412305678:AAF.... Copy this and save it somewhere safe. You’ll paste it in your .env file shortly.
4. Get your personal Chat ID
Search for @userinfobot in Telegram and send any message to it. It will reply with your numeric user ID (e.g. 123456789). Copy that number.
Never share your bot token publicly. Anyone with your token can control your bot. If it gets exposed, go back to @BotFather, send /mybots, select your bot, choose API Token → Revoke current token.
Phase 2 — Get Your API Keys
10 min — Anthropic, Google Maps, and Supabase credentials.
Anthropic API Key
1. Go to console.anthropic.com
Click API Keys in the sidebar → Create Key.
2. Name it and copy
Name it agency-bot and click Create. Copy the key immediately — it is only shown once. It starts with sk-ant-...
Make sure your Anthropic account has a payment method and at least $10–20 in credits. The system uses Claude for research and analysis tasks.
Google Maps API Key
1. Go to console.cloud.google.com
Navigate to APIs & Services → Library.
2. Enable Places API (New)
Search for “Places API (New)” and click Enable. Do NOT enable the old Places API.
3. Create the API Key
Go to APIs & Services → Credentials → Create Credentials → API Key. Copy the key (starts with AIza...).
4. Restrict the key (optional but recommended)
Click Edit API Key → under Application Restrictions, set it to IP addresses and add your server IP for security.
Supabase Credentials
1. Create a new project
Go to supabase.com → click New Project. Name it something like “agency-os” and set a strong database password.
2. Navigate to Settings → API
Once the project is ready, go to Project Settings → API.
3. Copy two values
- Project URL — e.g.
https://xxxx.supabase.co - anon / public key — the long
eyJ...string
Use the anon / publishable key — NOT the secret service_role key. The anon key is safe to use in server-side code with Row Level Security.
Phase 3 — Set Up the Project
15 min — Clone the repo, install dependencies, and configure your environment.
Clone and Install
git clone [your-repo-url]
cd elons-agent
npm install
The install step downloads Puppeteer (a headless browser) which may take 1–2 minutes as it downloads Chromium. This is normal.
Create Your .env File
Create a file named .env in the root of the project folder and paste in the following, replacing each value with your actual keys:
# ── Anthropic (Claude AI) ──────────────────────
ANTHROPIC_API_KEY=your-key-here
# ── Telegram ───────────────────────────────────
TELEGRAM_BOT_TOKEN=from-botfather
TELEGRAM_ALLOWED_CHAT_IDS=your-numeric-id
# ── Google ─────────────────────────────────────
GOOGLE_MAPS_API_KEY=your-google-key
GOOGLE_VOICE_NUMBER=+15551234567
# ── Test Lead Identity ─────────────────────────
TEST_LEAD_NAME=Your Test Name
TEST_LEAD_EMAIL=your-gmail@gmail.com
# ── Supabase ───────────────────────────────────
SUPABASE_URL=https://xxx.supabase.co
SUPABASE_ANON_KEY=eyJ...
# ── Server ─────────────────────────────────────
PORT=3000
NODE_ENV=development
Variable Reference
| Variable | Example Value | Description |
|---|---|---|
ANTHROPIC_API_KEY | sk-ant-api03-... | From Anthropic Console → API Keys |
TELEGRAM_BOT_TOKEN | 7412305678:AAF... | From @BotFather when you created the bot |
TELEGRAM_ALLOWED_CHAT_IDS | 123456789 | Your numeric ID from @userinfobot |
GOOGLE_MAPS_API_KEY | AIzaSy... | Google Cloud → Credentials. Places API must be enabled. |
GOOGLE_VOICE_NUMBER | +15551234567 | Your Google Voice number (with country code) |
TEST_LEAD_NAME | John T | Fake name used when submitting contact forms |
TEST_LEAD_EMAIL | test@gmail.com | Your Google Voice Gmail (receives form replies) |
SUPABASE_URL | https://xxx.supabase.co | Project URL from Supabase Settings → API |
SUPABASE_ANON_KEY | eyJ... | anon/public key from Supabase Settings → API |
PORT | 3000 | HTTP port the server listens on |
NODE_ENV | development | Set to production when deployed to a server |
Phase 4 — Set Up the Database
5 min — Run the migration to create your prospects table in Supabase.
1. Find the migration file
In your project folder, open data/migrations/001_create_prospects.sql. Copy the entire contents.
2. Open the Supabase SQL Editor
Go to your Supabase dashboard → select your project → click SQL Editor in the left sidebar.
3. Paste and run
Click the + icon to create a new query. Paste the SQL. Click Run (or press Cmd+Enter). You should see: Success. No rows returned.
4. Verify
Click Table Editor in the sidebar — you should see a prospects table listed.
The prospects table tracks every lead through the full pipeline: new → funnel_tested → researched → called → signed. Every command you run feeds into and reads from this table.
Phase 5 — Launch and Test
5 min — Start the server and verify everything is connected.
Start the Server
npm run dev
Expected Output
✓ Telegram bot initialized
✓ Supabase connected
✓ Server running on port 3000
Test Commands — Send These to Your Bot
/start— should reply with a welcome message/dashboard— should reply with agency overview stats/status— system health check, should confirm all services online/prospect roofing companies [Your City] 3— runs the full prospecting pipeline (takes ~1–2 min)
Telegram Command Reference
| Command | Description |
|---|---|
/start | Welcome message and quick-start overview |
/dashboard | Agency overview — client count, pipeline stats, recent activity |
/newclient | Add a new client to your roster (interactive wizard) |
/clients | List all active clients with status overview |
/deleteclient [id] | Remove a client by their ID (get the ID from /clients) |
/status | System health check — confirms API connections are live |
/prospect [niche] [city] [count] | Launch the full prospecting pipeline: scrape → test funnels → research → brief |
/help | Show full command list with usage examples |
Troubleshooting
Bot not responding to my messages
This is almost always a configuration issue. Check in order:
- Verify
TELEGRAM_BOT_TOKENin your.envmatches exactly what BotFather gave you — no extra spaces or quotes - Verify
TELEGRAM_ALLOWED_CHAT_IDSis your numeric user ID (from @userinfobot) — not a username - Restart the server with
npm run devafter making any.envchanges (the server doesn’t auto-reload env vars) - Make sure you messaged your bot (the one you created), not BotFather
Places API returns REQUEST_DENIED
The API key exists but doesn’t have access to the Places API.
- Go to console.cloud.google.com → APIs & Services → Library
- Search for “Places API (New)” — make sure it shows as Enabled (not the legacy Places API)
- If billing isn’t set up, add a credit card (Google gives $200/month free credits)
- Wait 1–2 minutes for the API activation to propagate, then retry
Claude Code authentication expired
If Claude Code stops working or throws an auth error, reset the auth file and re-authenticate:
rm -rf ~/.claude/auth.json
claude
This will open a browser login flow. Complete it and Claude Code will be re-authenticated.
Supabase connection error on startup
Two common mistakes:
SUPABASE_URLmust end with.supabase.co— copy it exactly from Settings → API, don’t retype itSUPABASE_ANON_KEYmust be the anon / public key (starts witheyJ) — NOT the secretservice_rolekey- Make sure there are no trailing spaces or invisible characters in your
.envvalues
npm install fails or Puppeteer won’t install
Puppeteer downloads Chromium during install and can fail on some systems.
node --version # Must be v18 or higher
npm cache clean --force
npm install
If you’re on an M1/M2 Mac and Chromium errors, try: PUPPETEER_SKIP_DOWNLOAD=true npm install then configure Puppeteer to use your system Chrome.
Follow @natevanwag on IG for more AI agency builds.