> ## Documentation Index
> Fetch the complete documentation index at: https://graph.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Authoring plans

> From blank file to running plan

This walkthrough builds `project_status` — a real plan — from scratch. The workflow generalizes: **probe the tools, chain the steps, shape the finish.**

## 1. Probe the tools you'll use

Before writing any step, learn each tool's input schema and *actual* output shape:

```bash theme={null}
graph tools show linear__list_projects          # input schema
graph tools test linear__list_projects '{"query":"New Relic"}'   # real output
```

Probing pays twice: you author correct `{{Ex.path}}` references, and every probe feeds the [shape cache](/tools/shape-cache).

<Tip>
  Prefer tool parameters that accept **names** over ids when available — `linear__list_issues` takes `project` by name, which means fewer fragile deep references between steps.
</Tip>

## 2. Header and inputs

```yaml theme={null}
identifier: project_status          # tool-name-safe: [a-zA-Z0-9_-]
name: Project Status
description: Status report for a Linear project — health, activity, risks.
exemplars:                          # how users will ask for this (routing signal)
  - "How is the New Relic migration going?"
requires_servers: [linear]          # MCP dependencies — unconfigured: hidden from the catalog, loud error by name
input_schema:                       # JSON Schema; referenced as {{input.*}}
  type: object
  required: [project]
  properties:
    project: { type: string, description: The Linear project name }
```

Missing required inputs are handled for you: `plan run` exits with code 3 and prints the schema; in chat, the agent receives the error, asks the user, and re-calls with complete inputs.

## 3. Steps

Steps run **sequentially**; each input may reference plan inputs and any earlier step. Tool names are namespaced catalog names, plus the bare control steps — [`exit`](/plans/exit-gates), [`decide`](/plans/branching), [`map`/`reduce`](/plans/iteration), [`agent`](/plans/agent-step), and [`ask`](/plans/ask-step) — and [`plan_and_execute`](/plans/the-planner), the reserved planner tool.

Step ids are identifiers — letters, digits, and `_`, not starting with a digit — unique across the plan (body sub-steps included). The planner's `E0`, `E1`, … convention and descriptive names like `fetch_project` are equally valid. Ids may not shadow the reserved template roots `input`, `item`, `index`, `accumulator`, or `length`.

```yaml theme={null}
steps:
  - id: E0                                        # any unique identifier — E0-style or descriptive (fetch_project)
    tool_name: linear__list_projects
    input: { query: "{{input.project}}", limit: 5 }
    reasoning: Find the project and its metadata.  # optional, shown in traces
  - id: E1
    tool_name: linear__list_milestones
    input: { project: "{{E0.projects.0.name}}" }
  - id: E2
    tool_name: linear__list_issues
    input: { project: "{{E0.projects.0.name}}", updatedAt: "-P14D", limit: 250 }
  - id: E3
    tool_name: linear__get_status_updates
    input: { project: "{{E0.projects.0.name}}", type: project, limit: 3 }
```

Design notes worth stealing:

* **One deep reference, reused.** Only `{{E0.projects.0.name}}` reaches into a result; if the project isn't found, that produces one clean "empty data" outcome instead of four different failures.
* **Types survive templating.** `limit: 5` stays an integer; a string that is *exactly* one tag splices the raw JSON value. See [Template language](/plans/template-language).
* **Steps are LLM-free.** However many steps you add, execution costs zero inference.

## 4. The finish

Choose how the plan ends — a solver report, structured output, or silence ([details](/plans/finish-modes)):

```yaml theme={null}
solver:
  query_to_answer: |
    Write a status report for the "{{E0.projects.0.name}}" Linear project.
    1. Header: "# <name>: <health emoji> <HEALTH>" from the latest update's health field.
    2. "## Recent activity" — group issues by label; exact counts; link every issue.
    {{#E1.milestones}}{{#@first}}
    3. "## Milestones" — one line each with target date.
    {{/@first}}{{/E1.milestones}}
  data:
    project: "{{E0.projects.0}}"
    milestones: "{{E1.milestones}}"
    recentIssues: "{{E2.issues}}"
    statusUpdates: "{{E3.statusUpdates}}"
```

* `data` is what the solver sees — whole results spliced by template. Oversized payloads are automatically truncated/sampled.
* `query_to_answer` is itself a template: conditional sections (like the milestones block above) adapt the instructions to the data.
* The tighter the output spec, the more consistent the report run-over-run. For strict formats, write the structure as a grammar — see `sprint_analysis` in the [cookbook](/cookbook/reporting).

## 5. Validate and run

```bash theme={null}
graph plan validate project_status
graph plan run project_status '{"project":"New Relic"}'
```

Validation is layered: structural checks (templates, references, ids) run at every load, and `plan validate` / `plan run` additionally resolve every step tool against what is actually loadable, refusing to start before any step executes when a tool can't resolve. What no static layer can catch — a path that doesn't exist in a tool's real output — surfaces at run time as a typed error with the available keys listed. The full layering, including how `requires_servers` declarations behave, is in [where validation happens](/plans/errors-and-replanning#where-validation-happens).

For interactive authoring, the [plan workbench](/workbench/plan-workbench) wraps this whole loop in a TUI: the chat agent drafts into a side pane, validation runs on every change, and a gated run pauses before each tool call so you can test a plan before its writes are trustworthy.

<Frame caption="The authoring loop in one screen: the draft's step tree, its validation verdict, and the agent that edits it.">
  <img src="https://mintcdn.com/graph/VaTetSEpy4ieswMa/images/workbench/workbench-overview.svg?fit=max&auto=format&n=VaTetSEpy4ieswMa&q=85&s=42e162ae591c04bc9d2a192e60b3882c" alt="The authoring loop in one screen: the draft's step tree, its validation verdict, and the agent that edits it." width="1044" height="720" data-path="images/workbench/workbench-overview.svg" />
</Frame>

## Authoring from the command line

The same loop runs as [individual commands](/reference/cli#authoring-plans) — useful in scripts, and the surface a plan-managing agent drives. Each command applies one edit to the file and writes it back; there is no session to hold open.

```bash theme={null}
graph plan new report --name "Report" --description "roll a team's issues into a digest"
graph plan set report input_schema '{"type":"object","properties":{"team":{"type":"string"}},"required":["team"]}'
graph plan step add report E1 linear__list_issues '{"teamId":"{{input.team}}"}'
graph plan step add report E2 builtin__reshape '{"shape":{"count":"{{E1.length}}"}}'
graph plan set report output '{"count":"{{E2.count}}"}'
graph plan validate report
graph plan run report '{"team":"Core"}'
```

Note what this walkthrough does *not* do: call the planner. `graph plan draft "<goal>"` is available and mirrors the workbench's drafting (per-step validation, salvage on exhaustion), but it is the only authoring command that costs inference. When you already know the steps — or an agent does — building them directly is free, deterministic, and reviewable as a diff.

Two properties make this safe to script against:

* **Edits can only improve things.** An edit is rejected if it introduces a validation problem, and a rejected edit leaves the file untouched — so `step rm` fails when a later step still references the step, naming the template that would dangle. Problems that were *already* there never block an edit, which is what keeps a half-built plan (a fresh `plan new` has no steps yet) editable.
* **Nothing is clobbered silently.** A write refuses a file that holds a different plan, and changing `identifier` writes a new file rather than overwriting the old one.

Add `--json` to any of these for a machine-readable envelope — including on rejection, where the problem list is what you want most. See the [scripting contract](/reference/scripting-contract#authoring-envelopes).

<Tip>
  To have your coding agent drive this loop, install the skill:

  ```shellscript theme={null}
  npx skills add tylerdavis/graph
  ```

  This installs [/graph-plan-authoring](https://github.com/tylerdavis/graph/blob/main/skills/graph-plan-authoring/SKILL.md) (Claude Code, Cursor, Codex, and most other agents). It teaches the loop the way it is meant to run — draft first, then repair — including the fixes a fresh draft usually needs and how to read a rejection envelope as a repair list.
</Tip>


## Related topics

- [CLI reference](/reference/cli.md)
- [Quickstart](/getting-started/quickstart.md)
- [graph as an MCP server](/tools/mcp-server.md)
- [Scripting contract](/reference/scripting-contract.md)
- [Plan file schema](/reference/plan-schema.md)
