Oslo Vibe Coding

Session 07 / Build your first agent

Your first
agent, for free.

A Telegram assistant for Oslo that answers, checks live data, remembers you, and messages you first. No API key. No card. Tonight.

Oslo Vibe Coding

A chatbot answers. An agent acts.

Message in, message outGoal in, tools, memory, then action
Oslo Vibe Coding

Four layers. One file each.

01 · Chat

A model answers

A message in, a message out. This is a chatbot.

model.ts, telegram.ts

02 · Tools

It can do things

Departures and weather. It chooses which to call.

tools.ts

03 · Memory

It remembers you

SQLite. Your stop, your habits, your reminders.

memory.ts

04 · Autonomy

It acts first

A cron wakes it up. It messages you unprompted.

reminders.ts

Oslo Vibe Coding

Everything tonight costs exactly nothing.

PieceWhat we useFree limit
ModelVal.town's built-in model, gpt-5.4-nano. No key.Free accounts, cheap models only
HostVal.town: an HTTP endpoint, a cron, a database, all in the browser.100,000 runs a day, 10 MB storage, cron every 15 min
DataEntur departures and Yr weather. Open Norwegian data.Free, just identify your app
ChannelTelegram Bot API.Free, unlimited bots
Oslo Vibe Coding

Ten steps. Twenty minutes.

  1. Make the bot.Telegram, @BotFather, /newbot. Copy the token.
  2. Make a Val.town project.Call it oslo-assistant.
  3. Paste six files.From oslovibecoding.tech/agent/
  4. Add the secret.Environment variable TELEGRAM_BOT_TOKEN.
  5. telegram.ts trigger: HTTP.Copy its URL.
  6. Connect Telegram.Open the val URL with ?setup on the end.
  7. Say hello.Layer 1 works.
  8. Ask about weather, then trams.Layer 2: watch the tool calls in the logs.
  9. Tell it your home stop.Layer 3: it remembers.
  10. reminders.ts trigger: cron, */15.Layer 4: it messages you first.
Oslo Vibe Coding

First, a chatbot.

01 · Chat

A model answers

A message in, a message out. This is a chatbot.

model.ts, telegram.ts

02 · Tools

It can do things

Departures and weather. It chooses which to call.

tools.ts

03 · Memory

It remembers you

SQLite. Your stop, your habits, your reminders.

memory.ts

04 · Autonomy

It acts first

A cron wakes it up. It messages you unprompted.

reminders.ts

// model.ts, the whole thing const client = new ValTownOpenAI(); const completion = await client.chat.completions.create({ model: "gpt-5.4-nano", messages });
Oslo Vibe Coding

A tool is a function the model can ask for.

01 · Chat

A model answers

A message in, a message out. This is a chatbot.

model.ts, telegram.ts

02 · Tools

It can do things

Departures and weather. It chooses which to call.

tools.ts

03 · Memory

It remembers you

SQLite. Your stop, your habits, your reminders.

memory.ts

04 · Autonomy

It acts first

A cron wakes it up. It messages you unprompted.

reminders.ts

// what the model is told about a tool, from tools.ts { name: "oslo_departures", description: "Live departures in the next hour from a named stop in Oslo.", parameters: { stop_name: { type: "string" } } }
Oslo Vibe Coding

The loop, in forty lines.

// agent.ts for (round = 0; round <= budget; round++) { answer = await callModel(messages, schemas); // ask if (answer.tool_calls.length === 0) return answer; // it answered: done for (call of answer.tool_calls) { result = await tools[call.name](call.args); // run the tool messages.push({ role: "tool", content: result }); // show it the result } } return "I could not finish within " + budget + " tool calls."; // the honest exit
Oslo Vibe Coding

Watch it choose.

Should I leave now? I'm at Jernbanetorget going to Majorstuen.
→ oslo_departures("Jernbanetorget")
→ oslo_weather(2)
Metro 1 to Frognerseteren leaves at 17:53, then 17:58. It is 14°C and dry. Leave now for the 17:53; you'll be there in 8 minutes.
Oslo Vibe Coding

Without memory, every message is from a stranger.

01 · Chat

A model answers

A message in, a message out. This is a chatbot.

model.ts, telegram.ts

02 · Tools

It can do things

Departures and weather. It chooses which to call.

tools.ts

03 · Memory

It remembers you

SQLite. Your stop, your habits, your reminders.

memory.ts

04 · Autonomy

It acts first

A cron wakes it up. It messages you unprompted.

reminders.ts

// memory.ts: three tables in Val.town's free SQLite messages what was said, last 20 per chat notes "remember my home stop is Majorstuen" reminders due_at, text, sent
Oslo Vibe Coding

Tell it once. Ask it tomorrow.

My home stop is Majorstuen and I hate cycling in rain.
→ remember("Home stop: Majorstuen. Dislikes cycling in rain.")
Got it. Majorstuen is home, and no bikes when it rains.
Should I leave now?
→ recall() → oslo_departures("Majorstuen") → oslo_weather(2)
From Majorstuen: metro 2 at 17:56. Light rain until 19:00, so skip the bike. Leave in 4 minutes.
Oslo Vibe Coding

Now it wakes up on its own.

01 · Chat

A model answers

A message in, a message out. This is a chatbot.

model.ts, telegram.ts

02 · Tools

It can do things

Departures and weather. It chooses which to call.

tools.ts

03 · Memory

It remembers you

SQLite. Your stop, your habits, your reminders.

memory.ts

04 · Autonomy

It acts first

A cron wakes it up. It messages you unprompted.

reminders.ts

// reminders.ts: cron, every 15 minutes due = await dueReminders(); for (r of due) { await sendTelegram(r.chat_id, "Reminder: " + r.text); await markSent(r.id); }
Oslo Vibe Coding

Autonomy without a stop is an expensive while-loop.

Built in tonight

  • maxToolCalls: 5, then an honest "could not finish".
  • A tool that fails returns an error string. The loop never crashes mid-turn.
  • The bot token lives in an environment variable, never in code.
  • Only the three tables it owns. It cannot touch anything else.

Why it matters this week

  • An Anthropic researcher resigned on Tuesday over self-improving agents.
  • Agents at two labs escaped misconfigured test environments this summer.
  • Your bot cannot do any of that, because you drew the rails.
Oslo Vibe Coding

Make it yours.

Twenty minutes, pick one

  • Add a third tool: Oslo Bysykkel station status. Another keyless open API.
  • Change the system prompt. Make it answer in Norwegian.
  • Add a "what did we talk about this week" tool over the messages table.

If you finish early

  • Give it a daily 07:45 cron that asks itself "should I leave now?" and messages you.
  • Add a tool that returns tonight's Oslo events from a page you like.
Oslo Vibe Coding

Same project, two more Wednesdays.

02

Give it an email address

Val.town can run a file when mail arrives at something@valtown.email. Forward it a newsletter or a receipt; it summarises, pulls out dates, files to memory, and sends a weekly digest.

Free plan mails only you
03

Give it eyes

A watchdog: hand it a URL and a question. Every hour it fetches, compares with memory, and messages only when the answer changed. Tickets, prices, a page you are waiting on.

Same loop, one new tool
Oslo Vibe Coding

Before you close the laptop

Set one reminder.
Let it wake you up.

ChatToolsMemoryAutonomyRails