Skip to main content

Output and manifests

Rank programs usually return one of two result shapes from pub main:

  • an ordinary emit-compatible document value
  • an opaque std::Emit<T> descriptor such as Emit::manifest(...) or Mutation::commit(...)

The distinction matters because the CLI treats them differently.

Single-document output

The simplest program returns one structured value:

config = {
host: `api.example.com`,
port: 8080,
}

pub main = || config

Running the program prints YAML to stdout by default:

rank src/main.rank
host: api.example.com
port: 8080

Pass --format json to emit the same value as JSON instead:

rank src/main.rank --format json
{
"host": "api.example.com",
"port": 8080
}

Field order is preserved exactly as the program evaluates it.

Multi-file output with Emit::manifest

Use std::Emit when one evaluation should describe multiple artifacts.

use std::Emit
use std::Path

manifest = Emit::manifest({
entries: [
{
path: Path::from(`README.md`),
format: `text`,
value: `# api\n`,
},
{
path: Path::join([`k8s`, `deployment.yaml`]),
format: `yaml`,
value: {
service: {
name: `api`,
port: 8080,
},
},
},
]
})

pub main = || manifest

Each entry has three parts:

  • path — a Path::RelativePath, not a raw string path
  • format — one of json, yaml, or text
  • value — the payload to emit for that file

std::Emit<T> is a pure descriptor. Constructing it does not write anything to disk or perform commit execution during ordinary evaluation.

What the CLI does

When pub main returns an ordinary document, rank <entry> prints YAML by default and accepts --format json for JSON output.

When pub main returns Emit::manifest(...), rank <entry> prints a descriptor envelope to stdout instead. YAML remains the default, and --format json switches the descriptor envelope to JSON:

kind: rank/output-manifest
version: 1
entries:
- path: README.md
format: text
value: |
# api
- path: k8s/deployment.yaml
format: yaml
value:
service:
name: api
port: 8080

To materialize those files on disk, pass an explicit output root:

rank src/main.rank --file-root ./out

The CLI still prints the descriptor to stdout, then applies the entries under ./out as a second stage.

Common mistakes

  • Duplicate destination paths are errors, including duplicates that appear only after path normalization.
  • format: \text`requiresvalue` to be a string.
  • --file-root is valid only when pub main returns Emit::manifest(...).
  • Nested std::Emit<T> values are not allowed inside ordinary objects or lists; the descriptor must be the top-level pub main result.
  • Paths are relative by design. Absolute paths and upward escapes are rejected by std::Path.
  • See Standard library for the std::Emit and std::Path signatures.
  • See Mutations for the Mutation::plan(...) / Mutation::commit(...) lifecycle.
  • See CLI reference for --file-root and command behavior.
  • See Examples for complete manifest-producing programs.