syntax
Use this page to look up the parts of a
.mar plan. You can ask an AI assistant to draft the file, but
it is designed to remain readable and easy to review by hand.
Anatomy of a plan
// Comments run to the end of the line.
VAR iteration = 0 // typed variables: number, boolean, "string"
VAR approved = false
-> build_mvp // optional explicit start (default: first phase)
=== build_mvp === // a phase (node)
Ship the smallest testable slice. // prose body: what this phase is
~ iteration += 1 // mutation, applied on entry (=, +=, -=)
* [Metrics green] @human -> beta_launch // once-only choice, human checkpoint
+ {iteration < 3} [Go again] ~loop~ -> build_mvp // sticky choice, gated, declared loop
* {iteration >= 3} [Three strikes] -> pivot
=== beta_launch ===
Launch to the beta cohort.
-> END // fallthrough divert; END terminates the plan
=== pivot ===
* [Pivot] @human ~loop~ -> build_mvp
* [Kill it] @human -> ENDConstructs
| Construct | Syntax | Notes |
|---|---|---|
| Phase | === name === |
Unique [A-Za-z_]\w* id; trailing === optional. END is reserved. |
| Body | prose lines | Joined verbatim; the first line becomes the node title in renders. This prose is the executing agent's task description. |
| Variable | VAR name = literal |
Preamble only. Type inferred from the literal (number, true/false, "string"). |
| Mutation | ~ name = expr · ~ name += expr · ~ name -= expr |
Applied in order when the phase is entered. +=/-= require numbers. |
| Choice (once) | * [Label] -> target |
May be taken at most once per traversal. |
| Choice (sticky) | + [Label] -> target |
Repeatable. Use for loop edges — and for every choice a traversal can revisit. |
| Gate | {expr} before or after the label |
The choice is available only while the expression is true. |
| Human checkpoint | @human on a choice |
The agent must pause and escalate; only a human may record this decision. Enforced by the walker. |
| Loop | ~loop~ on a choice |
Declares an intentional cycle. A cycle counts as declared when any one of its edges carries ~loop~ (convention: the returning edge). Undeclared cycles are compile errors. |
| Divert | -> target on its own line |
Fallthrough edge. At most one per phase; must come after the choices. |
| End | -> END |
Terminal. Reaching it completes the plan. |
| Metadata | # key: value · # tag |
Plan-level in the preamble, node-level inside a phase. Namespaced keys (github:issue) are the extension mechanism. Repeated keys accumulate into a list. |
Expressions
Operands: numbers (3, 1.5), booleans,
"strings", variables. Operators, loosest to tightest:
||/or · &&/and ·
== != · < <=
> >= · + - ·
* / % · unary
!/not, - · ( ).
Comparisons are type-checked at runtime; + concatenates
strings.
What the compiler guarantees
Structural errors fail the build: dead ends
(MAR006), unreachable phases (MAR007), undefined
targets (MAR003) and variables (MAR004),
duplicates (MAR002, MAR005), undeclared cycles
(MAR008), loops with no exit (MAR009) or
provably-unsatisfiable exits (MAR010), @human
without an escalation path (MAR012), type mismatches
(MAR015).
Warnings ask for review — or fail the build with
--strict: constant-false gates (MAR011),
~loop~ on a non-cycle (MAR013), unverified gates
(MAR014 — anything beyond constant expressions and monotonic
counters; the compiler never claims "verified" for gates it cannot decide),
unused variables (MAR016), once-only loop edges
(MAR017), malformed external refs (MAR018),
unknown delivery values (MAR019). The full table with fixes:
reference.
Loop verification
A declared loop passes when its cycle has at least one exit that is
ungated, or whose gate is trivially decidable and satisfiable — the
canonical shape is a monotonic counter:
~ i += 1 inside the loop with an exit gate
{i >= 3}. A loop-continue gate that provably shuts
({i < 3} with an increasing i) also counts, on
any edge of the cycle. Everything else is enumerated as an unverified-gate
warning. Resetting a counter (~ i = 0) anywhere makes its
gates non-monotonic and therefore unverifiable — those warn by design;
review them manually.
Authoring rule of thumb: keep every choice on a path a traversal can
revisit sticky (+). A once-only (*) choice inside
a cycle is consumed on the first pass and can strand a later iteration at
runtime; the compiler warns (MAR017) only when the
~loop~ edge itself is once-only.
Well-known metadata namespaces
Any key accepts the fenced """ form for well-formed
multiline text; an unterminated fence is a parse error.
summary and prompt anchor the plan to its
origin — summarize leads with them and the executor's brief
carries them as plan.intent, so the file never operates in a
vacuum. The provider namespaces normalise into structured refs and
delivery config (see execution); all other
namespaces pass through untouched as extension metadata.