Memory & datasets
Two kinds of remembering, kept in the same store: a SQLite file locally, Postgres in the cloud.
| Â | Notes | Datasets |
|---|---|---|
| Shape | free-form facts | a fixed list of fields |
| Written by | the agent, unprompted | the user, one answer at a time |
| Read back | by search (recall_memory) | as a completed version |
| Defined where | nowhere, it grows as you talk | marketplace/datasets/*.json |
Notes
The agent writes a note whenever it learns something lasting about you or your work. It doesn’t ask first.
Each note has a key (a stable id like user:communication-style), the content, an importance of low, medium or high that weights recall ranking, optional tags, and a sticky flag.
Notes belong to whoever is talking. The terminal, each Telegram user and, in the cloud, each widget visitor have separate sets, so a visitor’s notes never reach your chats or another visitor.
---
config:
look: handDrawn
theme: neo-dark
---
flowchart LR
A["đź§ Agent learns something"] --> R["remember_note<br><small>upsert by key</small>"]
R --> DB[("notes")]
DB -->|"sticky = true"| Boot["Injected into<br>every new session"]
DB -->|"on demand"| Rec["recall_memory<br><small>query + tag/importance filters</small>"]
Rec --> A2["đź§ Agent uses it"]
Boot --> A2
| Tool | What it does |
|---|---|
remember_note | write or update a fact. It upserts by key, so the same key overwrites instead of duplicating |
recall_memory | search notes, filtered by tags, minimum importance or sticky-only |
list_notes | list what’s stored |
forget_note | delete one note by key, or every note with a tag |
Sticky notes skip search and go into the system prompt at the start of every session. Use them for the few things that should always be in context, and leave the rest non-sticky so they’re recalled only when relevant.
You can ask for any of this in plain words: “what do you remember about me?”, “forget the note about my old job”.
Datasets
A dataset is a questionnaire the agent fills in during conversation, across as many sessions as it takes. Datasets are abilities: one JSON file per topic in ~/.config/kaja/marketplace/datasets/, synced or your own. A persona opts into one with dataset = "<id>". Every dataset in the folder loads, but does nothing until a persona names it or it’s a profile.
{
"label": "Mood check-in",
"revalidateAfterDays": 7,
"fields": [
{ "name": "mood", "prompt": "How has your week felt overall?" },
{ "name": "energy", "prompt": "How's your energy been?", "accepted": ["low", "okay", "high"] }
]
}
| Field | Purpose |
|---|---|
label | display name (required) |
fields[].name | the stored key (required) |
fields[].prompt | what to ask. The agent rephrases it naturally instead of reading it out |
fields[].accepted | a fixed answer list. Anything else is rejected (case-insensitively) and asked again |
revalidateAfterDays | how long a completed set stays fresh before a new version starts |
profile | it’s about the user, so every persona sees the answers (see below) |
The onboarding profile
The shipped onboarding dataset is a profile: what to call you, pronouns, age, look, where you live, languages, work, interests, household, pets and diet. The onboarding persona walks you through it, but only the name matters. Every other question is fine to skip, and a skipped one is recorded as prefer not to say, so it’s never asked again.
Because it’s a profile, every persona gets an “About the user” section in its system prompt with what you shared (never the skipped fields), and records a missing detail when you happen to mention it, without quizzing you for the rest. While your name is unknown, the assistant asks for it once, kindly. Like sticky notes, that section goes to the model provider with each message.
Versions
Answers are grouped into versions. A complete set is stamped with a completion time. Once revalidateAfterDays has passed, the next check quietly opens a new version and the agent asks everything again. That’s what makes a mood or check-in questionnaire useful over time: each version is a dated snapshot you can compare with the last.
The agent drives all of this through one tool, dataset_info, with four actions: list_datasets, get_status (progress, and what’s still unanswered), answer (record one field) and start_new_version (redo the set early, when you ask).
Next: