# Show HN: VAEN – Package and import portable AI coding-agent Harnesses

> Source: <https://github.com/sjhalani7/vaen>
> Published: 2026-05-27 20:52:31+00:00

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](/sjhalani7/vaen/blob/main/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:

``` python
vaen validate
vaen build
vaen inspect
vaen import
vaen doctor
vaen cleanup
```

See [docs/quick-start.md](/sjhalani7/vaen/blob/main/docs/quick-start.md) for a minimal instructions-only bundle flow.

The [ dist/agents/](/sjhalani7/vaen/blob/main/dist/agents) directory contains ready-to-import

`.agent`

archives for popular, reputable public agent setups.Current packages:

— complete promoted skill set from`mattpocock-skills.agent`

`mattpocock/skills`

— engineering skills`mattpocock-engineering.agent`

— productivity skills`mattpocock-productivity.agent`

— misc utility skills`mattpocock-misc.agent`

See [ dist/agents/README.md](/sjhalani7/vaen/blob/main/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`

, and`instructions.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, or`NAME=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 to`AGENTS.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 either`stdio`

or`http`

.`command`

and`args`

define how stdio MCP servers are launched.`url`

defines the HTTP MCP endpoint.`env_vars`

and`bearer_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:

``` php
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 machine`bundle 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`

and`CLAUDE.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](/sjhalani7/vaen/blob/main/LICENSE) for the full license text.
