Skip to content

app.yaml reference

app.yaml tells Space CLI how to build one application from source when that application is not a container. The build produces an OCI artifact and an artifact manifest. A space.yaml project can then refer to a named output from that manifest.

Build an OCI container from its Dockerfile with space build Dockerfile or space build -f Dockerfile --project-root DIR. A Dockerfile is the app manifest for that path and needs no app.yaml wrapper.

The space.app decoder refuses an undeclared member by name. A row carrying a WIP badge names a member the decoder accepts and the rest of the product does not act on yet.

Examples

Host executable

schema: space.app
version: "1"
name: hello
source: .
kind: host
targets:
- platform: host
arch: arm64
policy:
network: none
reproducible: true
outputs:
arm64:
target: host-arm64
path: hello.sh
kind: host-service

Unikraft

schema: space.app
version: "1"
name: unikraft-hello
source: .
kind: unikraft
kraftkit_image: kraftkit.sh/base@sha256:<digest>
targets:
- platform: qemu
arch: arm64
policy:
network: replay
reproducible: true
outputs:
flight:
target: qemu-arm64
path: .unikraft/build/app_qemu
kind: unikernel

MirageOS

schema: space.app
version: "1"
name: mirage-hello
source: .
kind: mirage
mirage_version: "4.9.0"
ocaml_version: "5.4.1"
opam_repo: https://github.com/ocaml/opam-repository.git
opam_repo_rev: "<full-git-commit>"
targets:
- platform: hvt
arch: arm64
image: ocaml/opam:debian-ocaml-5.4
policy:
network: replay
reproducible: true
outputs:
flight:
target: hvt-arm64
path: dist/http-fetch.hvt
kind: unikernel

Common fields

FieldTypeRequiredDescription
schemastringyesMust be space.app.
versionstringyesSchema version. The current version is "1".
namestringyesApplication name written to the artifact manifest.
sourcepathyesSource tree. Relative paths start at the manifest directory.
kindhost, unikraft, or mirageyesBuild path used to prepare the source. A container app builds from its Dockerfile and needs no app.yaml.
targets[]listyesPlatform and CPU variants to build.
policymapyesNetwork and reproducibility settings for the build.
cache[]listnoNamed, content-addressed inputs available to an offline build.
outputsmapno (default: none)Named outputs published in the artifact manifest. A build that declares none publishes none.
output_budget_mbintegerno (default: 8192)Size in MiB of each writable output disk the builder VM writes this build's outputs to. Raise it when the outputs exceed 8 GiB. Must be positive. A build whose disks the output volume cannot hold is refused before the builder VM starts.
requiresmapnoWIP Portable accelerator requirements. The accelerator requirements section lists their fields.

Accelerator requirements

WIP requires.accelerators holds one requirement for each logical role the workload uses, keyed by the role's name, such as inference. The decoder takes these fields, and the shared matcher checks them against a target's inventory. A workload cannot drive the device yet.

FieldTypeRequiredDescription
requires.acceleratorsmapno (default: none)WIP One requirement for each role.
requires.accelerators.<name>.kindgpu or fpgayesAccelerator kind, matched exactly.
requires.accelerators.<name>.classstringno (default: any class of the kind)Namespaced class, matched exactly.
requires.accelerators.<name>.countintegerno (default: 1)Distinct allocation units the role needs. A count below 1 matches no target.
requires.accelerators.<name>.apistringyesNamespaced API name, matched exactly and case-sensitively.
requires.accelerators.<name>.api_versionversionyesOne to three dotted non-negative integers, such as 12.4. A unit matches when its version has the same major number and is at least this one, so 12 accepts 12.4 and refuses 11.8 and 13.0.
requires.accelerators.<name>.featureslist of stringsno (default: none)Namespaced features, each of which a unit must offer.
requires.accelerators.<name>.memory_mibintegernoUsable memory in MiB each allocation unit must have, never summed across units.
requires.accelerators.<name>.assignmentshared, exclusive, or shared-or-exclusiveno (default: shared-or-exclusive)How a unit is assigned to the run. shared needs an isolation mechanism the target profile authorizes; exclusive gives the run sole use of the unit for the grant's lifetime.

Target fields

FieldTypeRequiredDescription
targets[].platformstringyesThe platform the backend configures for, such as hvt for a MirageOS target or qemu for an Unikraft one. It reaches the backend's own configure step as text, so it must be a plain identifier.
targets[].archstringyesCPU architecture: arm64 or amd64. Any other name is refused.
targets[].optionslist of stringsnoWIP Extra options for this target's backend. No backend takes them yet: a MirageOS target that sets any is refused, and the Unikraft and host backends ignore them.
targets[].imageOCI referenceconditional (yes for kind: mirage)Pinned toolchain image the build runs in for this variant. A MirageOS target without one is refused.

outputs.<name>.target must equal the target id formed from its platform and architecture, joined by a hyphen, such as hvt-arm64. One app build produces the outputs for one target; use a separate manifest or a separate run for another architecture.

Host applications

kind: host packages an existing executable without starting a builder VM. The output path must name an executable file under source. Host execution covers local development and CI, and it is off by default. A host-isolated service runs uncontained, so the runner refuses to launch one unless it was started with --allow-host. The refusal names the service. The substrates reference lists that flag with the other backends.

Unikraft fields

FieldTypeRequiredDescription
kraftkit_imageOCI referenceno (default: kraftkit.sh/base:latest)KraftKit build image. Pin it by digest: the default is a mutable tag, and a build that pins nothing is not the same build twice.

MirageOS fields

FieldTypeRequiredDescription
mirage_versionstringyesMirageOS release used to configure the application. It becomes an opam version selector, so it takes opam's version grammar and nothing else.
ocaml_versionstringyesOCaml compiler version.
opam_repoURLyesOpam repository used to solve dependencies.
opam_repo_revGit commityesThe full forty-character commit id that pins the opam repository. A branch, a tag, HEAD and an abbreviation are all refused: a revision resolved against whatever the remote currently says is not a pin.

Build policy

FieldTypeRequiredDescription
policy.networkallow, none, or replayyesNetwork access for the prepare and build phases. The table below gives each value.
policy.reproduciblebooleanyesAsk for the reproducibility check described below.
ValueNetworkUse
allowonResolve and build mutable inputs.
noneoffBuild from inputs already present.
replayoffRebuild from cache inputs. Today the builder treats it exactly as none; the two spellings are kept apart so a manifest can say which of the two it meant.

Set policy.reproducible to true to ask for the reproducibility check. The check builds the recipe twice, into two separate stores, and exports the OCI layout only when the two results are identical. The builder runs it on a Dockerfile build today; a MirageOS, Unikraft, or host build records the setting in its cache key and does not run the check yet.

Each cache[] entry names a builder cache. The build attaches that cache as a disk, filled from this computer's copy of it, so an offline build finds the inputs an earlier build fetched. A MirageOS build attaches the opam, dune, apt, and oci caches without being asked. The build record lists every cache input and base image that went into the result.

FieldTypeRequiredDescription
cache[].namestringyesBuilder cache to attach, such as opam or dune. It must be a plain identifier, and no two entries may share one.
cache[].seedstringyesWIP A backend-defined operation that fills the cache. No backend reads it yet.

Output fields

FieldTypeRequiredDescription
outputs.<name>.kindstringyesArtifact kind, such as unikernel or host-service.
outputs.<name>.targetstringyesTarget id, such as hvt-arm64 or host-arm64.
outputs.<name>.pathpathyesBuilt file to package. It must be relative and stay inside the source tree; a path that escapes it is refused.

Run the build from the application directory:

Terminal window
$ chmod +x hello.sh
$ space build app.yaml -t ghcr.io/parsimoni-labs/hello:dev
Building an app from app.yaml
✓ ghcr.io/parsimoni-labs/hello:dev built in ...
Run it here: space run ghcr.io/parsimoni-labs/hello:dev

The host build writes the executable manifest and layer to the local OCI store. MirageOS and Unikraft builds place their declared files under the configured builder output directory.