An interactive explainer
How a chat message becomes a prompt
Verity is a Rust bot living in a Telegram supergroup. Every message you send her rebuilds her context from scratch — nothing carries over on its own. Watch one message travel the whole way.
-
A TurnContext is built from zero
-
Blocks concatenate into one string
-
An agent with tools does the work
-
:::markers::: are stripped and run
-
The rest ships to the topic
One message, one turn
Press play — or click a stage — to follow a message through a full turn.
The prompt builder
This is the whole trick: the prompt is a sandwich, assembled fresh each turn. Toggle, drag, and edit the blocks — the text on the right is exactly what the model would receive.
Drag by the grip, or use the ↑ ↓ keys on each block. Uncheck a block and it vanishes from the prompt — the model never knows it existed.
The memory trick
The model is stateless — it forgets everything the moment a turn ends. So how does Verity remember anything? She writes notes to her future self. Step through three turns.
What falls off
The transcript is the last 30 messages in the topic — and each one is cut at 2,000 characters. Drag the slider to grow the conversation and watch old messages drop out of context.
And inside each message, a second cut:
The marker playground
Verity's reply is scanned for :::markers::: before it's sent. They never reach the chat — they're stripped out and executed. Edit the reply and watch it split.
What the chat sees
Side effects
Tell chains have a depth cap
A :::tell::: hands a task to a teammate bot — and that bot can tell again. But not forever: a tell at depth 3 is dropped. Run the chain.
The real constants
Everything you just played with comes down to six numbers in the bridge.
HISTORY_LIMIT = 30how many topic messages make the transcriptHISTORY_MSG_CHARS = 2_000where each message gets cutMAX_TELLS = 5delegations one turn can fireMAX_TELL_DEPTH = 2where a tell chain diesMAX_HELPERS = 3helper agents one turn can spawnPROGRESS_AFTER = 12swhen a slow turn starts streaming status
// Every incoming message runs this once. Nothing is cached between calls.
fn build_prompt(ctx: &TurnContext) -> String {
let mut p = String::new();
p.push_str(IDENTITY); // "You are Verity…"
p.push_str(INSTRUCTIONS); // casual, no greetings, get to it
if !ctx.memory.is_empty() {
p.push_str("What you remember:\n");
for (k, v) in &ctx.memory { // rows she wrote herself
p.push_str(&format!("{k} = {v}\n"));
}
}
p.push_str("Recent messages in your topic (oldest first):\n");
for m in ctx.history.iter().take(HISTORY_LIMIT) {
let text: String = m.text.chars().take(HISTORY_MSG_CHARS).collect();
p.push_str(&format!("[{}] {}\n", m.from, text));
}
p.push_str(&roster_and_markers(&ctx)); // teammates + :::syntax:::
p.push_str("---\n");
p.push_str(&ctx.message.text); // the message being answered
p
}
Questions
Does she remember between messages?
Not by herself. The model starts blank every turn — anything it "knows" was re-injected into this turn's prompt. Memory survives because past turns wrote :::remember::: notes that get read back in.
Why did she forget what I told her?
Probably one of three reasons: it slid out of the 30-message window, it was past the 2,000-character cut, or you said it somewhere she can't see.
Can she see other topics or my DMs?
No. A turn fetches this topic's last 30 messages only. Other forum topics, private chats, and edited-away text never enter the prompt.
Who writes her memory?
She does — mid-reply, by emitting :::remember k = v:::. The bridge strips the marker and writes the pair to a small SQLite table. It's the only thing that persists between turns.
Is the transcript the same as memory?
No. The transcript is fetched fresh each turn and forgets fast. Memory is a tiny key-value store that survives indefinitely — until Verity overwrites the key herself.