HomeZero · Agent Model on Flue · 2026-06-23
A spec for getting one buyer's advisor off the birth table and onto a living loop — native Flue skills it can rewrite on itself, a private brain of yearnings and journal, and five beats of rhythm that make it get better every day.
Today the advisor is born but mute: it self-configures an identity at birth, then chats — and writes nothing to the buyer's board. New users get an empty board. This spec turns it into a working agent.
Four things make the advisor operational, and each maps to a layer it doesn't have yet:
SKILL.md) paired to each tool, teaching the model how and when to use it.The keystone idea: skills are files the agent owns, and Flue re-reads them every session — so a skill can measure itself and rewrite its own playbook overnight. That gives us self-improving skills with no framework support, just writeFile and a metric.
Verified in code (flue/src/agents/advisor.ts, flue/src/advisor/*) on 2026-06-23. Everything the loop needs is genuinely net-new — there's nothing to retrofit.
check_identity, set_step, write_identity, finish_birth) that writes /IDENTITY.md to a Durable Workspace and marks the advisor born in Convex.WorkspaceFileSystem(getDefaultWorkspace()) over the DO's SQLite — but the wrapper only exposes exists / readFile / writeFile (no directory listing).anthropic/claude-opus-4-8, thinking medium, direct API (no gateway). GPT-5.5 registered, unused.route middleware gating on AUTH_PASSWORD (Bearer or ?key=).callConvex / callConvexQuery with a deploy-key admin client — can call internal mutations.board.authorHomeCard exists; nothing in the advisor calls it. the real riskextend / schedule / scheduleEvery / onStart / queue all absent — grep-verified). The advisor DO is pure request/response. The only cron wakes the market..agents/skills/ — only /IDENTITY.md on disk.web-xxxx instance id; the doorbell uses the real userId. Different DOs. The loop must key on userId.One DO per buyer (/agents/advisor/:userId). Inside it, four layers with clean boundaries. The first column is the layer; the second is where it physically lives.
author_home_card, pin_ask, read_board, read_reactions, brain_read/write, journal_append, scout_query — agent-level defineTools in flue/src/advisor/. The actual capability..agents/skills/<name>/SKILL.md in the Workspace. Teaches the model how/when to use its paired tool. Loaded on demand via activate_skill.yearnings (what it's learning) + per-skill metrics + tuned params + a sessions log (the transcript). Private learned state. A public-safe confidence subset is projected to Convex for the board's "what I'm learning" panel.IDENTITY.md, JOURNAL.md (relationship, tagged by home slug), and each skill's PLAYBOOK.md — all rows in a files table in the same per-buyer Turso db. One addressable mind: brain + filesystem + session log together.We read the installed runtime (@flue/runtime@1.0.0-beta.2). Skills are real and fully implemented, not a stub. Here's exactly what they are, so we build on truth.
| Fact | What it means for us |
|---|---|
A skill is a SKILL.md — frontmatter (name, description) + a markdown body. | Each capability gets a plain file. The body is the playbook the model reads. |
Discovered from .agents/skills/<name>/SKILL.md in the agent's own workspace (or registered as metadata in createAgent({skills})). | We use workspace skills — files the advisor owns and can rewrite. That's the whole game (see §04). |
Progressive disclosure. The system prompt lists only names + descriptions; the model calls a native activate_skill tool to load the full body on demand. | Skill instructions don't burn context until needed. The catalog can be large and cheap. |
| Reusable across agents — the same skill object drops into both the advisor and the market. | The shared Brain skill (how to use Turso) is written once, used by both. |
Skills do not bundle tools. Tools stay agent-level; allowed-tools frontmatter is parsed but not enforced. | The tool↔skill pairing is our convention, by discipline — exactly the model "a tool needs a skill so it knows how to use it." |
session.skill(name, {args, result}) can invoke a skill programmatically, with structured output. | Beats can run a skill in code (e.g. the dream calls a reweight skill and gets back a typed result). |
SKILL.md); we pair them ourselves and reference the tool inside the skill's body. That's lighter and more flexible than a welded primitive — and it's what makes self-rewriting possible.
Flue has no native eval / metric / tune hook — grep-verified (the only version machinery is schema-versioning). So self-improvement is ours to build. But it falls out almost for free, because of one fact: workspace skills are files, and Flue re-discovers them every session.
So a skill is not static know-how. It's a unit with three parts and a loop:
SKILL.md — the playbook.SKILL.md body itself.The dream closes the loop overnight:
// nightly, per skill const m = brain.metric(skill) // e.g. board: 👍-rate & answer-rate on cards it authored const verdict = reflect(skill, m) // what's working, what isn't (a reasoning turn) brain.tuneParams(skill, verdict) // numeric weights/thresholds → Turso fs.writeFile(`.agents/skills/${skill}/SKILL.md`, rewrite(body, verdict)) // the playbook edits itself // next session: Flue re-discovers the improved SKILL.md automatically
Build-time check (in the plan): confirm the Cloudflare DO adapter runs workspace skill-discovery against getDefaultWorkspace() — the primitive is built for it, but we prove the self-rewrite takes effect on our substrate before leaning on it.
Every agent's whole mind is one per-agent Turso db, addressed by its id. For the advisor that's a per-buyer db named from the userId (1:1 — the db IS the user), provisioned at birth. Because it's libSQL, you can connect to it from anywhere — the basis for the SSH/TUI operability below. It holds three things:
// the FILESYSTEM files( path PRIMARY KEY, content, updated_at ) // IDENTITY.md · JOURNAL.md · <skill>/PLAYBOOK.md // the BRAIN yearnings( key PRIMARY KEY, prompt, confidence REAL, weight REAL, status, source, last_touched ) skill_metrics( skill, metric_key, value REAL, n, window, updated_at ) skill_params( skill, param_key, value, updated_at ) // tuned by the dream // the SESSION LOG (mirror of the DO's transcript, so the dream reads full history) sessions( turn_id PRIMARY KEY, started_at, role, content )
The filesystem is a table. IDENTITY.md (who I am), JOURNAL.md (the relationship — entries tagged by home slug, so the advisor's "wiki" grows out of the journal), and each skill's learned PLAYBOOK.md are all rows in files, read/written via fsRead/fsWrite. Nothing of the agent's lives in the DO workspace anymore.
Yearnings = the advisor's standing questions about the buyer (budget comfort, town-vs-land, fixer appetite, owned water, timeline, who it's for, commute), seeded at birth, plus custom ones. One drives each card's question; the dream reweights confidence from answers. A public-safe confidence subset is projected to Convex for the board's "what I'm learning about you" panel — the brain db stays source of truth.
What stays in the DO: Flue's own engine tables (flue_sessions, flue_session_entries, flue_runs…) — how the agent runs (fiber recovery, replay). The brain db is what it knows. A turn-end hook mirrors the DO transcript into the brain's sessions table so the nightly dream consolidates the full history before Flue compaction drops it.
The DO gets a rhythm via extend({ base }) from @flue/runtime/cloudflare: onStart() registers the recurring beats with scheduleEvery; one-shots use schedule. Backed by DO alarms (Flue owns alarm() — we never set it directly). The 0 9 * * * Worker cron stays as a billing-safe floor.
A buyer zeroes a home → doorbell. Brief it through the buyer's lens, author a card, ask one good question, set 👍/👎.
Board housekeeping. Append to clusters, narrate shifts, keep the board coherent. Cheap.
A short WhatsApp check-in — greeting + one overnight highlight + a gentle question + board link. Simple now, tuned later (§09 B). Board-card fallback if WhatsApp unwired.
Read the market's Turso, rank unzeroed homes by active yearnings, author scout cards. Never scrapes Zillow.
Consolidate. Answers → yearning confidence; per-skill metric → rewrite each skill's SKILL.md + params; summarize the journal; re-org the board.
body: { message: JSON.stringify({ kind:'zero', slug }) } — the model parses the kind. The react beat is fired by a new advisor doorbell (sibling of the market's ringMarket), rung from stars.ts at the same two if (created) branches that ring the market, scoped to the zeroing buyer's userId.
Each row is a tool ↔ skill pair: the hands, the playbook that teaches their use, the metric that measures the pair, and the state the dream tunes. brain is the one shared with the market.
ask.reactedAt / answers)Phase 1 scout ranks structurally over the market's listings. Phase 2 swaps to vector_top_k once the market lands brief_vectors / listing_vectors — same skill, better query.
"Set up its local environment" has a precise meaning now: at birth the advisor provisions its own brain, memory, and skill files — then reconciles the identity it already self-authors. The existing birth ladder (waking → studying_market → authoring → scouting → ready) extends to do it:
| Step | What gets provisioned |
|---|---|
waking | ensureAdvisorSchema() on the advisor Turso (yearnings, skill_metrics, skill_params). Seed the skill files into .agents/skills/ from the birth template. |
studying_market | Read the market's Turso to ground itself in the place it serves. |
authoring | Write /IDENTITY.md (today) + seed yearnings from onboarding (universal core + custom). Start /JOURNAL.md. |
scouting | First scout pass → the buyer's first board cards (no longer an empty board). |
ready → finish_birth | onStart registers the recurring beats. The loop is live. |
Because skills are seeded as files, every newborn advisor starts with the current best playbook — and then diverges as it tunes itself for its own buyer.
SKILL.md the agent rewrites on itself ✓ confirmedLocked (Pete, 2026-06-23): skills that rewrite themselves. Flue gives us discovery + progressive disclosure + re-read-per-session; we add the metric and the overnight rewrite. Every skill is a metric skill.
Locked (Pete, 2026-06-23): a real daily morning briefing on WhatsApp — stubbed and simple to start; we tune the content later. Pete's framing: "remember our audience — someone shopping for a home. A little morning check-in. Don't overwhelm. They have the board."
What it is (winged, v0):
flue/src/advisor/whatsapp.ts; if a buyer has no number/opt-in yet, fall back to a "good morning" board card so it always works. Meta template compliance is a known follow-up — fine to wing the first cut.Example: "Morning 👋 Found one new place overnight that fits your 'space without the upkeep' lean — a 3-bed with a flat lot. Want me to dig in, or skip it? Your board's here: [link]"
Already locked earlier and not re-opened here: advisor brain = journal + yearnings; first-class native Flue skills; scout reads the market's Turso; Turso = private brain, Convex = shared projection; build on the latest @flue (pin the version, confirm the tool shape).
The advisor becomes useful the moment it can write to the board — so that's the first shippable cut, before the full rhythm.
| Milestone | Delivers | Beats live |
|---|---|---|
| 1A · It writes | @flue pinned + tools confirmed · board tool + skill · advisor doorbell · react beat · chat keyed to userId. New users get a real, agent-authored board. | react |
| 1B · It has a brain | Advisor Turso + yearnings + birth seeding · the brain & memory & reactions skills · learning-panel projection. | react |
| 1C · It has rhythm | extend/scheduleEvery · tend · scout · dream (incl. the self-rewrite loop). | + tend · scout · dream |
| 1D · It greets | Morning-brief beat → a simple daily WhatsApp check-in (whatsapp.ts), board-card fallback if a buyer isn't WhatsApp-wired. Content tuned later. | + morning brief |
Then the market agent spec (depth: county records, Turso vectors, the wiki) — same skill model, same rhythm primitive, the shared brain skill already written here.