axiom.yaml manifest reference
The complete schema of the axiom.yaml package manifest: every field, its type, default, validation rule, and which CLI commands read or write it.
View as Markdownaxiom.yaml is the package manifest. It sits at the root of every Axiom
package and declares the package's identity, its nodes, the message types
it imports from other packages, and optional build overrides. The Axiom CLI
locates the package root by walking up from the current directory until it
finds axiom.yaml.
Three fields are required: name, version, and language. Everything
else is optional. axiom validate checks the manifest before publishing
(see Validation rules).
Complete example
Every field the parser accepts, in one manifest:
# axiom.yaml — at the package root
name: christian/text-tools
version: 1.2.0
language: python
description: Text processing nodes
author: Christian Lucas
license: MIT
tags:
- text
- nlp
nodes:
- name: SummarizeText
description: Summarize input text
input: TextRequest
output: SummaryResult
required_secrets:
- OPENAI_API_KEY
- name: StreamTokens
input: TextRequest
output: TokenFrame
type: pipeline
imports:
- package: axiom-official/axiom-conv-ai
version: 1.0.0
messages:
- ChatTurn
env:
- name: LOG_LEVEL
description: Verbosity of node logging
required: false
secret: false
default: info
build:
dockerfile: custom/Dockerfile
system_deps:
- ffmpegA minimal valid manifest is just the three identity fields — axiom init
writes exactly that (plus your --description if given, and a commented
example nodes: block you can delete).
Top-level fields
| Field | Type | Required | Default | Purpose |
|---|---|---|---|---|
name | string | yes | — | Scoped package name, handle/package-name |
version | string | yes | — | Semantic version of the package |
language | string | yes | — | One of go, python, rust, java, typescript, csharp |
type | string | no | "" | proto-only to skip build and deployment; otherwise omit |
description | string | no | "" | Shown in the registry on publish |
author | string | no | "" | Stored with the package record on publish |
license | string | no | "" | Stored with the package record on publish |
tags | list of string | no | [] | Discovery tags, stored in the registry's tag index on publish |
nodes | list of node | no | [] | The package's nodes (see nodes) |
imports | list of import | no | [] | Message types from other packages (see imports) |
env | list of env var | no | [] | Runtime environment variables (see env) |
build | object | no | unset | Build overrides (see build) |
description, author, and license are written to the registry when you
publish with axiom push. tags are written to the registry's tag index
on publish. Marketplace search currently matches on package name,
description, and author — not on these tags.
Identity fields: name, version, language
name must be scoped: your-handle/package-name. Both parts may
contain only lowercase letters, digits, and hyphens, and each part must
start with a letter or digit (pattern:
^[a-z0-9][a-z0-9-]*/[a-z0-9][a-z0-9-]*$). An unscoped or missing name
fails validation. axiom init christian/text-tools creates a local
directory named after the part after the last / (text-tools/).
version must be semantic versioning: MAJOR.MINOR.PATCH, with an
optional leading v and an optional pre-release suffix of letters, digits,
and dots after a hyphen (pattern:
^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$). Examples: 1.0.0,
v2.1.3, 0.4.0-beta.1. axiom init writes 0.1.0 unless you pass
--version.
language must be exactly one of go, python, rust, java,
typescript, csharp. It selects the node templates, the generated
service code, and the Dockerfile the build uses. axiom init defaults to
go unless you pass --language (-l).
nodes
Each entry in nodes declares one node in the package. axiom create node
appends entries here for you; you can also edit the list by hand.
| Field | Type | Required | Default | Purpose |
|---|---|---|---|---|
name | string | yes | — | PascalCase node name, unique within the package |
description | string | no | "" | Shown in the registry |
input | string | yes | — | Input message name |
output | string | yes | — | Output message name |
type | string | no | unary | Omit or unary for one-in/one-out; pipeline for a streaming generator |
required_secrets | list of string | no | [] | Secret names the node reads at runtime |
mutation_capable | bool | no | false | Declares the node emits state mutations on its response |
name — axiom create node enforces PascalCase: the first character
must be uppercase, and only letters and digits are allowed. Duplicate node
names in one manifest are rejected. The node's source file is the
snake_case form of the name (SummarizeText → nodes/summarize_text.py).
input / output — each must name a message
defined in messages/messages.proto or available from an imported package.
axiom validate fails when a referenced message cannot be found.
type — a node is unary unless type: pipeline is set. axiom create node --type accepts only unary or pipeline and writes type: pipeline
to the manifest only for pipeline nodes (the key is omitted for unary).
See execution model.
required_secrets — names of tenant secrets
the node reads at runtime. The declaration is informational: the platform
does not enforce it at invocation time. A missing secret does not block a run —
secrets.Get("NAME") simply yields a not-found result (found = false) at read
time, which the node handles. The marketplace displays the list so users know
which secrets to register. axiom validate emits a non-blocking warning when
node source calls secrets.Get("NAME") with a name missing from this list. See
manage secrets.
mutation_capable — declares that the node emits state mutations on
its response. The flow compiler reads this across a flow's nodes to decide
whether to enable the mutation path; the default false keeps a node out
of that path entirely.
imports
Each entry in imports declares a dependency on another package's message
types. Do not write these entries by hand — run
axiom import <package>[@version], which downloads the package's .proto
files into imports/<flattened-name>/<version>/ (scope / becomes -,
e.g. christian/text-ops → imports/christian-text-ops/1.0.0/), adds or
updates the manifest entry, and runs axiom generate.
| Field | Type | Required | Purpose |
|---|---|---|---|
package | string | yes | Scoped name of the imported package |
version | string | yes | Exact version of the imported package |
messages | list of string | yes | Message names imported from that package |
Validation rules for imports:
- An import entry with an empty
messageslist is a hard error and blocks publishing. Fix it by re-runningaxiom import <package>@<version>, which populates the list. - A message name listed here but not found in the downloaded proto files is a warning — it usually means a stale entry after the imported package changed.
- The downloaded proto files must exist locally under
imports/<flattened-name>/<version>/; if they are missing, re-runaxiom import <package>@<version>.
See import package types for the full workflow.
env
Each entry in env describes a runtime environment variable for the
package. All fields except name are optional.
| Field | Type | Required | Default | Purpose |
|---|---|---|---|---|
name | string | yes | — | Variable name |
description | string | no | "" | What the variable controls |
required | bool | no | false | Whether the variable must be set |
secret | bool | no | false | Whether the value is sensitive |
default | string | no | "" | Default value |
The env section is declarative metadata about what the package expects;
axiom validate does not check it. For credentials read by node code at
runtime, use secrets and
required_secrets instead — secrets are tenant-scoped and reach node code
through AxiomContext.
build
The optional build section overrides how the package's container image is
built. Most packages never need it — axiom build and axiom push
generate a Dockerfile automatically from the package language.
| Field | Type | Required | Purpose |
|---|---|---|---|
dockerfile | string | no | Path (relative to the package root) to a custom Dockerfile used instead of the generated one |
system_deps | list of string | no | Extra OS-level packages installed into the generated image |
system_deps entries are installed by the generated Dockerfile as
OS-level packages. For Python packages, the special value axiom installs
the Axiom CLI binary into the image instead of an OS package.
For Python packages, axiom validate scans node source for subprocess
calls and emits a non-blocking warning when a node invokes a common tool
that is absent from the slim base image and not listed in
build.system_deps — without the entry, the tool would be missing from the
runtime image. The scan covers a fixed list of tools: git, curl,
wget, ssh, rsync, zip, unzip, make, gcc, g++, svn, jq.
A tool outside that list (such as ffmpeg) still needs a system_deps
entry to be present in the image — it just is not flagged by validation.
Proto-only packages
A proto-only package publishes message types for other packages to import, with no nodes and no running service. A package is treated as proto-only when either:
type: proto-onlyis set explicitly, or- the
nodeslist is empty (proto-only is inferred).
For a proto-only package, the publish pipeline skips the Docker build and
the service deployment, and stores only the proto definitions and package
metadata. Other packages then pull its messages with axiom import. See
the type system.
Which commands read and write axiom.yaml
axiom init <name>creates the manifest withname,version(default0.1.0),language(defaultgo), and your--description. Unless--no-example-commentis passed, it appends a commented examplenodes:block showing therequired_secretsfield.axiom create node <Name>appends a node entry (name,description,input,output, andtype: pipelinefor pipeline nodes) after scaffolding the source files.axiom import <package>[@version]adds or updates animportsentry, merging newly downloaded message names into themessageslist.axiom validate,axiom build,axiom push,axiom dev, andaxiom testread the manifest; they must be run inside a package directory (any directory below the one containingaxiom.yaml).
When a CLI command rewrites the manifest, it re-serializes the whole file — inline comments you wrote in axiom.yaml are not preserved by these operations. Keep notes elsewhere if you need them to survive.
Validation rules
axiom validate (also run as a gate by axiom push) checks the manifest
as its first layer. Failures block publishing unless marked as warnings:
| Check | Severity |
|---|---|
name present and scoped (handle/package-name, lowercase/digits/hyphens) | error |
version present and valid semver | error |
language one of the six supported values | error |
Every node's input and output resolves to a known message | error |
Every import entry has a non-empty messages list | error |
| Imported message names exist in the downloaded proto files | warning |
secrets.Get("NAME") calls covered by required_secrets | warning |
Python subprocess tools covered by build.system_deps | warning |
Later validation layers check the proto files, node function signatures, and node tests — see the axiom validate reference.