A bot is a message loop
You will learn
How a bot waits for a message, picks a reply from a table and goes back to waiting, and why the same message always gets the same reply.
A bot is not magic. It is a loop with four beats: wait for a message, read it, pick a reply, send it, and wait again. In message_loop.t27 a message is a small number: 1 is start, 2 is help, 3 is stop, and anything else is not understood. A table maps each message to a reply, so one turn of the loop is one lookup. The inbox holds 5 messages and the loop stops at the stop message, so it answers 4. Send the widget a few messages and notice that the same message always gets the same reply.
Try it
Send start, then help, then an unknown word, then stop, and count the replies. In the spec frame, find the inbox and the index of its stop message, and the test that turns red when two commands share a reply.
Send start, help or an unknown word to a toy bot and watch the four beats of its message loop: wait, read, reply, wait again. A stop message ends it. Nothing is sent.
specs/vibecoding/message_loop.t27
// SPDX-License-Identifier: Apache-2.0
; specs/vibecoding/message_loop.t27 -- lesson "A bot is a message loop" of the course Vibecoding from zero
; The one idea: a bot is a loop. It takes the next message, decides a reply from the message alone,
; sends the reply, and goes back for the next message, until a stop message arrives.
; Messages are small numbers here so the loop is easy to read: 1 is start, 2 is help, 3 is stop,
; anything else is a message the bot does not know. Replies are numbers too: 10 hello, 20 help,
; 90 not understood. The reply table is indexed by the message, so one turn of the loop is one
; lookup. ASCII only (L3), English only (LANG-EN).
; phi^2 + 1/phi^2 = 3 | TRINITY
module vc_message_loop;
pub const MSG_START : u8 = 1;
pub const MSG_HELP : u8 = 2;
pub const MSG_STOP : u8 = 3;
pub const REPLY_HELLO : u8 = 10;
pub const REPLY_HELP : u8 = 20;
pub const REPLY_UNKNOWN : u8 = 90;
; The reply for message 0, 1, 2 and 3; message 3 is the stop message and gets no reply (0).
pub const REPLY_TABLE : [4]u8 = [90, 10, 20, 0];
; The inbox: five messages waiting. The third one (9) is not a known command.
pub const INBOX : [5]u8 = [1, 2, 9, 2, 3];
; One turn of the loop: the reply depends on the message and on nothing else.
pub fn reply_for(msg: u8) -> u8 {
if (msg == 1) {
return 10;
}
if (msg == 2) {
return 20;
}
return 90;
}
; The loop: go through the inbox from the first message, stop at a stop message, and count the
; replies sent. A stop message is not answered.
pub fn replies_sent() -> u8 {
var sent : u8 = 0;
var i : u8 = 0;
while (i < 5) {
if (INBOX[i] == 3) {
return sent;
}
sent = sent + 1;
i = i + 1;
}
return sent;
}
; The loop stops at the first stop message: index 4, so four replies were sent.
pub const STOP_AT : u8 = 4;
test start_gets_hello {
assert REPLY_TABLE[MSG_START] == REPLY_HELLO;
}
test help_gets_help {
assert REPLY_TABLE[MSG_HELP] == REPLY_HELP;
}
test an_unknown_message_is_not_understood {
assert REPLY_TABLE[0] == REPLY_UNKNOWN;
}
test the_loop_answers_four_messages_then_stops {
assert INBOX[STOP_AT] == MSG_STOP;
assert INBOX[0] != MSG_STOP;
assert INBOX[1] != MSG_STOP;
assert INBOX[2] != MSG_STOP;
assert INBOX[3] != MSG_STOP;
}
; Negative control: two different commands must not get the same reply. Plant the bug
; (REPLY_TABLE = [90, 20, 20, 0], two commands mixed up) and this test turns red.
test two_commands_never_share_a_reply {
assert REPLY_TABLE[MSG_START] != REPLY_TABLE[MSG_HELP];
assert REPLY_TABLE[MSG_START] != REPLY_TABLE[0];
}
All lessons
Module 1 · What vibecoding is
You describe, an agent writes, you run it and check. What a program is, and five myths put to a test.
Module 2 · Your desk
An editor with an agent beside it, ten terminal commands, and reading an error message.
Module 3 · Save points with git
A commit is a save point, a branch is a safe try, and a key is a pair of which one stays private.
Module 4 · Prompting
The parts of a prompt, an example in place of an adjective, and one small step at a time.
Module 5 · The working loop
Four phases from idea to ship, the loop of ask, run, read and fix, and what to do when it is stuck.
Module 6 · A test as the judge
A test says yes or no, a planted bug shows the test works, and a diff is read before it is accepted.
Module 7 · The parts of an agent
What an agent answers with, what it can do with tools, and what it keeps between messages.
Module 8 · A first bot
A bot is a message loop, a bot comes from a spec, and a secret stays out of the repository and the prompt.
Module 9 · Your own project
A spec for your own idea, one thing measured after it runs, and an honest plan for the next month.