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.

1

Authenticate with your Calabasas account

npx calabasas login
2

Initialize the config file in your Convex project

npx calabasas init
3

Register your Discord bot

npx calabasas bot add
4

Generate type-safe handlers

npx calabasas generate
5

Add 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";
6

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 key

CLI flags always take priority over .env.local values.

calabasas bot add will offer to write these automatically after creating a bot.

Authentication

Login

calabasas login

Authenticate 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.json

Your credentials are stored in ~/.calabasas/config.json

Authentication expires after a period of inactivity

Logout

calabasas logout

Clear your stored credentials. Use this when switching accounts or to remove local authentication data.

Example

npx calabasas logout

# Output:
# ✓ Logged out successfully

Project Setup

Initialize Config

calabasas init

Create 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 add

Register 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=abc123

Bot 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 list

Display 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 view

Example

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 --once

The 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 prompt

Example

npx calabasas bot remove abc123
# Alias: calabasas bot rm abc123

# Skip confirmation (for scripts):
npx calabasas bot remove abc123 --yes

This action cannot be undone

The bot will immediately disconnect from Discord

Monitoring

Status Dashboard

calabasas status

Full-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            Quit

Data 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 events

Example

# 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 timeout

Events stream in real-time as they arrive

Press q to quit the log viewer

Code Generation

Generate Types

calabasas generate

Generate 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 push

Upload 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 successfully

Run 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 config

View 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 properties

Example

# 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 presence

After 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 handler

Handle 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.

messageCreate
messageUpdate
messageDelete
interactionCreate
guildMemberAdd
guildMemberUpdate
guildMemberRemove
messageReactionAdd
messageReactionRemove
voiceStateUpdate
presenceUpdate
typingStart