Skip to main content

Writing compositions

Author a new composition package when you want to introduce a new component type without changing the core planner.

1. Create a Stack package root​

The recommended format is a stack.yaml manifest with a compositions/ subdirectory. Each composition type lives in its own subdirectory using either inline or split-kind authoring.

my-platform/
├── stack.yaml
└── compositions/
└── mytype/
├── composition.yaml
├── schema.yaml
├── jobs/
│ └── mytype-apply.yaml
└── profiles/
├── mytype-verify.yaml
└── mytype-deploy.yaml

2. Define the Stack manifest​

stack.yaml describes the package and an optional OCI registry target. When spec.compositions is omitted, the packager auto-discovers composition files by walking the directory tree.

apiVersion: orun.io/v1
kind: Stack
metadata:
name: my-platform-stack
version: 1.0.0
description: Platform compositions for my-platform
owner: my-org
registry:
host: ghcr.io
namespace: my-org
repository: my-platform-stack
visibility: public

3. Choose an authoring style​

Split each concern into its own file and kind. This makes each piece independently versionable, reusable, and easier to review.

KindOwnsChanges when
CompositionType binding and defaultsYou introduce/rename a component type
ComponentSchemaInput validationComponent contract changes
JobTemplateSteps, capabilities, runner defaultsRuntime implementation changes
ExecutionProfileWhich behavior to use per trigger/envPR/release/env behavior changes

composition.yaml — The public facade:

apiVersion: sourceplane.io/v1alpha1
kind: Composition
metadata:
name: mytype
spec:
type: mytype
description: My component type
schemaRef:
name: mytype-component
defaultJob: apply
defaultProfile: verify
jobs:
- name: apply
templateRef:
name: mytype-apply
profiles:
- name: verify
profileRef:
name: mytype-verify
- name: deploy
profileRef:
name: mytype-deploy

schema.yaml — Input validation contract (kind: ComponentSchema):

apiVersion: sourceplane.io/v1alpha1
kind: ComponentSchema
metadata:
name: mytype-component
spec:
type: mytype
schema:
$schema: http://json-schema.org/draft-07/schema#
type: object
required: [name, type, parameters]
properties:
name:
type: string
type:
const: mytype
parameters:
type: object
required: [target]
properties:
target:
type: string

jobs/mytype-apply.yaml — Reusable execution template (kind: JobTemplate):

apiVersion: sourceplane.io/v1alpha1
kind: JobTemplate
metadata:
name: mytype-apply
spec:
description: Apply mytype changes
runsOn: ubuntu-22.04
timeout: 15m
capabilities:
- mytype.setup
- mytype.apply
steps:
- id: setup
name: setup
capability: mytype.setup
run: mytool version
onFailure: stop
- id: apply
name: apply
capability: mytype.apply
run: mytool apply {{.parameters.target}}
onFailure: stop

profiles/mytype-verify.yaml — Behavior overlay (kind: ExecutionProfile):

apiVersion: sourceplane.io/v1alpha1
kind: ExecutionProfile
metadata:
name: mytype-verify
spec:
description: Verify without applying
jobs:
apply:
includeCapabilities:
- mytype.setup
- mytype.apply
stepOverrides:
apply:
run: mytool apply --dry-run {{.parameters.target}}

Inline authoring​

For simpler compositions, define everything in a single compositions.yaml:

apiVersion: sourceplane.io/v1alpha1
kind: Composition
metadata:
name: mytype
spec:
type: mytype
defaultJob: apply
parameterSchema:
$schema: http://json-schema.org/draft-07/schema#
type: object
properties:
type:
const: mytype
parameters:
type: object
required: [target]
properties:
target:
type: string
executionProfiles:
verify:
jobs:
apply:
stepsEnabled:
- setup
- apply
jobs:
- name: apply
runsOn: ubuntu-22.04
steps:
- id: setup
name: setup
run: mytool version
- id: apply
name: apply
run: mytool apply {{.parameters.target}}

4. Test with an example component​

apiVersion: sourceplane.io/v1
kind: Component
metadata:
name: demo
spec:
type: mytype
subscribe:
environments:
- name: development
profile: verify
parameters:
target: demo-service

5. Validate and inspect​

orun pack --root ./my-platform
orun validate --intent examples/intent.yaml
orun compositions mytype --intent examples/intent.yaml
orun plan --intent examples/intent.yaml --output /tmp/mytype-plan.json

6. Publish to a registry​

orun login ghcr.io
orun publish --root ./my-platform

Teams consuming the stack reference it by OCI ref:

compositions:
sources:
- name: my-platform
kind: oci
ref: oci://ghcr.io/my-org/my-platform-stack:1.0.0

See Stacks for the full packaging and distribution guide.

Authoring guidelines​

  • Use split-kind authoring when your composition has multiple profiles or jobs that might be reused across types.
  • Use inline authoring for simple compositions with 1-2 profiles and a single job.
  • Tag steps with capability fields so profiles can select behavior semantically.
  • Prefer includeCapabilities over stepsEnabled — step IDs are implementation details.
  • Use stepOverrides in profiles to alter behavior (e.g., --dry-run) without duplicating steps.
  • Add policies to release profiles for enforcement rules like requireApproval.
  • Keep schemas strict enough to reject invalid inputs early.
  • Set defaultJob and defaultProfile explicitly.