# Show HN: 80s computing era meets small local decision models

> Source: <https://github.com/HuyNguyenAu/amber-8>
> Published: 2026-10-20 09:41:33+00:00

Amber-8 is a small deterministic stack machine that uses a local language model like an analog to digital converter: turning messy, subjective data into clean measurements on a stack, while keeping execution deterministic. It is a call to go back to basics and throw away all the modern complexities and comforts.

Currently there are two extremes in software: complex chains of autonomous agents on one side, and manual programming without any assistance on the other.

A lot of useful input in programming is messy: user feedback, complaints, or someone typing "It's too dark to read and I am sweating." Handling that with regexes or keyword rules gets fragile fast because they break on any sentence you did not plan for. At the same time, handing your entire program flow over to an agent framework or prompt chain makes behavior unpredictable and hard to debug.

Amber-8 keeps things simple. The machine is just a data stack, a call stack, and a program counter. The language model does not write code or decide branching. Three model instructions pass unstructured text to the model and push numbers, choices, and confidence values directly onto the stack. From there, the rest of the program is ordinary deterministic code: arithmetic, comparisons, and jumps.

Compiled binaries are tiny, with all example programs compiling to bytecode under 2 KB. How often can we claim that the binaries produced by our programs are measured in bytes?

Here is an example that converts room comfort feedback into a temperature adjustment:

```
psh "It's too dark to read and I am sweating."
br temperature
end

temperature:
  dup
  psh "How does the room temperature feel?"
  psh [ "Much too cold" "Cold" "Comfortable" "Warm" "Much too warm" ]
  scl                             ; Stack = [confidence, score, feedback]
  psh 0.5 ge ife adjust ask_person
  ret

adjust:
  psh 2 sub                       ; "Comfortable" is index 2
  psh -3 mul                      ; 3 degrees celsius per step
  prt
  ret

ask_person:
  pop
  psh "Unsure about the temperature: passing to a person." prt
  ret
```

In this program, `scl` scores the feedback against an ordered scale from 0 to 4. It pushes the expected score and a confidence value between 0 and 1. The program checks if confidence is at least 0.5. If it is, `adjust` subtracts the index of "Comfortable" (2) and multiplies by -3 to calculate the change in degrees celsius. If confidence is too low, the program branches to `ask_person` instead.

The full program, which also adjusts lighting, is in [examples/room-comfort.a8s](https://github.com/HuyNguyenAu/amber-8/blob/main/examples/room-comfort.a8s). Other examples are in [examples](https://github.com/HuyNguyenAu/amber-8/blob/main/examples).

Amber-8 provides three instructions to query the model:

| Instruction | Stack effect | Result | 
|---|---|---|
| `ask` | `[instructions, state] -> [conf, p]` | Probability `p` that a yes or no statement holds for`state` | 
| `pck` | `[criteria, instructions, state] -> [conf, choice]` | The option from list `criteria` that best fits`state` | 
| `scl` | `[criteria, instructions, state] -> [conf, s]` | Expected index `s` of`state` on the ordered scale`criteria` | 

Each instruction pushes its result with a confidence value from 0 to 1 on top of the stack. Putting confidence on top lets you check it against a threshold and branch immediately if the model is unsure.

I like how simple and elegant the concept is. The whole machine is a data stack, a call stack, and a program counter. There is no hidden state, nothing running in the background, and no runtime to install. All instructions consume from the data stack in a LIFO manner. The mechanism is small enough to fit in your head.

When working with a probabilistic language model, the model is the one piece of the system you cannot fully predict. For everything else surrounding it, execution should be explicit and easy to audit. If a program encounters bad data or makes a wrong move, you can trace the exact instruction that ran. In Amber-8, control flow is explicit: every block has one entry and one exit, and control never falls through between blocks. When a fault occurs, the machine halts immediately and leaves the data stack intact so you can inspect what happened.

Many agent setups let the model decide the next step. That works for quick demos, but it makes guarantees and debugging difficult. In Amber-8, the model only evaluates fuzzy text, while control flow stays in assembly where branching is explicit.

Most real world work has two distinct parts: judgement (interpreting messy, subjective input) and procedure (running strict rules in order). Modern prompts mix both into a single probabilistic block of text that cannot be unit tested. Amber-8 splits them apart: procedure stays in verifiable code, while the model is only invoked where human judgement is required. Even as models advance, the strict layer remains essential for accountability, auditability, and cost. (See [Moving Up a Layer](https://github.com/HuyNguyenAu/amber-8/blob/main/docs/thesis.md) for the essay on this).

This project is a continuation of my earlier work on [llm_native_virtual_machine](https://github.com/HuyNguyenAu/llm_native_virtual_machine).

In that project, I explored what an assembly language powered by an LLM could look like by building a RISC-V inspired register machine with 33 general purpose registers and 33 context registers. It decomposed prompts into instructions like `INF` and `EVAL`, but programs had to manage context stacks manually and run assembly retry loops to validate generated text.

Amber-8 simplifies that concept down to a minimal stack machine. The earlier VM relied on context registers, prompt strings, and free form text generation. Amber-8 treats the language model strictly as a sensor. By narrowing the model interface to three primitive operations (`ask`, `pck`, `scl`) that return numbers, choices, and confidence scores onto the stack, control flow branches directly on clean values without parsing text outputs or managing prompt histories in registers.

The execution model draws from early microcomputing like Forth, the MOS 6502, and the PDP-8, where machine state was small enough to hold in your head. The name and visual appearance come from the amber monochrome CRT monitors of that era, like the DEC VT220 (`#FFB000` text on black).

Programs are self contained files, similar to cassette software on 8 bit computers. Source code (`.a8s`) compiles into a single bytecode binary (`.a8b`) that runs without runtime dependencies beyond the model server. The VM is small enough to run on a cheap single board computer, while the language model runs on a separate machine.

Other direct inspirations include Bob Nystrom's [Crafting Interpreters](https://craftinginterpreters.com/) for interpreter design, and Andrej Karpathy's ideas around Software 2.0 and LLM OS.

1. Install [Rust](https://rust-lang.org/tools/install/) .
2. Start a llama.cpp server with the System One endpoint (`POST /v1/systemone` ) on`127.0.0.1:8080` .
3. Build and run an example:
Or run the steps manually:

```
./run.sh examples/room-comfort.a8s
cargo run build examples/room-comfort.a8s
cargo run run examples/room-comfort.a8b
```

Reference docs:

- [Specification](https://github.com/HuyNguyenAu/amber-8/blob/main/docs/specification.md) : instructions, assembly syntax, bytecode format, and runtime faults.
- [System One](https://github.com/HuyNguyenAu/amber-8/blob/main/docs/system-one.md) : how model instructions map to the API and how confidence scores work.
- [Vision](https://github.com/HuyNguyenAu/amber-8/blob/main/docs/vision.md) : design notes and background philosophy.
- [Thesis](https://github.com/HuyNguyenAu/amber-8/blob/main/docs/thesis.md) : moving up a layer, separating judgement from procedure, and why the deterministic layer stays.

- Calibrate confidence thresholds against labelled test data for each example.
- Runtime string operations beyond joining with `add` , and dynamic lists.
- Parsing strings to numbers.
- File writing.
- Step and call depth limits.
- Stack helpers like `rot` and`pick` .
