Setup & usage guide
Everything you need to create, embed, and manage AI chatbots with Bot Forge — by no-code dashboard, command line, or AI agent.
# Overview
Bot Forge is a multi-tenant chatbot platform. Each business is a tenant (one chatbot) identified by a tenantId. There are four ways to work with it:
- Embed — drop one
<script>tag on any website. - Console — no-code management at
/admin(sign in with email or Google). - CLI —
npx bot-forge, an interactive shell (or one-shot commands) for terminal control. - MCP — connect one URL to an AI agent (Claude) and it builds & manages bots as tools.
Sign in (or create a workspace) to get a console for your team — your workspace only ever sees its own clients. Base URL for everything: https://bot.ops4ge.com.
# Quickstart (5 minutes)
- Create your workspace — sign up at https://bot.ops4ge.com/signup (email + password or Google). You become the Owner of a fresh, empty workspace.
- Create a chatbot — via the console, the CLI (
bot-forge loginfirst), or just ask an agent (MCP). Pick atenantIdlikeacme. - Embed it — paste the snippet on the client's site:
<script src="https://bot.ops4ge.com/embed.v1.js" data-tenant="acme" defer></script>
# Concepts
- User — you sign in with email + password or Google. Your account belongs to one or more workspaces.
- Workspace (org) — a team's container. Tenants, API keys, leads, and usage all belong to a workspace; you only ever see your own.
- Role — Owner (full control), Admin (manage tenants, keys, members), Member (create/edit tenants). See Accounts & teams.
- Tenant — one chatbot for one business. The
data-tenantin the embed snippet selects it. - API key / token — authenticates the CLI / MCP / a project backend.
bot-forge loginmints one for you; or create one in the console for CI. Scope to one tenant to limit it. Stored hashed; shown once. - Provider — each tenant runs on Claude, GPT, or Gemini.
- RAG — optional vector search over the business's uploaded knowledge.
# Embed on a website
Paste once, right before </body>. Swap the tenant id:
<script src="https://bot.ops4ge.com/embed.v1.js" data-tenant="acme" defer></script>
The widget renders in a Shadow DOM, so it never clashes with the host site's CSS. It loads its branding automatically from https://bot.ops4ge.com/api/config?tenant=acme.
Branding (color, logo, greeting, tone) comes from the tenant config. Set autoTheme: true to sample the host page's accent color instead of a fixed brand color. Optional attribute data-api="https://bot.ops4ge.com" overrides the API origin.
The snippet loads /embed.v1.js — a version-pinned widget, so a future breaking change never ships silently to live sites (those land as /embed.v2.js).
# Voice vs chat
Every tenant can run two channels off the same knowledge and rules:
- Chat — the text widget (💬 bubble). Streams replies, shows booking buttons, captures leads. On by default.
- Voice — a human-like spoken agent (ElevenLabs Conversational AI). Same facts and guardrails as the chat bot, just a more conversational, spoken delivery. When enabled, a 🎙 button stacks directly above the chat bubble — a site can offer chat only, voice only conceptually, or both.
Both ship in the same one-line snippet — there's nothing extra to embed. The voice button only appears when the tenant has voice enabled:
<script src="https://bot.ops4ge.com/embed.v1.js" data-tenant="acme" defer></script>
Enable voice
Flip it on per tenant — dashboard (Tenants → Edit config → Voice bot), CLI, or create_chatbot/patch_chatbot (voiceEnabled):
npx bot-forge set acme voice.enabled=true npx bot-forge set acme voice.voiceId=<elevenlabs-voice-id> # optional npx bot-forge set acme voice.tone="warm, natural, conversational" # optional npx bot-forge set acme voice.firstMessage="Hi! How can I help?" # optional spoken greeting
In the console (Tenants → Edit config → Voice), the voice is a dropdown of your ElevenLabs voices — no need to paste an id (a custom-id field is still there if you want one). On the first voice session, Bot Forge provisions an ElevenLabs agent for that tenant (synced from its facts) and reuses it after that.
Voice needs ELEVENLABS_API_KEY set on the server — without it, voice stays off and the chat bot is unaffected. Twilio is not required to embed voice on a website; it's only for a later phase (linking a phone number to an agent for phone/SMS). Leads spoken during a call are captured via a post-call webhook, same as chat.
Try it live: the demo widget on the home page and /demo.html has both — tap 💬 to chat or 🎙 to talk.
# Chat protocol & security
Allowed domains (who can embed a bot)
Each tenant has an allowedDomains list that controls which origins may use its chatbot — this stops anyone copying a public data-tenant id and running the bot (and your LLM bill) from their own site.
- Empty / unset — locked down: only same-origin requests work.
/api/chatrejects other origins with403 ORIGIN_NOT_ALLOWEDbefore calling the model. - List of origins — only those exact origins, e.g.
["https://acme.com","https://www.acme.com"]. - ["*"] — any site may embed it. Public demos only.
Set it in the dashboard (Tenants → Edit config → Allowed domains), the CLI (npx bot-forge domains acme https://acme.com), or on create_chatbot. /api/configonly ever exposes branding/booking/leadCapture — never facts or the system prompt.
Chat wire protocol (SSE)
Only needed if you build a custom UI instead of the widget. POST /api/chat with { tenantId, sessionId, messages:[{role,content}] } returns Server-Sent Events:
event: meta data: { "provider": "...", "model": "..." } // once at start
event: text data: { "delta": "..." } // incremental reply text
event: booking data: { "options": {...}, "reason": "..." } // show booking buttons
event: lead data: { "captured": true } // a lead was saved
event: done data: {} // turn complete
event: error data: { "message": "..." }# Console (no-code)
Sign in at https://bot.ops4ge.com/login with email + password or Google. The console is scoped to your workspace — you only see your own clients. From there:
- Tenants — view config, pick the voice, manage each chatbot's RAG knowledge.
- Leads — every captured contact with intent.
- Conversations — full transcripts.
- Team — invite members, set roles (Owner/Admin).
- API keys — create / scope / revoke keys for CI & integrations.
- Account — set or change your password.
# Accounts & teams
Bot Forge is multi-tenant for your team too. Each account belongs to a workspace that owns its tenants, keys, leads, and usage — fully isolated from other workspaces.
Sign in
- Email + password — sign up at /signup; manage your password under Account.
- Google — one-click sign-in; first sign-in creates your workspace automatically.
Roles
| Role | Can |
|---|---|
Owner | Everything — including billing/ownership of the workspace. |
Admin | Manage tenants, API keys, and team members (invite/role/remove). |
Member | Create and edit the workspace's tenants. |
Invite teammates
Console → Team → invite by email (as Admin or Member). Send them the generated link; they sign in (or sign up) and join your workspace.
New sign-ups always start with an empty workspace. Inviting an existing user adds them to yours — they may need to sign out and back in for the new workspace to become active.
# API keys & CLI login
There are two ways to authenticate programmatic access:
- CLI login (recommended) — run
bot-forge login. It opens a browser approval (the OAuth device flow), links this device to your account, and stores a token for you.bot-forge logoutrevokes it. - API key (CI / backends) — create one in the console at /admin/keys. Use it as the
BOTFORGE_API_KEYenv var, anAuthorization: Bearerheader (MCP / HTTP), orx-api-key(REST).
Either way the token belongs to your workspace; scope it to a single tenant for least privilege, and revoke anytime (logout, or the console). Secrets are shown once — store them safely.
# CLI — npx bot-forge
No install needed (npx), or npm i -g bot-forgefor a bare bot-forge. First, link this device to your account — it opens a browser approval and stores the token in ~/.bot-forge, so you never have to paste a key:
npx bot-forge login # opens the browser to approve this device # → Linked as you@email.com — owner of Your Workspace
CI or headless? Paste a token instead: bot-forge login <bf_live_…>, or set BOTFORGE_API_KEY. bot-forge logout revokes the device token server-side.
Interactive shell
Run bot-forge with no command to enter a branded shell: Tab completes commands and tenant ids, ↑/↓ walks history, live spinners show progress, and your working directory appears in the status panel. Type exit (or Ctrl-C) to leave.
npx bot-forge # or: bot-forge shell forge › whoami forge › create acme.json forge › test acme "what are your hours?" forge › usage --by day forge › embed acme
One-shot commands
Every command also runs directly — ideal for scripts & CI:
npx bot-forge whoami # verify key + list chatbots
npx bot-forge list # list chatbots
npx bot-forge create acme.json # create/update from JSON
npx bot-forge set acme branding.greeting="Hi!" # update fields
npx bot-forge domains acme https://acme.com # set allowed embed domains
npx bot-forge knowledge acme faq.txt # ingest RAG ('-' = stdin); list|clear too
npx bot-forge models # valid model ids per provider
npx bot-forge test acme "your hours?" # ask the bot, print its reply
npx bot-forge usage --by day # tokens, minutes & cost report
npx bot-forge leads acme # list captured leads
npx bot-forge embed acme # print the <script> snippet
npx bot-forge prime # print the /prime onboarding promptAccount & CLI
npx bot-forge login # link this device (browser approval) npx bot-forge login bf_live_... # or paste a token (CI / headless) npx bot-forge whoami # who you're linked as + chatbots npx bot-forge logout # revoke this device's token + clear it npx bot-forge version # version + check npm for updates (alias: -v) npx bot-forge update # upgrade to the latest release npx bot-forge help # full, colour-coded command list
Auth resolves in this order: BOTFORGE_API_KEY env var → a .env in the current folder → the token saved by login (in ~/.bot-forge). BOTFORGE_URL overrides the base URL (defaults to production).
Tenant JSON for create:
{
"tenantId": "acme",
"provider": "anthropic",
"branding": { "name": "Acme Plumbing", "primaryColor": "#0ea5e9",
"greeting": "Hi! Need a plumber? Ask me anything." },
"knowledge": { "facts": "Open Mon-Sat 7-7. Emergency repairs, water heaters...",
"tone": "friendly and reassuring", "ragEnabled": false },
"booking": { "calendly": "https://calendly.com/acme/visit" },
"leadCapture": true
}# MCP — let an agent build chatbots
Connect the Bot Forge MCP server to an AI agent (Claude Code, Claude Desktop, Cursor, …) and it builds & manages chatbots as tools — create, add knowledge, test, pull leads, get the embed snippet — all in plain conversation. Three steps.
Step 1 — Connect the agent (one URL)
Hosted, nothing to install. Point your agent at the MCP URL with your key as a Bearer token. Claude Code, one line (bash, zsh, PowerShell):
claude mcp add --transport http bot-forge https://bot.ops4ge.com/api/mcp --header "Authorization: Bearer bf_live_..."
Or add it to .mcp.json / Claude Desktop:
{
"mcpServers": {
"bot-forge": {
"type": "http",
"url": "https://bot.ops4ge.com/api/mcp",
"headers": { "Authorization": "Bearer bf_live_..." }
}
}
}On connect, the server's initializeresponse briefs the agent on every tool, the chat protocol, valid models, and the allowedDomains security model — so it knows the whole surface without probing. The token is a Bot Forge API key (from Console → API keys) — use a tenant-scoped key so an agent can only touch one client. Offline? Local stdio instead — it reuses your bot-forge login token automatically, or pass one explicitly: claude mcp add bot-forge -e BOTFORGE_API_KEY=bf_live_... -- npx -y -p bot-forge bot-forge-mcp.
Step 2 — Give it a starter prompt
That one URL is everything the agent needs. Just describe the business in plain language and let it drive the tools:
Using the Bot Forge MCP server, create a chatbot for Acme Plumbing (tenant id "acme"). Facts: open Mon-Sat 7-7, emergency repairs and water heaters, serving the Phoenix metro. Friendly, reassuring tone. Booking: https://calendly.com/acme/visit. Only allow it to embed on https://acme.com. Then test it with a few real questions and give me the embed snippet.
The agent calls create_chatbot, test_message, and get_embed_snippet for you and hands back the ready-to-paste <script>.
Step 3 — Or /prime a client's codebase
To build a bot from a client's own repo or website, open your agent in that project (with the MCP connected) and run:
npx bot-forge prime # prints the /prime prompt — paste it to your agent
# (or use the /prime slash command if your agent has one)The agent studies the codebase, drafts the facts and branding, detects the production domain for allowedDomains, creates the bot, verifies it with test_message, and returns the embed snippet — asking you only for what it genuinely can't infer. Review its summary and you're live.
Tools
whoami, list_models, list_chatbots, get_chatbot, create_chatbot, patch_chatbot, delete_chatbot, add_knowledge, list_knowledge, delete_knowledge, test_message, list_leads, get_embed_snippet.
# RAG knowledge
For larger knowledge bases, enable vector retrieval so answers stay grounded in the business's own docs.
- Backend prereqs: MongoDB Atlas +
OPENAI_API_KEY, and runnpm run setup-dbonce (creates the vector index). - Set
ragEnabled: trueon the tenant. - Ingest text — dashboard (Tenants → pick one → paste), CLI (
npx bot-forge knowledge acme faq.txt), or MCP (add_knowledge).
Without RAG, the chatbot still answers from the knowledge.facts field — plenty for most small businesses.
# Providers & models
Each tenant picks a provider and optional model:
| Provider | Default model | Good for |
|---|---|---|
| anthropic | claude-haiku-4-5 | Default — fast, cheap, great quality |
| openai | gpt-4o-mini | OpenAI ecosystem |
gemini-2.0-flash | Gemini ecosystem |
Set a stronger model (e.g. claude-sonnet-4-6) for complex knowledge bases. The matching API key must be set on the server.
# Tips & tricks
- Scope keys per client — give an agent or project a tenant-scoped key so it can only touch that one chatbot.
- Shell matters —
export VAR=…is bash; on Windows use$env:VAR="…". - Booking — add Calendly / Google Meet / Zoom links; the bot shows buttons when a visitor wants to book.
- Lead alerts — set a tenant
ownerEmail(Resend),slackWebhook, orleadWebhook(POSTs each lead to your CRM) to get notified instantly. - Auto-theme —
autoTheme: truemakes the widget match the host site's accent. - Rate limits — tune
RATE_LIMIT_PER_SESSION/_PER_IP/_WINDOW_SEC. - Restrict embedding — always set a tenant's
allowedDomainsto the client's origins. Empty = locked to same-origin;["*"]= any site (demos only). See Chat protocol & security.
# Troubleshooting
npx bot-forge login and approve the device in the browser — the token is saved to ~/.bot-forge for every future session. (An env var BOTFORGE_API_KEY or a .env file still work and take precedence; for CI use bot-forge login <token>.)https://bot.ops4ge.com/api/auth/callback/googleregistered on the OAuth client. If login 500s, confirm AUTH_SECRET is set on the server. Email + password works without any Google config.0.0.0.0/0 under Atlas → Network Access (Vercel uses dynamic IPs), confirm MONGODB_URIis set, and redeploy.--transport http and an Authorization: Bearer bf_live_… header pointing at https://bot.ops4ge.com/api/mcp. Make sure the key isn't revoked. claude mcp list shows status.ragEnabled: true, OPENAI_API_KEY is set, npm run setup-db built the vector index, and you've ingested text for that tenant.data-tenant matches a real tenant, the snippet is before </body>, and the browser console for errors.# Reference
Endpoints
POST /api/chat— streaming chat (used by the widget)GET /api/config?tenant=…— public branding configGET|POST /api/v1/tenants·GET|PATCH|DELETE /api/v1/tenants/:idPOST|GET|DELETE /api/v1/knowledge·GET /api/v1/leadsPOST /api/v1/test·GET /api/v1/models·GET /api/v1/whoami(returns user/org/role)POST /api/mcp— hosted MCP (Bearer auth)/api/auth/*— sign-in (Auth.js) ·POST /api/oauth/device/start|token— CLI device loginPOST /api/voice/session— mint a signed voice session ·POST /api/voice/webhook— ElevenLabs post-call hook/embed.v1.js— the version-pinned widget loader
Key env vars (server)
ANTHROPIC_API_KEY/OPENAI_API_KEY/GOOGLE_GENERATIVE_AI_API_KEYMONGODB_URI·AUTH_SECRET·AUTH_GOOGLE_ID+AUTH_GOOGLE_SECRET(Google sign-in) ·ADMIN_API_KEY(legacy superadmin)RESEND_API_KEY+LEAD_EMAIL_FROM·SLACK_WEBHOOK_URLELEVENLABS_API_KEY(+ELEVENLABS_DEFAULT_VOICE_ID,ELEVENLABS_WEBHOOK_SECRET) — voice bot
Full details in the repo README.