Skip to content

app.yaml reference

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

Examples

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

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

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

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.

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.
kindmirage, unikraft, or hostyesBuild lane 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.
requiresmapnoWIP Portable accelerator requirements under requires.accelerators, keyed by the logical role the workload uses: kind (gpu or fpga), an optional namespaced class, count, the API and version, features, memory, and the assignment mode. The decoder takes them and the shared matcher checks them against a target’s inventory; driving the device from a workload is next-release work.

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 stringsnoLane-specific build options for this target.
targets[].imageOCI referencenoPinned toolchain or base image for this variant.

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.

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.

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.

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 the host posture enabled, naming the service in the refusal.

Build policy

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 and the builder runs the recipe under its reproducibility check, exporting only the layout that verified.

Each cache entry has a name and seed mode. The build record lists every cache input and base image that went into the result.

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
Built ghcr.io/parsimoni-labs/hello:dev@sha256:8189b62a3f31bc4ec8891c708b03f3548461bd6486d1246451b4da0c01773d72 (arm64)

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.