Schema, creation paths, MCP tools, and resolution order for arizuko topics — the transient work-units overlaid on a group. Narrative introduction lives at concepts/topics.
| table.column | type | default | meaning |
|---|---|---|---|
messages.topic | TEXT NOT NULL | '' | topic-sessions key, set on inbound and outbound (migration 0008) |
chats.sticky_topic | TEXT | NULL | active-topic pin per chat; NULL / empty = default topic (migration 0016) |
chats.sticky_group | TEXT | NULL | orthogonal — folder pin, not topic (listed only to distinguish) |
sessions.(group_folder, topic) | TEXT, TEXT | '' | composite PK; one Claude session per (folder, topic) pair (migration 0008) |
chat_reply_state.(jid, topic) | TEXT, TEXT | '' | last bot reply ID per (chat_jid, topic) — threads outbound on platforms with thread/reply pointers (migration 0014) |
Four sources set a non-empty topic on a message:
#name prefixA message whose body starts with #name (optionally preceded by whitespace) opens topic #name. The prefix is stripped, a synthetic core.Message with Topic = "#" + name is inserted, and the queue fires a turn against that topic.
# sticky commandA message that is exactly #name (whole-message sticky) updates chats.sticky_topic for the chat. Bare # clears the sticky.
/new and /new #name/new alone clears the default-topic Claude session for the active folder. /new #name [rest] calls store.DeleteSession(folder, "#name"), then injects "#name " + rest as a fresh inbound, which re-enters handlePrefixLayer on the topic branch.
ChannelTypeGuildPublicThread or ChannelTypeGuildPrivateThread, the topic is set to the thread’s channel ID — discd/bot.go:177.msg.MessageThreadID is non-zero (forum-topic supergroup), the topic is set to that integer as a string — teled/bot.go:267.Topic empty; outbound goes into the default topic unless the chat carries a sticky.At turn-formation time the gateway calls effectiveTopic(chatJid, msgTopic) — gateway/gateway.go:1733:
func (g *Gateway) effectiveTopic(chatJid, msgTopic string) string {
stickyTopic := g.store.GetStickyTopic(chatJid)
if stickyTopic != "" {
return stickyTopic
}
return msgTopic
}
Precedence:
chats.sticky_topic on the chat row, if non-empty.topic column (from the inline prefix or adapter-set thread ID).The resolved value keys the Claude session lookup at gateway/gateway.go:729 and the multi-topic dispatch loop at gateway/gateway.go:799 (one Claude run per distinct topic per chat-turn batch).
#other while the chat is stuck on #current still runs under #current — the # prefix opens a topic via the synthesis path, not by overriding sticky on the current message. Clear sticky with bare # to escape.reset_sessionDrops the Claude session for a folder so the next message starts fresh context. Operates on the current resolved topic for that folder — the tool itself takes only groupFolder.
| param | type | required | meaning |
|---|---|---|---|
groupFolder | string | yes | target folder |
inspect_sessionReturns the current session_id for (folder, topic) plus recent session_log rows. Use to verify a reset took or to see whether a topic has a live session.
| param | type | required | default | meaning |
|---|---|---|---|---|
topic | string | no | '' | topic to inspect; empty = default topic |
limit | number | no | 10 | recent session-log rows; clamped to 1–100 |
Observed messages are surfaced to every trigger turn alongside the directly-routed messages. The query is folder-scoped, not topic-scoped — see store.ObservedMessagesSince:
SELECT … FROM messages
WHERE chat_jid IN (<jids routed to this folder, minus the firing chat>)
AND timestamp > ?
AND is_bot_message = 0 AND content != ''
ORDER BY timestamp ASC
LIMIT 100
The predicate omits topic entirely. A turn that fires in topic #tickets-42 on folder support sees recent inbound from every chat routed to support, no matter what topic those messages carry. Cross-cutting awareness is the design; operators wanting hard isolation should split into separate folders.
/new #name — clears the named session and starts fresh; with no argument, clears the default-topic session.#name to pin, bare # to clear. Acks with topic → <name> / topic reset to default.inspect_session MCP tool with a topic string to see whether that (folder, topic) has a live Claude session and what the recent session log looks like.reset_session with the target groupFolder. Clears the session for the resolved current topic of that folder.session_log rows and chat-level state including sticky_topic. No CLI subcommand on arizuko sets or inspects topics directly today — sticky changes go through chat, session inspection goes through MCP.See also: concepts/topics (narrative), concepts/routing (how a chat reaches a folder before topics enter the picture), reference/mcp (every MCP tool).