Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Reading this book

Redoubt is a headless, multi-user operating system for RISC-V, built so that hostile agents can run on it, do real work, and not get out. This book describes the whole system from its code: what each part does, which rule it keeps, which test attacks that rule, and what is still planned. The tenets outrank every other page.

Reading order

  1. The tenets: what Redoubt is, the threat model, the guarantees and the walls that hold them, the non-goals.
  2. The glossary: the one vocabulary every page uses. Skim it once; come back to it.
  3. The kernel: handles, IPC, memory, budgets, scheduling, the timer, processes, devices, boot, and the model that checks them.
  4. The servers: trust tiers and labels, then one page per server, from init and the steward to the network path.
  5. Userland: what a person, an agent and a developer see.
  6. The security register: every security property on one table, with the code that enforces it, the test that attacks it and its residual risks. An auditor starts here.
  7. The plan: one page per milestone, then the follow-ups in todo/ and the ideas past the plan in beyond/.
  8. The test bench: how every claim in this book is tested.

To build and run Redoubt, see GETTING-STARTED.md. How the work itself is organised, and in what order, is outside this book: AGENTS.md is the way in.

Written as if complete

Every page describes the system as it will be at the end of the plan. Whether a part exists today is said by the status line at the top of its section, never by the prose. A section that is part built and part planned is split in two.

Status lineMeaning
Status: built · tested: <tests>The code exists, and each named test attacks the section’s claim.
Status: built · partly tested: <gap> · tested: <tests>The code exists; the gap says what no test attacks yet, and the tests (when named) cover the rest.
Status: planned · M2 (usable shell)Nothing of it is built; it arrives in the named milestone. The section ends with an Open: list of what is still undecided.

A status with four or more tests folds them away, so the section opens on its claim and not on a list: the status sits in a <summary> with the count of tests, and the tests follow as a bullet list inside the <details>, one per line. The checker holds the count to the list.

<details><summary>Status: built · tested (3)</summary>

- bench:redoubt-ipc
- host:redoubt-sys::every_call_round_trips
- mutation:R2OneCursor

</details>

“Built” means the code exists and its named tests pass. A host test or a build case is not a boot: code built and host-tested is not thereby running in the integrated system, and running there is its own planned section.

A section without its own status line inherits its nearest parent’s. Purpose, Residual risks and Why sections carry none: they say why and what is left, not what is claimed. Status lines appear on the kernel, server and userland pages and on the test bench page; plan, follow-up and idea pages do not use them, and the security register has a status column instead.

A test is named by its kind:

FormWhat it is
bench:<case>a bench case, tests/<case>.toml: a real boot under QEMU, a host-test run or a source check (the test bench)
host:<crate>::<test>a Rust #[test] in that crate, run on the build machine; the model’s properties are host tests of redoubt-model
mutation:<name>a rule deliberately broken in the model, which its checks must catch (the model)
fuzz:<crate>/<target>a fuzz target in that crate’s fuzz/ directory

The milestones

A milestone is always written with its name.

MilestoneGoal
M1 (sessions over SSH, kept apart)Alice and Bob log in over SSH and on the console into Elixir sessions, kept apart in fixed sub-budgets per label set, with files; a dead steward restarts without a reboot.
M2 (usable shell)The Elixir shell is a working environment: commands, file operations, native programs and pipes, jobs, line editing, screens, the editor.
M3 (agents, approvals and the attack suite)Alice’s agent runs contained under a lease; approvals come only from approve@box; declassification, crash blame, and the scripted hostile agent and user.
M4 (files in and out)SFTP and SCP inside SSH, confined to the session’s capabilities and audited.
M5 (self-hosted development)Redoubt is developed on Redoubt: compilers, git and a model provider through gateways, the agent harness, the audit log and the escape room.
M6 (persist, install, share)The steward’s state survives reboots; signed packages, trust lists and shared projects; A/B updates; the supervisor; wall-clock time; log retention.

Anything past M6 (persist, install, share) is beyond M6: an idea, not a goal, one page each under beyond/.

Rule IDs

Every security property has an ID, defined once by a heading on the page that owns it and cited everywhere else with its short name the first time on a page:

IDs are cited one at a time, never as ranges, and never reused: a withdrawn rule keeps its heading, marked withdrawn. The security register lists every ID.

Rendering

The pages are plain Markdown and read on GitHub as they are. mdBook renders them as a book with navigation and search:

mdbook build docs      # output in target/book
mdbook serve docs      # the same, served on localhost with live reload

Diagrams are text inside the pages: Mermaid for flows, sequences, state machines and the packet diagrams that draw a record’s words and bits, which GitHub renders too; and memmap blocks for address maps, which the book’s own preprocessor (tools/mdbook-memmap) draws to scale on a log axis, one region per line with its first address, its name and a note per column, and which read as a table on GitHub. Solid lines are built; dashed lines are planned. The book needs the mdbook-mermaid preprocessor and cargo for its own. The docs checker, redoubt-doccheck, holds every page to these rules (the test bench).

The search index

The book’s search index (target/book/searchindex-<hash>.js) is held to a ceiling of 7,000,000 bytes, 30 % under the 10,000,000 at which mdbook warns and the build check fails; the_book_builds fails over the ceiling naming the size and the three largest pages, so the failure says what grew. The index is about three times the pages’ text (3.2× in October 2026: a term’s postings for every section it appears in), and the three largest pages hold a fifth of the text. The ceiling moves only by a stated, measured decision in the same change as the measurement, and never past mdbook’s 10,000,000. Headroom is kept by keeping the pages to their argument: measurements, evidence tables, transcripts and reasoning beyond what a rule or a design needs stay outside the book, in the working notes or a case’s comment, not on the page. A page leaving the book, or splitting, is the owner’s decision, never a way to pass the check. The index needs an mdbook built with elasticlunr-rs 3.1.0 or later (an older indexer doubles every field’s tokens into the next field; scripts/setup.sh installs the right one and the same check reads the version from the binary).