GLaDOS 1.2.26
The release where the machine changes itself.
134 commits since 1.1.0. The agent loop, the self-modification loop and the ability to write its own applications all existed as sketches then and exist as working paths now, each with judges in front of them. Everything below is checked by running it, and the boot output is the test suite.
The machine changes itself
godelis the loop that lets the kernel modify itself, andsrc/ai/godel.rsopens with why it departs from Schmidhuber's construction: there is no theorem prover here, so proof is replaced by a certificate cheaper to refute than to produce, over content-addressed inputs, re-derivable bit for bit by any later run.- Four judges, unanimity required, each a different failure mode. J1 is a paired McNemar test over the same cached decisions both variants answer, which is what a comparison of two percentages cannot be. J2 replays the machine's own curiosity goals along the frozen baseline's path. J3 is structural: finite factors, positive scales, finite logits. J4 is cost, in rank and resident bytes.
- Adoption is a pointer swap, so
godel rollbackcosts a pointer write, and/ai/godel/ledger.txtgets a line per trial either way. - One loop for any kind of change. A proposal is an adapter grid point, a routing rule, a deep training run, a skill or a council core, and the same judges decide all of them.
- The night branch rotates over every axis that has a judge. It knew two jobs and
godelalways won the tie, so the adapter grid was walked to exhaustion while the routing rule, deep training and core composition were never tried unattended at all. Search space exhausted was the end of self-improvement: eight points and then nothing, every night forever.godel nextnow reports where the rotation stands without spending the night finding out. - There is no random seed, and that was a bug rather than a virtue. Every trial trained a bit-identical adapter with the same content hash, so after the first adoption each later one was compared against itself: nothing repaired, nothing broken, rejected, forever. The fix is a declared grid walked in a fixed order with tried points marked, so the next point is a function of the ledger rather than a coin.
- The test slice carries a budget. It is consulted only after a variant has won on validation, the ledger counts the reads, and past three a test figure prints as stale and unquotable. A machine that improves itself every night reads the held-out set every night, and this project's measurement discipline does not survive that unless somebody counts.
- The routing rule is searchable at last, judged on calibration rather than accuracy, because what a rule moves is how much better the council's confident answers are than its unconfident ones. Requiring a win on J1 is exactly what made the axis unsearchable; the floor is symmetric now.
- A council core is a proposal, not just an operator command.
core trialwrites a node, a ledger line and somethingrollbackcan undo, and rollback restores the core as well, because rolling back an adopted core used to leave it installed and voting.
The agent, and applications it writes
- Agent episodes run applet calls in a loop, capture observations, write a transcript to
/ai/episodes, and freeze successes into skills. - Three-tier decisions: reflex dispatches on router-and-council agreement before the sampler runs, pulse takes one greedy constrained walk, deliberation forks sampled candidates and ranks them with the router.
- A skill is judged before it becomes a tool.
agent learnused to compile a successful episode into/ai/toolsand that was the whole of adoption. Four judges now decide, constrained by what a replay skill actually is: it parses, it runs under the powers an unadopted skill really has, it repeats, and it is cheap. - A skill is not automatically the operator. Every program under
/ai/toolsused to run with operator capabilities including raw memory, I/O ports, the network and the framebuffer. It was open by omission rather than by argument. Identity is the hash of the file, so editing a trusted skill revokes its trust by construction. run's argument is decoded under a grammar built from the live skill list. The applet name always was, but the argument was free text, so the model had to spell/ai/tools/learned-3f2a91c4.ai&xiexactly: adoption that put a tool in the toolkit nothing could pick up.- Applications are documents and programs at once. Manifests, lineage, and a grant that names one artifact rather than a capability class.
- The machine writes applications. Skeletons and drafts came first with no model involved at all, then the authoring loop, then the model driving it. Skeletons emit records and types, and the machine writes one unattended.
- A progress window shows step N of M, clauses met and the last verdict verbatim. No progress bar and no estimate, because a step can be a skeleton that lands instantly or a decode that takes seconds.
- The engine has one holder.
HOLDERrecords the task andwith_engineclaims it for the length of a call, replacing a flag-and-id pair per task, which is why a third holder was invisible: the nightly trial ran on the initiative task, set neither flag, and handed a second&mut Engineto anyone who asked for twenty seconds. - One queue, one busy flag, one abort, one task for episodes and authoring both, because a second task running a second kind of work needs a second entry in the engine's exclusion check.
- A resident mind thinks between commands, and
aixi-liteplans over the machine's own fitted dynamics with Monte Carlo rollouts.
The language
- The system language is called Aiksi, and its capability gate was inverted from a denylist to an allowlist. A denylist grants by default, so the builtin anyone forgets is the one that matters. Every row is name, touch class and arity, and an arm without a row is dead code rather than an ungated builtin.
- It reaches the kernel: text, integer arithmetic, lists, the namespace, the clock and counters, tasks and memory, PCI, network status, sockets, the model, the framebuffer, raw memory and I/O ports.
- Records, optional types and
use. A record is a declaration and a constructor in one, records are values so nothing has to explain aliasing, and types are checked where a value crosses a boundary somebody annotated rather than inferred by a solver. - Everything that is actually a struct answers a record now.
pci_listgivesDevice,rtc_nowgivesTime,net_ifacesgivesIface. It answered text only because there was nowhere to put a field, and every caller then wrote the same fragilesplitto take it apart. - A native code generator:
src/aiksi/jit.rscompiles integer arithmetic,if,whileandreturnto x86-64, emits into a page-aligned heap buffer and calls it through a pinned sysv64 pointer. Anything outside that slice is refused rather than half-compiled. diag differruns one program two ways and requires agreement on value, step count and error text, bit for bit, over 64 rounds. It carries a canary case that must fail, because a harness that has never reported a difference is indistinguishable from one that compares nothing.- A step was timed for the first time in this project's history, and the measurement refuted the plan that asked for it. The tree-walk was never the cost. Three rounds of removing allocations took a vote from about 418 step-equivalents to 146, and none of it came from compiling anything.
Training
- QDoRA adapters over the classifier and over every q/k/v site, with the backward kernels to match: activation adjoints for RMSNorm, SwiGLU, attention and RoPE, then full site gradients including the norm terms.
Tapekeeps the residual stream entering each layer and nothing else;Model::backwardwalks layers last to first and recomputes each from that stream.- The input gradient, which
Dora::backwardnever produced, and which was the single absence that made a classifier adapter trainable and a q/k/v adapter not. - An exact f32 KV cache for training, because the served int8 cache makes the loss piecewise constant in anything upstream of a cached key: differencing a layer-0 query through the quantised forward reported -0.305 against an analytic gradient of order 1e-6.
- The gradient check is directional and uses cross-entropy, both for resolution. A per-entry difference asks f32 to resolve a float quantum wearing the costume of a derivative.
- Adam and restricted cross-entropy, proven by overfit, with the gradient zeroed outside the grammar's candidate set so only rows the decoder can reach ever move: 132 rows out of 49,152 on the measured decision layer.
- Deep training is judged now. It was the one training path with nothing in front of it, walking gradients into the live model and keeping whatever came out.
The conversation
- One conversation, continued, that survives a reboot. It resumes the KV cache instead of re-sending a transcript, so the tenth exchange costs the tokens of the tenth exchange.
- It outlives its context. Within 64 positions of the trained length the cache becomes a ring with four sinks and evicts its oldest turns instead of stopping.
- The system turn is pinned, using the same sink mechanism, so the instructions and the applet list keep their original slots and RoPE angles for as long as the conversation runs.
- Autosnap is on by default and the KV context is deliberately not in it. Parking the cache per turn wrote 16,375 blocks and took half a 27 MiB region in two turns; removing it took the same measurement to one block.
More than one core
- Application processors start, walk up to long mode and run work.
Mat::matvecand the backward adjoint are both split across every core, the adjoint by column because it accumulates down rows. - The heap and the console are behind a real spinlock with
lock_irq, because allocation happens under interrupts and the clock task prints from a timer tick. - A scheduler shaped for more than one core: per-core GDT, TSS and APIC, per-core current and pending slots, pinning, and a task that migrates between cores and back.
- Every task this kernel spawns is still pinned to core 0 on purpose. Preemption on one core means two tasks never execute at the same instant; on two they genuinely overlap, so every
Racyreachable from two tasks becomes a live race.unpinexists and nothing calls it, which is the honest state of the audit rather than an oversight.
The desktop
- Every entry in the Program Manager opens a window, the Start menu grew a query row at its foot, and windows snap to edges, resize from any edge, and say so with the pointer.
- Two console grids, so the machine's own output stops arriving in the middle of an operator's half-typed command.
- Settings pages that show the machine's state, and caption buttons that have their glyphs back.
- 325 glyphs and UTF-8 decoding in the console: Latin-1, Greek, box drawing, arrows, maths and blocks.
fontprints the whole sheet.
Storage, updates and the rest
- Staged updates are applied before
ExitBootServices, verified by digest, and put back if the write fails. Driven end to end against real firmware with a throwaway key and two builds a version apart. - The NVMe write unlock names a range and the range is enforced. It was one bit for a long time: from the moment
store::initsucceeded, every LBA on the device was writable, including the partition table and the Windows volume that is still the only other thing on this disk. - FAT32 writing.
fat putandfat rm, with the cluster chain allocated before any data enters it and every copy of the table updated. - The sandbox copies nothing up front. It used to deep-copy the whole namespace so it had something to restore from, paying for a clone of every object to undo a program that usually touches one file.
- Corpus bundles, so a training set can be replaced on a running machine.
- File type detection and structure for text, markdown, json, jsonl, xml, csv, ini and eight languages.
- Temperature, measured frequency and HWP governors, behind a gate that checks vendor, CPUID and the absence of a hypervisor before touching an MSR.
- Per-task memory accounting: every allocation billed to the task that made it, with peak and outstanding.
- A fault inside a program the machine wrote for itself is caught and reported instead of halting. Recovery applies only to code running under a guard; a fault anywhere else stays fatal, because there is no isolation here.
- A midstate-cached SHA-256d miner with a scoreboard that prints the odds on every run, so nobody involved is allowed to forget them.
Fixed
- Aiksi was dynamically scoped by accident, so a callee could read and write its caller's locals.
- No fault this kernel ever took produced a readable report.
kprint!writes the console before serial and painting from an interrupt gate takes a #GP, so the first line died before serial was reached and the machine simply went quiet. - The desktop froze because the shell never yielded, not because drawing was slow. A scheduling bug wearing a rendering costume: the frame is 2.9 ms, measured.
- A menu nobody opened was eating every keystroke.
- The console kept one screen, so the boot log did not exist.
- The emulator was never the constraint. WHPX is roughly 160 times faster than TCG on this workload, and everything treated as too slow to test here was an untested assumption about the emulator, for months.
- A 1.8 GB checkpoint the UEFI pool refused, which nothing had tried pages for.
- A stored variant did not read back as itself, so lineage nodes described something that no longer reproduced.
- An adapter read the caller's buffer width instead of its own.
- The cl100k tokenizer test was broken, not the tokenizer.
- Twelve defects an adversarial audit found in one night's work, and three more the update swap found only when it was driven against real firmware.
- Blank console cells were painted pixel by pixel, about 1.2 million per-pixel stores a frame writing the colour already there.
- The version had been 0.1.0 since the first commit, so
update::decidecompared every staged image against a number that never moved. diag migratesampled one 200 ms window and called migration broken if a second core had not picked the task up inside it. It reported a failure on a boot that had just allocated a 768 MiB cache, and four consecutive runs on the same image afterwards saw the task on two, three, four and four cores. It samples up to eight windows now, bounded so a genuinely pinned task still fails.- The ISO claimed to carry the model's licence and did not, because the file lived in an ignored directory.
mkiso.pynow refuses to build a payload without one.
Images
Six bootable UEFI ISOs, checksums in SHA256SUMS. The 2B is offered at three context windows because the weights are identical and only the KV cache differs.
| Image | Model | Context | KV cache | Size |
|---|---|---|---|---|
glados-1.2.26.iso |
Qwen3-0.6B | 512 | 112 MiB | 576 MB |
glados-1.2.26-qwen35-2b.iso |
Qwen3.5-2B hybrid | 512 | 12 MiB | 1810 MB |
glados-1.2.26-qwen35-2b-8k.iso |
Qwen3.5-2B hybrid | 8192 | 192 MiB | 1810 MB |
glados-1.2.26-qwen35-2b-32k.iso |
Qwen3.5-2B hybrid | 32768 | 768 MiB | 1810 MB |
glados-1.2.26-smollm2-135m.iso |
SmolLM2-135M | 512 | 112 MiB | 133 MB |
glados-1.2.26-nomodel.iso |
none | 33 MB |
The hybrid carries a KV cache on only 6 of its 24 layers; the other 18 hold a 19.3 MiB recurrent state that is the same size at token 32 as at token 32,768. That is the whole argument for the architecture, and it is why a 32k window costs 768 MiB rather than several gigabytes.
The 2B images want 5 GB of RAM, and 8 GB for the 32k, since the weights are read whole into a pool before ExitBootServices. The 135M image is the one to reach for under emulation.
Known
- USB HID is written and does not work. It is blocked on an xHCI enumeration bug that the USB Ethernet path shares, so nothing has ever enumerated on that controller model.
- There is no battery reporting. That needs an AML interpreter.
- The update key is all zeroes, so staged updates verify as
NoKeyand are refused until a signer is provisioned. - The console takes a #GP if it paints from inside an interrupt gate. That bug is older than the fault reporter and is now visible rather than silent.
- An authored application is still left as a draft and never adopted, and
aixi's plan is stringified to a report rather than gating how much the loop attempts.
Licensing
The kernel source is not licensed for reuse. The model weights are Apache-2.0 and their licence travels in each image at \GLADOS\LICENSE.TXT.