# Owner Commands

URL: https://cogitator.app/docs/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

```typescript
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

| Command                 | Level      | Description                                           |
| ----------------------- | ---------- | ----------------------------------------------------- |
| `/status`               | authorized | Show uptime, sessions, message count                  |
| `/sessions`             | authorized | List recent sessions                                  |
| `/help`                 | authorized | Show available commands                               |
| `/users`                | owner      | List owners and approved users                        |
| `/model <name> [@user]` | owner      | Switch model globally or for a specific user          |
| `/compact [target]`     | owner      | Compact the current conversation (or `target` thread) |
| `/restart`              | owner      | Restart 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](/docs/channels/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

```typescript
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:

```typescript
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
