Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Existing documents and code get aligned to this section retroactively.
| Prompt | a person's original request, in ordinary natural language. `xmd plan` takes exactly one |
| Plan | the executable program produced from a Prompt: an Executable Markdown document combining readable prose that expresses the Prompt's intent with the components that carry it out, each placed beside the prose describing what it does. It begins with one descriptive level-one heading. A Plan is what `xmd plan` approves and then delivers: printed to stdout by default, written to an `--output` file, and run only under `--run`. It is not a synonym for a workflow, a policy document or any executable Markdown file |
| plan command document | the one exact checked-in first-party Markdown value root `xmd plan` executes. It is the command's adapter and nothing else: it projects the request into `<Plan>`, supplies the session, and returns the approved source. It is not itself a Plan. Internal: no command-line option selects another one, and no repository component search can answer for it |
| packaged `<Plan>` Component | the one exact checked-in first-party Markdown value component that converts a Prompt into a Plan, `packages/cli/src/documents/Plan.md`, declared to every ordinary run as the public `<Plan>`. It owns and implements the Plan authorship workflow — the Prompt wording, the draft and repair loops, the `<CheckDraft>` branches, human review, revision, approval, stopping, exhaustion and the final explanation turn — and returns the exact approved Plan source. Every Plan-producing turn in it states the complete Plan requirements for itself, so a replacement may add or correct a title rather than only carry one forward. Both surfaces expand these exact bytes under one origin and one digest; there is no generated TypeScript copy and no second Markdown implementation. Its four phase components are private to it, and it is not itself a Plan |
| packaged `<Plan>` Component | the one exact checked-in first-party Markdown text component that converts a prompt into a Plan, `packages/cli/src/documents/Plan.md`, declared to every ordinary run as the public `<Plan>`. It owns and implements the Plan authorship workflow — the Prompt wording, the draft and repair loops, the `<CheckDraft>` branches, human review, revision, approval, stopping, exhaustion and the automatic final explanation turn — and produces the exact approved Plan source as what it renders: written bare it emits those bytes, and `as` is ordinary text capture that binds them and emits nothing. Neither form evaluates the source. Every Plan-producing turn in it states the complete Plan requirements for itself, so a replacement may add or correct a title rather than only carry one forward. Both surfaces expand these exact bytes under one origin and one digest; there is no generated TypeScript copy and no second Markdown implementation. Its four phase components are private to it, and it is not itself a Plan |
| authorship profile | the trusted-host assembly the packaged `<Plan>` Component runs its authored turns under, installed by its own `<PlanAuthorship>` inside the invocation that owns it rather than around an execution — which is what makes it the same frame whether `xmd plan`, an ordinary document, or a configured `<TestAgent>` run child asked. Which Agent context goes under it is a trusted-host capability the declaration carries — the production ACPX one built from the run's Agent stack, or the deterministic one a canonical `<TestAgent>` child declaration produced — and a host that supplies none states the sentence a `<Plan>` written there is refused with. The fixed policy is installed in one place for both, so a second provider cannot bring a weaker one: its fixed inputs, a constrained Agent provider, Elicitation, the fixed first-party components and the host-declared `<CheckDraft>`. It uses no repository component search and exposes no custom root, and the policy it installs is not readable from the command line. Its working directory is one host-owned directory dedicated to the logical session, keyed by the digest of that name, created empty and required to be empty on the way in. An explicitly named session's directory is durable, because continuation derives the same session identity from it; an invocation-unique default session's is scope-owned, claimed before it is created, and exactly one cleanup is attempted after profile teardown and before admission on every ending — the leaf removed non-recursively when it is still the empty directory that was handed over, and left as found with the command failing terminally when it has gained content or vanished. Where those directories live is a host dependency no caller or document selects |
| upgrade command document | the one exact checked-in first-party Markdown streaming text root `xmd upgrade` executes to select and install a published release. It owns the exact-tag grammar, release selection, semantic-version comparison, consent, the status, already-current and installation branches, and the wording of every refusal and report; its rendered body is the command's output rather than a value it returns. Internal: no command-line option selects another one, and no repository component search can answer for it |
| upgrade assembly | what one runtime-named entrypoint states about the `xmd` that is running: its provenance, reported version, invoked executable path, platform, architecture, release target when the release publishes one, and — for an eligible compiled macOS or Linux host alone — the factory for the four phases an installation needs. It describes how this `xmd` is running, never how its files arrived |
Expand Down Expand Up @@ -3561,15 +3561,35 @@ registration can answer for it — one decision, shared by execution, inspection
and validation, so a repository file under a private name is described by none
of them and runs nowhere.

**The journal records the asset, not a lookup.** A declared import records
exactly `{ kind: "declared-markdown", origin, digest, content }`, and a private
one records exactly `{ kind: "declared-private", origin }`. A continuation reads
both as hostile data, verifies the recorded origin, digest and bytes against
what this run declares, and reads no file: a host that no longer declares the
name, or that declares different bytes under it, refuses rather than continuing
**The journal records the asset, not a lookup.** A declared import records one
of two closed shapes — `{ kind, origin, digest, content }`, and the same with
`exact: true` for a component the host declared as rendering a program's source
— and a private one records exactly `{ kind: "declared-private", origin }`. A
continuation reads all of it as hostile data, verifies the recorded origin,
digest, bytes and disposition against what this run declares, and reads no file:
a host that no longer declares the name, that declares different bytes under it,
or that publishes those bytes a different way, refuses rather than continuing
somebody else's Markdown. A recorded private import refuses unless the element
asking for it is inside the same declaration.

**Exact source is a provenance, not a property.** Whether bytes are published as
a program's source or presented as prose is decided from two things no answer
can write: that canonical execution authorized the import for a name this
execution closed, and that the host's own admitted declaration for that name
states it. A definition carrying the claim, a segment arriving already marked, a
frontmatter key and a middleware answer are each data that reached the engine
from somewhere, so none of them decides it — an ordinary
`Component.importComponent` handler answering an open name with a definition
claiming the disposition publishes prose, exactly as a repository file of that
name does.

The record of which segments an expansion produced as source belongs to the
execution that made it and is handed down **by value** on canonical core's
private expansion authority. Not through a context: a context resolves by name,
and a name is not a secret, so a component could build one, reach the record and
answer that everything is exact. It is reclaimed with its execution, reaches no
public entrypoint, and marks nothing on the segments themselves.

## The syntax catalog boundary

`xmd syntax` answers what a document may write here, and answering must cost
Expand Down
94 changes: 49 additions & 45 deletions packages/cli/src/documents/Plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ props:
properties:
session: { type: string, minLength: 1 }
additionalProperties: false
returns:
type: string
description: >-
Create an XMD program from a Prompt. `<Plan as="program">Ask for the user's
age.</Plan>` expands its content normally to form the complete Prompt.
as: Required. The exact approved Plan source after teardown and structural admission.
context: The complete Prompt, expanded once before authorship.
Create an XMD program from a prompt. `<Plan>Ask for the user's age.</Plan>`
emits the approved program source.
as: Binds the exact approved program source and emits nothing. Omitted, that source is emitted where the component is written.
context: The complete prompt, expanded once before authorship.
---

# Turning a Prompt into a Plan
Expand All @@ -21,8 +19,9 @@ available to carry them out. A coding agent turns both into one document that
explains and executes the sequence.

A draft remains text while this workflow reviews it. Nothing in it runs before
you approve it. After approval, the exact source is checked once more as
structure and handed back unchanged.
you approve it, and nothing runs it afterwards either: what this workflow
produces is the approved program's source, byte for byte, for you to keep,
read, or hand to something that runs it.

## Read the Prompt

Expand All @@ -37,7 +36,7 @@ nothing reaches no catalog, no session, no agent and no review.
<Fail message="<Plan> requires its body to render a non-empty Prompt." />
</If>

<PlanInputs session={props.session} as="inputs" />
<PlanInputs session={props.session} instruction={prompt} as="inputs" />

## Say what this surface calls things

Expand All @@ -48,13 +47,11 @@ of them is raised.

<If condition={inputs.surface === "command"}>
<Let as="stopped" value="xmd plan stopped at your request. Nothing was output or run." />
<Let as="exhausted" value="xmd plan reviewed ten drafts without an approved Plan. Nothing was output or run." />
<Let as="unresolved" value="xmd plan ended without an approved Plan. Nothing was output or run." />
<Let as="explained" value="xmd plan reviewed ten drafts without an approved Plan. The coding agent explained why:" />
<Let as="closing" value="Nothing was output or run." />
<Else>
<Let as="stopped" value="Plan authorship stopped at your request. No Plan was returned." />
<Let as="exhausted" value="Plan authorship reviewed ten drafts without an approved Plan. No Plan was returned." />
<Let as="unresolved" value="Plan authorship ended without an approved Plan. No Plan was returned." />
<Let as="explained" value="Plan authorship reviewed ten drafts without an approved Plan. The coding agent explained why:" />
<Let as="closing" value="No Plan was returned." />
Expand Down Expand Up @@ -162,18 +159,44 @@ explanation before or after it.
<CheckDraft source={draft} as="check" />
</Loop>

## Explain a tenth draft that could not be repaired

Ten drafts is the limit, and the tenth cannot be revised into an eleventh. So a
tenth draft that still has problems after its repair attempts leaves nothing to
approve and nothing to ask for — there is no decision left for you to make, and
this workflow does not ask you to make one.

Instead the coding agent is asked once, automatically, why the attempts did not
work and what would make a future prompt more likely to succeed. That answer is
explanation and nothing else: it creates no new draft, extends no limit, and
ends this Plan without a program.

<If condition={round === 10 && !check.valid}>
<Prompt as="explanation">
The final Plan still has these problems:

<Json value={check.diagnostics} as="problems" />
<CodeBlock value={problems} language="json" />

Explain briefly why the attempts did not resolve them and what the person should
clarify in their next Prompt. Do not create another Plan.
</Prompt>

<Fail message={`${explained}\n\n${explanation}\n\n${closing}`} />
</If>

## Review the draft

The workflow shows you the complete draft after its repair attempts.
Every draft you are shown has a decision left in it. The workflow shows you the
complete draft after its repair attempts.

- Choose **Approve** to accept a draft that passed its check.
- Choose **Request changes** to send feedback to the coding agent and create a
new draft.
- Choose **Stop** to end without returning anything.

A draft with remaining problems cannot be approved. You may review at most ten
drafts, and the tenth cannot be revised. If the tenth draft still has problems,
you may ask the coding agent to explain what went wrong or stop.
A draft with remaining problems cannot be approved, and the tenth draft cannot
be revised, so on either of those the choices you are offered are narrower.

<Elicit
as="review"
Expand All @@ -184,9 +207,7 @@ you may ask the coding agent to explain what went wrong or stop.
type: "string",
enum: check.valid
? (round === 10 ? ["Approve", "Stop"] : ["Approve", "Request changes", "Stop"])
: (round === 10
? ["Explain what went wrong", "Stop"]
: ["Request changes", "Stop"]),
: ["Request changes", "Stop"],
},
feedback: { type: "string" },
},
Expand Down Expand Up @@ -226,36 +247,15 @@ problems:
## Continue from your decision

Approve keeps this exact draft and leaves the review. Request changes sends your
feedback to the coding agent and starts a new draft. Stop ends here. On a tenth
draft that still has problems there is nothing left to revise into, so the two
remaining choices are to ask the coding agent what went wrong, or to stop.
feedback to the coding agent and starts a new draft. Stop ends here.

<If condition={review.decision === "Approve"}>
<Let as="approved" value={draft} />
<Break />
</If>

<If condition={review.decision === "Stop"}>
<If condition={round === 10 && !check.valid}>
<Fail message={exhausted} />
<Else>
<Fail message={stopped} />
</Else>
</If>
</If>

<If condition={review.decision === "Explain what went wrong"}>
<Prompt as="explanation">
The final Plan still has these problems:

<Json value={check.diagnostics} as="problems" />
<CodeBlock value={problems} language="json" />

Explain briefly why the attempts did not resolve them and what the person should
clarify in their next Prompt. Do not create another Plan.
</Prompt>

<Fail message={`${explained}\n\n${explanation}\n\n${closing}`} />
</If>

<Prompt as="draft">
Expand Down Expand Up @@ -286,17 +286,21 @@ explanation before or after it.
</Session>
</PlanAuthorship>

## Return the approved Plan
## Produce the approved Plan source

Only an approved Plan leaves this workflow, and only after the whole authorship
frame above has been taken down. Its exact source is checked once more as
structure — every declaration, resolution and form it uses — and then handed
back byte for byte.
structure — every declaration, resolution and form it uses — and retained
together with the prompt it was written for, so asking again restores these
exact bytes instead of writing a second Plan.

<If condition={approved !== null}>
<AdmitPlan source={approved} as="admitted" />
<Return value={admitted} />
<AdmitPlan source={approved} instruction={prompt} as="admitted" />
<Else>
<Fail message={unresolved} />
</Else>
</If>

The source is what this workflow produces, byte for byte. Nothing here runs it.

<Output>{admitted}</Output>
Loading
Loading