> ## 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.

# What is a plan

> Repeatable workflows as reviewable YAML files

A **plan** is a YAML document describing a workflow: a sequence of tool calls with data flowing between them, finished by a report, structured output, or nothing at all. Plans are the answer to a specific problem with agents: *improvisation is great until you need the same thing twice*.

```yaml theme={null}
identifier: project_status
name: Project Status
description: Status report for a Linear project — health, activity, risks.
exemplars:
  - "How is the New Relic migration going?"
requires_servers: [linear]
input_schema:
  type: object
  required: [project]
  properties:
    project: { type: string, description: The Linear project name }
steps:
  - id: E0
    tool_name: linear__list_projects
    input: { query: "{{input.project}}", limit: 5 }
  - id: E1
    tool_name: linear__list_issues
    input: { project: "{{E0.projects.0.name}}", updatedAt: "-P14D", limit: 250 }
solver:
  query_to_answer: |
    Write a status report for "{{E0.projects.0.name}}"…
  data:
    project: "{{E0.projects.0}}"
    recentIssues: "{{E1.issues}}"
```

## Three ways to run a plan

<CardGroup cols={3}>
  <Card title="Directly" icon="terminal">
    `graph plan run project_status '{"project":"New Relic"}'` — deterministic, scriptable, one LLM call (the solver) or zero (output/silent plans).
  </Card>

  <Card title="As an agent tool" icon="comments">
    Every plan is a tool named `plan__<identifier>`. In chat, "how's the migration going?" routes to it via the plan's exemplars.
  </Card>

  <Card title="Authored by the planner" icon="wand-magic-sparkles" href="/plans/the-planner">
    `plan_and_execute` writes a plan on the fly for novel tasks — same engine, same template language, plus replanning on failure.
  </Card>
</CardGroup>

## When to write a plan (vs letting the agent improvise)

Write a plan when any of these are true:

* **You'll run it more than twice.** Plans eliminate run-to-run variance in which tools get called and how.
* **It feeds automation.** [Output-mode plans](/plans/finish-modes) emit structured JSON; silent plans perform actions. Both are CI primitives.
* **The workflow embodies judgment.** Which fields matter, what "recent" means, how to group — encode it once, in review-able form, instead of hoping the model re-derives it.
* **Cost/latency matter.** A plan run makes 0–1 LLM calls regardless of how many tool calls it performs.

Let the agent improvise when the question is genuinely novel or conversational — that's what `ask`/`chat` and `plan_and_execute` are for.

## Composition

Plans call plans: a step whose `tool_name` is `plan__<identifier>` runs that plan and yields its result — a sub-plan's `output` map arrives as structured data your templates can reference:

```yaml theme={null}
steps:
  - id: E0
    tool_name: plan__urgent_issues      # a whole sub-plan as one step
    input: {}
  - id: E1
    tool_name: exit
    input:
      when: { value: "{{E0.count}}", op: eq, to: 0 }
      status: success
      message: "Nothing urgent."
```

An [`agent` step](/plans/agent-step) is the escape hatch for the one case plans can't express: when *which* tools to call depends on what earlier calls returned. It still returns schema-conforming JSON, so the rest of the plan stays typed.

An [`ask` step](/plans/ask-step) covers the other thing a plan can't compute: a value only a person can supply. It declares what happens when there is no person — which is what keeps the same plan runnable from a terminal, from an MCP client, and in CI.

Design small, single-purpose plans (fetch-and-shape, in output mode) and compose them from reporting or gating plans. Cycles fail immediately with the chain named (`a → b → a`); nesting is capped at 8.

## Plan discovery

Plans load from the directories in `[plans].paths` (default: `./.graph/plans` and `~/.config/graph/plans`, so repos carry their own and your global library fills in the rest). A plan whose `requires_servers` lists an unconfigured MCP server is hidden rather than broken — and asking for it by name (`plan run`, `plan show`, `plan validate`, `workbench plan`) says exactly which servers are missing instead of "no plan named".

A file that fails to parse or validate is **skipped with a warning** (stderr; the workbench log in the TUI) — one broken plan never takes down the catalog or the commands built on it. Files load in sorted order per directory, directories in the order configured, and the first definition of a duplicate identifier wins; later ones are skipped with a warning too. Asking for a skipped plan by name reports the file's load error.

On top of the structural check every load performs, `plan validate` and `plan run` resolve each step's tool name against what is actually loadable (enabled packs, user tools, the plan catalog, configured MCP servers) and fail before anything executes — see [where validation happens](/plans/errors-and-replanning#where-validation-happens).

```bash theme={null}
graph plan list
graph plan show project_status
graph plan validate project_status        # or a file path, pre-commit
```


## Related topics

- [Errors & replanning](/plans/errors-and-replanning.md)
- [The planner](/plans/the-planner.md)
- [Scripting contract](/reference/scripting-contract.md)
- [Authoring plans](/plans/authoring.md)
- [Quickstart](/getting-started/quickstart.md)
