Cogitator
Channels

Owner Commands

Manage your bot at runtime through slash commands in chat.

Overview

Owner commands let you monitor and control your AI assistant directly from your messaging app. The OwnerCommandsMiddleware intercepts slash commands from the configured owner before they reach the agent.

Setup

import { Gateway, ownerCommands } from '@cogitator-ai/channels';

const gateway: Gateway = new Gateway({
  // ...
  middleware: [
    ownerCommands({
      ownerIds: {
        telegram: '123456789',
        discord: '987654321',
      },
      onStatus: () => `Up 2h, 5 sessions, 847 messages`,
      onSessions: () => `Active: @john (telegram), @jane (discord)`,
      onModel: (model, forUser) => `Model switched to ${model}`,
      onCompact: (target, threadId) =>
        gateway.compactThread(target === 'current' ? threadId : target),
    }),
  ],
});

Available Commands

CommandLevelDescription
/statusauthorizedShow uptime, sessions, message count
/sessionsauthorizedList recent sessions
/helpauthorizedShow available commands
/usersownerList owners and approved users
/model <name> [@user]ownerSwitch model globally or for a specific user
/compact [target]ownerCompact the current conversation (or target thread)
/restartownerRestart the assistant

Arguments may follow on the next line, and Telegram group syntax /status@your_bot is recognized. /help also lists /pair <code>, which is handled by the pairing / DM policy middleware, not by this one.

/model without an onModel callback only echoes Model set to: … and changes nothing; wire it to your runtime as RuntimeBuilder does. With RuntimeBuilder, /model gemini-3.5-flash @42 sets a model for one user (bare model names get the configured provider prefix) and /restart exits the process with code 78, which cogitator up answers by starting the assistant again (unless it runs with --no-restart-loop, where the assistant just stops).

Configuration

interface OwnerCommandsConfig {
  ownerIds: Record<string, string>;
  authorizedUserIds?: string[]; // 'telegram:42' or bare '42'
  publicCommands?: string[]; // e.g. ['help'] — anyone may run these
  onStatus?: () => string;
  onSessions?: () => string;
  onUsers?: () => string;
  onCompact?: (target: string, threadId: string) => Promise<string>; // target is 'current' when omitted
  onModel?: (model: string, forUser?: string) => string;
  onRestart?: () => Promise<void>;
}

Callback Handlers

Each command maps to an optional callback. If a callback is not provided, the command returns a default message. Implement callbacks to hook into your gateway's runtime state:

ownerCommands({
  ownerIds: { telegram: process.env.OWNER_TG_ID! },
  onStatus: () => {
    const stats = gateway.stats;
    return [
      `Uptime: ${formatDuration(stats.uptime)}`,
      `Sessions: ${stats.activeSessions} active / ${stats.totalSessions} total`,
      `Messages: ${stats.messagesToday} today`,
    ].join('\n');
  },
  onModel: (model, forUser) => {
    // update model configuration
    return `Switched to ${model}${forUser ? ` for ${forUser}` : ''}`;
  },
});

Security

  • Commands are only processed from users with the required level (ownerIds for owner commands, authorizedUserIds for authorized ones, publicCommands for everyone)
  • With RuntimeBuilder (cogitator up) every command is wired to the live runtime: stats, sessions, approved users, compaction, per-user model overrides and restart
  • Non-owners sending /status or other commands see them passed through to the agent as regular messages
  • Unknown slash commands (e.g., /random) pass through to the agent

On this page