The bot feature provides a high-level framework on top of polling TeamTalk
events. It is designed for command bots, workflow bots, and multi-step dialog
scenes without forcing a specific persistence backend.
Enable it in Cargo.toml:
[dependencies]
teamtalk = { version = "6.0.0", features = ["bot"] }Router: routes commands, events, and dialog steps.Context: handler access to client, parsed command, state store, and dialog helpers.Bot/BotBuilder: sync bot runtime.AsyncBot/AsyncBotBuilder: async runtime (bot+async).BotApp: one place to wire router, scheduler, state store, and runtime.Scheduler: periodic jobs that share the sameStateStore.MemoryStateStore,RedisStateStore,SqliteStateStore: persistence options.
Use Router::on_command, on_command_pattern, on_event, on_any,
on_dialog_step, and on_dialog to register handlers. Middleware runs before
handlers, can stop dispatch early, and can run post-handler cleanup through
use_middleware_hooks.
Useful built-in middleware:
- preferred for authorization:
RequireClientRightsAnyRequireClientRightsAll
CommandOnlyRateLimitBySourceRequirePrivateMessageRequireChannelMessageRequireCommandRequireCommandPrefixRequireUserIdsRequireUserType(sender-cache-based, use only when cacheduser_typeis the signal you want)
For guard patterns and rate limiting, see guards.md.
For common rights bundles, use Permissions::moderator(),
Permissions::file_manager(), Permissions::channel_admin(),
Permissions::media_sender(), Permissions::desktop_controller(), and
Permissions::server_admin() / Permissions::admin().
Recommended layering:
- command parsing and validation
- reusable middleware guards
- scene/dialog handlers
- scheduler jobs
Context exposes four state scopes:
- global:
global_state_* - user:
user_state_* - channel:
channel_state_* - dialog/session:
dialog_state_*
Use dialog-scoped state for temporary scene scratch data. Dialog state keys are session-aware, so restarting the same dialog creates a new namespace instead of reusing old scene-local values.
Typed helpers are available for all scopes:
state_parse,state_set_typeduser_state_parse,user_state_set_typedchannel_state_parse,channel_state_set_typedglobal_state_parse,global_state_set_typeddialog_state_parse,dialog_state_set_typeddialog_metadata_parse
These helpers use FromStr and Display, so they work well for integers,
booleans, enums with manual parsing, and similar lightweight types without
adding serialization dependencies.
If you enable bot-serde, you also get JSON-backed helpers:
state_get_json,state_set_jsonstate_get_json_or_defaultuser_state_get_json,user_state_set_jsonuser_state_get_json_or_defaultchannel_state_get_json,channel_state_set_jsonchannel_state_get_json_or_defaultglobal_state_get_json,global_state_set_jsonglobal_state_get_json_or_defaultdialog_state_get_json,dialog_state_set_jsondialog_state_get_json_or_default
That is the preferred option when scene/user state is a structured payload.
For multi-step conversations, use DialogFlow, DialogState, and Context's
dialog helpers. The framework supports:
- explicit start, restart, advance, cancel, and finish
- pause/resume
- metadata attached to the dialog state
- dialog-local scratch storage
- optional timeout with policy control
The router also supports:
- command aliases through
alias_command - unknown-command suggestions through
with_unknown_command_suggestions
The bot macros crate provides #[teamtalk_command], #[teamtalk_command_help],
#[teamtalk_event], and #[teamtalk_middleware] to keep handler registration
compact.
Macros support aliases:
#[teamtalk_command("ping", "p")]
fn ping_handler(ctx: &mut teamtalk::Context<'_>) -> teamtalk::Result<HandlerResult> {
let _ = ctx.reply_private("pong");
Ok(HandlerResult::Continue)
}
#[teamtalk_command_help("help", "Show help", "h")]
fn help_handler(ctx: &mut teamtalk::Context<'_>) -> teamtalk::Result<HandlerResult> {
Ok(HandlerResult::Continue)
}See scenes.md for the full scene model.