Motivation
xmd run -e (#76) executes a program you already wrote. xmd prompt is the step before that: you describe the outcome, a readable Executable Markdown policy writes a complete root document, the command validates and shows the exact source, and the approved bytes enter the ordinary run path.
xmd prompt "ask me for my age and write the result to a file"
The unit of work remains an executable Markdown program. Planning adds authored generation and review around it; it does not add another execution model.
Architecture
The trusted host owns two root document executions with a complete scope boundary between them:
fixed command preflight
-> build the run-profile syntax catalog
-> execute the exact packaged plan program
-> one Session
-> generate, validate, repair, review, revise, approve or fail
-> Return the exact approved candidate source
-> await plan execution and provider teardown
-> validate the returned source again
-> optionally save the exact bytes
-> execute retainedSource("<prompt>", source) through the ordinary run path
The plan program is one exact, checked-in first-party Markdown value root shipped with the CLI. It owns the visible policy: prompt wording, the candidate and repair loops, validation branches, human review, revision, approval, abort, and exhaustion.
The plan profile is the trusted-host assembly used only for that exact root. It supplies the plan inputs, a constrained Agent provider, Elicitation, fixed first-party components, and the host-declared candidate validator. It uses no repository component search and exposes no custom root. These are internal architecture terms and are added to architecture.md with this change.
The plan program is trusted shipped source, not arbitrary user source. This issue therefore does not claim a general XMD sandbox. Public <Plan>, custom plan roots, projected context, read-only <File>/<Glob>, --plan, and --plan-eval are deferred to #660. General constrained or untrusted XMD execution remains the larger #536 boundary.
Command surface
xmd prompt <request> [options] [--props-<name> <value>]…
The request is exactly one positional string containing at least one non-whitespace character. Missing, repeated, empty, and whitespace-only requests fail before any catalog, Agent, plan execution, Elicitation, save, journal, or final execution. No stdin or editor form is included.
-- ends option parsing, so a dash-leading request follows it.
The command accepts the ordinary xmd run -e execution flags, except -e/--eval, plus:
--save <path> — exclusively create the approved source before final execution;
--session <name> — use this non-empty logical name for the planning Session instead of the invocation-unique default.
Agent provider selection, default Agent selection, and the whole-command timeout configure planning. Permission flags and exec/fetch timeouts configure only the approved document. Planning does not inherit the final run permission mode.
The request appears before every individual --props-* option. An individual option before it is refused during fixed preflight. Known fixed-arity options, including aggregate --props, --save, and --session, keep their ordinary positions.
Help
xmd prompt --help is generic and effect-free. It documents the request, --save, --session, aggregate props, the individual-property ordering rule, and the shared flags. It generates no individual property options and performs no catalog, Agent, document inspection, plan execution, Elicitation, save, journal, or final execution.
The packaged plan program
The host executes one immutable packaged Markdown value root under the stable internal source identity <prompt-plan>. Its declared return schema is exactly { type: "string" }.
The host supplies fixed internal inputs:
- the original request text;
- the rendered syntax catalog built from the current run profile and ordered
--include values; and
- the resolved logical planning-session name.
They are not candidate root props and consume none of the generated document property sources.
The program contains one enclosing <Session> expansion. Its body contains every initial, repair, and human-revision <Prompt>. A loop inside that one Session does not create another Session placement; sibling Sessions are not used, because sibling placements remain distinct even when their authored names match.
The host owns the provider instruction layer and Agent ceiling. The Markdown root owns the text of each generation, repair, and revision request. The initial prompt preserves the original request text and includes the current catalog supplied by the host. It instructs the Agent to return one complete replacement root as source only and to preserve the request as meaningful Markdown narrative, not merely as an imperative script with comments.
<Prompt> remains one Agent turn. It gains no hidden repair, retry, review, or approval behavior.
Planning Agent authority
The planning Agent is assembled separately from the final run provider:
- a fresh host-owned empty working directory;
- no additional directories;
- no MCP servers;
- an empty requested native-tool allowlist;
- strict denial of every native permission request without consulting an authored approval scope; and
- no document Files, command, service, or XMD-mediated network capability.
The provider may use its own transport to perform the model turn; that does not grant the Agent a native network tool.
--approve-all, --approve-reads, and --deny-all do not change this ceiling. They apply to the approved document later. A provider unable to establish the planning ceiling refuses before session materialization or a turn; there is no silent downgrade.
The approved document later receives the caller-selected ordinary run Agent and permission configuration. It inherits neither the planning Session nor its instruction layer.
Planning Session
Without --session, the host generates a logical name unique to the invocation. The exact name is supplied to the plan root, and its one enclosing <Session> materializes only at the first consuming <Prompt> (#648).
--session <name> replaces that generated logical name. Ordinary provider Session continuation semantics apply when the selected provider already holds that name; the plan program still supplies the current request and current catalog in the invocation's initial turn. Every turn within this invocation uses the one enclosing Session.
A generation turn produces a candidate only from its complete successful close value. Failed, cancelled, unavailable, or protocol-invalid turns discard partial text and reach no human review, save, or final execution.
The plan execution closes after approval or failure. The host observes its result only after every Prompt task, Agent provider resource, Elicitation resource, and other child has completed teardown. A teardown failure wins over a selected source and prevents final validation, save, and execution.
Candidate source remains data
An Agent reply is an inert string during planning. The plan program may bind it, pass it to the validator, serialize its diagnostics, present it with <CodeBlock>, and return it. It never evaluates the candidate and never dynamically imports it.
Only after approval, plan teardown, and final host validation may those exact bytes enter ordinary execution.
Host-declared candidate validation
The plan profile declares one internal value component, <ValidateCandidate source={candidate} as="assessment" />, to the execution. Canonical execution supplies its invocation identity; repository resolution cannot replace it.
Its result is a closed candidate assessment:
{ valid: true, diagnostics: {} }; or
{ valid: false, diagnostics }, where diagnostics contains the complete versioned DocumentValidation when core produced one and the structured generated-binding diagnostic when property binding failed.
The component performs no candidate execution. For each source it:
- validates the supplied root declaration without execution;
- once a usable root props schema exists, derives bindings from that schema;
- checks every frozen supplied individual-option signature before consuming tokens;
- resolves the original CLI and invocation-environment property sources under that schema; and
- calls
validateDocument() with those exact props, the caller's includes, and the run profile's identity-component declarations.
Candidate-authored failures return valid: false and are eligible for repair:
- source, frontmatter, target, root props, and return-declaration diagnostics;
- generated binding collisions;
- missing required root props; and
- every other definite document diagnostic.
Caller-source failures raise out of the component and terminate the plan execution immediately:
- malformed aggregate CLI or environment JSON;
- a supplied individual option the usable candidate schema does not declare;
- an individual CLI or environment value that cannot be decoded;
- an extra positional exposed by the candidate's arity; and
- a later candidate removing a frozen supplied option or changing its token arity or accumulation behavior.
A caller-source failure causes no repair turn, candidate presentation, approval, save, final journal, or final execution. The plan program cannot catch and recategorize it as candidate feedback.
An opaque not-statically-checkable invocation is not a diagnostic and does not by itself make a candidate invalid.
Automatic repair
The initial draft and every human-requested revision each start a fresh automatic repair budget:
- the base candidate is attempt one;
- at most three repair turns may replace it;
- every repair prompt contains the complete structured candidate diagnostics;
- every answer must be another complete replacement root.
The fourth invalid candidate is repair-exhausted and proceeds to human review with its diagnostics. No fence is stripped, no Markdown substring is extracted, and no patch is applied.
Human review bound
The default plan program permits at most ten candidate presentations: the initial review plus at most nine human revisions.
Rounds one through nine offer:
- for a valid candidate:
approve, revise, or abort;
- for an invalid repair-exhausted candidate:
revise or abort.
revise requires non-empty feedback, sends one complete-replacement request through the same enclosing Session, and resets the three-turn automatic repair budget.
Round ten offers no further revision:
- a valid candidate offers
approve or abort;
- an invalid candidate is presented with its diagnostics and offers only
abort.
The review message uses #658's <CodeBlock> to present the exact candidate and, when invalid, its complete JSON diagnostics. Candidate text cannot close the presentation fence and is never interpreted.
approve selects <Return value={candidate} />. abort, review exhaustion, and any path that produces no approvable candidate select #659's <Fail> with an actionable message. Failure is authored in Markdown rather than hidden in the host or represented by a missing-<Return> accident.
Planning history and presentation
The plan root runs with an invocation-owned in-memory durable stream because ordinary document and Prompt semantics require one. That stream is never written to --journal, persisted as a workflow, reused, or replayed. It is discarded after complete plan teardown.
The configured ACP provider may retain the planning Session under its normal provider contract, especially when the caller selected --session.
Plan-root rendered output is not command output. Human-visible planning presentation occurs through Elicitation. The plan root's successful public result is the approved source string and nothing else.
Final admission, save, and execution
After successful plan teardown, the host treats the returned string as untrusted again. It repeats candidate validation and property resolution using:
- the exact returned source;
- the original raw CLI and invocation-environment property sources;
- the frozen individual-option signatures established during planning;
- the caller's ordered includes; and
- the ordinary run profile declarations.
A final caller-source failure or document validation failure exits nonzero before save or execution. It does not re-enter the plan program or ask for repair.
The final resolved props belong to those exact source bytes. No props object from an earlier candidate is reused.
--save <path> then exclusively creates the target with those exact bytes. An existing target remains unchanged and prevents execution. Without --save, no generated-source file is created.
The host executes retainedSource("<prompt>", source) through the ordinary supplied-source run path. The contextual working directory, includes, output, value result, secret detection, Agent configuration, permission mode, timeouts, runtime failures, and exit status behave exactly as under xmd run -e.
The final execution creates --journal only when it begins. That journal contains no plan root, planning Session, Agent turn, candidate validation, repair, or human-review event.
A runtime failure does not return to planning. A successful --save remains.
Cancellation and failure ordering
The whole-command deadline encloses catalog construction, plan execution, Elicitation, plan teardown, final validation, save, and final execution.
Cancellation halts the active plan work and awaits its structured teardown. No final validation, save, or final execution begins until the plan scope has completed successfully. A plan teardown failure prevents all later phases.
After the ordinary final execution begins, its existing outcome and teardown precedence remain unchanged.
Acceptance
The amended evidence replaces PR #657's TypeScript-policy acceptance matrix. Existing focused green tests on the feedback commit do not prove this contract.
The new structural checklist is:
- Fixed grammar and help — request cardinality, individual-property ordering, aggregate props before the request,
--session, and effect-free generic help.
- Exact packaged root — the command executes the checked-in Markdown value root under
<prompt-plan>; no TypeScript authorship loop or custom root chooses policy.
- Visible policy — generation, three-turn repair, ten-round review, revision, approval, abort, and exhaustion are present in Markdown;
<Prompt> remains one turn.
- One Session — one enclosing Session expansion carries every turn; default names differ across invocations and
--session supplies the exact override.
- Planning Agent ceiling — empty cwd, no additional directories, MCP servers or native tools, strict private denial, and final-run permission flags cannot widen planning.
- Candidate inertness — candidate source is only data during planning and no candidate effect occurs before final execution.
- Validation classification — candidate failures return structured facts; caller-source failures escape immediately; frozen signatures are checked before token extraction.
- Bounds — one base plus three automatic repairs per draft and no more than ten human presentations, with no revision offered on the last.
- Safe presentation and authored failure — arbitrary source cannot close
<CodeBlock>; abort and exhaustion reach <Fail>, not host policy or a missing Return.
- Final gate — the host revalidates after complete plan teardown and resolves props for the exact returned bytes.
- Exact bytes — approval, exclusive save, and
<prompt> execution receive the Agent close value without rewriting or fence removal.
- Journal separation — the plan uses only disposable in-memory history; the final journal begins with the approved document.
- Lifetime — cancellation and every teardown failure settle before final validation, save, or execution.
- Narrative preservation — the shipped generation instruction asks for meaningful explanatory Markdown that preserves the user's intent, and the scripted Agent evidence proves that narrative survives approval and execution.
- Ordinary run — the approved source retains normal cwd, includes, props, output/value, permission, timeout, failure, and save behavior.
Use one discriminating regression per distinct boundary. Do not carry forward permutations whose only purpose was to prove the superseded TypeScript policy loop.
Dependencies and delivery order
Delivered foundations:
New parallel prerequisites:
Deferred and not blocking:
After #658 and #659 merge, PR #657 is reworked in place. Preserve its fixed argument scan, generated-property resolution and signature freezing, syntax-catalog construction, Agent-stack resolution, ordinary failure reporting, exclusive save, and supplied-source final execution where those implementations still satisfy this contract.
Replace its TypeScript author(), evaluate(), and direct review() policy with:
- the packaged Markdown plan root;
- the plan profile and constrained provider assembly;
- the host-declared candidate validator;
- the post-teardown final admission gate; and
- the new acceptance evidence above.
Rewrite specs/prompt-command-spec.md, the Tier PR section of specs/executable-mdx-spec.md, the prompt-specific Agent configuration in specs/acp-client-spec.md, and any generated-props wording affected by the two-root lifecycle. Add the internal terms and built-state entry to architecture.md.
Out of scope
- arbitrary custom planning roots or public
<Plan>;
--plan and --plan-eval;
- File/Glob planning context;
- a general arbitrary-code sandbox or constrained expression language;
- the collaborative playground;
- stdin or editor request input;
- automatic revision after runtime failure;
- a terminal Elicitation provider; and
- journaling or replay of planning as a resumable workflow.
Motivation
xmd run -e(#76) executes a program you already wrote.xmd promptis the step before that: you describe the outcome, a readable Executable Markdown policy writes a complete root document, the command validates and shows the exact source, and the approved bytes enter the ordinary run path.xmd prompt "ask me for my age and write the result to a file"The unit of work remains an executable Markdown program. Planning adds authored generation and review around it; it does not add another execution model.
Architecture
The trusted host owns two root document executions with a complete scope boundary between them:
The plan program is one exact, checked-in first-party Markdown value root shipped with the CLI. It owns the visible policy: prompt wording, the candidate and repair loops, validation branches, human review, revision, approval, abort, and exhaustion.
The plan profile is the trusted-host assembly used only for that exact root. It supplies the plan inputs, a constrained Agent provider, Elicitation, fixed first-party components, and the host-declared candidate validator. It uses no repository component search and exposes no custom root. These are internal architecture terms and are added to
architecture.mdwith this change.The plan program is trusted shipped source, not arbitrary user source. This issue therefore does not claim a general XMD sandbox. Public
<Plan>, custom plan roots, projected context, read-only<File>/<Glob>,--plan, and--plan-evalare deferred to #660. General constrained or untrusted XMD execution remains the larger #536 boundary.Command surface
xmd prompt <request> [options] [--props-<name> <value>]…The request is exactly one positional string containing at least one non-whitespace character. Missing, repeated, empty, and whitespace-only requests fail before any catalog, Agent, plan execution, Elicitation, save, journal, or final execution. No stdin or editor form is included.
--ends option parsing, so a dash-leading request follows it.The command accepts the ordinary
xmd run -eexecution flags, except-e/--eval, plus:--save <path>— exclusively create the approved source before final execution;--session <name>— use this non-empty logical name for the planning Session instead of the invocation-unique default.Agent provider selection, default Agent selection, and the whole-command timeout configure planning. Permission flags and exec/fetch timeouts configure only the approved document. Planning does not inherit the final run permission mode.
The request appears before every individual
--props-*option. An individual option before it is refused during fixed preflight. Known fixed-arity options, including aggregate--props,--save, and--session, keep their ordinary positions.Help
xmd prompt --helpis generic and effect-free. It documents the request,--save,--session, aggregate props, the individual-property ordering rule, and the shared flags. It generates no individual property options and performs no catalog, Agent, document inspection, plan execution, Elicitation, save, journal, or final execution.The packaged plan program
The host executes one immutable packaged Markdown value root under the stable internal source identity
<prompt-plan>. Its declared return schema is exactly{ type: "string" }.The host supplies fixed internal inputs:
--includevalues; andThey are not candidate root props and consume none of the generated document property sources.
The program contains one enclosing
<Session>expansion. Its body contains every initial, repair, and human-revision<Prompt>. A loop inside that one Session does not create another Session placement; sibling Sessions are not used, because sibling placements remain distinct even when their authored names match.The host owns the provider instruction layer and Agent ceiling. The Markdown root owns the text of each generation, repair, and revision request. The initial prompt preserves the original request text and includes the current catalog supplied by the host. It instructs the Agent to return one complete replacement root as source only and to preserve the request as meaningful Markdown narrative, not merely as an imperative script with comments.
<Prompt>remains one Agent turn. It gains no hidden repair, retry, review, or approval behavior.Planning Agent authority
The planning Agent is assembled separately from the final run provider:
The provider may use its own transport to perform the model turn; that does not grant the Agent a native network tool.
--approve-all,--approve-reads, and--deny-alldo not change this ceiling. They apply to the approved document later. A provider unable to establish the planning ceiling refuses before session materialization or a turn; there is no silent downgrade.The approved document later receives the caller-selected ordinary run Agent and permission configuration. It inherits neither the planning Session nor its instruction layer.
Planning Session
Without
--session, the host generates a logical name unique to the invocation. The exact name is supplied to the plan root, and its one enclosing<Session>materializes only at the first consuming<Prompt>(#648).--session <name>replaces that generated logical name. Ordinary provider Session continuation semantics apply when the selected provider already holds that name; the plan program still supplies the current request and current catalog in the invocation's initial turn. Every turn within this invocation uses the one enclosing Session.A generation turn produces a candidate only from its complete successful close value. Failed, cancelled, unavailable, or protocol-invalid turns discard partial text and reach no human review, save, or final execution.
The plan execution closes after approval or failure. The host observes its result only after every Prompt task, Agent provider resource, Elicitation resource, and other child has completed teardown. A teardown failure wins over a selected source and prevents final validation, save, and execution.
Candidate source remains data
An Agent reply is an inert string during planning. The plan program may bind it, pass it to the validator, serialize its diagnostics, present it with
<CodeBlock>, and return it. It never evaluates the candidate and never dynamically imports it.Only after approval, plan teardown, and final host validation may those exact bytes enter ordinary execution.
Host-declared candidate validation
The plan profile declares one internal value component,
<ValidateCandidate source={candidate} as="assessment" />, to the execution. Canonical execution supplies its invocation identity; repository resolution cannot replace it.Its result is a closed candidate assessment:
{ valid: true, diagnostics: {} }; or{ valid: false, diagnostics }, wherediagnosticscontains the complete versionedDocumentValidationwhen core produced one and the structured generated-binding diagnostic when property binding failed.The component performs no candidate execution. For each source it:
validateDocument()with those exact props, the caller's includes, and the run profile's identity-component declarations.Candidate-authored failures return
valid: falseand are eligible for repair:Caller-source failures raise out of the component and terminate the plan execution immediately:
A caller-source failure causes no repair turn, candidate presentation, approval, save, final journal, or final execution. The plan program cannot catch and recategorize it as candidate feedback.
An opaque
not-statically-checkableinvocation is not a diagnostic and does not by itself make a candidate invalid.Automatic repair
The initial draft and every human-requested revision each start a fresh automatic repair budget:
The fourth invalid candidate is repair-exhausted and proceeds to human review with its diagnostics. No fence is stripped, no Markdown substring is extracted, and no patch is applied.
Human review bound
The default plan program permits at most ten candidate presentations: the initial review plus at most nine human revisions.
Rounds one through nine offer:
approve,revise, orabort;reviseorabort.reviserequires non-empty feedback, sends one complete-replacement request through the same enclosing Session, and resets the three-turn automatic repair budget.Round ten offers no further revision:
approveorabort;abort.The review message uses #658's
<CodeBlock>to present the exact candidate and, when invalid, its complete JSON diagnostics. Candidate text cannot close the presentation fence and is never interpreted.approveselects<Return value={candidate} />.abort, review exhaustion, and any path that produces no approvable candidate select #659's<Fail>with an actionable message. Failure is authored in Markdown rather than hidden in the host or represented by a missing-<Return>accident.Planning history and presentation
The plan root runs with an invocation-owned in-memory durable stream because ordinary document and Prompt semantics require one. That stream is never written to
--journal, persisted as a workflow, reused, or replayed. It is discarded after complete plan teardown.The configured ACP provider may retain the planning Session under its normal provider contract, especially when the caller selected
--session.Plan-root rendered output is not command output. Human-visible planning presentation occurs through Elicitation. The plan root's successful public result is the approved source string and nothing else.
Final admission, save, and execution
After successful plan teardown, the host treats the returned string as untrusted again. It repeats candidate validation and property resolution using:
A final caller-source failure or document validation failure exits nonzero before save or execution. It does not re-enter the plan program or ask for repair.
The final resolved props belong to those exact source bytes. No props object from an earlier candidate is reused.
--save <path>then exclusively creates the target with those exact bytes. An existing target remains unchanged and prevents execution. Without--save, no generated-source file is created.The host executes
retainedSource("<prompt>", source)through the ordinary supplied-source run path. The contextual working directory, includes, output, value result, secret detection, Agent configuration, permission mode, timeouts, runtime failures, and exit status behave exactly as underxmd run -e.The final execution creates
--journalonly when it begins. That journal contains no plan root, planning Session, Agent turn, candidate validation, repair, or human-review event.A runtime failure does not return to planning. A successful
--saveremains.Cancellation and failure ordering
The whole-command deadline encloses catalog construction, plan execution, Elicitation, plan teardown, final validation, save, and final execution.
Cancellation halts the active plan work and awaits its structured teardown. No final validation, save, or final execution begins until the plan scope has completed successfully. A plan teardown failure prevents all later phases.
After the ordinary final execution begins, its existing outcome and teardown precedence remain unchanged.
Acceptance
The amended evidence replaces PR #657's TypeScript-policy acceptance matrix. Existing focused green tests on the feedback commit do not prove this contract.
The new structural checklist is:
--session, and effect-free generic help.<prompt-plan>; no TypeScript authorship loop or custom root chooses policy.<Prompt>remains one turn.--sessionsupplies the exact override.<CodeBlock>; abort and exhaustion reach<Fail>, not host policy or a missing Return.<prompt>execution receive the Agent close value without rewriting or fence removal.Use one discriminating regression per distinct boundary. Do not carry forward permutations whose only purpose was to prove the superseded TypeScript policy loop.
Dependencies and delivery order
Delivered foundations:
xmd run -e "<inline document>"to run inline content without a file #76 — supplied-root-source execution;xmd syntaxfor discoverable component documentation #632 — the structured syntax catalog;New parallel prerequisites:
<CodeBlock>#658 — safe arbitrary-text fenced presentation with<CodeBlock>;<Fail>#659 — deliberate authored failure with<Fail>.Deferred and not blocking:
<Plan>component #660 — public<Plan>, custom plan roots, projected context, and related CLI surface;After #658 and #659 merge, PR #657 is reworked in place. Preserve its fixed argument scan, generated-property resolution and signature freezing, syntax-catalog construction, Agent-stack resolution, ordinary failure reporting, exclusive save, and supplied-source final execution where those implementations still satisfy this contract.
Replace its TypeScript
author(),evaluate(), and directreview()policy with:Rewrite
specs/prompt-command-spec.md, the Tier PR section ofspecs/executable-mdx-spec.md, the prompt-specific Agent configuration inspecs/acp-client-spec.md, and any generated-props wording affected by the two-root lifecycle. Add the internal terms and built-state entry toarchitecture.md.Out of scope
<Plan>;--planand--plan-eval;