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.
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 in topological order, 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.