Plan vs run
Orchard has two execution modes. They share parsing, validation, and graph construction but diverge on how they deal with providers and side effects.
orchard plan
orchard plan is a read-only preview. It:
- Parses the scenario file and any component files it references.
- Loads provider schemas.
- Validates the scenario: every reference resolves, every required attribute is set, every type matches.
- Builds and sorts the dependency graph.
- Prints the plan — what will run, in what order, with what inputs.
orchard plan --show-values also lists each action’s evaluated attributes;
values that come from other actions show as (known after run).
plan never configures a provider and never executes an action. It cannot
open database connections, make HTTP requests, or spawn subprocesses. For
built-in providers, plan skips Configure entirely. For external providers,
plan uses a short-lived schema probe that runs <binary> schema, reads the
schema JSON, and exits immediately.
This is a deliberate design choice: plan should be fast, deterministic, and side-effect-free. You can run it in CI against a scenario that points at production without touching production.
orchard run
orchard run executes the scenario. It:
- Does everything
plandoes. - Calls
Configureon each provider with its evaluated configuration. - Executes each action once its dependencies have completed (up to
--parallelismat a time, default 1), passing evaluated attributes and capturing outputs. - Resolves scenario outputs and prints them.
- Calls
Shutdownon each provider.
For external providers, run starts a long-lived subprocess per provider and
keeps it alive until the scenario finishes. Communication happens over stdio
in JSON Lines.
Why split them
The split mirrors Terraform’s plan/apply split, for the same reason: a plan should be cheap and safe enough to run constantly. Bundling describe and configure into a single handshake would force every plan invocation to supply real credentials and open real connections — which is both slow and risky.
In Orchard’s case the split also makes external providers easier to write. A provider binary only needs to implement two things to support plan:
- Respond to
<binary> schemaby printing a JSON schema. - (For run) Implement the full stdio protocol.
See provider protocol for details.
When to use each
- Run
planfreely. In CI, before merge, whenever you want to check scenario validity. It’s cheap and safe. - Run
rundeliberately. It modifies real systems. Treat it like any other side-effectful command.