Skip to main content

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​

FieldMeaning
apiVersionorun.io/v1
kindAlways Plan
metadataName, 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
executionconcurrency, 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.jobBindingsOptional metadata about bound jobs
jobsThe concrete execution DAG
lanesPresent 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​

FieldMeaning
idJob ID in the form <component>.<environment>.<job>
name, component, environmentRequired identity of the job
composition, jobRegistry, jobWhich composition and job template the job was bound from
runsOn, pathRunner image and working directory
laneThe id of the lane the job runs in (only with execution.lanes)
stepsThe ordered step list (required)
dependsOnHard dependency edges on other job IDs
advisoryDependsOnAdvisory edges that order but do not gate
dependencyMode, dependencySource, dependencyRuleTriggerRefHow the dependency edges were derived
gatesCross-plan promotion gates: type (environment-promotion), environment, component, condition, match
timeout, retriesJob-level limits
envMerged environment variables
secretRefsSecret references the job resolves at run time — see below
materializeValue-free delivery step for resolved secrets — see below
labelsString labels
parametersThe 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.

FieldMeaning
id, nameStep identity
phasepre, main (default), or post
orderInteger ordering within a phase
runShell command
useGitHub Actions-style action reference
workflowWorkflow file to run — see below
with, envStep inputs and environment
shell, working-directoryShell and working directory overrides
timeout, retryStep-level limits
onFailurestop 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:

FieldMeaning
workflowThe workflow file (or remote reference) this step runs
workflowDigestContent digest of the workflow pinned at compile time; folds into the plan checksum
connectionsCompile-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
resumeWhen true, a retry re-executes only the steps that did not succeed in the prior attempt; the default re-runs from the top
approvalA 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.

FieldRequiredMeaning
approval.promptnoWhat the approver is asked
approval.timeoutyesHow long the gate waits; a gate without a timeout is rejected at validation so a forgotten gate cannot hang CI silently
approval.onTimeoutyesfail 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 each secret:// reference the runner resolves, as { "asEnv": "<ENV_VAR>", "ref": "secret://…", "optional": false }. Hard references fail closed when the key is absent; optional: true marks a best-effort reference that is skipped instead.
  • materialize on 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.
  • connections on a workflow: step maps connection fields to secret:// 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.