Two-layer model
Authoring a PRD has two distinct modes:
- Writing what and why in prose. Optimised for humans skimming, for LLMs reading.
- Writing how in structure. Optimised for codegen consuming, for tools validating.
Cramming both into one field forces compromise. AtomPRD splits them.
Layer 1 — Intent
Section titled “Layer 1 — Intent”Available on every atom kind. The shape is the same everywhere:
{ "intent": { "userStory": "<prose, optional>", "relatedAtoms": ["<atom_id>", ...], "notes": "<commentary, optional>" }}Free-form, prose-friendly, no schema constraints beyond required-string semantics. Vietnamese, English, Markdown — whatever. This is the source of truth for what this atom is. The LLM Pattern D suggester reads it as part of every prompt.
Layer 2 — Behavior
Section titled “Layer 2 — Behavior”Available on 5 atom kinds out of the 26:
| Kind | Behavior shape |
|---|---|
feature | { trigger?, steps: Step[], onOk?, onErr? } — Step is validate, call, dispatch, setState, navigate, log, or if. |
ui_view | { rootScreen, screens: { [id]: { sections: Section[] } } } — Section is heading, text, list, form, detail, button, input, switch. |
rule | { enforced_at: EnforcedAt[] } — ui_disabled, pre_call, or validator. |
criterion | { before_after: { state_diff, api_calls, derived_diff? } } |
fixture | { shape, before?, after?, api_calls? } |
These five are precisely the kinds where codegen needs structure. A feature lowers into an action chain. A ui_view lowers into a screen tree. A criterion lowers into a scenario fixture. Without structure, codegen has to guess.
The other 21 kinds (vision, persona, module, entity, field, integration, plus the 11 content blocks and 6 DevOps blocks) are descriptive. Their semantics are fully captured by their kind-specific top-level fields — no need for a structured Behavior layer.
Why split?
Section titled “Why split?”Three reasons.
1. PMs author Layer 1 before engineers fill Layer 2
Section titled “1. PMs author Layer 1 before engineers fill Layer 2”A PM writes a feature’s user story in five minutes. Filling in the action chain takes engineering judgement. Splitting the layers means:
- The PM saves a feature with
intent.userStoryfilled andbehaviorempty. That’s a valid atom. - An engineer (or LLM) fills
behaviorlater. The PM’s prose stays untouched. - Codegen falls back to Pattern B convention defaults when
behavioris empty ({ $do: log, level: warn, msg: "TODO ..." }).
2. Diffs target the layer that changed
Section titled “2. Diffs target the layer that changed”Refining the prose of a user story should not show up as a diff against the action chain. Splitting layers means a Layer 1 edit and a Layer 2 edit are separate jsonb columns in storage and separate audit-log entries.
3. Layer 2 lowers deterministically
Section titled “3. Layer 2 lowers deterministically”Once the schema is fixed, codegen tools can write a pure function:
function lowerStep(step: Step): SenAction { switch (step.kind) { case "setState": return { $do: "setState", path: step.path, value: step.value }; case "call": return { $do: "callApi", endpoint: step.endpoint, /* ... */ }; // ... }}Same input → same output. No LLM call required to translate. The bridge @atomprd/codegen-senlang is exactly this — about 200 lines of pure TypeScript that walks atoms and lowers each Layer 2 field.
See atomprd/packages/codegen-senlang/src/project/lower.ts for the full lowering table.
Layer 2 is optional
Section titled “Layer 2 is optional”A v0.3-conforming atom can have Layer 2 absent. The bridge applies Pattern B convention defaults:
feature.behaviorabsent →events[<slug>] = [{ $do: log, level: "warn", msg: "TODO..." }].ui_view.behaviorabsent +viewType=list+rendered_byentity → Box + Heading + List +$Eachoverstate.<entitySlot>.rule.behaviorabsent → rule preserved inrules[<slug>]but not bound to UI / pre-call gates.criterion.behaviorabsent → scenario emits a TODO stub; schema-valid butsenlang testfails until filled.
This is why a PM can save half-filled atoms and the bridge still produces something runnable. See Four patterns → Pattern B.
See also
Section titled “See also”- Four patterns — A / B / C / D provenance.
- Spec → Layer 2 schemas — exact Zod shapes per kind.
- Authoring → Six-tab editor — how the cloud UI surfaces both layers.
- Codegen → SenLang bridge — the deterministic lowering rules.