-
Notifications
You must be signed in to change notification settings - Fork 18
Slash Commands
Every Kai feature is accessible through a Telegram slash command. This page is the authoritative reference for all commands, their subcommands, arguments, and behavior.
Commands are handled by Kai's bot process, not by the agent. When you send /new, Kai restarts the subprocess directly - the agent never sees the message. Only regular text messages (and file/photo/voice attachments) are passed through to the agent.
Authorization: All commands except /start require you to be in users.yaml. Unauthorized users get no response. When TOTP is configured, every command except /start and /help additionally sits behind the authentication gate; an expired session prompts for a code first.
Persistence: Settings written via commands are canonical: Telegram and the Workshop browser client mutate the same stored state, so a model change here shows up there and vice versa. The precedence chain for any setting is: runtime settings > users.yaml > install defaults.
Aliases: /ws is a full alias for /workspace. Every subcommand works identically.
Sends the initial greeting. This is the only command that does not require authorization - it responds to anyone so new users know the bot is alive.
/start
→ Kai is ready. Send me a message.
Kills the current agent subprocess and starts a fresh session, clearing the session record from the database.
Use this when the conversation context has grown unwieldy, when the agent is stuck in a bad state, or when you want a clean slate without changing any other settings.
/new
→ Session cleared. Starting fresh.
Aborts the current response mid-stream. Sets the per-chat stop event (checked by the streaming loop) and immediately kills the Claude subprocess. The in-progress Telegram message gets "(stopped)" appended.
/stop
→ Stopping...
Note: the bot uses concurrent_updates=True, which is what makes /stop reachable while Claude is streaming. Without it, the stop message would queue behind the current response.
Switches the active model immediately. The choice persists to the database and survives restarts. Also restarts the subprocess and clears the session (model is a CLI flag baked in at process start).
Valid model names depend on your configured provider:
-
Anthropic (Claude backend):
haiku,sonnet,opus -
OpenAI (Goose backend):
gpt-5.4,gpt-5.4-mini,gpt-5.4-nano -
Google (Goose backend):
gemini-3.1-pro,gemini-3-flash,gemini-3-deep-think - openrouter / ollama: any model ID your provider supports
/model sonnet
→ Model set to ⚡ Sonnet. Session restarted.
/model badname
→ Choose: opus, sonnet, or haiku
Shows an inline keyboard for model selection. The current model is highlighted with a green circle. Tapping a different model is equivalent to /model <name>. Tapping the current model dismisses the keyboard with "No change."
For open-ended providers (openrouter, ollama), no keyboard is shown. Instead, the current model ID is displayed with a prompt to use /model <id> to switch to any model your provider supports.
Shows your current backend, or switches it. Switching is bounded by the runtime options the operator granted on your runtime profile; a backend outside your grants is rejected. Multi-provider backends take the backend:provider form.
/backend
→ Backend: claude (anthropic)
/backend codex
→ Backend set to codex. Session restarted.
Inline keyboard listing your granted backend and provider options; tap to switch.
Your personal PREFERENCES.md: the standing guidance injected into every session. show prints it, set replaces it (revisioned; concurrent edits are detected), history lists prior revisions, and restore <n> brings one back without losing the current text. The same document is editable in Workshop Settings.
Your notification delivery controls: adapters lists per-adapter toggles (adapter <n> on|off flips one), channels shows per-channel levels, muted-mentions toggles the direct-mention override, dnd manages the do-not-disturb window, and /notifications <github|generic> [number|reset] picks the destination channel per integration class. See GitHub Notification Routing.
Manages the memory project registry: which project the current workspace's memories belong to. register adds the current workspace (or a named entry), unregister removes one. /workspace new registers its directory automatically. See Memory.
Global per-user settings. These are your defaults across all workspaces. Workspace-specific overrides are set separately with /workspace config.
Shows your current settings with source attribution for each field - whether the value comes from your database override, users.yaml, or the global default.
/settings
→ Your settings:
Model: sonnet (user override)
Provider: anthropic
Timeout: 120s (global default)
The "Provider" line shows your effective LLM provider (derived from backend and provider in your config). This is always displayed so you know which backend you are on.
Sets your default model. Same effect as /model - persists, restarts the subprocess, clears the session. On canonical runtimes the name validates against the model catalogue for your backend, so what the picker offers tracks what the backend actually serves.
/settings model opus
→ Default model set to 🧠 Opus. Session restarted.
Sets how long Kai waits for the agent to respond before giving up. Must be a positive integer. The upper bound comes from your protected runtime profile; the legacy 600-second cap applies only on compatibility paths without one.
/settings timeout 300
→ Default timeout set to 300s.
Takes effect immediately on any running subprocess.
Clears your database override for the specified field, reverting it to the users.yaml value or global default. Omitting the field name resets everything.
Valid field names: model, timeout
/settings reset timeout
→ timeout reset to default.
/settings reset
→ All settings reset to defaults.
Always restarts the subprocess, even for fields (timeout) that could take effect without one. This simplicity is intentional.
Workspaces are directories where Claude operates. Switching workspaces changes Claude's working directory and restarts the subprocess. Each workspace can have its own model, timeout, env vars, and system prompt (set via /workspace config).
/ws is a full alias for /workspace.
Shows your current workspace - the short name and the full absolute path.
/workspace
→ Workspace: kai
/Users/kai/Projects/kai
Switches to a workspace by short name. Resolution order:
-
workspace_base/<name>- if a base directory is configured and the subdirectory exists - The allowed workspace list - matched by directory name
Absolute paths and ~ are rejected. If the name is ambiguous (exists in both base and allowed list), the base directory wins.
/workspace my-app
→ Switched to my-app. Session cleared.
Switches to your home workspace (the home_workspace in users.yaml, or CLAUDE_WORKSPACE globally). Always allowed regardless of access restrictions.
/workspace home
→ Switched to Home. Session cleared.
Creates a new directory under workspace_base, runs git init inside it, and switches to it. Requires workspace_base to be configured (in users.yaml or WORKSPACE_BASE env var).
The name must not contain path separators.
/workspace new my-project
→ Created my-project. Session cleared.
Adds an absolute path to your personal allowed workspace list, stored in the database. The path must exist and be a directory. Paths already covered by workspace_base are silently rejected (they're already accessible).
/workspace allow /home/alice/client-work
→ Added: /home/alice/client-work
/workspace allow /Users/kai/Projects
→ Already covered by your workspace base:
/Users/kai/Projects
Removes a path from your personal allowed workspace list. Only paths you added via /workspace allow can be removed; globally-configured paths (from ALLOWED_WORKSPACES or admin config) cannot be removed via Telegram.
/workspace deny /home/alice/client-work
→ Removed: /home/alice/client-work
Lists all workspaces you can access, with source attribution for each entry.
/workspace allowed
→ Workspace base: /Users/kai/Projects
Allowed workspaces:
/Users/kai/extra-repo (you)
/opt/shared-docs (global)
If neither a base nor any allowed paths are configured, all directories are accessible (permissive mode).
Shows an inline keyboard of your recent workspaces. The top button is always Home; the rest are drawn from your workspace history. Tapping your current workspace dismisses the keyboard with "No change." Stale entries (directories that no longer exist or are no longer allowed) are removed automatically when you tap them.
Shows the effective configuration for your current workspace, with source attribution for each field.
/workspace config
→ Config for kai:
Model: opus (workspace override)
Timeout: 120s (global default)
Env vars: GITHUB_TOKEN, DEBUG
Prompt: You are working on the Kai project... (workspace override)
Source labels follow the full precedence chain: workspace override (set via /workspace config) > workspaces.yaml > user setting (set via /settings) > users.yaml > global default.
Env var keys are shown but values are never displayed (they may contain secrets).
Sets the model for the current workspace only. Overrides your global /settings model when in this workspace.
/workspace config model haiku
→ Model set to haiku.
Sets the response timeout for the current workspace.
/workspace config timeout 60
→ Timeout set to 60s.
Sets an environment variable that is injected into Claude's subprocess when working in this workspace. Useful for workspace-specific API keys or flags.
/workspace config env GITHUB_TOKEN=ghp_xxxx
→ Set GITHUB_TOKEN.
Remove a variable: Prefix the key with -
/workspace config env -GITHUB_TOKEN
→ Removed GITHUB_TOKEN.
List variables: Omit the value
/workspace config env
→ Workspace env vars:
GITHUB_TOKEN
DEBUG
Sets a system prompt appended to Claude's instructions when working in this workspace. Useful for project-specific context (coding standards, architecture notes, personas).
/workspace config prompt You are working on the Kai project. All code must be thoroughly commented.
→ Prompt set.
Clear the prompt:
/workspace config prompt clear
→ Prompt cleared.
You can also send a text file as an attachment with the command in the caption - useful for long prompts that would be awkward to type in Telegram.
Clears the workspace config override for a specific field, reverting to workspaces.yaml or the global default. Omitting the field name clears everything.
Valid field names: model, timeout, env, prompt
/workspace config reset model
→ model reset to default.
/workspace config reset
→ All workspace config cleared. Using global defaults.
Commands for managing GitHub webhook subscriptions, notification routing, and agent feature toggles. The full settings surface is displayed by /github with no arguments.
Shows your current GitHub configuration: notification destination, subscribed repos (with source attribution), feature toggle states, and token status.
/github
→ GitHub settings:
Notifications: this chat
PR reviews: on (global default)
Issue triage: off (users.yaml)
Subscribed repos:
dcellison/kai (users.yaml)
dcellison/other-repo (added via /github add)
GitHub token: stored
Subscribes you to webhook events from owner/repo. If a GitHub token is stored, Kai registers the webhook on the repository automatically. If not, it prints the webhook URL and a manual cURL command for you to run.
/github add dcellison/new-project
→ Subscribed to dcellison/new-project. Webhook registered.
/github add dcellison/new-project (no token stored)
→ Subscribed to dcellison/new-project.
Register the webhook manually:
URL: https://<your-kai-host>/webhook/github
...
If you previously removed the repo via /github remove, adding it again un-removes it (clears the remove entry) rather than creating a duplicate add entry.
Unsubscribes you from owner/repo. If no other users are subscribed to that repo and a token is stored, Kai removes the webhook from GitHub automatically.
/github remove dcellison/old-project
→ Unsubscribed from dcellison/old-project. Webhook removed.
For repos in your users.yaml baseline, the removal is stored as a delta override in the database. The users.yaml file is not modified. If the admin later removes the repo from users.yaml, the delta is redundant but harmless.
Stores a GitHub personal access token for automatic webhook registration and removal. The token is saved in the database and never echoed back or written to logs.
Required token scope: admin:repo_hook (or write:repo_hook if you don't need deletion). For organization repos, the token owner must have admin access to the repo.
/github token ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
→ GitHub token stored.
Removes your stored GitHub token. Does not affect existing webhooks.
/github token clear
→ GitHub token removed.
Chooses which canonical destination channel receives your GitHub notifications. With no argument it lists your available destinations as a numbered list; pick one by number. Raw chat IDs are rejected; destinations are channels, not chats.
/github notify
→ 1. GitHub feed (current)
2. Direct channel
/github notify 2
→ GitHub notifications will go to Direct channel.
Restores your GitHub destination to the operator's protected policy.
Enables or disables the PR review agent for your account (the users.yaml pr_review field is the admin baseline; there is no global env toggle). The same switch lives in Workshop Settings.
/github reviews off
→ PR reviews disabled.
Enables or disables the issue triage agent for your account, same model as reviews.
/github triage off
→ Issue triage disabled.
Runs a PR review on demand (repository inferred from your subscriptions when omitted). The result comes back to you as a document attachment; no GitHub comment is posted. See PR Review Agent.
Voice output requires TTS_ENABLED=true in your environment. All voice commands return an error message if TTS is not enabled.
Three voice modes exist:
| Mode | Behavior |
|---|---|
off |
Text only (default) |
on |
Text message + voice note (both sent) |
only |
Voice note only (no text) |
Bare toggle: switches between off and only. Does not cycle through on - use /voice on explicitly if you want both text and audio.
/voice (currently off)
→ Voice mode: ONLY (voice only) (voice: Nova)
/voice (currently only)
→ Voice mode: OFF (voice: Nova)
Enables text + voice mode. Both a text message and a voice note are sent for each response.
Disables voice. Text only.
Enables voice-only mode. No text is sent, only the audio file.
Sets the TTS voice by name. If voice mode was off, it is automatically set to only. If mode was already on or only, it stays as-is.
/voice nova
→ Voice set to Nova. Voice mode: ONLY (voice only)
Run /voice with an invalid name to see the list of available voice names.
Shows an inline keyboard of all available TTS voices. Tapping a voice sets it and auto-enables voice mode to only if it was previously off. Same behavior as /voice <name> via the keyboard.
Kai's semantic memory layer (Mem0 + Qdrant) extracts facts from conversations and stores them with tags, confidence scores, and embeddings. The /memory command surface lets you browse, search, and prune these facts directly from Telegram. Memories are scoped per user by Telegram chat ID, so each user only sees and manages their own facts.
For the broader memory architecture, see System Architecture - Memory system.
Opens the memory dashboard: a one-line summary of how many extracted facts and episodes you have, plus a single utility row of inline buttons for browsing them. The row holds Facts (N) (when you have any extracted or migration rows), Episodes (N) (when you have any episode rows), and Stats (always). The Facts and Episodes buttons drill into a paginated list; tapping a row opens a detail view with full text, source, and confidence, plus per-record actions: Forget, a scope-change flow (move between global and project scope), and a source view showing the originating conversation.
/memory
→ Memory: 24 facts, 6 episodes.
Tap Facts or Episodes to browse. Tap Stats for details.
[Facts (24)] [Episodes (6)] [Stats]
There is no Search button on the dashboard - Telegram inline keyboards cannot accept free text. Use /memory search <query> for search. There is no tag-browse axis; tags are visible on individual rows but are not a primary browse surface.
Runs a semantic search across all your facts and returns the top matches. Search is vector-based, not keyword - phrasing the query as a question or rough description works as well as an exact phrase. Each result is tappable for the same detail view as the dashboard drill-down.
/memory search what coffee do I like
→ Top matches:
• Prefers light-roast pour-over from Counter Culture (preferences, 0.87)
• Drinks decaf after 2pm (preferences, 0.71)
Shows the total count of remembered facts plus the distribution of confidence scores (how certain Kai is about each fact). Useful for spot-checking whether the memory layer is accumulating noise or producing high-confidence extractions.
/memory stats
→ 24 facts
Confidence: high (0.8+) 14 | medium (0.5-0.8) 7 | low (<0.5) 3
Compact subcommand reference. Same content shown when an unrecognized /memory subcommand is typed.
Shows your current session details: session ID (truncated), model in use, when the session started, when it was last used, and whether the Claude subprocess is alive.
/stats
→ Session: a3f91b2c...
Model: sonnet
Started: 2026-04-05 14:23:11
Last used: 2026-04-05 17:44:02
Process alive: True
If no session exists yet (no messages sent since last restart), reports "No active session."
Unified command for managing scheduled jobs. Without arguments (or with list), shows all active jobs. Subcommands handle inspection and cancellation.
Aliases: /jobs works as a shortcut for /job list.
Lists all your active scheduled jobs. Each job shows its ID, name, and schedule in human-readable form. Job type is indicated by an emoji: bell (reminder) or robot (Claude job).
/job
→ Active jobs:
🔔 #3 Laundry reminder (once at 2026-04-06T19:00:00+00:00)
🤖 #7 Daily weather (daily at 08:00 UTC)
🤖 #12 Package tracker (every 1h)
Shows full details for a specific job: type, schedule, auto-remove status, and the prompt text. You can only inspect your own jobs.
/job info 7
→ Job #7 - Daily weather
Type: claude
Schedule: daily at 08:00 UTC
Auto-remove: no
Prompt:
Check the weather forecast for today and send me a summary.
Permanently cancels a scheduled job. Removes it from the database and from APScheduler's in-memory queue. You can only cancel your own jobs.
/job cancel 7
→ Job #7 cancelled.
/job cancel 99
→ Job #99 not found.
If you pass an unrecognized subcommand, Kai shows usage help:
/job blah
→ Usage:
/job - List all jobs
/job info <id> - Show job details
/job cancel <id> - Cancel a job
Prints a compact command reference. This page is the full reference; /help is the quick-lookup version for when you forget a specific syntax.
Shows the webhook server's status, port, and advertised endpoints, plus GitHub webhook setup instructions when configured. (The generic /webhook endpoint still exists when GENERIC_WEBHOOK_SECRET is set; this listing just no longer advertises it.)
/webhooks
→ Webhook server: running
Port: 8080
Endpoints:
GET /health
POST /api/schedule
POST /api/services/*
POST /webhook/github
GitHub setup:
1. Set Payload URL to https://your-host/webhook/github
...
| Command | What it does |
|---|---|
/start |
Initial greeting (no auth required) |
/new |
Start a fresh session |
/stop |
Abort the current response |
/model <name> |
Switch model |
/models |
Model picker keyboard |
/backend [b:p] |
Show or switch backend within your grants |
/backends |
Backend picker keyboard |
/preferences ... |
Show, set, or restore your PREFERENCES.md |
/notifications ... |
Adapters, levels, DND, destinations |
/project ... |
Memory project registry |
/review [repo] <pr> |
On-demand PR review, delivered as a document |
/settings |
Show your settings |
/settings <field> <value> |
Set model/timeout |
/settings reset [field] |
Reset to default |
/workspace |
Show current workspace |
/workspace <name> |
Switch by name |
/workspace home |
Go to home workspace |
/workspace new <name> |
Create and switch |
/workspace allow <path> |
Add to allowed list |
/workspace deny <path> |
Remove from allowed list |
/workspace allowed |
List all allowed workspaces |
/workspace config |
Show workspace-specific settings |
/workspace config <field> <value> |
Set per-workspace model/timeout/env/prompt |
/workspace config reset [field] |
Reset workspace overrides |
/workspaces |
Workspace picker keyboard |
/ws |
Alias for /workspace
|
/github |
Show GitHub settings |
/github add <owner/repo> |
Subscribe to repo |
/github remove <owner/repo> |
Unsubscribe from repo |
/github token <value> |
Store GitHub token |
/github token clear |
Remove token |
/github notify <chat_id> |
Route notifications to a group |
/github notify reset |
Restore notifications to DM |
/github reviews on|off |
Toggle PR review agent |
/github triage on|off |
Toggle issue triage agent |
/voice |
Toggle voice off/only |
/voice on|off|only |
Set voice mode |
/voice <name> |
Set voice (enables voice if off) |
/voices |
Voice picker keyboard |
/memory |
Browse facts and episodes (inline buttons) |
/memory search <query> |
Semantic search over remembered facts |
/memory stats |
Counts and confidence distribution |
/memory help |
/memory subcommand reference |
/stats |
Session cost and status |
/job |
List scheduled jobs |
/job info <id> |
Show job details |
/job cancel <id> |
Cancel a job |
/jobs |
Alias for /job list
|
/help |
Compact command reference |
/webhooks |
Webhook server status |