VAEN is a portable CLI for packaging and importing agentic coding setups.
It takes an agent.yaml
manifest, bundles instructions, skills, and project-scoped MCP declarations into an OCI-backed .agent
archive, and imports that setup into another repository without transporting secrets.
Watch the 24-second flow: docs/assets/vaen-demo.mp4
vaen validate -f agent.yaml
vaen build -f agent.yaml -o team-setup.agent
vaen inspect team-setup.agent
vaen import team-setup.agent --client codex
vaen doctor --client codex
VAEN packages configuration and authoring files, not runtime environments.
- Main instructions and optional instruction includes
- Skill directories and their files
- Project-scoped MCP declarations
- Bundle metadata used for import, inspection, and validation
VAEN never packages credential values, .env
files, private keys, OAuth state, or MCP server implementations.
A zip file can move files, but it does not explain what the setup is, what should be imported, where files should land, or which credential variable names the receiver must provide locally.
VAEN keeps that handoff explicit:
agent.yaml
declares the instructions, skills, MCP declarations, and required variable names.vaen validate
catches malformed manifests before sharing.vaen inspect
lets the receiver review bundle contents before import.vaen import
materializes the setup into predictable client-specific locations.vaen doctor
checks the imported structure without reading credential values.
Install from GitHub with pipx
:
pipx install git+https://github.com/sjhalani7/vaen.git
Or install from a local clone:
python3 -m venv .venv
. .venv/bin/activate
pip install -e .
The CLI provides:
vaen validate
vaen build
vaen inspect
vaen import
vaen doctor
vaen cleanup
See docs/quick-start.md for a minimal instructions-only bundle flow.
The dist/agents/ directory contains ready-to-import
.agent
archives for popular, reputable public agent setups.Current packages:
— complete promoted skill set frommattpocock-skills.agent
mattpocock/skills
— engineering skillsmattpocock-engineering.agent
— productivity skillsmattpocock-productivity.agent
— misc utility skillsmattpocock-misc.agent
See dist/agents/README.md for import commands and attribution.
agent.yaml
is the source of truth for a bundle.
version: "0.1"
publisher: "Shiv Jhalani"
instructions:
main: "~/.codex/AGENTS.md"
includes:
- "./style.md"
artifacts:
- type: skills
path: "~/.codex/skills/code-review"
- type: skills
path: "~/.codex/skills/refactor"
requiredVars:
- OPENAI_API_KEY
mcp:
servers:
- name: context7
transport: stdio
command: npx
args: ["-y", "@upstash/context7-mcp"]
env_vars:
- CONTEXT7_API_KEY
- name: docs
transport: http
url: https://example.com/mcp
http_headers:
X-Region: us-east-1
bearer_token_env_var: DOCS_MCP_TOKEN
header_env_vars:
X-API-Key: DOCS_MCP_TOKEN
Manifest rules:
version
,publisher
, andinstructions.main
are required.instructions.includes
is optional.artifacts
is a list and may be empty for instructions-only bundles.skills
is the supported artifact type.requiredVars
and MCP env fields store environment variable names only, never values.- Manifest authors are responsible for writing names such as
OPENAI_API_KEY
, not credential values such as API keys, tokens, URLs with passwords, orNAME=value
assignments. http_headers
stores non-secret static HTTP headers for MCP servers.mcp
is optional and lives at the top level of the manifest.- Source paths may point inside or outside the repo.
Correct:
requiredVars:
- OPENAI_API_KEY
mcp:
servers:
- name: docs
transport: http
url: https://example.com/mcp
bearer_token_env_var: DOCS_MCP_TOKEN
Incorrect:
requiredVars:
- OPENAI_API_KEY=sk-proj-secret
- sk-proj-secret
mcp:
servers:
- name: docs
transport: http
url: https://user:password@example.com/mcp
bearer_token_env_var: sk-proj-secret
MCP support is host-neutral in the manifest. During import, VAEN writes the selected client format for Codex, Claude Code, or Copilot.
Instructions only:
version: "0.1"
publisher: "Your Name"
instructions:
main: "./AGENTS.md"
artifacts: []
instructions.main
points toAGENTS.md
or another main agent instruction file.
Instructions with skills:
version: "0.1"
publisher: "Your Name"
instructions:
main: "./AGENTS.md"
includes:
- "./style.md"
artifacts:
- type: skills
path: "./skills/code-review"
- type: skills
path: "./skills/refactor"
instructions.includes
is for extra Markdown instruction/context files.- Each
artifacts
entry points to one skill directory.
MCP servers:
version: "0.1"
publisher: "Your Name"
instructions:
main: "./AGENTS.md"
artifacts: []
mcp:
servers:
- name: context7
transport: stdio
command: npx
args: ["-y", "@upstash/context7-mcp"]
env_vars:
- CONTEXT7_API_KEY
- name: figma
transport: http
url: "https://mcp.figma.com/mcp"
bearer_token_env_var: FIGMA_OAUTH_TOKEN
http_headers:
X-Figma-Region: us-east-1
name
is the local MCP server name.transport
is eitherstdio
orhttp
.command
andargs
define how stdio MCP servers are launched.url
defines the HTTP MCP endpoint.env_vars
andbearer_token_env_var
contain environment variable names only, never secret values.http_headers
contains non-secret static headers.
vaen validate -f examples/synthetic-fixture/agent.yaml
vaen build -f examples/synthetic-fixture/agent.yaml
If -o
is omitted, VAEN writes <manifest-directory-name>.agent
in the working directory:
examples/synthetic-fixture/agent.yaml -> synthetic-fixture.agent
You can choose the archive name:
vaen build -f examples/synthetic-fixture/agent.yaml -o shiv-setup.agent
Explicit output paths must end in .agent
.
vaen inspect synthetic-fixture.agent
inspect
reads the OCI archive and prints bundle metadata, normalized bundle paths, instructions, skills, MCP declarations, and required variable names.
In the target repo:
vaen import /path/to/synthetic-fixture.agent
If the bundle contains MCP declarations, select the client config to write:
vaen import /path/to/synthetic-fixture.agent --client codex
vaen import /path/to/synthetic-fixture.agent --client claude
vaen import /path/to/synthetic-fixture.agent --client copilot
Default import (no --client
and no target override flags) writes root instructions to AGENTS.md
and CLAUDE.md
, and mirrors skills to .agent/skills/...
and .claude/skills/...
.
If --client
is provided and none of --target
, --target-instructions-file-name
, --target-skills-directory
are provided, activated outputs default to the client:
--client claude
:CLAUDE.md
and.claude/skills/...
--client codex
:AGENTS.md
and.codex/skills/...
--client copilot
:AGENTS.md
and.copilot/skills/...
To target another agent directory:
vaen import /path/to/synthetic-fixture.agent --target copilot
This writes COPILOT.md
and .copilot/skills/...
.
Optional import overrides:
vaen import /path/to/synthetic-fixture.agent --target copilot --target-instructions-file-name copilot-instructions
vaen import /path/to/synthetic-fixture.agent --target copilot --target-skills-directory vscode
These write copilot-instructions.md
and .vscode/skills/...
.
vaen doctor
Use the same targeting and MCP client flags that were used during import:
vaen doctor --client codex
vaen doctor --target copilot --client copilot
vaen doctor --target copilot --target-instructions-file-name copilot-instructions
vaen doctor --target copilot --target-skills-directory vscode
doctor
validates the imported structure and reports required environment variable names as warnings.
After confirming the activated files look right, remove the canonical stored copy:
vaen cleanup /path/to/synthetic-fixture.agent
Cleanup deletes .agent/<bundle-name>
only. It does not delete root instruction files, skill mirrors, or MCP client config.
A .agent
file is an OCI-style archive:
bundle.agent
├── oci-layout
├── index.json
└── blobs/sha256/
├── <manifest blob>
├── <config blob>
└── <layer blob>
The layer blob is a tar payload:
vaen/metadata.json
instructions/...
skills/...
mcp/...
Path terminology:
source path
: where a file lives on the builder's machinebundle path
: where that file is stored inside the.agent
materialized path
: where that file is written during import
This lets a builder reference files from places like ~/.codex/AGENTS.md
while keeping the bundle layout stable and machine-independent.
Import writes a canonical stored copy first:
.agent/<bundle-name>/
├── instructions/
├── mcp/
├── skills/
└── vaen/metadata.json
Then it writes activated files for the target repo:
- Root instruction files:
AGENTS.md
andCLAUDE.md
, or the configured target filename. - Skill mirrors:
.agent/skills/...
and.claude/skills/...
, or the configured target skill directory. - MCP client config:
.codex/config.toml
,.mcp.json
, or.github/mcp.json
when--client
is used.
Included instruction files remain in .agent/<bundle-name>/instructions/...
; they are not concatenated into the root instruction file.
VAEN fails before overwriting existing setup files.
- Existing root instruction files block import.
- Existing
.agent/<bundle-name>
directories block import. - Existing mirrored skill names block import.
- Existing MCP client config files block import.
Skill directories should contain only instructions, scripts, references, and assets needed by the agent. Do not place credential files such as .env
, .env.*
, private keys, or credential stores inside a skill directory before building a bundle.
Build rejects obvious declared secret file paths such as .env
, .env.*
, *.pem
, *.key
, and id_rsa
. Detected secret values are never printed.
Credential handling is metadata-only:
requiredVars
and MCP env fields store variable names only.doctor
does not read.env
files.doctor
does not inspect shell environment variables, keychains, or other credential stores.- MCP validation checks local config syntax and expected file placement; it does not connect to MCP servers or validate auth.
The test fixture is a compact reference manifest:
The project-specific example is here:
VAEN is released under the MIT License.
The software is provided as-is, without warranty of any kind. The authors and copyright holders are not liable for claims, damages, or other liability arising from use of the software. See LICENSE for the full license text.