# YAML spec format
A jan tree is a YAML document with optional `metadata`, optional root-level `include`, and a `commands` map. After `jan use`, that document (plus grafted includes) **is** the CLI.
## Root document
```yaml
metadata:
name: myapp
description: |
Shown at the root help level.
include:
- fragments/extra.yaml
commands:
hello:
about: Say hello
exec:
argv: ["echo", "hello"]
```
| `metadata.name` | string | Optional display name |
| `metadata.description` | string | Root help blurb |
| `include` | list | Merge other YAML command maps into this root |
| `commands` | map | Top-level subcommands |
## Command node fields
Each entry under `commands` is a **command node**:
| `about` | string | Shown in help |
| `commands` | map | Nested subcommands |
| `exec` | object | Run a program or print literal text |
| `include` | string or map | Graft YAML as a subtree, or a script file as an exec leaf |
| `os` | list | Offer this node only on listed platforms (`linux`, `macos`, `windows`; `darwin` → `macos`) |
| `computer` | list | Offer this node only on listed registered computer ids (`jan computer set`); empty = all computers |
| `path` | string | Directory prepended to `PATH` when this script runs |
| `dependencies` | list | Other script **names** whose `path` dirs are prepended first |
| `packages` | map | `uv` / `pnpm` / `gradle` deps (see [Packages](packages.md)) |
| `requires` | list | External binaries that must exist on `PATH` before run |
| `env` | map | Public / private / `pass` (see [Env](env.md)) |
| `inputs` | map | Named `--flags` (see [Inputs](inputs.md)) |
| `cron` | string or list | Five-field crontab expression(s) (see [Cron](cron.md)) |
| `system` | string | Agent-system name; inherited by descendant script leaves. Empty string (`""`) clears inheritance. Enables `jan systems list/show/status` and tags cron wakeups / outer spans with `system=<name>` |
| `tests` | map | Given/When/Then cases (see [Tests](tests.md)) |
| `aliases` | string, list, or map | Extra `jan alias` names and/or traditional shell aliases (see [`jan alias`](../cli/alias.md)) |
| `config` | map | Host configuration for `jan config` emit / link / unlink / apply / deps (see [`jan config`](../cli/config.md)) |
## Constraints
- A node cannot define both `exec` and nested `commands`.
- A node with `include` cannot also define `exec` or `commands` in the same map (the include *becomes* the node body).
- Language `exec` fields (`url`, `file`, `kotlin`, `python`, `node`, `bash`, `sh`, `zsh`, `text`) are mutually exclusive.
- `exec.argv` for a plain argv leaf must be non-empty; the first element is the program.
- `exec.url` requires `sha256`. `exec.file` may optionally pin `sha256`.
## Nested subcommands
```yaml
commands:
android:
about: Android workflows
commands:
skills:
about: Skill tools
commands:
list:
about: List skills
exec:
argv: ["echo", "listing"]
```
Invoke: `jan android skills list`
## Platform filtering (`os`)
```yaml
commands:
ports:
os: [linux]
about: List listening ports (Linux only)
exec:
argv: ["ss", "-tlnp"]
```
Nodes hidden on other platforms are omitted from help and cannot be invoked. Override the detected platform with `JAN_OS` (this is a same-user footgun, not a security boundary).
## Conventional `run` / `help` children
Script-style nodes often look like:
```yaml
sum:
about: Add numbers
commands:
help:
exec:
text: |
sum — add comma-separated integers
run:
exec:
bash: |
IFS=, read -r -a n <<< "$1"
...
passthrough: true
```
`jan alias` emits aliases for `run` leaves, plus any extra names or shell RHS declared in `aliases:`. Subcommand `--help` lists those aliases. `jan cron` executes the `run` child of a scheduled script.
## Chain merge
When you invoke a deep path, jan merges `dependencies`, `requires`, `env`, `inputs`, `packages`, and `path` from every node along the chain:
- Deeper nodes override public `env` keys, package-manager decls, and input defs
- Private env names are unioned
- `packages.uv` / `pnpm` / `gradle` are replaced per manager (no list merge)
Then it resolves typed inputs, interpolates `${{ inputs.* }}`, prepends PATH, checks `requires`, and spawns the leaf.