CLI Documentation
Everything you need to know about the Calabasas CLI
New? Start with the Getting Started guide
Build a working bot with /ping and /server-info in under 10 minutes
Quickstart
Get up and running with Calabasas in under 5 minutes. This guide assumes you have a Convex project set up already.
Authenticate with your Calabasas account
npx calabasas loginInitialize the config file in your Convex project
npx calabasas initRegister your Discord bot
npx calabasas bot addGenerate type-safe handlers
npx calabasas generateAdd the generated tables to your Convex schema
// convex/schema.ts
import { defineSchema } from "convex/server";
import { calabasasTables } from "./calabasas/schema";
export default defineSchema({
...calabasasTables,
// your other tables...
});Then re-export sync mutations in convex/discord.ts:
export { syncGuild, syncChannel, syncRole, syncMember } from "./calabasas/sync";Push your configuration to Calabasas
npx calabasas push.env.local
Set these variables in your project's .env.local to avoid passing --bot on every command. The CLI reads this file automatically.
# .env.local
CALABASAS_BOT_ID=abc123 # Bot ID
CALABASAS_PLATFORM_API_KEY=cpk_abc123 # Platform API keyCLI flags always take priority over .env.local values.
calabasas bot add will offer to write these automatically after creating a bot.
Authentication
Login
calabasas loginAuthenticate with Calabasas using OAuth. Opens your browser to complete the authentication flow and stores your API key locally for future commands.
Example
npx calabasas login
# Output:
# Opening browser for authentication...
# Waiting for authentication (timeout: 5 minutes)...
# ✓ Authenticated as developer@example.com
# API key saved to ~/.calabasas/config.jsonYour credentials are stored in ~/.calabasas/config.json
Authentication expires after a period of inactivity
Logout
calabasas logoutClear your stored credentials. Use this when switching accounts or to remove local authentication data.
Example
npx calabasas logout
# Output:
# ✓ Logged out successfullyProject Setup
Initialize Config
calabasas initCreate a calabasas.config.ts file in your Convex project. This file defines which Discord events to handle and what data to sync.
Example
npx calabasas init
# Creates convex/calabasas.config.ts with:
import { defineCalabasas } from "calabasas";
export default defineCalabasas({
// Sync Discord data to Convex tables
sync: {
guilds: true,
channels: true,
roles: true,
members: false, // Requires privileged intent
},
// Events to handle
events: {
messageCreate: true,
interactionCreate: true,
guildMemberAdd: true,
},
});Requires a convex/ directory in your project
Will not overwrite an existing config file
Bot Management
Add Bot
calabasas bot addRegister a new Discord bot with Calabasas. Runs an interactive wizard by default, or pass all flags for fully non-interactive use (great for scripts and AI agents). After creating the bot, offers to save CALABASAS_BOT_ID to .env.local.
Options
-n, --name <name>Bot name-a, --app-id <id>Discord Application ID-t, --token <token>Bot token-i, --intents <intents>Intents value (number, default: 513)Example
# Interactive mode
npx calabasas bot add
# Non-interactive mode (all required flags)
npx calabasas bot add \
-n "my-bot" \
-a 123456789012345678 \
-t "BOT_TOKEN"
# ✓ Bot registered successfully
# Saved to .env.local:
# CALABASAS_BOT_ID=abc123Bot tokens are encrypted before storage
Privileged intents require approval in the Discord Developer Portal
Bots inherit their Convex URL from the platform
Save the platform secret - you'll need it as CALABASAS_SECRET in your Convex deployment
When all flags are provided, .env.local is written automatically
List Bots
calabasas bot listDisplay all your registered Discord bots with their connection status and configuration. Shows a live-updating real-time view by default with status indicators, relative timestamps, and error details. Use --once for a static one-shot output.
Options
--onceOne-shot static output instead of real-time viewExample
npx calabasas bot list
# Real-time view (default):
# calabasas v0.2.3 · 2 bots · Press q to quit
#
# my-awesome-bot ● connected 123456789012345678 2m ago
# test-bot ● error 987654321098765432 5h ago
# Token expired
# Static output:
npx calabasas bot list --onceThe real-time view updates automatically via WebSocket subscriptions
Press q to quit the real-time view
Edit Bot
calabasas bot edit <botId>Update an existing bot's configuration. You can change the name, Convex URL, token, or gateway intents.
Options
-n, --name <name>New bot name-u, --url <url>New Convex URL-t, --token <token>New bot token-i, --intents <value>New intents value (numeric)Example
# Update bot name
npx calabasas bot edit abc123 --name "production-bot"
# Update Convex URL
npx calabasas bot edit abc123 --url "https://new-project.convex.cloud"
# Update multiple properties
npx calabasas bot edit abc123 -n "new-name" -u "https://new.convex.cloud"The gateway automatically reconnects with new settings
At least one option must be provided
Remove Bot
calabasas bot remove <botId>Delete a registered bot. This disconnects the bot from Discord and removes all associated configuration.
Options
-y, --yesSkip confirmation promptExample
npx calabasas bot remove abc123
# Alias: calabasas bot rm abc123
# Skip confirmation (for scripts):
npx calabasas bot remove abc123 --yesThis action cannot be undone
The bot will immediately disconnect from Discord
Monitoring
Status Dashboard
calabasas statusFull-screen real-time dashboard showing all your bots, their connection status, event stats, and live event logs. Navigate between bots to see detailed stats and recent events for each one.
Example
npx calabasas status
# Alias: calabasas dashboard
# Full-screen dashboard with:
# - Bot list with live status indicators
# - Stats panel (total events, success/failure counts, avg latency)
# - Live event log for the selected bot
#
# Navigation:
# j/k or ↑/↓ Select bot
# q QuitData updates in real-time via WebSocket subscriptions
Stats show events from the last hour
Event Logs
calabasas logs [botId]Live event log viewer that streams events in real-time. Shows logs from all bots in the platform, or a specific bot if provided.
Options
-b, --bot <id>Bot ID (omit for all bots in platform)-n, --limit <number>Number of log entries to show (default: 50)--onceOne-shot output instead of real-time view--errorsShow only failed events--successShow only successful eventsExample
# With .env.local set, no flags needed:
npx calabasas logs
# Live output:
# Event Log (live · 12 events)
# 14:32:05 ✓ messageCreate 12ms
# 14:32:04 ✓ interactionCreate 45ms
# 14:31:58 ✗ guildMemberAdd 102ms Handler timeoutEvents stream in real-time as they arrive
Press q to quit the log viewer
Code Generation
Generate Types
calabasas generateGenerate type-safe Discord event handlers and sync table schemas based on your calabasas.config.ts. Creates validators, TypeScript types, and handler wrappers.
Options
-o, --output <path>Output path (default: convex/discord.generated.ts)Example
npx calabasas generate
# Output:
# ✓ Generated convex/discord.generated.ts
# → 12 event handlers
# → 47 type definitions
# → 4 sync table schemas
# → 1 handleDiscordEvent wrapper
# Usage in your code:
import { handleDiscordEvent } from "./discord.generated";
export const receive = handleDiscordEvent({
messageCreate: async (ctx, event) => {
// Full TypeScript autocomplete!
console.log(event.content);
console.log(event.author.id);
},
});Re-run this command after changing calabasas.config.ts
Generated files are marked as auto-generated - don't edit manually
After generating, add the tables to your convex/schema.ts: import { calabasasTables } from "./calabasas/schema" and spread into defineSchema()
Re-export sync mutations in convex/discord.ts: export { syncGuild, syncChannel, syncRole, syncMember } from "./calabasas/sync"
Push Config
calabasas pushUpload your calabasas.config.ts configuration to Calabasas. This tells the gateway which events to forward to your Convex backend. Bot is resolved from --bot flag, CALABASAS_BOT_ID in .env.local, auto-selected if only one, or prompted interactively.
Options
-c, --config <path>Path to config file (default: convex/calabasas.config.ts)-b, --bot <botId>Bot ID to configure (resolved from .env.local if not specified)Example
# With .env.local set, no flags needed:
npx calabasas push
# Or specify explicitly:
npx calabasas push -b abc123
# ✓ Configuration pushed successfullyRun this after modifying your config to apply changes
Changes take effect immediately
Bot resolved from --bot flag > CALABASAS_BOT_ID in .env.local > auto-select > prompt
Config Management
calabasas configView and modify your convex/calabasas/config.ts interactively or with flags. Three modes: interactive multiselect (default), --list for read-only display, and flags for scripting.
Options
-c, --config <path>Path to config file (default: convex/calabasas/config.ts)-l, --listList current and available config options--add-event <events...>Enable event handlers--remove-event <events...>Disable event handlers--add-sync <properties...>Enable sync properties--remove-sync <properties...>Disable sync propertiesExample
# Interactive mode
npx calabasas config
# List current config
npx calabasas config --list
# Add events via flags
npx calabasas config --add-event messageCreate presenceUpdate
# Enable sync properties
npx calabasas config --add-sync presence members
# Combine flags
npx calabasas config --add-event messageCreate --add-sync presenceAfter modifying config, run calabasas generate to regenerate type-safe handlers
Unknown event or sync names produce an error listing valid options
Comments in the original config file are not preserved when writing
Slash Commands
Define Commands
commands: { ... }Define slash commands in your calabasas.config.ts. Commands are registered with Discord when you run calabasas push, so users can invoke them with / in any channel.
Example
// convex/calabasas.config.ts
import { defineCalabasas } from "calabasas";
export default defineCalabasas({
events: { interactionCreate: true },
commands: {
ping: {
description: "Check bot latency",
},
ban: {
description: "Ban a user",
options: [
{ name: "user", type: "user", description: "User to ban", required: true },
{ name: "reason", type: "string", description: "Ban reason" },
],
},
settings: {
description: "Bot settings",
subcommands: {
view: { description: "View current settings" },
set: {
description: "Update a setting",
options: [
{ name: "key", type: "string", description: "Setting name", required: true },
{ name: "value", type: "string", description: "New value", required: true },
],
},
},
},
},
});Commands appear globally after push (may take up to 1 hour for global commands).
Option types: string, integer, number, boolean, user, channel, role, mentionable, attachment.
Enable interactionCreate in events to handle command interactions.
Interaction Responses
interactionCreate handlerHandle slash command interactions by returning a response object from your interactionCreate handler. Calabasas forwards the interaction to your mutation and responds directly to Discord with the result.
Example
// convex/discord.ts
import { handleDiscordEvent } from "./discord.generated";
export const receive = handleDiscordEvent({
interactionCreate: async (ctx, event) => {
if (event.data?.name === "ping") {
return { content: "Pong!" };
}
if (event.data?.name === "ban") {
const userId = event.data.options?.find(
(o: any) => o.name === "user"
)?.value as string;
// Schedule a Convex action for Discord API calls
await ctx.scheduler.runAfter(0, internal.discordActions.banUser, {
guildId: event.guildId!, userId,
});
return { content: `Banned <@${userId}>`, ephemeral: true };
}
},
});Return { content, embeds, components, ephemeral } for message responses.
Return { choices: [...] } for autocomplete responses.
For Discord API calls (ban, kick, etc.), schedule a Convex action via ctx.scheduler.runAfter.
Responses are sent directly to Discord — you control ephemeral visibility.
Discord Actions
discord.sendMessage(...)Call Discord API from your Convex actions using the generated helper. Actions like sending messages, banning users, and managing roles are all available without touching the Discord API directly.
Example
// convex/discordActions.ts
import { discord } from "./discord.actions.generated";
import { internalAction } from "./_generated/server";
import { v } from "convex/values";
export const banUser = internalAction({
args: { guildId: v.string(), userId: v.string() },
handler: async (ctx, { guildId, userId }) => {
await discord.ban(guildId, userId, { reason: "Violated rules" });
},
});
export const welcome = internalAction({
args: { channelId: v.string(), userId: v.string() },
handler: async (ctx, { channelId, userId }) => {
await discord.sendMessage(channelId, {
content: `Welcome <@${userId}>!`,
});
},
});Discord actions only work in Convex actions (not mutations/queries) because they use fetch.
Requires CALABASAS_GATEWAY_URL environment variable in your Convex deployment.
Rate limiting is handled automatically by the gateway.
Available methods: sendMessage, editMessage, deleteMessage, kick, ban, unban, addRole, removeRole, createInvite, and more.
Supported Events
Calabasas supports all major Discord gateway events. Each event comes with full TypeScript types for the payload data.
messageCreatemessageUpdatemessageDeleteinteractionCreateguildMemberAddguildMemberUpdateguildMemberRemovemessageReactionAddmessageReactionRemovevoiceStateUpdatepresenceUpdatetypingStart