Channels and Voice
Anda can stay in the terminal, or it can join team channels. Channels bring context back into the same runtime and memory system.
Supported Channels
- Telegram
- Discord
- Lark / Feishu
Channel configuration lives under channels in ~/.anda/config.yaml.
Multiple Users
One daemon can serve multiple trusted users through the same Anda agent. Create a user key, then set a channel entry's user to that id. If user is omitted, the channel uses the local owner identity stored in the OS secure credential store. Daemon controls (configuration, model reload and switching, update installation, shutdown) remain reserved for the local owner.
anda user create alice
anda user list
The command writes the new public key under top-level users and saves the matching private key in the local encrypted credential store under ~/.anda/credentials/. The credential file contains an encrypted COSE Key, with its encryption key derived from the local daemon identity secret. Use anda user export below when you explicitly need a file key.
On Linux, if no Secret Service provider is available or unlocked, Anda can read existing daemon/owner key files at ~/.anda/keys/anda_bot.key and ~/.anda/keys/user.key, and prints/logs a warning. Both files must be present: an unavailable keyring never causes replacement identities to be generated. For an existing installation, unlock the provider or restore the original keys. Trusted-user private keys remain encrypted with a key derived from the original daemon identity.
For a new installation without an OS keyring, explicitly run anda user init-file-keys before anda start. This creates missing private key files without overwriting existing files, and refuses initialization if local database/credential data or accessible keyring identities already exist. Do not use it to recover an existing installation. Imported COSE keys must identify the Ed25519 curve; an algorithm, when present, must be EdDSA, and a private key’s public component must match its secret. Raw 32-byte Base64 keys remain supported.
To use Secret Service, start and unlock a provider in a user D-Bus session, for example gnome-keyring-daemon --start --components=secrets, make sure DBUS_SESSION_BUS_ADDRESS is set for Anda, then restart it. KDE users can unlock KWallet instead. Existing file identities are migrated together to one keyring bundle; the source files are removed only after the bundle is saved successfully.
To export an existing identity private key to a file, use anda user export. The identity can be daemon, owner, default, or a trusted user id:
anda user export daemon --key-path ./anda-daemon.key
anda user export owner --key-path ./anda-owner.key
anda user export alice --key-path ./alice.key
Keep exported private key files out of source control and shared folders.
The config still looks like this:
users:
- id: alice
pubkey: "ALICE_ED25519_PUBLIC_KEY"
- id: ops
pubkey: "OPS_ED25519_PUBLIC_KEY"
Telegram Example
channels:
telegram:
- id: personal
user: alice
bot_token: "YOUR_TELEGRAM_BOT_TOKEN"
username: "YOUR_TELEGRAM_BOT_USERNAME"
allowed_users:
- "*"
mention_only: false
WeChat Example
channels:
wechat:
- id: personal
user: alice
# Leave empty to run anda channel init wechat, scan the QR code, and get a token.
bot_token: ""
username: anda-wechat
allowed_users:
- "*"
Discord Example
Discord uses a bot token and a Gateway connection. Create and install the bot before editing config.yaml:
- Open the Discord Developer Portal, then create or open your app.
- On the app's Bot page, copy or reset the bot token. Also enable Message Content Intent under Privileged Gateway Intents so Anda can read normal message text.
- On the Installation page, make Guild Install include the
botscope. Without thebotscope, the app can appear under your Discord Apps but not as a server bot member. - Grant the bot at least
View Channels,Send Messages, andRead Message History. AddAttach Filesif Anda should send files, and addAdd Reactionswhenack_reactions: true. - Install the app to your server. The bot should appear in the server member list after a server install.
channels:
discord:
- id: server
user: ops
bot_token: "YOUR_DISCORD_BOT_TOKEN"
username: anda-discord
# Optional. Restrict this entry to one Discord server.
guild_id: "YOUR_DISCORD_GUILD_ID"
allowed_users:
- "YOUR_DISCORD_USER_ID"
mention_only: true
ack_reactions: true
Only bot_token is required by config validation. For a usable and safer setup, set allowed_users to Discord user IDs; an empty allowed_users list with allow_external_users: false ignores non-allowlisted senders. Use allow_external_users: true only when untrusted external users should be able to talk to Anda as $external_user.
After saving the config:
anda channel list
anda restart
In a server channel, mention the bot:
@anda-discord summarize this thread
In a DM with the bot, send a normal message without mentioning it. If the bot is not visible, check that Guild Install includes the bot scope and that the daemon is running.
Lark / Feishu Example
channels:
lark:
- id: work
user: ops
app_id: "cli_xxx"
app_secret: "YOUR_APP_SECRET"
platform: feishu
receive_mode: websocket
mention_only: true
Channel Safety Checks
allowed_usersdecides who can trigger Anda; use"*"only when open access is acceptable.userdecides which trusted Anda caller owns conversations, resources, and memory for this channel entry.- Telegram and Discord usually require
bot_token. - WeChat can use a saved token, or QR login when
bot_tokenis empty. - Lark / Feishu needs
app_idandapp_secret; Feishu endpoints useplatform: feishu. - Channel routes are persisted so later replies can return to the original thread, room, or contact.
Message delivery
https_proxy applies to channel API requests, media transfers, and Discord/Lark WebSocket connections; WeChat does not need a proxy and connects without it. Discord resumes recoverable sessions and checks heartbeat acknowledgements while attachments download separately.
Use list_im_channels to discover recent recipients and threads. It scans the latest 300 stored messages and keeps threads distinct. For send_im_message, thread is a Telegram topic ID, a Discord thread channel ID, or a Lark/Feishu root message ID (om_...). Telegram also accepts the older chat_id:topic_id recipient format; an explicit thread takes precedence.
Text chunks and attachments retry independently. Successfully delivered parts are not replayed when a later part fails, and a history-write failure does not resend a delivered message. A failure after partial delivery is reported rather than replaying the whole reply. Transport timeouts with an unknown delivery outcome are not automatically repeated.
Replies containing only artifacts are delivered too. Lark/Feishu links HTTP(S) attachments in the card and uploads local files and binary attachments as image or file messages (images up to 10 MB, files up to 30 MB). Incoming user images and direct or localized rich-text messages are supported. When Anda rejects a message from a trusted user (for example /goal without a prompt), the reason is sent back to the chat; external users get no internal details.
Channel history references attachments already stored in the channel workspace; keep its attachments directory with database backups. WeChat reuses its HTTP client and migrates the legacy context-token files to context_tokens_v2.json, which stores each token and its update time together.
Voice Input and Playback
Voice input requires transcription.enabled: true. Start a voice session with:
anda voice --record-secs 8
If you also want Anda to play the answer, configure tts.enabled: true. For microphone input and text output only:
anda voice --record-secs 8 --no-playback
Audio attachments can enter context after transcription is enabled, so voice messages in channels can become part of the same memory thread.