Skip to main content

Avalon

An adaptive AI runtime. MIT © Lunar Labs.

The LLM is a stateless function f(context) -> token. Avalon is the runtime around it that persists, perceives continuously, holds state, learns while running, and acts on a clock — the model is demoted to a frozen language cortex; all learning lives in hot-swappable LoRA adapters gated by measured fitness.

This is v1: the first slice of a much larger vision. Every module maps to a constraint measured on real hardware (Mac Mini M4 / MacBook M1 Pro, Qwen3-4B 4-bit, MLX, 2026-07). Where the research hit a wall, v1 ships an honest interface instead of a fake.

Architecture

                 external events (sensors, messages, tools)
                              │  land whether or not anyone is talking
                              ▼
   ┌──────────────────────────────────────────────────────────┐
   │ HEARTBEAT  (intrinsic time)                              │
   │ tick loop · nested clocks now/day/project/life           │
   │ ONE append-only event stream · atomic JSON state         │
   │ daemon mode: avalon serve · intake: avalon inject        │
   └──────────────────────────────────────────────────────────┘
                              │
                              ▼
   ┌──────────────────────────────────────────────────────────┐
   │ DEEP TIME  (memory with half-lives)                      │
   │ salience decays exponentially (36 h default) · surprise  │
   │ events RE-INK referenced memories · event stream ->      │
   │ episodes · learned circadian histogram (starts blank)    │
   └──────────────────────────────────────────────────────────┘
                              │
                              ▼
   ┌──────────────────────────────────────────────────────────┐
   │ EPISODIC BUFFER  (provenance-typed, surprise-gated)      │
   │ observed │ inferred │ said-by-assistant                  │
   │ ONLY observed is trainable — anti-fabrication defense    │
   └──────────────────────────────────────────────────────────┘
                              │ observed entries, retrieval-task Q→A
                              ▼            (NEVER transcripts)
   ┌──────────────────────────────────────────────────────────┐
   │ CONSOLIDATION  (sleep)                    per night      │
   │ sufficiency gate → 2:1 mandatory rehearsal → collapse    │
   │ cap → training manifest → pluggable Trainer              │
   └──────────────────────────────────────────────────────────┘
                              │ candidate adapter (one file)
                              ▼
   ┌──────────────────────────────────────────────────────────┐
   │ FITNESS GATE  (git for a mind)                           │
   │ probe fixed held-out set ± adapter → DIFF = what it      │
   │ learned → regression check FIRST → promote | roll back   │
   └──────────────────────────────────────────────────────────┘
                              │ promoted
                              ▼
   ┌──────────────────────────────────────────────────────────┐
   │ ADAPTER REGISTRY  (the registry IS the tool list)        │
   │ named callable skills · base-version pin · fitness score │
   │ ONE live adapter · 2-3 hot pre-fetched · 5 ms swap       │
   └──────────────────────────────────────────────────────────┘
                              │ adapter_path per request
                              ▼
   ┌──────────────────────────────────────────────────────────┐
   │ FROZEN BASE  (OpenAI-compatible server, mlx_lm style)    │
   │ never trains · auto-launched local mlx_lm server on a    │
   │ free port (pilot-run), or your own base_url              │
   └──────────────────────────────────────────────────────────┘

Measured operating points

These are bench numbers, not defaults pulled from thin air. They live in avalon/config.py with citations in comments.

Constraint Measured value Where it's enforced
Consolidation point lr 5e-5, 48 iters — 3/3 recall after full context wipe; 8 iters = degenerate loops config.py, pinned in every manifest
Paraphrases per fact ~10 (27 rows about one fact = mode collapse) consolidate.cap_rows_per_fact
Rehearsal 2:1 mandatory — 0:1 → 0/3 prior facts survive; 2:1 → 3/3 consolidate.build_manifest
Training shape Q→A retrieval task — transcripts scored 0/3 on a perfect loss curve consolidate.pair_from_entry, lunarlabs-core TrainingPair
Sufficiency skip empty days — updates on signal, not schedule build_manifest sufficiency gate
Live adapters ONE — multi-adapter composition costs ~40% each registry.activate
Adapter swap 5 ms attach; pre-fetch 2-3 hot registry hot cache + swap latency
Adapter size rank-16, 8 layers = 14.7 MB config.py
Trainable memory observed only — inferred / said-by-assistant never train buffer.trainable()
Memory half-life 36 h default — salience = surprise × strength × 0.5^(age/half-life); re-inking resets the clock deeptime.effective_salience, buffer.reink
Episodes 30 min silence closes an episode; consolidation reads episodes, not a flat day-file deeptime.segment_episodes
Circadian learned histogram — 24 hour buckets fed by ticks/events; uniform until lived heartbeat.hour_histogram, deeptime.expected_activity
Promotion behavioral gate — loss lies at 48 iters (fact blending looked perfect) gate.run_gate

Run the public proof

Requirements: an Apple-silicon Mac, Python 3.10 or newer, git on your path (for a one-time dependency fetch; run git --version and install the Xcode command line tools if macOS prompts you), about 4 GB of free disk space, and an internet connection for the first run. The first run downloads a roughly 2 GB model once. Later runs reuse it. Training time depends on the Mac and may take a few minutes.

pip install "avalon-ai[mlx]"
avalon demo

The command runs two proofs with one local 4-bit model:

  1. It teaches five invented toy facts, starts fresh answering processes whose prompts contain only the questions, and measures recall from the adapter.
  2. It gives the unguarded model a poisoned toy note, then asks Avalon's witnessed-fact gate the same question. With no witnessed fact, the gate answers I do not know. and the model is called zero times.

No API key is needed. No cloud model receives the prompts. The only network use is the one-time public model download. Demo files stay in .avalon/demo_run. Exit code 0 means all five trained questions survived the context wipe and the poison gate refused with zero model calls. Exit code 1 means the proof or runtime failed. Exit code 2 means the machine cannot run MLX.

If startup reports that MLX cannot use Metal, run the command from a normal Terminal rather than a headless or virtualized session. If the model download is interrupted, reconnect and rerun the command. The download resumes and is reused.

The latest isolated-environment terminal capture is in launch/clean-run-output.txt. It records 5/5 trained recall, 5/5 unseen-phrasing recall, and poison refusal with zero model calls. Its header states the one untested first-run condition: the model was already present in this Mac's shared Hugging Face cache.

Use it on your own facts

Turn your own structured config into witnessed facts, arm the gate, and ask:

avalon ingest-facts ./chatterbox.json        # dry-run first: shows every candidate, mints nothing
avalon ingest-facts --commit ./chatterbox.json
avalon facts-gate on
avalon answer "what port is chatterbox on"   # -> 8100 (witnessed: chatterbox.json:12).
avalon answer "what is the door code"        # -> refusal: I do not know.  (model calls: 0)

What the gate guarantees, stated plainly:

  • It answers only from facts you minted, each carrying a verbatim source line. The value it returns is the witnessed value — never a guess.
  • On a fact-shaped question whose key it cannot find among your witnessed facts, it refuses with I do not know. and the model is never invoked (zero model calls — there is no channel for it to confabulate into). That is the anti-fabrication guarantee, and it is the honest boundary of the claim: the gate refuses on a witnessed key it cannot find, not on every possible phrasing. A question it cannot key (e.g. chatterbox port?) is not a fact query and falls through to the normal chain.
  • A witnessed value still passes your send-time constraints (P09): a rule like "never reveal the door code" blocks even a witnessed value.
  • Non-fact questions go to the normal draft + coverage chain, which needs a model backend — --backend resident reuses the demo's local model, or point base_url at a server you run. A buyer with no model server still gets the canned witnessed value on fact queries (the refusal and the canned value need no model at all).

The gate defaults off — avalon answer behaves exactly as before until you turn it on. avalon facts-gate status prints the resolved verdict (so a config typo is visible) and how many facts you have minted (a flag with no facts still falls through — flags are not reachability). avalon facts-gate off disarms it.

Daily use on your own data (real training)

One command a night, on your own notes, with real learning — no server to set up, no mock, no silent hang. Apple silicon + the mlx extra:

pip install "avalon-ai[mlx]"

# 1. drop tonight's facts in (a .txt / .md / .jsonl file, or inject one line)
avalon ingest notes ~/notes/today.md
avalon inject "the Northstar cache listens on port 49321"

# 2. run the night — this trains for real and proves it
avalon pilot-run --ask "What port is the Northstar cache on?"

What pilot-run does, in order (each stage prints a wall-clock line):

  1. Preflight — Apple silicon, mlx_lm importable, Metal usable, ≥ 4 GB free. It stops here (exit 2) before any download if the machine can't run.
  2. Intake — your notes become OBSERVED facts (re-running the same file is a no-op; nothing is trained twice).
  3. Extract — turns notes into Q/A pairs through a model server it auto-launches for you on a free port (first run downloads the model once, ~2.5 GB), then shuts it down before training. --no-extract trains the notes as-is with no server.
  4. Sleep — one real LoRA night (the shipped MaskingMLXTrainer + a resident gate that actually attaches the candidate adapter).
  5. Verify — the adapter on disk must be a real (> 1 MB) LoRA, or you get TRAINING DID NOT PRODUCE A REAL ADAPTER and exit 1. No stub ever counts.
  6. Morning proof — the base model's answer vs the live-adapter answer to each --ask, printed verbatim, so you can see the weights changed.

--nights N loops it; a night with no new facts is a valid skip (exit 0) — updates happen on signal, not on a schedule. Roughly 3–6 min per night on an M-series Mac after the one-time download.

Exit codes: 0 promoted or validly skipped · 1 rolled back / stub adapter · 2 this Mac can't run it · 3 the model server couldn't start · 130 Ctrl-C (the child server is killed).

Privacy: nothing leaves your Mac except the one-time public model download. Your notes train into local weights and stay there.

pilot-run never uses MockTrainer. config.trainer_backend (the safe default for every other command) is ignored here — this command always trains for real, by construction.

Optional: deploy/ai.lunarlabs.avalon.pilot.plist runs pilot-run nightly at 03:00 with logs under <home>/logs/pilot.log.

No-GPU smoke test (FAKES learning, CI only)

python3 -m venv .venv
.venv/bin/pip install -e ".[dev,mlx]"   # lunarlabs-core comes from git; mlx extra powers the live demo
.venv/bin/pytest                    # no GPU, no network
.venv/bin/avalon tick
.venv/bin/avalon serve --interval 60   # daemon mode; SIGTERM stops it cleanly
.venv/bin/avalon inject "the deploy moved to friday"   # event -> buffer bridge
.venv/bin/avalon consolidate --dry-run
.venv/bin/avalon status

State lives in ./.avalon (override with --home). The default trainer hook for serve / consolidate is MockTrainer, which writes a stub .safetensors and learns nothing — it exists for CI and plumbing checks only. Never use it to evaluate Avalon; use avalon pilot-run, which always trains for real. On a GPU host, consolidate --mlx plugs in LocalMLXTrainer (shells to mlx_lm lora). The default model backend is FrozenBaseClient; tests use MockModel — no GPU in tests, ever.

The organs (P01–P22)

Every research proposal in the program now exists as a module: an interface matching the measured constraint, a PROVISIONAL default where the real signal isn't built yet, and the proposal's falsifier as runnable code whose kill condition exits nonzero. The full map from inventory item to module, status, and falsifier price is docs/the-organism.md.

bpc (P12, the north-star eval — first real run: docs/p12-first-run.md), wagers (P06), coverage (P05, gate 3), nightindex (P03), vetoes (P02), constraints (P09), retraction (P10), changes (P18), timeweight (P15), flywheel (P01+P04), ledger (P07), masking (P08), dreaming (P11), skills (P13), physio (P14), perception (P16), stratify (P17), river (P19), cortex (P21), middlememory (P22), plus tools/do-ceiling/ (P20, gate 2 kit).

What is still a wall

Stated plainly — the organs build interfaces around these, not over them:

  • The real surprise signal — the MECHANISM now ships in Avalon: predictive_surprise.PredictiveSurpriseScorer scores surprise as the live adapter's measured BPC prediction error on incoming observed text (DEFAULT OFF until avalon predict-latency prices the per-event forward pass). What stays JARVIS-side is the owner corpus, the owner model, and the felt-present tuning — not the organ. The other token-overlap heuristics (wager resolver, ledger matcher, change join) remain PROVISIONAL behind their Protocols.
  • Implicit adapter routing — untested; NoRouter abstains, embedding similarity is the named candidate.
  • P12 first run (2026-08-04) — all three adapters LOSE to the frozen base on future-Carter BPC: a uniform style-drift tax (~+0.23) and zero future-specific gain. The adaptive thesis is unproven where it counts; the instrument to fix that now exists with baselines.
  • Constraint application in weights — recites 3/3, applies 2/3; the runtime verifier tier (constraints.py) is the live answer.
  • Surgical forgetting — 3 methods failed; the organ is replay-with- exclusion + periodic rebase (retraction.py), not subtraction.
  • Subjective time / anticipation gradients — still research; deep time remains half-lives + episodes + circadian histogram.
  • Base-upgrade retraining bill — pins enforced; cortex.SwapBill prices it, the number is still an estimate.
  • Real training in CI — LocalMLXTrainer and MLXScorer need a GPU host; the suite exercises contracts via mocks only.

Metadata

Release files for avalon-ai 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for avalon-ai 0.1.1
File Size Uploaded
avalon_ai-0.1.1.tar.gz 1.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for avalon-ai 0.1.1
File Interpreter ABI Platform
avalon_ai-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 3.3 MB

Release files / avalon_ai-0.1.1.tar.gz

Download URL avalon_ai-0.1.1.tar.gz
Size 1.9 MB
Tags Source
SHA-256 checksum
How to use checksums
8d621225b5a4aab9c58590548476b51ec35dd2ea6b62a376c210245f4e70bf0d
BLAKE2b-256 checksum
How to use checksums
67a2613c39be0093d022377ca8c2d6e35071f61186aa32bb10e3bf1b0177b367
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / avalon_ai-0.1.1-py3-none-any.whl

Download URL avalon_ai-0.1.1-py3-none-any.whl
Size 1.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
ebc12cc202c82b3b4bf5b234592fb2ddd846be5f96ea2ebe7cffc71f06e85d98
BLAKE2b-256 checksum
How to use checksums
6d1a21d9a2977f4464809ec2634a3dc5615916916f1ab22f2ed8ddda336d51a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page