Plan schema
The plan is the artifact produced by orun plan and consumed by orun run. The core shape is described by the JSON Schema at assets/config/schemas/plan.schema.yaml; the complete field set below is taken from the plan types in internal/model/plan.go (Plan, PlanJob, PlanStep). Field names are the exact JSON keys.
Top-level fields
| Field | Meaning |
|---|---|
apiVersion | orun.io/v1 |
kind | Always Plan |
metadata | Name, description, namespace, checksum, selection, trigger, and revision; metadata.lanes (mode, maxLanes, maxLanesFrom: intent, default, flag or env; weightsFrom: declared, history or file when the plan carries packing weights; upstreamWait when the intent sets execution.lanes.upstreamWait) when the intent sets execution.lanes |
execution | concurrency, failFast, stateFile, and timeout (the intent's execution.defaults.timeout, the bound on every step whose job and step set none; absent, the runner applies 60m) |
spec.jobBindings | Optional metadata about bound jobs |
jobs | The concrete execution DAG |
lanes | Present only when the intent sets execution.lanes: the units a runner takes — id, name, index, environment, jobs, concurrency (0 is auto: orun run --lane sizes it to the runner's cores), runsOn, source, estimatedSeconds and vcpu when the plan carries weights or declared cpu, splitFrom/reason after a cycle split, and what the lane waits on: level (0 for a lane no other lane feeds, else one more than the deepest lane it waits on), upstreamLanes and upstreamJobs. See Lanes |
Plans are deterministic: the same inputs produce byte-identical plan.json. jobs[] is in a stable topological order (the same graph always yields the same order and the same job index), so a plan diff in a pull request only shows real changes. Plans carry no generation timestamp. metadata.generatedAt is still accepted when reading plans written by older versions, but it is volatile and is left out of metadata.checksum and metadata.revision.planHash.
jobs[].resources is what the job's template declared (cpu, memory, estimatedSeconds) and jobs[].estimatedSeconds the job's effective packing weight — the declared estimate, or the one orun plan --weights supplied; both are absent when nothing was declared or supplied.
Each jobs[].steps[] entry carries the composition step's fields after templating; scope: lane marks a step the first job of a lane runs once for every job that shares it (see Lanes).
Job fields
| Field | Meaning |
|---|---|
id | Job ID in the form <component>.<environment>.<job> |
name, component, environment | Required identity of the job |
composition, jobRegistry, job | Which composition and job template the job was bound from |
runsOn, path | Runner image and working directory |
lane | The id of the lane the job runs in (only with execution.lanes) |
steps | The ordered step list (required) |
dependsOn | Hard dependency edges on other job IDs |
advisoryDependsOn | Advisory edges that order but do not gate |
dependencyMode, dependencySource, dependencyRuleTriggerRef | How the dependency edges were derived |
gates | Cross-plan promotion gates: type (environment-promotion), environment, component, condition, match |
timeout, retries | Job-level limits |
env | Merged environment variables |
secretRefs | Secret references the job resolves at run time — see below |
materialize | Value-free delivery step for resolved secrets — see below |
labels | String labels |
parameters | The merged component parameters the job was rendered with, including secretOutputs when declared |
Step fields
Each step declares id and exactly one execution form: run, use, or workflow.
| Field | Meaning |
|---|---|
id, name | Step identity |
phase | pre, main (default), or post |
order | Integer ordering within a phase |
run | Shell command |
use | GitHub Actions-style action reference |
workflow | Workflow file to run — see below |
with, env | Step inputs and environment |
shell, working-directory | Shell and working directory overrides |
timeout, retry | Step-level limits |
onFailure | stop or continue |
The workflow: step form
A workflow: step runs a kind: Workflow file through the workflow engine instead of a shell or an action. The compiler pins the reference so the plan records what will run, never the outcome:
| Field | Meaning |
|---|---|
workflow | The workflow file (or remote reference) this step runs |
workflowDigest | Content digest of the workflow pinned at compile time; folds into the plan checksum |
connections | Compile-checked credential grant: connection name → field → secret:// reference. Names and references only — the plan is the reviewable grant, and only mapped references cross to the engine at run time |
resume | When true, a retry re-executes only the steps that did not succeed in the prior attempt; the default re-runs from the top |
approval | A human gate evaluated before the engine is invoked — see below |
Every field here is durable plan content; the workflow's run state lives under .orun/ as run facts.
Approval gates
approval on a step declares a human gate. The run pauses before the step, and the pending request and the decision are sealed run facts under .orun/approvals, never plan content.
| Field | Required | Meaning |
|---|---|---|
approval.prompt | no | What the approver is asked |
approval.timeout | yes | How long the gate waits; a gate without a timeout is rejected at validation so a forgotten gate cannot hang CI silently |
approval.onTimeout | yes | fail or proceed |
orun approve answers a pending gate.
Secret references
Secrets appear in the plan as references only; no value field exists, structurally.
secretRefs[]on a job lists eachsecret://reference the runner resolves, as{ "asEnv": "<ENV_VAR>", "ref": "secret://…", "optional": false }. Hard references fail closed when the key is absent;optional: truemarks a best-effort reference that is skipped instead.materializeon a job is the value-free delivery step rendered from the profile's runtime-delivery block:{ "target": "<adapter id>", "secrets": ["KEY", …] }. The adapter and key names fold into the checksum; values never do.connectionson aworkflow:step maps connection fields tosecret://references, as described above.
secretOutputs
secretOutputs is not a top-level plan field. It is a component parameter, so it arrives in the plan under parameters.secretOutputs as a comma-separated KEY=producer-hint list. When it is present the runner exports ORUN_SECRET_OUTPUTS — the path of a per-job sink file — to every step of the job, then parses the sink, enforces the declared-key allow-list, registers the values with the redactor, and publishes them over the run's lease-bound channel. See secrets.
Minimal example
{
"apiVersion": "orun.io/v1",
"kind": "Plan",
"metadata": {
"name": "demo",
"checksum": "sha256-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
},
"execution": {
"concurrency": 4,
"failFast": true,
"stateFile": ".orun-state.json"
},
"jobs": []
}
Treat the plan as an immutable artifact. Do not hand-edit it unless you are debugging the runtime itself.
Related
- Workflow schema — the
kind: Workflowdocument aworkflow:step runs. - Workflow actions —
workflow:steps, connections, resume, and approvals in context. - Secrets —
secretEnv,optionalSecretEnv, andsecretOutputs. - Scope references — the
secret://grammar. orun approve— answering a pending approval gate.