Skip to main content

Manifest

A compiled manifest is shaped by two independent choices:

ChoiceWhat it controlsValuesSet in coco.nutCompile override
Manifest formatHow the whole manifest file is encodedYAML, JSON, POLO[target.moi] format-f, --fileform
Executable formatHow the code of each endpoint and function is written inside the manifestASM, HEX, BIN[target.pisa] format-c, --codeform

coco compile produces the manifest in the formats set in coco.nut. The coco manifest command works on a manifest that's already compiled: it converts it to other formats and encodes it for deployment, without the source code.

Manifest Formats

FormatFile extensionDescription
YAML.yamlHuman-readable. The default of coco nut init
JSON.jsonThe same structure as YAML, for tools and scripts
POLO.poloThe manifest encoded as POLO binary and written as hex. Compact and deterministic, but not meant to be read

Executable Formats

The executable format only changes how the instructions under executes are written. Here is the Init endpoint of the Flipper manifest in each format:

ASM — readable assembly, one instruction per line
executes:
asm:
- LLOAD $0 &0
- PMAKE $1 &1
- NOT $1 $1
- ORIGIN $2
- SETKEY $0 $2 $1
- STORE $0
HEX — the bytecode as one hex string
executes:
hex: '0x9000002a01016201018402590002019f00'
BIN — the same bytecode, one number per byte
executes:
bin:
- 144
- 0
- 0
- 42
# ... 17 bytes in total

HEX and BIN hold the same bytes (0x90 is 144, 0x2a is 42), and ASM is their disassembly. Converting between the three is lossless in every direction: a manifest converted from ASM to BIN and back is identical to the original.

What Changes With the Format

Formats change how the manifest is written down, not what the logic does:

  • Behavior is identical. Endpoints, state layout, return values and execution fuel are the same whichever formats you choose.
  • The artifact is identical. When a manifest is deployed, it's turned into an artifact, the form the network stores and PISA executes. All nine combinations of manifest and executable format produce the same artifact, which you can check with coco manifest <file> artifact.
  • Size and compile cost differ with the executable format. Before building the artifact, the engine has to decode HEX and assemble ASM, while BIN is used as is. For the Flipper logic:
Executable formatPOLO-encoded manifestCocolab compile fuel
ASM796 bytes525
HEX629 bytes447
BIN550 bytes395

Cocolab charges compile fuel per instruction: 5 for BIN, 7 for HEX and 10 for ASM in v0.9.1. The manifest format doesn't affect it: the YAML and POLO manifests with ASM code both cost 525.

Choosing formats

Keep the YAML and ASM defaults while developing: the manifest is readable and easy to review and diff. Convert to BIN when you want the smallest manifest to deploy. The logic behaves the same.

Changing the Formats

There are three ways to change formats, depending on when you decide:

WhenHow
For every compilation of a moduleSet [target.moi] format and [target.pisa] format in coco.nut
For a single compilationcoco compile -f <format> -c <codeform>
After compilation, without the sourcecoco manifest convert
PISA version

coco manifest keeps the manifest's PISA version (engine.version). The PISA version decides which language features compile and which instructions are generated, so to target a different version, change [target.pisa] version in coco.nut and compile again.

coco manifest Command

coco manifest <manifest_file>
coco manifest convert <manifest_file> [-f <format>] [-c <codeform>] [-o <output_file>]
coco manifest <manifest_file> artifact

The input format is taken from the file extension: .yaml or .yml, .json, or .polo.

Encoding a Manifest

coco manifest flipper.yaml

Prints the manifest POLO-encoded, as hex with a 0x prefix:

0x0e6f031ef601ce02013f064e56504953410f302e382e306c6f676963df010e9e04de0a...

This is the whole manifest as a single value. Cocolab accepts it in place of a file path, e.g. compile Flipper from manifest(0x0e6f031e...).

Converting Manifests

coco manifest convert <manifest_file> [-f <format>] [-c <codeform>] [-o <output_file>]
flagdescriptionsupported values
-f, --fileform <FORMAT>output manifest format [default: the input's format]yaml, json, polo
-c, --codeform <CODE_FORMAT>output executable format [default: unchanged]asm, hex, bin
-o, --output <OUTPUT>write to this file instead of printing to standard outputa path whose extension matches the output format

At least one of -f and -c is required.

# YAML to JSON, printed to standard output
coco manifest convert flipper.yaml -f json

# Switch the code to BIN and keep the YAML format
coco manifest convert flipper.yaml -c bin -o flipper-bin.yaml

# Change both at once: a POLO manifest with HEX code
coco manifest convert flipper.yaml -f polo -c hex -o flipper.polo

# Turn a manifest you received back into readable YAML and assembly
coco manifest convert flipper.polo -f yaml -c asm -o flipper-asm.yaml
note

The extension of -o must be exactly .yaml, .json or .polo. .yml is accepted as input but rejected as output. A .polo file written by convert holds the hex without the 0x prefix that coco manifest <file> prints. Both forms are accepted as input.

Producing the Artifact

coco manifest flipper.yaml artifact

Prints the artifact built from the manifest, POLO-encoded as hex (without a 0x prefix). The manifest file comes before artifact: coco manifest artifact flipper.yaml is rejected.

Since the artifact doesn't depend on the manifest or executable format, comparing artifacts tells you whether two manifests deploy the same logic:

[ "$(coco manifest flipper.yaml artifact)" = "$(coco manifest flipper.polo artifact)" ] \
&& echo "same logic"

Errors

ErrorCause
format flag or codeformat flag must be used with `manifest convert`convert without -f or -c
Output file extension does not match selected formatThe -o extension differs from the output format, including .yml
Unsupported file formatThe input extension isn't .yaml, .yml, .json or .polo
Input file has no extensionThe input file name has no extension
Invalid combination of manifest command and inputNo input file, or an input file given both before and after convert
unexpected argument '<file>' foundThe input file was placed after artifact