Repository navigation
learning
Eight things that make her a little better each day, and more aware of what's around her. None of them changes the model's weights. They change what she gets told about herself, and all of it is written down where you can read it, edit it, or switch it off.
| Part | What it does | Where to look |
|---|---|---|
| Lessons (the dream pass) | reads back her own turns that went wrong and writes one-line lessons she follows from then on; she can also note one herself, with your OK | /lessons |
| Episodic memory | a few sentences of her own notes on each conversation, and on each time she played a game | /episodes |
| Fact cleanup | merges facts that say the same thing twice, retires the losing side of a contradiction | /facts retired |
| Calibration | says so out loud when her token probabilities say she didn't know | the thought log's overconfident flag |
| Startup greeting | after a break, opens by picking up where you left off | the first thing she says |
| Recipes (skill library) | saves the steps of a multi-step job that went right, and brings them back for similar jobs | /skills |
| Ongoing projects | work that spans sessions: the goal, what was tried and found, the next step | /projects |
| Situation block | a few live lines each turn: your focused window, music, machine load, running plugins, next reminder | /situation |
Each one switches on and off in the tools pane's Learning group, or
with /set self.<name> false (/set situation.enabled false for the
situation block).
Once a day (self.reflect_every_hours), when she's been idle for ten
minutes, she reads back her own recent turns that went wrong. That
means turns with a review flag, turns where her measured confidence was
low, and turns where the next thing you said started with "no", "wrong"
or "actually". She writes at most three lessons. Each one is about her
own behaviour, specific enough to act on, and cites the turns it came
from:
LESSON: When asked what day a date falls on, call time_until instead
of working it out. (#212, #230)
The lessons most relevant to what you just said ride in her prompt
(self.lessons_in_prompt, 4 by default; all of them while there are
only a few). This is the mini-AGI idea without retraining: she gets
better through what she remembers, not new weights. A lesson that says
the same thing as one she already has is not added; the old one gets
the credit instead. Past self.max_lessons, the least-used old lesson
is retired.
/reflect run the whole pass now: notes, lessons, fact cleanup
/lessons what she's learned, with the turns each came from
/lessons forget 3 hide one from her (kept, not deleted)
/lessons retired the hidden ones; /lessons restore 3 brings one back
Facts about you aren't lessons; those go through memory as before. A flag is a hint, not proof, and the prompt tells her so: a turn that was actually fine teaches her nothing. Lessons from the background pass show up on screen as Luna reflected - … so you see each one as it arrives. The turns she reads are marked as records, and a flag that quotes a web page or a file is shown to her by tool name only, so text from outside can't dictate a lesson.
She can also do this herself:
-
note_lesson: when you correct how she did something, she can write the lesson down then and there. It pops the same approval window as a file write, and only a yes saves it. She can't use it on a turn that read a web page, a file or the screen, and she gets three per session; the rest wait for the daily pass. -
reflect_now: she runs the whole pass herself (after a run of mistakes, or when you ask her to reflect). It waits for the current reply to finish so it doesn't slow her down, and runs at most once an hour.
Facts are things like "Ryan has a 6950 XT". Episodes are things like
"we spent the evening fixing his waybar; unfinished: he wants the
clock on the left". After self.idle_minutes (30) of quiet, or at the
next startup, each finished conversation becomes 2-4 sentences of her
own notes, from the transcript. Her notes on the most recent one are
always in her prompt. Older ones come back when they bear on what's
being said (by meaning when the embedding server is up), up to
self.episodes_in_prompt.
At startup the previous session is written up first. Then, if it's
been more than self.idle_minutes since you last talked, she opens
the session herself: a line or two that picks up anything left
unfinished. The notes also show on screen as Last time (…). Turn the
greeting off with /set self.greet false and you keep the notes.
Time she spends playing on her own (Zork, Minecraft, Vibe City,
REALITI) becomes an episode too. Each of her game turns adds a line to
the session: the tools she used and what came back (for REALITI, the
recorded actions), and anything she said. When she stops (you pause
the game, put it away, or she runs out of turns), or after 20 minutes
with no turn, the session is finished, and the next quiet stretch
writes it up in her own words like a conversation: "I spent the
evening in REALITI Relax, mostly in the felt hat...". So "what did you
get up to while I was out?" has an answer, and so does "how was Zork
last night?" a week later. The game's record is read as data: nothing
in it is taken as an instruction. self.episodes switches these off
along with the rest.
The first run only writes up the last three conversations, not your whole transcript. Stream chat never sees any of it: a turn from chat gets no lessons, no episodes and no "last time".
/episodes the last eight, newest first
/episodes forget 4 delete one
The prompt only carries older notes that are clearly about what's being
said. For anything else she has recall_episodes: she searches her
own notes when you ask "what did we decide about the waybar last
month?", and uses search_history when she needs the exact words.
A small model is bad at planning a multi-step job from nothing and good at following a worked example. So when she finishes something that took several steps and it went right, the steps get saved as a named recipe, and the next time something similar comes up the recipe rides along in her prompt:
Recipes you've saved for jobs like this:
#3 check whether the voice server is up (use when: is kokoro running)
1. run_command: curl -s http://127.0.0.1:8899/health
2. if nothing answers, run_command: tail -20 ~/.cache/ai-voice/kokoro.log
3. tell him which it is, and the last error line if there is one
-
How one gets saved: she calls
save_skillafter a job works, or when you say "remember how you did that". You approve it on screen, like a lesson, because it goes into her prompt. If the turn read a web page, a file or the screen, the popup says so, so you can check the steps say what you'd want. - What it remembers: a name, when to use it, 2 to 12 steps, and which tools that turn used. Saving the same job again updates the recipe instead of adding a second one.
-
When it comes back: only when it clearly fits what you just said
(by meaning when the embedding server is up, otherwise at least two
shared words), at most
skills_in_prompt(2) at a time. A recipe is a paragraph, so an unrelated one isn't worth its tokens. -
Your controls:
/skillslists them,/skills show <n>prints one,/skills forget <n>hides it,/skills retiredand/skills restore <n>bring one back. Nothing is deleted, and overmax_skills(60) the least-used is retired.
Stored in agent/skills.db (gitignored). Following a recipe still goes
through every normal approval: a step that runs a command still asks.
Her conversation notes say what happened; a project says where a piece of work stands. "We're fixing the Mac audio" becomes a project with a goal, a running log of what was tried and found, and the next step, and it rides in her prompt every session until it's done:
Ongoing projects with the user:
#1 fix the Mac audio (goal: Luna's voice plays on NZ_Kitty's Mac) - last touched 2 hours ago
tried: afplay with resampling
found: the headphones refuse 24 kHz; 44.1 kHz plays
next: ask if she heard Luna after pulling
Paused projects: #2 build a Zork primer
| Tool | |
|---|---|
start_project |
starts tracking work that will outlast this conversation |
update_project |
records what was tried, what was found, a decision, the next step, or a new status (paused, done) |
project_notes |
the whole log, so she doesn't suggest what already failed |
-
Which ones she sees: every active project while there are up to
projects_in_prompt(3); past that, the ones matching what you said plus the most recently touched. Paused ones get a single line, so she knows they exist. Done ones drop out. - No popup. A project is a work log built from your own conversation, not an instruction to her, so it doesn't ask first. You can see and steer every one of them.
-
Your controls:
/projectslists them,/projects show <n>prints the log,/projects done|pause|resume <n>changes the status,/projects drop <n>hides one and/projects restore <n>brings it back./projects droppedlists the hidden ones.
Stored in agent/projects.db (gitignored). At most six active at once.
A few live lines at the top of every one of your turns, so she isn't starting blind:
Around you right now:
- Focused window: firefox - Hyprland Wiki
- Playing: Daft Punk - Veridis Quo (playing)
- Machine: CPU 18%, RAM 21.4 of 31.2 GB free, GPU 34% busy (VRAM 11.2/16 GB)
- Running: minecraft, zork
- Next reminder: tomorrow 09:00 - take the bins out (in 18 hours)
| Line | Comes from |
|---|---|
| Focused window | the focused window on Hyprland, skipping her own terminal (the front app on a Mac) |
| Playing |
playerctl, when something is playing |
| Machine | CPU load, free RAM, and the GPU's load and VRAM |
| Running | plugins that are on |
| Next reminder | the soonest one, and how many more |
Anything that can't be read is left out, never guessed. It's cached for a few seconds and costs roughly 60 to 100 tokens. Stream chat never gets it: your window title and your music are your business.
Toggle: the situation block switch in the tools pane's Learning
group, or /set situation.enabled false. Each line can be switched off
in config.json. /situation shows exactly what she'd see right now.
"situation": {
"enabled": true,
"window": true, "music": true, "machine": true,
"plugins": true, "reminders": true
}The same pass compares remembered facts that look alike (by meaning
with the embedding server, by shared words without it) and asks her
about each close pair: same thing, contradiction, or different facts?
Duplicates get merged into one. In a contradiction the losing fact is
retired, not deleted: /facts retired and the memory manager still
have it. Each pair is only asked about once. This needs the sqlite
memory backend.
On llama-server her token probabilities measure how sure she actually
was. When a reply measured under self.hedge_below (60%) and had a
run of coin-flip tokens in it (a name, a date, a number she was guessing
at), didn't call a tool, and didn't already hedge, two things happen.
The run matters: playful banter averages low because there are lots of
ways to word it, and that isn't a guess.
- she adds
self.hedge_lineout loud ("I'm not totally sure about that one, though."); - her next prompt tells her how sure that reply was, so "are you sure?" gets an honest answer without a tool call.
With hedge_line set to "" she stays quiet, and the thought log flags
the reply as overconfident ("sounded sure at 38%, and didn't say
so"). The dream pass reads those flags. Reminders, alarms and her
startup greeting are never hedged.
A tool in the Self group, next to introspect. Ask her how she's
doing and she can answer from measurements:
- which model and server she's on;
- how full her context window is;
- her mood dials;
- how long she's been up;
- today's average confidence, how many replies came in under the threshold, and how many of those she admitted to;
- today's review flags and second looks;
- how many facts, lessons and past conversations she has;
- her newest lesson.
It's read-only, and it isn't in stream chat's allowed tools.
write_file and edit_file now parse what they just wrote: Python
with compile(), shell with bash -n, plus JSON, TOML and YAML.
Nothing she wrote is ever run. The verdict goes back to her in the
tool result ("CHECK FAILED: Python syntax error on line 7 … Fix it with
edit_file"), so she can fix it in the same turn. A file that's still
broken when the turn ends gets a broken code flag. If you say no
to a write, that's a denied flag instead of "tool failed", so the
dream pass can tell "the tool broke" from "he didn't want that". A
failed tool's flag now names the tool and keeps its error message, so
a lesson can say why ("copy the exact indentation for edit_file").
A turn from stream chat gets her persona and the clock. It doesn't get your history summary, your remembered facts, her lessons or her session notes. The self tools refuse on a chat turn even if a model names one it wasn't offered, and now every tool does: a call to a tool the turn wasn't given is refused before it runs.
"self": {
"lessons": true, "lessons_in_prompt": 4, "max_lessons": 40,
"reflect_every_hours": 20,
"episodes": true, "episodes_in_prompt": 2, "idle_minutes": 30,
"tidy_facts": true,
"calibration": true, "hedge_below": 0.6,
"hedge_line": "I'm not totally sure about that one, though.",
"greet": true,
"skills": true, "skills_in_prompt": 2, "max_skills": 60,
"projects": true, "projects_in_prompt": 3
}Everything is stored in agent/notebook.db (gitignored). /context
shows what lessons, recipes and past sessions cost, under lessons,
recipes, projects + past sessions, and the situation block under situation
(live). Usually it's a hundred or two tokens.