Wardian docs

Decisions

Every choice that shapes Wardian is written down as an architecture decision record, or ADR. An ADR says what was decided, why, what it costs, and how anyone can check that the code still follows it. They live in docs/adrs/.

How an ADR is written#

Each ADR is one Markdown file, named ADR-<yymmddhhmm>-<short-title>.md. The number is the time it was written, so the files sort in the order the decisions were made. Each has the same parts:

PartSays
Status, Date, DriversWhether it holds, when it was decided, and what made it necessary: often the user's own words or a failure.
ContextHow things were before, with file names and numbers.
DecisionWhat Wardian does now, as numbered points.
ConsequencesWhat gets better, what gets worse, and what breaks.
ImplementationThe files that carry it out.
Enforced-By and GateThe command that fails if the code stops following the decision.
ReferencesRelated ADRs and sections of the package format.

A decision is not done until its gate passes. hexa adr gates runs every gate, and hexa analyze . --grade A checks the rules that .hexa/ADR-rules.toml ties to a decision. Both run in tests/run-all.sh when hexa is installed (How Wardian is built). A gate builds into target/verify, never into the copy of Wardian you run.

To change a decision, write a new ADR that supersedes it.

The first three ADRs were made in hexa, the tool that grades Wardian. Wardian adopted them when it chose to be graded by hexa analyze; their full reasoning lives in hexa.

Every decision#

All of them are Accepted.

ADRTitleDateDecision
ADR-2609121400hexa is a scaffolding system with two gates2026-10-07Wardian follows hexa's shipped rules: no hard-coded absolute paths or addresses, no model names outside inference, careful casts, no innerHTML.
ADR-2609211430the domain imports only what it is allowed2026-10-07The domain may import only what an allow-list in .hexa/ADR-rules.toml names; file, network, process and environment access are denied.
ADR-2609211600a reference is an import2026-10-07hexa analyze counts inline paths, macro arguments and qualified paths as imports when it checks the import policy.
ADR-2610071055viewer state lives on the server2026-10-07Arrange layouts, apps' saved data and the latest channel messages are kept in the data folder under state/, with a copy in the browser for viewers who are not admins.
ADR-2610071106Claude through Amazon Bedrock2026-10-07Make an app and claude:sample can also use Claude through Amazon Bedrock, with a Bedrock API key or AWS access keys signed by Wardian's own SigV4 code.
ADR-2610071110browser notices are not app faults2026-10-07The browser's ResizeObserver notice is not reported as a fault, ctx.observe calls once per frame, and the fault box shows repeats once with a count.
ADR-2610071122a working folder outside the source, and a history for each app2026-10-07Wardian serves and saves apps in DATA_DIR/apps, never in the repository; every save is a numbered version; wardian promote copies an app back to commit it.
ADR-2610071200the domain reads JSON2026-10-07The domain may use serde and serde_json, which are pure; every other outside crate stays out.
ADR-2610071219SQLite as the db capability, with paging2026-10-07Each package gets its own SQLite database, with paging, an authorizer that keeps it in its file, size and time limits, and reads of another package's tables only with permission.
ADR-2610071248export an app as a .wardian file2026-10-07An app exports as one .wardian zip with a manifest, and its data only when the user asks; keys, permissions and history never go in.
ADR-2610072033what must be true before Wardian 1.02026-10-071.0 ships when security tests, live checks against real services, a stop log, a first-run setup, CI and signed builds are done or written down as left out.
ADR-2610072118long calls run as background jobs2026-10-07Splunk searches, loads into a table and Claude requests run as server jobs that answer at once; the browser asks how they go, and can leave and come back.
ADR-2610080900a suite is made of small parts2026-10-08A suite has one part per job; the Splunk table becomes five parts, and wardian check warns about a part that does too much.
ADR-2610080903a documentation site, and an example app for every capability2026-10-08The docs are Markdown in the repository, served at /docs and written to website/ by wardian docs; every capability but splunk gets an example app that runs with no account.
ADR-2610080905save an app as a web page2026-10-08Save as web page writes one .html file of what the viewer sees, HTML and CSS only, cleaned by an allow-list and locked by a policy that blocks every request.
ADR-2610080915install with one command2026-10-08A curl … | sh installer, release tarballs built on a tag, and a wardian that finds its own data folder and example apps. Built: scripts/install.sh, .github/workflows/release.yml, and the data-folder rule in src/config.rs.
ADR-2610080928Wardian ships its AI skills2026-10-08The AI skills (wardian-app-factory, wardian-app-doctor) are built into the program with their references, wardian skills installs them into a project, and this repository uses the same copy.
ADR-2610080930a friendly first run in the terminal2026-10-08In a terminal, wardian prints a short block and opens the browser, finds a Wardian already running instead of failing on a busy port, and moves to the next free port when another program holds it.
ADR-2610081003a page app reaches only its own package2026-10-08Each page gets a policy that allows requests only to its own /apps/<name>/ and /sdk/; a test proves no request gets out, and that the three routes a policy cannot close are still open.
ADR-2610081041every claim names its test2026-10-08Every claim in an ADR, in SPEC.md and on the security page is tested, marked "not built", or a stated limit with a test that proves the limit; vague words become measures.
ADR-2610081500keys and Claude settings in one place2026-10-08Every secret on one list in Settings, with its last test, Test again and Remove; the admin token set in Settings; Claude's models and limits as settings; tokens counted per app with a daily cap.
ADR-2610081501keys sealed at rest2026-10-08Every saved secret is sealed with AES-256-GCM under a master key kept in a file outside the data folder, so a copy of the data folder holds no readable key.
ADR-2610081600example apps are built in2026-10-08The example apps are built into the program, and each start adds the ones a working folder has not had, so every Wardian shows them.
ADR-2610081700back up the master key2026-10-08wardian key says where the master key is; export backs it up into a private file, and import restores it, refusing a key that opens no saved key.
ADR-2610081900examples run on the website2026-10-08Each example's page on the website shows the app running when it needs no server (eleven of sixteen, suites included), and links a zip of every example to import.

Gates#

ADRGate
ADR-2609121400, ADR-2609211430, ADR-2609211600, ADR-2610071200hexa analyze . --grade A
ADR-2610071055cargo test --release viewer_state
ADR-2610071106cargo test --release bedrock_inference
ADR-2610071110tests/run-suite-e2e.sh
ADR-2610071122cargo test --release -- history seeding_history_and_promote
ADR-2610071219cargo test --release -- db:: sqlite_store splunk_results_load
ADR-2610071248cargo test --release export
ADR-2610072033none: it has no Gate section. It lists the tests and checks that 1.0 needs.
ADR-2610072118cargo test --release jobs
ADR-2610080900cargo test --release check
ADR-2610080903cargo test --release docs_
ADR-2610080905tests/run-snapshot-e2e.sh
ADR-2610080915tests/run-install-e2e.sh
ADR-2610080928cargo test --release skills_
ADR-2610080930cargo test --release start_
ADR-2610081003cargo test --release page_csp; in a browser, tests/run-page-sandbox-e2e.sh
ADR-2610081041cargo test --release claim_; in a browser, the suite, page-sandbox, channels, snapshot and splunk e2e tests; scripts/release-check.sh for release steps
ADR-2610081500cargo test --release keys_, agent_, usage_; tests/run-keys-e2e.sh in a browser
ADR-2610081501cargo test --release sealed_
ADR-2610081600cargo test --release examples_
ADR-2610081700cargo test --release key_
ADR-2610081900cargo test --release demos_; tests/run-website-e2e.sh in a browser

hexa adr gates runs each cargo test gate with CARGO_TARGET_DIR=target/verify.

This page is docs/site/decisions.md in the repository. Something wrong or missing? Change that file.