# CLI Commands This page is the operator-facing user guide for the `clisbot` CLI. It answers two questions: - what command family does this job - what that command family does in practice ## Principles - use kebab-case for all public flags - one noun maps to one concept - use `list`, `add`, `remove`, `enable`, `disable`, `get-`, `set-`, and `clear-` consistently - `add` creates a new object only - when `add` would overwrite existing state, it fails and points to the right `set-` command ## Mental Model - `app`: global runtime behavior - `bots`: provider bot identities, credentials, and provider-level defaults - `routes`: admitted inbound surfaces under a bot - `agents`: execution identity, workspace, and runner behavior ## Resolution Order When more than one level is configured: - route agent wins over bot fallback agent - bot fallback agent wins over app default agent - route settings inherit from the bot first, then route-specific settings override them ## Happy Paths Start from what you want to do. - Start from zero: - `clisbot start ...` - Add one more bot identity: - `clisbot bots add ...` - Add one more channel, group, topic, or DM surface under a bot: - `clisbot routes add ...` - Route one specific surface to one specific agent: - `clisbot routes set-agent ...` - Set one fallback agent for one whole bot: - `clisbot bots set-agent ...` - Set the app-wide default agent: - `clisbot agents set-default ...` - Inspect current bot or route state: - `clisbot bots list ...` - `clisbot routes list ...` - `clisbot bots get- ...` - `clisbot routes get- ...` ## Common Flags - `--channel ` - `--bot ` - `--agent ` - `--json` - `--persist` Use `--bot` as the bot selector. Bot id rules: - with `--channel`, use the provider-local bot id - `--channel slack --bot default` - `--channel telegram --bot support` - without `--channel` on a bot-specific command, use the fully qualified form - `--bot slack:default` - `--bot telegram:support` - when a bot-specific command targets one provider and `--bot` is omitted, it defaults to `default` ## Top-Level - `clisbot start` - `clisbot restart` - `clisbot stop` - `clisbot status` - `clisbot version` - `clisbot logs` - `clisbot update` - `clisbot bots ...` - `clisbot routes ...` - `clisbot agents ...` - `clisbot auth ...` - `clisbot message ...` - `clisbot runner ...` - `clisbot pairing ...` - `clisbot loops ...` - `clisbot queues ...` - `clisbot init` ## Service Lifecycle - `clisbot start [first-run flags...]`: bootstrap config if needed and start the detached runtime - `clisbot restart`: stop then start again - `clisbot stop [--hard]`: stop runtime, optionally clean all tmux sessions on the clisbot socket - `clisbot status`: inspect runtime, config, log, tmux state, and the five most recent runner sessions - `clisbot logs [--lines N]`: print recent logs - `clisbot update --help`: print the update guide, including stable/beta defaults plus migration, release-note, and release-guide links - `clisbot init [first-run flags...]`: bootstrap config and optional first agent without starting runtime Focused help: - `clisbot start --help`: first-run help for tokens, bot bootstrap, and examples - `clisbot init --help`: same bootstrap help without starting the runtime - `clisbot update --help`: install/update checklist for humans and agents ## Bots One bot is one provider identity. Examples: - a Slack bot entry stores one app token source and one bot token source - a Telegram bot entry stores one bot token source - a Zalo Bot entry stores one bot token source A bot can define: - one bot-specific fallback agent - conversation admission defaults for direct messages, groups, and Slack channels - provider credential sources Core commands: - `clisbot bots list [--channel ] [--json]` - `clisbot bots add --channel telegram [--bot ] --bot-token [--agent ] [--cli --bot-type ] [--persist]` - `clisbot bots add --channel zalo-bot [--bot ] --bot-token [--agent ] [--cli --bot-type ] [--persist]` - `clisbot bots add --channel slack [--bot ] --app-token --bot-token [--agent ] [--cli --bot-type ] [--persist]` - `clisbot bots enable --channel [--bot ]` - `clisbot bots disable --channel [--bot ]` - `clisbot bots remove --channel [--bot ]` - `clisbot bots get --channel [--bot ] [--json]` - `clisbot bots get-agent --channel [--bot ]` - `clisbot bots set-agent --channel [--bot ] --agent ` - `clisbot bots clear-agent --channel [--bot ]` - `clisbot bots get-default --channel ` - `clisbot bots set-default --channel --bot ` - `clisbot bots get-credentials-source --channel [--bot ]` - `clisbot bots set-credentials --channel telegram [--bot ] --bot-token [--persist]` - `clisbot bots set-credentials --channel zalo-bot [--bot ] --bot-token [--persist]` - `clisbot bots set-credentials --channel slack [--bot ] --app-token --bot-token [--persist]` - `clisbot bots get-dm-policy --channel [--bot ]` - `clisbot bots set-dm-policy --channel [--bot ] --policy ` Token aliases: - Slack app token: `--app-token`, `--slack-app-token` - Slack bot token: `--bot-token`, `--slack-bot-token` - Telegram bot token: `--bot-token`, `--telegram-bot-token` - Zalo Bot token: `--bot-token`, `--zalo-bot-token` Important behavior: - `bots add` creates a new bot only - `bots add` does not admit any routes by itself - if the bot already exists, `bots add` fails and points to `set-agent`, `set-credentials`, or another matching `set-` command - `disable` keeps the bot in config but stops using it for now - `remove` deletes the bot from config - `bots enable` and `bots disable` are the fast toggle when you want to keep config but stop or resume handling - `bots remove` fails while any route still references that bot - `bots set-agent` defines the bot-specific fallback agent - if no bot-specific fallback agent is set, routing falls back to the app default agent - if `--agent` is passed on `bots add`, it binds an existing agent - if `--cli` and `--bot-type` are passed on `bots add`, the command creates and bootstraps a new agent for that bot - `bots add` rejects ambiguous input such as passing both `--agent` and `--cli` - shared-route admission for normal users comes from `groupPolicy` or Slack `channelPolicy` - with default admission `allowlist`, normal users need explicit routes such as `group:` or `topic::` - stored `groups["*"]` is the default sender rule after that shared surface is admitted ## Routes One route is one inbound surface under one bot. It inherits bot defaults first, then overrides only what needs to differ for that one surface. Examples: - one Slack public channel under one Slack bot - one Slack private group or MPIM under one Slack bot - one Slack DM fallback or one specific Slack DM peer under one Slack bot - one Telegram group under one Telegram bot - one Telegram topic inside one Telegram group under one Telegram bot - one Telegram DM fallback or one specific Telegram DM peer under one Telegram bot - one Zalo Bot DM fallback or one specific Zalo Bot DM peer Notes: - a Slack thread inside a channel uses the parent channel route - a Telegram topic is its own route because topics are explicit sub-surfaces inside a group - Zalo Bot has no topic sub-surface model in the current provider Route ids: - Slack shared surface: `group:C123456` or `group:G123456` - Shared default fine-grain route: `group:*` - Slack direct message fallback: `dm:*` - Slack specific DM peer: `dm:U123456` - Telegram group: `group:-1001234567890` - Telegram topic: `topic:-1001234567890:42` - Shared default fine-grain route: `group:*` - Telegram direct message fallback: `dm:*` - Telegram specific DM peer: `dm:1276408333` - Zalo direct message fallback: `dm:*` - Zalo specific DM peer: `dm:aaa741c34d8fa4d1fd9e` Notes: - canonical CLI shared wildcard route id is `group:*` - canonical stored wildcard key under a bot is `groups["*"]` - legacy shorthand `*`, old `groups:*`, and Slack `channel:` input are still accepted for compatibility - canonical operator naming treats `group:` as the preferred multi-user route id only for providers that support shared surfaces; Zalo Bot is DM-only - `group:*` is the bot default multi-user sender policy node and should be updated, not treated as removable - `clisbot routes --help --channel ` prints channel-scoped route syntax and examples Core commands: - `clisbot routes list [--channel ] [--bot ] [--json]` - `clisbot routes add --channel slack [--bot ] [--policy <...>] [--require-mention ] [--allow-bots ]` - `clisbot routes add --channel telegram [--bot ] [--policy <...>] [--require-mention ] [--allow-bots ]` - `clisbot routes add --channel zalo-bot > [--bot ] [--policy <...>] [--require-mention ] [--allow-bots ]` - `clisbot routes enable --channel [--bot ]` - `clisbot routes disable --channel [--bot ]` - `clisbot routes remove --channel [--bot ]` - `clisbot routes get --channel [--bot ] [--json]` - `clisbot routes get-agent --channel [--bot ]` - `clisbot routes set-agent --channel [--bot ] --agent ` - `clisbot routes clear-agent --channel [--bot ]` - `clisbot routes get-policy --channel [--bot ]` - `clisbot routes set-policy --channel [--bot ] --policy <...>` - `clisbot routes get-require-mention --channel [--bot ]` - `clisbot routes set-require-mention --channel [--bot ] --value ` - `clisbot routes get-allow-bots --channel [--bot ]` - `clisbot routes set-allow-bots --channel [--bot ] --value ` - `clisbot routes add-allow-user --channel [--bot ] --user ` - `clisbot routes remove-allow-user --channel [--bot ] --user ` - `clisbot routes add-block-user --channel [--bot ] --user ` - `clisbot routes remove-block-user --channel [--bot ] --user ` - `clisbot routes get-follow-up-mode --channel [--bot ]` - `clisbot routes set-follow-up-mode --channel [--bot ] --mode ` - `clisbot routes get-follow-up-ttl --channel [--bot ]` - `clisbot routes set-follow-up-ttl --channel [--bot ] --minutes ` - `clisbot routes get-response-mode --channel [--bot ]` - `clisbot routes set-response-mode --channel [--bot ] --mode ` - `clisbot routes clear-response-mode --channel [--bot ]` - `clisbot routes get-additional-message-mode --channel [--bot ]` - `clisbot routes set-additional-message-mode --channel [--bot ] --mode ` - `clisbot routes clear-additional-message-mode --channel [--bot ]` Policy rules: - for Slack public channels, Slack groups, Telegram groups, and Telegram topics, route policy is one of: - `disabled` - `allowlist` - `open` - for DM wildcard routes `dm:*`, route policy is one of: - `disabled` - `pairing` - `allowlist` - `open` - exact DM routes such as `dm:U123456` or `dm:1276408333` may now carry per-user admission and behavior overrides when needed Important behavior: - `routes add` fails if the target bot does not exist - `routes add` fails if the same route already exists under that bot and points to `set-agent` or another `set-` command - `routes add` can set route creation options in one command, including `--policy`, `--require-mention`, and `--allow-bots` - `disable` keeps the route in config but stops using it for now - `remove` deletes the route from config - `routes enable` and `routes disable` are the fast toggle when you want to keep the route definition but stop or resume handling - `routes set-agent` answers the operator question: which agent should handle this surface? - an explicit route agent always wins over the bot-specific fallback agent - shared surfaces use two gates: - gate 1 admission: `groupPolicy` or Slack `channelPolicy`; default `allowlist` means normal users need an explicit shared route such as `group:` or `topic::` - gate 2 sender policy: stored `groups["*"]` plus any route-local `allowUsers` and `blockUsers`; default is `open` - shared routes enforce sender lists at ingress for Slack channels or groups and Telegram groups or topics - app `owner` and app `admin` do not bypass `groupPolicy`/`channelPolicy` admission; after a group is admitted and enabled, they bypass sender allowlists, while shared `blockUsers` still applies - `disabled` means silent, even for app `owner` and app `admin` - adding `group:` without `--policy` inherits the default in-group sender policy from `group:*`; exact group/channel/topic routes should omit `policy` unless that surface intentionally differs - the deny message intentionally uses `group` as the common human-facing many-people term - shared allowlist failures are denied before runner ingress with: - `You are not allowed to use this bot in this group. Ask a bot owner or admin to add you to \`allowUsers\` for this surface.` - `pairing approve ` writes the approved sender into the requesting bot's wildcard DM route allowlist How to add or block users: - Slack DM allow: `clisbot routes add-allow-user --channel slack dm:* --bot --user U123ABC456` - Slack DM block: `clisbot routes add-block-user --channel slack dm:* --bot --user U123ABC456` - Telegram DM allow: `clisbot routes add-allow-user --channel telegram dm:* --bot --user 1276408333` - Telegram DM block: `clisbot routes add-block-user --channel telegram dm:* --bot --user 1276408333` - Zalo DM allow: `clisbot routes add-allow-user --channel zalo-bot dm:* --bot --user aaa741c34d8fa4d1fd9e` - Zalo DM block: `clisbot routes add-block-user --channel zalo-bot dm:* --bot --user aaa741c34d8fa4d1fd9e` - Shared default allow: `clisbot routes add-allow-user --channel slack group:* --bot --user U_OWNER` - Shared default block: `clisbot routes add-block-user --channel telegram group:* --bot --user 1276408333` - `group:*` writes to the default sender rule for all admitted groups under that bot, stored as `groups["*"]` - Shared channel/group allow or block stays on that shared route itself, for example `group:` or `topic::` - If one DM peer needs different admission or behavior, mutate that exact `dm:` route Examples: - `clisbot routes add --channel slack group:C_GENERAL` - `clisbot routes add --channel slack group:G_SUPPORT --bot support --require-mention false` - `clisbot routes add --channel telegram group:-1001234567890 --bot alerts --require-mention false --allow-bots true --policy allowlist` - `clisbot routes add --channel slack dm:* --bot support --policy allowlist` - `clisbot routes add --channel slack dm:U_OWNER --bot support` - `clisbot routes add --channel telegram group:-1001234567890` - `clisbot routes add --channel telegram topic:-1001234567890:42 --bot support --require-mention false` - `clisbot routes add --channel zalo-bot dm:user-123 --bot default --policy open` - `clisbot routes set-agent --channel slack group:C_GENERAL --agent product` - `clisbot routes set-require-mention --channel telegram topic:-1001234567890:42 --value false` - `clisbot routes set-allow-bots --channel telegram group:-1001234567890 --bot alerts --value true` - `clisbot routes set-policy --channel telegram group:* --bot alerts --policy allowlist` - `clisbot routes add-allow-user --channel telegram group:* --bot alerts --user 1276408333` - `clisbot routes add-allow-user --channel slack dm:* --bot support --user U_OWNER` - `clisbot routes add-block-user --channel telegram group:-1001234567890 --user 1276408333` ## Agents One agent is one execution identity. The most important mental model is: - one workspace - one identity and instruction set - one CLI tool family - one set of runner startup and runtime overrides Examples: - one Codex work agent with its own workspace and memory - one Claude support agent with another workspace and different guidance - one Gemini personal agent for one specific bot or route Core commands: - `clisbot agents list [--json]` - `clisbot agents get [--json]` - `clisbot agents add --cli --bot-type [--workspace ] [--startup-option ]...` - `clisbot agents enable ` - `clisbot agents disable ` - `clisbot agents remove ` - `clisbot agents get-default` - `clisbot agents set-default ` - `clisbot agents bootstrap --bot-type [--force]` - `clisbot agents get-response-mode --agent ` - `clisbot agents set-response-mode --agent --mode ` - `clisbot agents clear-response-mode --agent ` - `clisbot agents get-additional-message-mode --agent ` - `clisbot agents set-additional-message-mode --agent --mode ` - `clisbot agents clear-additional-message-mode --agent ` Important behavior: - `agents add` creates a new execution identity only - `agents add` fails if the agent already exists - `agents add` without `--bot-type` is valid and does not seed any bootstrap files - `disable` keeps the agent in config but stops exposing it through routing - `remove` deletes the agent from config - `agents enable` and `agents disable` are the fast toggle when you want to keep the agent but stop or resume exposing it - `agents remove` fails while any bot or route still references that agent - `agents set-default` defines the global fallback agent when a more specific bot or route choice is absent - `--workspace` is optional; a sensible default workspace path exists - `--bot-type` on `agents add` or `agents bootstrap` is the template seeding mode, not a general runtime requirement - bootstrap is optional and mainly for fresh workspaces where you want clisbot to seed guidance files - `AGENTS.md` is the canonical workspace instruction file across supported CLIs - Claude and Gemini bootstrap also create `CLAUDE.md` or `GEMINI.md` as symlinks to `AGENTS.md` for CLI discovery - `agents bootstrap` is the template refresh or update path - without `--force`, `agents bootstrap` shows what files would change before overwriting them - when practical, `agents bootstrap` shows a diff or at least a file-by-file overwrite plan ## Auth - `clisbot auth list [--json]` - `clisbot auth show [--agent ] [--json]` - `clisbot auth get-permissions --sender --agent [--json] [--verbose]` - `clisbot auth add-user --role --user [--agent ]` - `clisbot auth remove-user --role --user [--agent ]` - `clisbot auth add-permission --role --permission [--agent ]` - `clisbot auth remove-permission --role --permission [--agent ]` Important behavior: - `app` edits `app.auth` - `agent-defaults` edits `agents.defaults.auth` - `agent --agent ` edits one agent override under `agents.list[].auth` - `add-user` and `remove-user` mutate `roles..users` - `add-permission` and `remove-permission` mutate `roles..allow` - `get-permissions` is read-only and returns the sender's effective permissions for one agent - use `--sender ` for permission checks and `--user ` for role assignment - `principal` format is `:`, for example `telegram:1276408333` or `slack:U123ABC456` - agent-specific writes clone the inherited role from `agents.defaults.auth.roles.` into the target agent override on first mutation - app permissions are limited to the app permission set: `configManage`, `appAuthManage`, `agentAuthManage`, `promptGovernanceManage` - agent permissions are limited to the agent permission set shown by `clisbot auth --help` - contact graph operations use `contactsManage`, provider group operations use `groupsManage`, and other sensitive channel-native operations such as mutating polls or reading poll voter ids use `sensitiveChannelActionManage` - this CLI writes config; config remains the source of truth for routed auth - `clisbot auth --help` is the detailed operator help surface for scopes, examples, and permission names - app `owner` and `admin` principals bypass DM pairing automatically once granted ## Message Tooling - `clisbot message send ...` - `clisbot message poll ...` - `clisbot message react ...` - `clisbot message reactions ...` - `clisbot message read ...` - `clisbot message edit ...` - `clisbot message delete ...` - `clisbot message pin ...` - `clisbot message unpin ...` - `clisbot message pins ...` - `clisbot message search ...` Quick guide: - use `send` to post a new message - use `edit` to update one existing message - use `react` or `reactions` for emoji reactions - use `read` or `search` to inspect message history - use `pin`, `unpin`, or `pins` for pinned messages - use `poll` to create a poll - use `clisbot channel-native ...` for provider-specific commands that do not belong in the shared stable action list Required vs optional: - `message send` requires `--channel`, `--target`, and one of `--message` or `--body-file` - `message edit` requires `--channel`, `--target`, `--message-id`, and one of `--message` or `--body-file` - `message react` requires `--channel`, `--target`, `--message-id`, and `--emoji` - `message poll` requires `--channel`, `--target`, `--poll-question`, and at least one `--poll-option` - `message search` requires `--channel`, `--target`, and `--query` Important behavior: - `--bot` chooses which provider bot sends or edits the message; if omitted, the provider default bot is used - `--account` remains a compatibility alias for `--bot` - `clisbot message --help --channel ` prints channel-scoped target syntax, render hints, examples, and support boundaries - `message custom` has been removed; use named `channel-native` commands instead of a raw provider subtree - shared message actions are capability-gated before provider dispatch, so unsupported channel/action pairs fail fast - `--target` is the destination: - Slack uses destination ids such as channels, groups, or DM destinations - Telegram uses the numeric chat id - `--thread-id` chooses the Slack thread container - `--topic-id` chooses the Telegram topic container - `--reply-to` replies to one specific message inside that destination - `message send` and `message edit` accept: - `--input ` - `--render ` - `--body-file ` as an alternative to `--message` - `--message-file ` as a compatibility alias for `--body-file` - `--file ` as the preferred attachment flag - `--media ` as a compatibility alias for `--file` - default behavior is intentionally short and stable: - `--input md` - `--render native` - keep agent reply prompts short by channel: - Telegram `native` or `html`: the final payload must stay under `4096` characters, so Markdown-to-HTML paths should leave headroom - Slack text or `mrkdwn`: prefer text under `4000` characters; Slack truncates very long text after `40000` - Slack `blocks`: keep header text under `150`, section text under `3000`, and total blocks under `50` - `native` means channel-owned rendering: - Telegram currently resolves to Telegram-safe HTML - Slack currently resolves to Slack `mrkdwn` - use `--render none` when the content is already in the destination-native format - Telegram example: `--input html --render none` - Slack example: `--input mrkdwn --render none` - Slack raw Block Kit example: `--input blocks --render none` - use `--render blocks` when you want Slack Block Kit output from markdown input - invalid combinations fail fast: - `--message` and `--body-file` cannot be used together - `--body-file` and `--message-file` are aliases; use only one - Telegram does not use `mrkdwn` or `blocks` - Slack does not use `html` - `--progress` and `--final` cannot be used together - `--progress` and `--final` are conversation-tracking signals for agent flow; they are not body formatting options - for the full contract, channel matrix, and current renderer behavior, see [Message Command Formatting And Render Modes](../features/channels/message-command-formatting-and-render-modes.md) ## Runner Debugging - `clisbot runner list` - `clisbot runner inspect |--latest|--index [--lines ]` - `clisbot runner watch [--lines ] [--interval ]` - `clisbot runner watch --index [--lines ] [--interval ] [--timeout ]` - `clisbot runner watch --latest [--lines ] [--interval ] [--timeout ]` - `clisbot runner watch --next [--lines ] [--interval ] [--timeout ]` - `clisbot inspect ...` - `clisbot watch ...` - `clisbot runner smoke ...` Important behavior: - main help promotes `clisbot runner list` and `clisbot watch --latest` as the fastest tmux debug entry points - `runner list` shows the saved `sessionId` plus a simple persisted state when available; `sessionId: not stored` means clisbot has not saved one yet - `clisbot status` includes the newest five runner sessions by default; if there are more, it prints `(n) sessions more` - `runner list` prefixes each row with a 1-based index such as `[1]`; `inspect --index ` and `watch --index ` use that exact order - top-level `clisbot inspect` and `clisbot watch` are shorthand for `clisbot runner inspect` and `clisbot runner watch` - `inspect --latest` means the session with the newest admitted prompt - `watch --latest` means the session with the newest admitted prompt, not the newest tmux spawn - `watch --next` waits for the first newly admitted prompt after the command starts, then sticks to that session - `--lines` controls the pane tail window for both `inspect` and `watch`; `inspect` defaults to 100 lines - `--interval` controls polling cadence for `watch` - `runner watch` keeps the header compact with `session`, `agent`, `sessionId`, `lines`, and current `state` - use raw tmux only when you need lower-level actions beyond this control surface ## Pairing - `clisbot pairing list [--json]` - `clisbot pairing approve ` - `clisbot pairing reject ` - `clisbot pairing clear ` Important behavior: - pairing is only relevant for direct-message routes that use `policy=pairing` - `list` shows pending pairing requests for one provider at a time - `approve` and `reject` operate on one pairing code - `clear` removes pending pairing requests for one provider ## Loops - `clisbot loops list` - `clisbot loops status` - `clisbot loops status --channel slack --target group:C1234567890 --thread-id 1712345678.123456` - `clisbot loops create --channel slack --target group:C1234567890 --thread-id 1712345678.123456 --sender slack:U1234567890 every day at 07:00 check CI` - `clisbot loops --channel telegram --target group:-1001234567890 --topic-id 42 --sender telegram:1276408333 5m check CI` - `clisbot loops --channel slack --target group:C1234567890 --thread-id 1712345678.123456 --sender slack:U1234567890 3 review backlog` - `clisbot loops cancel ` - `clisbot loops cancel --channel slack --target group:C1234567890 --thread-id 1712345678.123456 --all` - `clisbot loops cancel --all` Targeting: - `--target` selects the routed surface - Slack accepts `group:`, `dm:`, or raw `C...` / `G...` / `D...` ids - Telegram accepts the route-style `group:` or `topic::` target; raw numeric chat ids are accepted for compatibility - `--thread-id` means an existing Slack thread ts - `--topic-id` means a Telegram topic id - omitting the sub-surface flag targets the parent Slack channel/group/DM or Telegram chat - use `clisbot loops --help --channel ` or `clisbot loops create --help --channel ` for channel-specific loop extensions - `--sender ` is required for loop creation and records the human creator as `slack:`, `telegram:`, or `zalo-bot:` - `--sender-name ` and `--sender-handle ` optionally store readable creator context for scheduled prompts - in Telegram forum groups, omitting `--topic-id` targets the parent chat surface; sends then follow Telegram's normal no-`message_thread_id` behavior, which is the General topic when that forum has one Examples: - recurring loops are created from chat with `/loop 5m check CI` or `/loop every day at 07:00 check CI` - use scoped `clisbot loops ... --channel ... --target ...` when you want the same session-specific create, status, or cancel behavior from the operator CLI - CLI loop creation fails without `--sender` so delayed work keeps a real creator instead of rendering sender as unavailable - use app-wide `clisbot loops list`, `clisbot loops status`, or `clisbot loops cancel --all` when you want global inventory or emergency cleanup - use scoped `clisbot loops list --channel ... --target ...` when you want one routed session - CLI creation accepts the same expression families as `/loop`: interval, forced interval, times/count, and calendar schedules - advanced recurring loop creation also accepts `--loop-start ` to override the default scheduled start notification behavior for that one loop; omit it to keep the route default - loop creation also accepts `--progress ` to override injected agent progress-message instructions for that loop only; omit it to keep the normal `clisbot.json` prompt policy, use `0` to disable progress updates, or use a positive count to cap them - omit the prompt body to load `LOOP.md` from the target workspace for maintenance loops - count/times loops reserve all iterations immediately as durable queue items for the routed session; recurring loops are persisted for the runtime scheduler - the first wall-clock loop create attempt returns confirmation-required output and does not persist a loop until rerun with `--confirm` - AI agents should inspect `clisbot loops --help --channel ` for schedule, loop, or reminder requests and follow the CLI output instead of guessing loop state ## Queues - `clisbot queues list` - `clisbot queues list --channel telegram --target group:-1001234567890 --topic-id 4335` - `clisbot queues status` - `clisbot queues create --channel telegram --target group:-1001234567890 --topic-id 4335 --sender telegram:1276408333 review backlog` - `clisbot queues clear --channel telegram --target group:-1001234567890 --topic-id 4335` - `clisbot queues clear --all` Important behavior: - `list` shows pending queued prompts only - `status` shows pending and running queued prompts - `clear` removes pending prompts only and does not interrupt a running prompt - `create` matches the documented `loops create` addressing shape and requires explicit `--channel/--target` routed addressing - `create` requires `--sender ` so durable queued work has sender metadata - `create` is capped by `control.queue.maxPendingItemsPerSession`; the default is `20` pending items per session when the config key is omitted - `create` posts a visible acknowledgement to the target surface after persistence, for example `Queued: 2 ahead. Prompt: ...` - `--current` is not supported - use `--channel/--target` for scoped inspection, creation, and clearing - use `clisbot queues --help --channel ` when AI agents need channel-specific durable queue targeting instead of guessing provider syntax - queued prompts are stored under `StoredSessionEntry.queues` in `session.storePath` - stored queue items are the canonical queue inventory; the live runtime hydrates them into the same ordered drain used by `/queue`, so ordering, `positionAhead`, active-run idle guards, lazy prompt rebuild, start notifications, and cleared-pending settlement stay consistent ## Timezone - `clisbot timezone get` - `clisbot timezone set Asia/Ho_Chi_Minh` - `clisbot timezone clear` - `clisbot timezone doctor` - `clisbot agents get-timezone --agent default` - `clisbot agents set-timezone --agent support-us America/Los_Angeles` - `clisbot agents clear-timezone --agent support-us` - `clisbot routes get-timezone --channel telegram group:-1001234567890 --bot default` - `clisbot routes set-timezone --channel telegram group:-1001234567890 --bot default Asia/Ho_Chi_Minh` - `clisbot routes clear-timezone --channel telegram topic:-1001234567890:4 --bot default` - `clisbot bots get-timezone --channel telegram --bot default` - `clisbot bots set-timezone --channel telegram --bot default Asia/Ho_Chi_Minh` - `clisbot bots clear-timezone --channel telegram --bot default` Timezone guidance: - app timezone is the normal default; prefer `clisbot timezone set ` when the whole install should use one timezone - agent timezone is for one assistant/workspace that mostly serves a different timezone - route timezone is for one Slack channel, Telegram group, or topic that has different local time from its app or agent default - bot timezone is advanced fallback for a concrete provider bot; do not use provider-default timezone fields - CLI first wall-clock loop creation prints the resolved timezone before persisting; if it is wrong, set timezone first, then create again ## First-Run Flows ### Start From Zero Telegram personal bot: ```bash clisbot start \ --channel telegram \ --bot-token TELEGRAM_BOT_TOKEN \ --cli codex \ --bot-type personal \ --persist ``` Slack team bot: ```bash clisbot start \ --channel slack \ --app-token SLACK_APP_TOKEN \ --bot-token SLACK_BOT_TOKEN \ --cli claude \ --bot-type team \ --persist ``` ### Add One More Route To The Existing Default Bot Slack channel to the same default agent: ```bash clisbot routes add --channel slack group:C_GENERAL ``` Telegram topic to the same default agent: ```bash clisbot routes add --channel telegram topic:-1001234567890:42 ``` If that route should use another agent: ```bash clisbot routes set-agent --channel telegram topic:-1001234567890:42 --agent alerts ``` ### Add One New Bot With One New Agent Slack support bot with a fresh Claude team agent: ```bash clisbot bots add \ --channel slack \ --bot support \ --app-token SLACK_SUPPORT_APP_TOKEN \ --bot-token SLACK_SUPPORT_BOT_TOKEN \ --cli claude \ --bot-type team \ --persist clisbot routes add --channel slack group:C_SUPPORT --bot support --require-mention false ``` Telegram alerts bot with a fresh Gemini personal agent: ```bash clisbot bots add \ --channel telegram \ --bot alerts \ --bot-token TELEGRAM_ALERTS_BOT_TOKEN \ --cli gemini \ --bot-type personal \ --persist clisbot routes add --channel telegram dm:* --bot alerts clisbot bots set-dm-policy --channel telegram --bot alerts --policy allowlist clisbot routes add-allow-user --channel telegram dm:* --bot alerts --user 1276408333 ```