Personalised recommendations when the chat opens

The moment a user opens the chat, the model looks at who they are and where they are, calls your API and renders the best things to do as cards. Every user sees something different.

Goal

User taps the launcher → before typing anything, the assistant says “Hey Omar, you’re 180 points from level 4” and shows the two quests nearest his interests, two offers, the live stream next door and his progress bar. Maya, standing 300 metres away with other interests, sees different cards.

Pieces

  • Context from the app: userId, name, level, surgePoints, interests, area, lat, lng, plan, listed as public context keys in the agent’s Behaviour tab.

  • Tool get_recommendations: GET https://your-api/recommendations?userId={{ context.userId }}&lat={{ context.lat }}&lng={{ context.lng }}&interests={{ context.interests }}. Templates may read context, so the model passes nothing and cannot get it wrong.

  • Components your app renders: sc.questCard, sc.offerCard, sc.liveCard, sc.progressCard, declared in Dart and synced.

  • Rule kind opens the chat, condition properties.messages <= 1 (greeting only), reaction Agent responds with AI with the instruction:

    The user just opened the chat in {{ context.area }}. Call get_recommendations once, then make ONE render_ui call whose root is a built-in column containing the top 2 quests as sc.questCard, the top 2 offers as sc.offerCard, one sc.liveCard if a stream is live and one sc.progressCard. Then greet them by name in one sentence that mentions their area and how close they are to the next level. Do not ask what they want.

  • SDK: nothing extra. open() sends kletso.chat_opened on its own.

What happens

  1. Kletso.instance.open(context) shows the chat and tracks kletso.chat_opened { userMessages: 0 }.
  2. The rule matches; the runtime stores the instruction as a hidden user turn and runs the agent loop on the user’s conversation with their context.
  3. The model calls the tool, renders one surface, writes one sentence. The app shows agent.typing, then the cards and the text. No user bubble appears.
  4. Tapping a card runs a local action (open_quest, open_offer, watch_live) that navigates the app.

Verify

  • Triggers → Simulate: track, kletso.chat_opened, { "userMessages": 0 }. The simulator shows trigger.fired, tool.completed get_recommendations, ui.render and the greeting.
  • Switch persona in the app and open the chat again: different cards, different sentence.
  • Reopen after the recommendations rendered: the rule does not fire again because messages is above 1.

Tips

  • Name the container type explicitly in the instruction (column). Models sometimes assume custom prefixes apply to built-ins; the runtime’s rejection message lists the allowed types so a retry succeeds, but being explicit saves a round.
  • Keep cards to required props plus one distance field. Smaller surfaces mean faster turns; 10 to 20 seconds on Claude Sonnet 5 with one tool call.
  • Cap the rule with a frequency cap if you do not want recommendations on every open.

Last updated 2026-09-28 · Report an issue with this page