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.
Demo
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
What VAEN Packages
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.
Why Not Just Zip the Files?
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.yamldeclares the instructions, skills, MCP declarations, and required variable names.vaen validatecatches malformed manifests before sharing.vaen inspectlets the receiver review bundle contents before import.vaen importmaterializes the setup into predictable client-specific locations.vaen doctorchecks the imported structure without reading credential values.
Install
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
Quick Start
See docs/quick-start.md for a minimal instructions-only bundle flow.
Public Agent Setup Packages
The dist/agents/ directory contains ready-to-import .agent archives for popular, reputable public agent setups.
Current packages:
mattpocock-skills.agent— complete promoted skill set frommattpocock/skillsmattpocock-engineering.agent— engineering skillsmattpocock-productivity.agent— productivity skillsmattpocock-misc.agent— misc utility skills
See dist/agents/README.md for import commands and attribution.
Manifest
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.mainare required.instructions.includesis optional.artifactsis a list and may be empty for instructions-only bundles.skillsis the supported artifact type.requiredVarsand 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=valueassignments. http_headersstores non-secret static HTTP headers for MCP servers.mcpis 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.
YAML Examples
Instructions only:
version: "0.1" publisher: "Your Name" instructions: main: "./AGENTS.md" artifacts: []
instructions.mainpoints toAGENTS.mdor 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.includesis for extra Markdown instruction/context files.- Each
artifactsentry 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
nameis the local MCP server name.transportis eitherstdioorhttp.commandandargsdefine how stdio MCP servers are launched.urldefines the HTTP MCP endpoint.env_varsandbearer_token_env_varcontain environment variable names only, never secret values.http_headerscontains non-secret static headers.
Typical Flow
1. Validate
vaen validate -f examples/synthetic-fixture/agent.yaml
2. Build
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.
3. Inspect
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.
4. Import
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.mdand.claude/skills/...--client codex:AGENTS.mdand.codex/skills/...--client copilot:AGENTS.mdand.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/....
5. Verify
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.
6. Cleanup
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.
Archive Layout
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.agentmaterialized 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 Layout
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.mdandCLAUDE.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.jsonwhen--clientis used.
Included instruction files remain in .agent/<bundle-name>/instructions/...; they are not concatenated into the root instruction file.
Safety Rules
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:
requiredVarsand MCP env fields store variable names only.doctordoes not read.envfiles.doctordoes 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.
Examples
The test fixture is a compact reference manifest:
The project-specific example is here:
License
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.