.vio file is a portable definition of a whole agent — prompt, model, skills,
connectors and memory — in one YAML file. Everything the agent is made of is inside the
file, so you can deploy a .vio someone sent you without any other assets.
Needs
vio 1.0.0 or later for the checks on this page. --check-tools, the connector
URL check and the warnings need 1.0.6. Check with vio --version.Validate
From the shell:--check-tools. A valid file prints a summary of what it
contains. An invalid one exits 1 and names each field that’s wrong.
Point vio at a folder and it looks for the .vio inside it (one level deep, not
subfolders):
What it checks
A bundle can be valid YAML, match the schema, and still fail the first time the deployed agent runs.vio validate catches those cases here, where they are one edit to fix, and
vio deploy runs the same checks before it sends anything.
-
The schema — every field the
.vioformat requires. - Artifact digests — see Editing a bundle below.
-
Memory files the runtime can parse. Each memory artifact needs the frontmatter the
runtime reads, including a
metablock:A missingmetablock, an unquotedschemaVersion, or ameta.idthat differs from the artifact’s id is refused, with the reason. -
Template variables the agent never receives. When an agent declares inputs, every
{name}in the text it runs with — its first prompt, the skills it references, and the memory it reads or writes — must be one of them. Otherwise validation refuses the bundle and names the placeholder:Declare the input, or remove the placeholder. Literal braces such as a JSON example ({"a": 1}) are fine. -
An optional field with no default. Every
{name}must be declared exactly once — either as a persona-prompt variable withsource: input,required: falseand adefault, or as an agent input with no default (which must then berequired: true). Declaring the same name both ways is not redundant: an agent-declared input always wins the collision, which silently discards the prompt variable’sdefault— so a field left optional with no default is a run that omits it and fails with a missing-variable error.vio validaterefuses this and names the fix, which differs by where the field lives:If the field is an agent input, the fix instead is to declare it only as a prompt variable (source: input,required: false,default: …) and remove it from the agent’sinputs— an agent input can never carry adefault. -
A connector given as an
https://URL. Inrequires[].connector, a catalogue id such asgithubis refused. The error prints the MCP URL to use instead. -
A connector tool no referenced skill allows. Once an agent has one or more skills, the
runner binds tools only from each skill’s own
allowed-toolsfrontmatter — a connector tool named inrequires[].toolsreaches the agent only if some referenced skill’sallowed-toolsalso lists it.allowed-toolsis one line, space-separated, not a YAML list:A skill with noallowed-toolsline, or one missing a tool it needs, gets none of what’s missing — the deployed agent completes its run having told the model no tools are available.vio validaterefuses a bundle with an unreachable connector tool and names it.
Check tool names against the live server
Plainvio validate never touches the network, so it can’t tell you that a tool name is
wrong. A name the connector doesn’t offer is skipped at run time with no error. To check:
--check-tools runs the normal checks first. Then it asks each OAuth connector which tools
it offers and compares every tool your bundle names, in requires[].tools and in each
skill’s allowed-tools. It needs the network, and an authorisation that
vio connect staged in the bundle’s Space. It’s opt-in, and
in the shell it’s /validate agent.vio --check-tools.
- A tool the server doesn’t offer fails the bundle with
bundle.invalidand exit1. The error names the closest real tools, for exampleDid you mean search_docs?. - A connector that can’t be asked is only a warning, and never changes the exit code. That
covers one that isn’t staged, is unreachable, or refuses the check. If the provider says
the authorisation lacks a scope (
insufficient_scope), the message names the connector and thevio connect <connector> --scopes …command that fixes it. - To see a connector’s tools yourself, run
vio connectors tools <connector>.
vio deploy runs the same check on staged connectors before it creates anything, so you
only need --check-tools to find out earlier.
Warnings
Some problems don’t stop a deploy but probably aren’t what you meant.vio validate prints
them as warnings and the exit code stays 0:
- A skill-less agent with no input named
task. Without skills, an agent only gets its task from an input namedtask. Rename the input totask, or give the agent a skill. memoryin a skill’s frontmatter. The runner ignores it. Memory is bound on the agent, in itsmemoryblock. See Memory.- A skill’s
toolsfield. The runner never reads it. List the tools in the skill’sallowed-toolsfrontmatter instead.
Digest
In the shell,/digest agent.vio. As a subcommand:
vio show
and the Hub compare against. --content prints the whole-file content digest instead, and
--json prints both.
Editing a bundle: fix the digests
Each artifact inside a.vio — every prompt, agent, skill and memory — carries its own
digest in the manifest. Edit a body and its recorded digest no longer matches, and the
deploy is refused. The file is still valid YAML and still passes the schema, so this is
not something you can spot by eye.
vio validate checks these, and vio digest --fix repairs them:
0. If it cannot rewrite the manifest it says so and writes
nothing, rather than reporting a fix it did not make. It only runs on a bundle that is
otherwise valid, so fix a schema, memory or placeholder problem first.
So the loop for editing a bundle by hand, or with an AI coding agent, is:
--json tells the failures apart, which is what an AI agent should branch on:
Deploying a .vio you were given
1
Put it in a folder
2
Validate it
3
Deploy it
Follow Deploy an agent. The file never contains a provider key: either
it runs on Viorant credits, or you provide the key.