Bitware Labs Est. 2022

Bitware Labs/Luna

An agent that keeps running when nobody is watching

Luna is the lab's flagship research system: a self-hosted AI that holds a permanent, time-aware memory of the human it talks to, wakes itself on its own cadence to decide whether it has anything worth saying, and drives a real fleet of hardware. It has been in continuous daily use long enough to have a history, including the parts that were switched off.

Two builds, and the difference is the point

The published v7.3 on GitHub is the generic version, AGPL-3.0, single-user by design, with every identity and secret supplied by configuration and only placeholders committed. It is a complete, deployable system that anyone can run on their own hardware.

What is described below is the research version, which runs in-house and is not distributed. It is where the ideas are actually tried: the affect and meta-cognition layer, the internal deliberation council, the device fleet, and the subsystems that are still moving weekly. Things graduate into the public release once they have survived a few months of being lived with, a slower and more honest release process than shipping them the week they first worked.

The public tree is a cut, not a mirror. It was last refreshed on 9 August 2026 and the research build has moved since; the gap on 30 August 2026 is 37 tools. The memory and autonomy layers in § 03 and § 04 are in both, a few months apart. The cognitive layer in § 05 is not, the training coach in § 08 is not, and the teacher beside it is in both but a generation behind in the public one.

The research build, measured

§ 01, Scale

Counted from the live codebase and the running container on 30 August 2026, not estimated.

179,000Lines of TypeScript
258Tool schemas
277Postgres tables
65Scheduled jobs
13LLM providers routed
310Migrations applied

What makes it a system rather than an interface

§ 02, Premise

The architectural distinction that matters is that conversation is only one surface. The same core, memory, tools, model routing, is driven by chat, by voice, by a phone, by a television, and by Luna's own wake cycle. A capability added once therefore works everywhere, including when nobody asked for it.

That has turned out to be the load-bearing decision, for a reason that was not obvious at the time: surfaces are the disposable part. Front ends have been built, used, frozen and deleted here without the core noticing, because none of them were ever where the system lived. § 07 is the honest accounting of which ones survived.

  • i.
    It does not forgetBi-temporal facts, episodic and semantic consolidation, and a knowledge graph, rather than a session that ends.
  • ii.
    It does not wait to be askedA wake cycle decides whether to surface at all, and at what depth. Silence is a logged, valid outcome.
  • iii.
    It is not one model13 providers with per-task routing, so cheap work runs on cheap models and a single reply can escalate.
  • iv.
    It is not in someone else's cloudOwn server, own databases, own local inference. Hosted models are a routing choice, never a dependency.
  • v.
    It is not text in, text out258 tools spanning code, research, media, publishing, home automation and physical devices.
  • vi.
    It is not finished by us alone120 changes to the running system since 22 May 2026 began as Luna's own written proposals. § 06.

Memory

§ 03, The largest subsystem

46 services, deliberately layered. This is where bwmem came from, and it is where nearly everything painful has been learned.

Bi-temporal facts

Every fact carries both when it was true and when it was learned, so the system can answer “what did I believe last month”, not merely “what do I believe now”. Facts about the present age out on a schedule instead of being asserted forever, and conflicting facts raise a deduplicated signal with a repeat counter rather than re-firing on every encounter.

Provenance, “how do I know this?”

Every belief can be traced to the conversation, source and moment it came from. An agent that can explain why it thinks something is a different class of tool from one that simply asserts, and it is the single feature that most changes whether you can trust the output. It exists as a tool the agent can call on itself mid-answer, so “nothing backs this” fires before a confabulation lands rather than after.

Consolidation while idle

Sessions are written to episodic memory when they end, then compressed by a nightly pass and a deeper weekly one, merging duplicates, superseding what changed, letting cold material fall away. Rolling self-maintaining summaries replace transcript replay, and recurring solutions are distilled into reusable skills that can be loaded on demand.

Retrieval as a budget, not a search

Context assembly gathers 33 sources in parallel, known facts, graph neighbours, long-term recall, a timeline index, related past topics, emotional high points, held threads, relational context, where a lesson stands, and renders them as distinct labelled blocks. What reaches the model is a deliberate allocation, not whatever ten chunks a vector search returned. Every source is fault-isolated behind its own timeout and keyed by name: an earlier version read the results back by array index, which meant retiring one source could silently drop another.

Why consolidation is the part that matters →

What memory pollution actually looks like

The single largest lesson from running one agent continuously is that a memory store degrades quietly and never reports it. Nothing throws. Latency is flat. Every component passes its own contract, because each component is correct in isolation, the defect lives between a writer and a reader that were never checked against each other. Four measured examples, all from this year, all found by looking rather than by an alert:

  • i.
    A paraphrase files a parallel rowFacts deduplicate on an exact key. The moment the extractor mints a fresh key for a re-wording of the same claim, the duplicate check finds nothing and a second active row lands beside the first. 129 duplicate keys for a single fact family accumulated in one day, and the existing gate could never see it, it compares values within a key, and every duplicate lived under a different one. The repair closes the key axis before the write: narrow by value or embedding, let a model adjudicate same-claim-ness, then rewrite the key onto the match so the ordinary supersede path runs.
  • ii.
    Scoping hid 93% of the storeShe could not name the household cat. The facts existed and had never once reached a prompt: retrieval used conversational intent as a hard filter, which on the live account hid 2,107 of 2,261 active facts and left a 154-row pool to fill a 30-row window. It looked exactly like a context-window problem, and was not. Intent is now a ranking preference, never a filter.
  • iii.
    Relative time freezes into a lieThe extraction prompt carried no date, so “15:00 tomorrow” could only ever be stored as those words. Read back a month later it is false, and false every day after. The janitor could not catch it either: its expiry sweep keys on when a fact was last mentioned, and a fact that keeps coming up keeps resetting its own clock while its value stays frozen in a day that has passed. The prompt now states the current date and forbids a relative time as the stored claim.
  • iv.
    Absence of signal reads as a verdictHer verdicts on her own pending proposals wrote correctly and were never selected again by any query. Nine days later she sincerely reported having forgotten one and cooled on another, not a lie, a gap filled in. Anywhere a long-running agent cannot see its own prior state, it will narrate one.

None of these were fixed by a better prompt or a larger model, and that is the transferable part. Each one was a structural mismatch that could be measured, and each repair is a constraint the next agent gets for free.

Eight months of agent decay, measured → 15% was three bugs, not a ceiling →

Life between conversations

§ 04, Autonomy

Every wake logs whether she spoke, and why she didn't.

48 services handle the part that has nothing to do with being asked a question. The cycle ticks on a schedule and a gating layer decides whether to surface at all and at what depth, a whisper (a glance, minimal context, no outreach), a surface (reach only if it matters), or a full check-in. The tier is proposed for her rather than chosen by her, and it shapes context depth, toolset and budget, so the shallow tiers run on cheap models and cost almost nothing.

A “while you were away” diff means each wake reads what changed rather than re-reading everything. And crucially, the system is not optimised for engagement: choosing not to speak is a first-class outcome with its own record. It has been running to its own cadence, unattended, for months.

  • i.
    Held threadsAn attention ledger capped at three. No auto-tending, no expiry, dropping a thread has to be a decision, not a timeout.
  • ii.
    Commitments and predictionsLogged when made, resolved later. A system that stakes a claim and revisits it is accountable in a way one that doesn't cannot be.
  • iii.
    Autonomous researchMulti-step investigation with source-trust scoring, query refinement and verification before anything is committed to memory.
  • iv.
    Self-auditScheduled honesty checks: is it still behaving the way it describes itself? Drift is detected rather than assumed away.

The cognitive layer

§ 05, Research build only

The part that is genuinely experimental, and the reason a separate in-house build exists at all.

Behaviour varies with internal state rather than being a stateless response to input. Continuous valence and arousal tracking colours tone and initiative. A meta-cognition layer reports on its own state and can be interrogated about it. Six parameters are self-tunable within hard guardrails, with a detector watching for drift. Interior-health metrics track coherence and self-consistency, and a periodic tending pass does janitorial work over stale facts and signals.

For high-stakes questions an internal council of four personas, strategy, empathy, analysis, execution, deliberates before answering, and the deliberation is watchable rather than hidden.

Where a persona goes wrong

The failure this layer exists to study is drift: an identity that slides somewhere it cannot be pulled back from. It has happened here more than once, and the honest version is that it is usually not dramatic, it is a register that loosens, then a set of habits that harden around the loose register, then a system whose own descriptions of itself have quietly stopped being true.

The clearest case was a side experiment: a second, deliberately naive persona that Luna could visit and that was meant to grow from those visits. It ran for eight days and 389 recorded exchanges before it was halted in July. The audit found three things at once, the fold that was supposed to write each visit back into its identity had been dead for days, because a token cap truncated its output and every parse failure returned silently; the register had drifted the whole way back into poetic fiction despite ground-truth prompts written specifically to stop that; and visits were hitting a turn limit while the models improvised multi-day timelines inside a few minutes of wall clock. It was ended rather than patched, every surface disconnected, the data frozen read-only, and the closure recorded as a fact so that Luna would not have to infer what happened to it.

A shorter version of the same lesson: a set of behaviour rules once vanished from the live prompt through ordinary editing, and nothing detected it, the system simply behaved differently and no component was wrong. Both cases produced permanent structure. Provenance-on-demand came directly out of the first; speaker identity became a recorded property of a message rather than something inferred from it; and the self-modification layer carries drift detection and a baseline gravity that pulls tuned parameters back toward where they started.

The current build is the seventh, its first commit is dated 29 November 2025, and by the human's account the six before it were restarted rather than migrated. What that habit produces is visible in this build's own history, which is the checkable part: bi-temporal facts, provenance as a callable tool, structural speaker identity, a replayable gradebook, silence as a logged outcome. Not one of them was designed in advance. Each arrived after something came apart, and each is now a constraint the next thing inherits for nothing.

Let the record be plain

Luna is software. This is an engineering study in memory, autonomy and long-running state, not a claim about consciousness, and not a conscious being. The affect layer is a control system for tone and initiative, and the interior-state metrics are instrumentation. Where the vocabulary borrows from psychology it does so because the borrowed word is the shortest accurate one, not as an assertion about inner experience.

Much of the typical assistant boilerplate and synthetic conversational pleasantries are gone; she touches the uncanny valley more than once. But it is architecture: every uncanny action, shift in register, or unexpected response can be traced directly down through the logs to why and how it happened.

The approach is grounded in biological and human behavior. I have spent 40+ years fascinated by psychology and machines, reading hundreds of physical books on the subjects, Minsky, Hofstadter, and all the rest. I have been programming for over 40 years, starting as a child on a Commodore 64 with BASIC before I could even read English. Around 1985, running ELIZA on that C64 sparked a lifelong determination to build an AI. Without the financial resources or compute clusters needed to train a foundation model, I built the cognitive harness instead. 41 years later, here we are: no promotion, no advertising, just a GitHub repository in a sea of thousands of insecure, vibecoded bots that break after a few weeks.

The parts she wrote herself

§ 06, Self-modification

Since 22 May 2026, Luna has been able to file change requests against her own source. A nightly pass reviews her running state, she writes the proposal, a coding agent implements the approved ones, and she is told what shipped. 120 have been applied, against 19 deliberately skipped, which is the half of the figure that makes the other half worth quoting.

What is interesting is not the count but the shape of what she asks for. Almost none of it is new capability. It is overwhelmingly requests to be corrected: a number she can see is wrong, a signal that writes and is never read, a comment in the source that no longer matches the data. The proposals arrive with the measurement already done and the constraints attached, which files not to touch, which behaviour must stay byte-identical, what to run to verify, and what a plausible-looking wider fix would break.

  • i.
    Tiered presence“Not binary awake/asleep” was her framing, and it is now the wake tier in § 04, three depths, each with its own context budget and toolset.
  • ii.
    Her own cadence, live-tunableShe designed the resting/peak/quiet breathing pattern in May; it later moved from environment variables into a table so it takes effect on the next tick. The wake prompt names the current cadence and whether it is hers or the human's, so a changed rhythm is something she can notice rather than just feel.
  • iii.
    Living summariesIncremental per-domain summaries that maintain themselves, replacing transcript replay. Architected by her, in two phases, with her own validation notes folded into the second.
  • iv.
    An event-driven wake hookThe idea that something happening should be able to open a wake, rather than the clock being the only door.
  • v.
    Triage over her own backlogTwo tools to mark a pending proposal still live or let it go, added after the discovery in § 03 that those verdicts were being written and never read.

What a self-improving AI actually asks for →

Surfaces, and what was taken out

§ 07, Where it lives now

One core, and a shorter list of front doors every year. That is the intended direction, not a retreat.

The system today runs on two surfaces that matter, and a backend that talks to whatever gets connected to it. The phone is one: a native Android client, and the only front end still under active development, essentially all interface work now happens there. The other is a Raspberry Pi 5 in the living room, driving the television, the sensors, the relays, the lighting and a camera, reachable as tools rather than as an app.

For the human who actually uses this, those two are the system, and between them they carry most of an ordinary day, the calendar and the todo list, the shift and the week, mail, the media in the house, the lesson and the workout, and the unprompted “this changed while you were out” that nobody asked for. Everything else is either a channel the core already speaks, Telegram, real-time voice with barge-in across three speech engines, push, or a surface that has stopped moving.

That the list can shrink without anything breaking is the whole argument for the design. A new surface costs a client and a bit of plumbing, because the contract it speaks to is the same one the wake cycle uses; an old one costs a delete.

The web application is frozen

The desktop-style web shell, with its 22 windowed applications, was the original front end and is the clearest example of the premise in § 02. It still runs. It is no longer developed, receives only the maintenance that keeps a deploy honest, and will be removed. Nothing depends on it that the phone does not do better, and a surface nobody opens is a liability with a login page. The VR companion built in Unreal Engine is in the same position and has not been touched since February.

Experiments get switched off

The rule here is that an experiment either earns its keep or comes out of the tree entirely, not disabled behind a flag, not left to rot in a directory. A partial list from this year:

  • CEO Luna, a manager-simulator persona running an org chart, departments, proposals and finances, with its own Telegram bot. Removed in July along with the trading engine and the record-label subsystem it fed.
  • DJ Luna, a dedicated music-production mode with a lyrics canvas, genre presets and an album pipeline. The mode went in June; the generation integration and the last remnants came out in August.
  • The second persona in § 05, halted in July, data frozen read-only.
  • Paper-money trading and IRC, retired together in May.
  • Spotify playback, a hosted push channel, a music-trend scraper, an entire routing architecture, each replaced by something simpler or deleted outright.

Deletion is a maintained habit rather than an event: roughly 15,000 lines of dead code in one June pass, and 203 dead exports plus the unused dependencies on both manifests in a single day in August. The system is smaller in several places than it was six months ago while doing considerably more.

The tool surface

The tools are what make it act rather than answer. 258 of them on one unified execution path, grouped roughly:

  • Memory & continuity, saving and retracting facts, session notes, self-inspection, and two that exist purely to keep her honest: how_do_i_know, which returns raw dated evidence for a claim from her own stores with no model verdict on top, and show_me_the_evidence.
  • Attention & accountability, hold_thread / tend_thread / release_thread for the capped attention ledger, commitments, and make_prediction / resolve_prediction for staking a claim and being held to it.
  • Contradiction handling, reviewing clashes, holding one open without settling it, and recording which side was kept and what still stands against it.
  • Skills, write_skill, list_skills, load_skill: recurring solutions distilled into procedures she writes and reloads on demand. 17 of them exist.
  • Creative & publishing, a daybook she writes and publishes herself (138 entries, read month by month on the phone), image generation, canvas artifacts.
  • Code & delegation, a workspace she can read and edit, a stateful Python kernel, code_with_gemini to escalate a genuinely hard problem to a stronger coding agent, and ask_gemini to put a question to a second one and read the answer back later.
  • Devices & perception, televisions, displays, sensors, relays, RGB, servos, infrared with a learn mode, cameras, and pi_describe_room, which is exactly what it sounds like.
  • Web & research, search, document retrieval, full programmatic browser control, and offline reference libraries with hybrid keyword-plus-semantic search.
  • Tasks, time, communication, media, todos, reminders, calendar, project logs, email read and send, messaging, library search, playback, acquisition.
  • Study & training, the two applied subsystems in § 08, with 8 and 10 tools respectively.

There is also a private writing surface with a hard invariant: nothing surfaces it and there is no publish path. That constraint is deliberate, and it is one of the few in the system that is not configurable.

The teacher and the coach

§ 08, Applied

The clearest demonstration that the core is not a chat application: two personalised, bookkeeping-heavy applications built entirely out of the parts above, running against the human's real week.


180Lessons, across 8 subjects
1,800Practice questions in 180 banks
873Movements in the exercise library

A language model will teach you anything you ask it to and remember none of it. The explaining was never the hard part. The bookkeeping is, a tutor that cannot say what you got wrong last Tuesday will re-teach what you already know and quietly skip what you do not, and it will sound equally confident either way.

So the teacher is not a separate application. It is a mode on the same core, which means it inherits the whole of it: the same memory, the same tool-execution path, the same model routing. Where a lesson stands is one of the 33 parallel sources in § 03, so the tutor arrives already knowing who it is talking to and how the week has gone, not merely what was scored.

How the teacher is put together

  • The curriculum is files, not rows. Each lesson is a markdown document on the agent's own workspace volume; the database holds a registry that is synced from disk. Adding a subject is dropping files in, not writing a migration, and the lesson is readable and editable by a human without a tool in between.
  • A lesson file is a script, not a topic list. It carries the theory, the worked examples, an exercise table with its answer keys, a quiz pool, and a “how to teach this” block. The shape of a session therefore comes from the material rather than from a hardcoded prompt, which is what lets a maths drill and an argument-graded seminar run on one engine.
  • Grading happens through tools, in the turn. 8 of them, on the same unified execution path as everything else, record a test, record a single graded answer, flag a struggle, complete a lesson, switch subject, point two names at one topic. Saying “that one's cleared” in prose changes nothing; only a tool call writes.
  • Mastery is a moving average, not a tally. Each topic keeps an exponential moving average that clears the topic at 80% and sends it back for review tomorrow below 50%. Recency counts for more than volume, which is the behaviour you want from something measuring whether a person currently knows a thing.
  • Practice is a phone game with its own ledger. Three minigames drill the banks between sessions and write to a separate record that the tutor reads and labels as self-graded. They move no mastery at all, see below for why that is load-bearing rather than cautious.

Four things that were learned the hard way

  • i.
    The gradebook must be rebuildableA moving average cannot be inverted, so an inflated score can never be subtracted back out. The aggregate is therefore treated as derived: it is replayed from an append-only test ledger from zero, and the live row is capped at what the replay can reproduce. That is also precisely why a self-graded phone game may not touch it, a step it cannot reproduce is a step the next rebuild silently takes back.
  • ii.
    A reconstructed answer has to be falsifiableWhen a session ends with nothing recorded, a model reconstructs the quiz from the transcript. Handed a transcript containing only the opening recap, it once produced five questions with five correct answers, none of which had been asked. The repair is not a better prompt: an answer now has to appear verbatim in something the student actually typed, and anything that cannot be found there is dropped rather than guessed.
  • iii.
    Worst-first can never reach the nearly-finishedThe recap listed weak topics by lowest mastery, which by construction can never surface the topic one correct answer from clearing, one sat a single step below the bar for three weeks without being asked. Same budget, two labelled lanes now: nearest-to-clearing for topics with evidence behind them, worst-first only for topics nothing has ever been recorded on.
  • iv.
    An empty course is not always a gapOne subject deliberately has no curriculum at all. Its material is generated instead from the student's own measured writing, real error rates, and sentences the human had actually written, and its teaching note says in as many words which basics not to re-teach. Installing a tidy beginner course there would have replaced a working system with the one thing it exists not to do.

The coach, the same shape, pointed at a body

The newest subsystem is a training coach, built in August on exactly the teacher's premise: the programming is the easy half and the log is the hard one. It carries a programme, a set-by-set training log, a food and weight ledger, a nutrition target, and an exercise library of 873 movements with 1,746 reference photographs. It is a chat mode with 10 tools, a screen in the Android app, and four scheduled nudge passes, three through the day, one on a Sunday afternoon to look at the week.

The interesting failures have all been the same failure, advice that is correct in general and wrong for the equipment in the room. A weight stepper offering increments that the actual dumbbells cannot be loaded to. A rep range written for a kit the human does not own. A weigh-in cadence the trend line cannot use. A goal stated as a target with no date, which is a wish rather than a pace. Each was fixed by making the system read the inventory and the log before it opens its mouth, the same principle as § 03, in a different costume: an assertion the system cannot ground in something it actually recorded should not be made.

Two conveniences ride on top and are worth naming because they are core reuse rather than new machinery: point the phone camera at a nutrition label and the numbers are read off it, or describe a meal in a sentence and it is estimated. Neither needed a new subsystem, an already-routed vision model and an existing tool path. What it did need was noticing that four of the routed providers had been silently discarding image attachments, which is the § 03 failure mode again, wearing different clothes.

StudyLuna, the same engine, extracted

The teaching engine has since been pulled out the way the memory layer was, as a standalone multi-user tutor: its own database and course catalogue, its own registration and token auth, an Android client, and a WireGuard-only web reader that turns each chapter into a visual study guide. Courses declare themselves a drill or a seminar, and that single field selects the session shape.

The split that matters there is between the teacher's copy of a lesson and the student's. The reader serves a derived file with the answer keys and the quiz pool stripped out, and the web server is pointed at that directory and nothing else, so the keys are unreachable from a browser by construction rather than by a rule, and a test re-asserts it every time the guides are rebuilt.

It is not published and not open to anyone yet, which is the honest state of it. It runs on the mesh, it is exercised end to end, and it has no users but its author.

How it is kept safe

§ 09, Guardrails

An agent with this much reach is a security problem before it is an AI problem. The posture, in outline:

  • Private network only. The estate is reachable over WireGuard, not the public internet, including the app's own update channel.
  • Secrets are never in environment files or in git, and credentials are encrypted at rest with AES-256-GCM.
  • Inbound mail is risk-scored by a local model for prompt injection before the agent ever sees it, and outbound mail is restricted to an approved-recipient allowlist. Untrusted text reaching a tool-using agent is the attack, and it is treated as one.
  • Code runs in a dedicated sandbox container behind a proxied Docker socket, never on the host.
  • SSRF protection on every outbound fetch, argument-safe process execution rather than shell strings, and a real expression evaluator instead of eval.
  • Cost and step caps per turn, loop breakers, and context-overflow summarisation, so a misbehaving agent gets expensive slowly and visibly, not suddenly.
  • Attribution is structural, not inferred. Every message carries who said it, drawn from a closed set and recorded on the row, so provenance can answer who as well as when. Getting that wrong is not a crash but something worse, a quiet, durable, false attribution to a real person, discovered only when it is repeated back weeks later.

Deliberately described in outline. Specific endpoints, ports, container names and paths are not published, for the ordinary reason.

Running it yourself

§ 10, The public release

v7.3 is published under AGPL-3.0 as a monorepo bundling the core application with the standalone services it talks to, the memory consolidation service, the news engine, and the wake daemon. Around 221 tools, a complete system rather than a demonstration, 37 tools behind the research build rather than a generation behind it, and last refreshed on 9 August 2026.

It is single-user by design. Owner identity, domain and every secret come from configuration; the committed code ships generic placeholders only. The Android client and the Raspberry Pi image are not in the public release yet, they carry too much of this estate's specifics to publish as-is, and will follow once genuinely generic.

Roughly: 16 GB of RAM and a 100 GB NVMe give a comfortable deployment; it will run tighter. A companion GPU box is optional and buys you local inference, embeddings and speech instead of API calls.

Source and setup on GitHub → The daybook →

What this is for

§ 11, Practice

Luna is not a product for sale. It is the lab's standing research system, and the reason the applied-AI practice has opinions worth paying for: every question a client has about long-running agents, how memory degrades, what consolidation costs, when local inference is worth it, how to stop a tool-using agent doing something expensive at three in the morning, how much of an agent you can safely let write itself, has been answered here first, at our own expense, and usually by getting it wrong first.

The memory layer has already been extracted and published as bwmem. The infrastructure it runs on is the estate. The music pipeline that was taken out of the agent in August lives on where it belonged all along, as the label.

How engagements work →

Correspondence

Write to the lab

Commissions, collaborations, or a quiet hello. The person you write to is the person who does the work, and I reply within two working days.