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

anatomy.mar — every construct at a glance
// Comments run to the end of the line.
# project: my-project          // plan-level metadata tag (preamble)
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
# github:issue: 12                      // node-level metadata tag
~ 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 -> END

Constructs

ConstructSyntaxNotes
Phase=== name === Unique [A-Za-z_]\w* id; trailing === optional. END is reserved.
Bodyprose lines Joined verbatim; the first line becomes the node title in renders. This prose is the executing agent's task description.
VariableVAR 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.

metadata vocabulary
# summary: One-line abstract: what this plan achieves and why.
# prompt: """
The original ask, verbatim. A fenced value is a container for
markdown — blank lines, lists and # characters are plain text.
"""

# github:repo: acme/platform        // context for github refs
# github:issue: 22                  // → https://github.com/acme/platform/issues/22
# github:pr: other/repo#9           // explicit repo wins over context
# jira:site: https://acme.atlassian.net
# jira: PROJ-123, PROJ-124          // comma-separated lists allowed
# linear:workspace: acme
# linear: ENG-42
# ref: https://wiki.acme.dev/brief  // generic link

# delivery: pr-per-phase            // or branch-per-phase | single-pr | single-branch | none
# delivery:branch: replatform/{phase}
# report: per-phase                 // or at-checkpoints | at-end