Deterministic checks with stable codes
Programmers have compilers that read code and point at the line that breaks. Asten does the same for a story’s facts, with deterministic rules, stable codes, and evidence for every mark.

In short
Asten’s compiler is a deterministic rule engine written in Rust. It reads your settled facts, your timeline, and the page itself, and emits diagnostics with stable codes (CANON-E013 to E601, NAME-W001 to W004, PLOT-I001, and optional CRAFT hints) at four severities: error, warning, information, and hint. Each mark explains itself in a numbered chain and offers repairs. It runs entirely on your machine and never changes your text.
Deterministic
Same project, same marks. No model, no randomness, no “it depends on the prompt”.
Stable codes
CANON-E013 always means an attribute contradiction. Search it, discuss it, suppress it.
Four severities
Errors for confirmed against confirmed, warnings for the page against a confirmed fact, information for clashes that are only possible, hints for confusable names and optional craft notes.
Evidence attached
Every mark points at a span in a document, reads as a numbered chain (①②③), and names the statement most likely at fault.
Repairs you own
Add an event, mark the scene a memory, retire a fact, silence the mark, or keep your sentence. Bisect finds the edit that raised a mark.
Append-only history
Document operations are recorded, and named snapshots restore a revision on your own disk.
Stable block ids
Paragraphs carry identities, so a mark can follow its sentence when you edit around it.
Which rules ship today?
| Code | Pack | What it notices | Default |
|---|---|---|---|
| CANON-E013 | Scribe | Two values for a one-valued attribute at the same story time in the same context, with no change event between them | Always on |
| CANON-E014 / E015 | Scribe | An immutable attribute (a birthplace) changed; an attribute on the wrong kind of thing | Always on |
| CANON-E101 / E102 / E103 | Lifecycle | Acting after a settled death; appearing before birth; an item used after it was destroyed | On |
| CANON-E201 / E202 / E203 | Clocks | Story time stepping backward inside a continuous run; dates that cannot all be true; an effect before its cause | On |
| CANON-E301 | Atlas | A journey that does not fit the time between two scenes. Two places at one story time is marked E013. | On |
| CANON-E401 | Knowledge | A character using knowledge no event has given them yet | On |
| CANON-E501 / E502 / E503 | Relations | Their own ancestor; two of an exclusive relation at once; a parent too young | On |
| CANON-E601 | Invariants | A rule you wrote in the invariants panel fails on the scene trace | On |
| NAME-W001 to W004 | Scribe | A name not in the cast; named before being introduced; confusable names; a fact pointing at a removed entity | Always on |
| PLOT-I001 | Invariants | A setup you marked for payoff has not been paid off yet | On |
| CANON-E302, CANON-E602, PLOT-I002 | Reserved | Codes the catalogue holds for later; no rule raises them yet | Not raised |
| CRAFT-H001 / H002 | Diction watch | Filter words such as “very” and “really”, as optional notes | Off |
Why rules and not an AI model?
Because a mark you can’t trust trains you to ignore all of them. Deterministic rules can be explained, tested, and argued with. They also run instantly on a laptop with no network. AI may later help propose facts, but the compiler that judges contradictions stays rule-based and inspectable. See our AI stance.
What’s under the hood?
For the curious: the engine is a set of Rust crates. A story IR holds entities, facts, events, scenes, and contexts; a block model gives every paragraph a stable id and a hash-chained history so marks follow their sentence through edits; perception reads the page with Unicode folding and dictionary matching, no model; the analyses are an event calculus, a lifecycle typestate, a temporal network, shortest routes, and a small temporal-logic checker for your own rules. Storage is SQLite. An Axum server exposes a local API on 127.0.0.1:4317 that answers only to paired clients. The interface is React and TypeScript; the Tauri desktop shell embeds the same API. More in For AI tinkerers.
About the compiler
Is the Asten compiler an AI?
What do Asten’s diagnostic codes mean?
Keep reading
Try the pre-alpha
Open the workbench in your browser on a sample novel, or download release 0.0.1b for Windows or Linux.