* fix(bundle): resolve bundle paths on the client and launch v2 installs from --target `rig bundle create/inspect/install` sent spec, output, bundle and target paths unresolved, so the daemon resolved them against its own cwd. The CLI now resolves them against the operator's cwd (files are still read on the daemon's host; nothing is uploaded). A schema-version-2 bundle apply launched from the temp extraction dir, which is removed right after instantiate, and ignored targetRoot: members with cwd "." and the spec/agent refs pointed at a deleted directory. Apply with a targetRoot now copies the verified extraction into the target and launches from there. A target with different content at any bundle path is refused with target_conflict and nothing written; identical files are accepted so a reinstall works. Plan mode, explicit cwdOverride, legacy v1 bundles and applies without a targetRoot are unchanged. Docs: rig-bundle.md install/inspect/--plan/--target/path behavior. * fix(cli): resolve local rig up --target and align its help with the v2 target contract On the local route, `rig up <bundle> --target <rel>` now resolves the target against the client's cwd before sending it, matching `rig bundle install`. The --target help now states the accepted contract: a v2 bundle is materialized into the target (default: current directory), relative member cwds resolve against it, and --cwd still overrides the launch cwd. Remote --host and topology routing are unchanged: --host sends --target as given, and it must exist on that host. Docs: drop the "pass an absolute --target" workaround for the local route. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: v-openrig-build <v-openrig-build@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
15 KiB
RigBundle Reference
Version: 2 (pod-aware)
Last validated against code: 2026-09-29 (install paths and --target only; other sections last checked 2026-04-11)
Source of truth: packages/daemon/src/domain/bundle-types.ts, packages/daemon/src/domain/bundle-archive.ts, packages/daemon/src/domain/pod-bundle-assembler.ts
A .rigbundle is a self-contained distributable archive that packages a rig spec, all referenced agent specs, their resources (skills, guidance, startup files), culture file, documentation, and an integrity manifest into a single file. The recipient can install and launch the rig without needing the original source tree.
Archive Format
A .rigbundle file is a gzip-compressed tar archive (.tar.gz) with a fixed structure.
File extension
The archive MUST have the .rigbundle extension. The packer rejects output paths that don't end with .rigbundle.
Sibling digest file
Every .rigbundle has a sibling .rigbundle.sha256 file containing the SHA-256 hex digest of the archive. This detects corruption during transfer. The unpacker verifies this digest before extraction.
Example:
my-rig.rigbundle — the archive
my-rig.rigbundle.sha256 — "a1b2c3d4..." (64-char hex SHA-256)
Determinism
The packer produces deterministic output:
- Files are sorted alphabetically
- A fixed mtime is used (
2026-01-01T00:00:00Z) - Portable mode normalizes uid/gid/mode
- Maximum gzip compression (level 9)
This means the same inputs always produce the same archive hash.
Archive Layout
bundle.yaml — manifest (required)
rig.yaml — the RigSpec (required, may be rewritten)
CULTURE.md — culture file (if declared in rig spec)
SETUP.md — documentation (if declared in rig spec docs field)
agents/
agent-name/
agent.yaml — AgentSpec
guidance/
role.md — guidance files
skills/
skill-name/
SKILL.md — skill files
startup/
context.md — startup files
Key rules
bundle.yamlis the manifest — always present, always at the rootrig.yamlis the rig spec — rewritten during assembly with vendoredagent_refpaths- Agent directories are vendored copies of the original agent specs with all their resources
- Import refs are rewritten from the original
local:orpath:paths to bundle-relativelocal:paths - All file paths within the archive are safe relative paths (no
.., no absolute, no symlinks)
Manifest (bundle.yaml)
The manifest is a YAML file at the archive root that describes the bundle contents.
Schema Version 2 (pod-aware, current)
schema_version: 2
name: my-bundle
version: "0.1.0"
created_at: "2026-04-11T22:32:48.570Z"
rig_spec: rig.yaml
agents:
- name: pm-lead
version: "1.0"
path: agents/pm-lead
original_ref: "local:agents/pm-lead"
hash: "ed4cff20..."
import_entries: []
- name: researcher
version: "1.0"
path: agents/researcher
original_ref: "local:agents/researcher"
hash: "11f8a077..."
import_entries:
- name: shared
version: "1.0"
path: agents/shared
original_ref: "local:../../shared"
hash: "abc123..."
culture_file: CULTURE.md
integrity:
algorithm: sha256
files:
rig.yaml: "b80c0674..."
CULTURE.md: "9354361b..."
agents/pm-lead/agent.yaml: "ed4cff20..."
# ... every file in the archive
Manifest Fields
| Field | Type | Required | Description |
|---|---|---|---|
schema_version |
number | yes | Must be 2 for pod-aware bundles. |
name |
string | yes | Bundle name. |
version |
string | yes | Bundle version. |
created_at |
string | yes | ISO-8601 timestamp of creation. |
rig_spec |
string | yes | Relative path to the rig spec within the archive. Safe relative path. |
agents |
AgentEntry[] | yes | Array of vendored agent entries. |
culture_file |
string | no | Relative path to the culture file if present. |
integrity |
Integrity | no | Per-file SHA-256 checksums for content verification. |
Agent Entry Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Agent name (from agent.yaml). |
version |
string | no | Agent version. |
path |
string | yes | Relative path to the vendored agent directory. Safe relative path. |
original_ref |
string | yes | The original agent_ref before rewriting. |
hash |
string | yes | SHA-256 hash of the agent.yaml content. |
import_entries |
ImportEntry[] | yes | Vendored imports for this agent (may be empty). |
Import Entry Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Imported agent name. |
version |
string | yes | Imported agent version. |
path |
string | yes | Relative path to the vendored import within the archive. |
original_ref |
string | yes | The original import ref before rewriting. |
hash |
string | yes | SHA-256 hash of the imported agent.yaml. |
Integrity Section
| Field | Type | Required | Description |
|---|---|---|---|
algorithm |
string | yes | Must be sha256. |
files |
map<string, string> | yes | Map of archive-relative file path → SHA-256 hex hash. Every file in the archive (except bundle.yaml itself) should be listed. |
Security Model
Bundle integrity provides self-consistency verification, not authenticity.
- The sibling
.sha256file detects corruption during transfer - The per-file integrity hashes detect tampering of individual files within the archive
- Neither mechanism authenticates the bundle author
An attacker who can rewrite the full bundle + digest can bypass verification. Users must trust the source they obtained the bundle from. This is the same trust model as unsigned npm packages and Docker images.
Future enhancement: cryptographic signing (Ed25519) for author authentication.
Safety Guarantees
The unpacker enforces these safety rules before extraction:
- No symlinks or hardlinks —
SymbolicLinkandLinkentries are rejected - No absolute paths — entries starting with
/are rejected - No path traversal — entries containing
..segments are rejected - Digest verification — archive SHA-256 must match the sibling
.sha256file - Content integrity — after extraction, per-file hashes are verified against the manifest
If any check fails, extraction is aborted and an error is thrown.
CLI Surface
Paths
rig bundle create, inspect and install resolve every path you give them (<spec-path>, -o, --rig-root,
<bundle-path>, --target) to an absolute path against your current directory before sending the request. The
daemon then reads and writes those paths on its own host: nothing is uploaded, so the files must already exist
where the daemon runs.
Create a bundle
rig bundle create <spec-path> -o <output.rigbundle> [--rig-root <dir>] [--name <name>] [--bundle-version <ver>]
| Flag | Required | Default | Description |
|---|---|---|---|
<spec-path> |
yes | — | Path to the rig spec YAML file. |
-o, --output |
yes | — | Output path. Must end with .rigbundle. |
--rig-root |
no | spec directory | Root directory for resolving agent_ref and other relative paths. |
--name |
no | my-bundle |
Bundle name in the manifest. |
--bundle-version |
no | 0.1.0 |
Bundle version in the manifest. |
The create command:
- Validates the rig spec
- Resolves all
agent_refpaths and their imports - Vendors all agent specs, resources, and startup files into a staging directory
- Rewrites
agent_refpaths to bundle-relativelocal:refs - Collects culture file, docs files, and rig-level startup files
- Computes per-file integrity hashes
- Writes the manifest (
bundle.yaml) - Packs into a deterministic
.tar.gz - Writes the sibling
.sha256digest
Inspect a bundle
rig bundle inspect <bundle-path> [--json]
Shows the manifest, digest validity, and integrity verification result. Inspect extracts the archive into a temporary directory for safe validation, then cleans that directory up. It does not install or launch anything.
Install a bundle
rig bundle install <bundle-path> [--plan] [--yes] [--target <root>] [--json]
| Flag | Required | Default | Description |
|---|---|---|---|
<bundle-path> |
yes | — | Path to the .rigbundle file. |
--plan |
no | false |
Preview without installing or launching. Not side-effect free: it runs the preflight, which executes the members' runtime --version probes, and it records a bootstrap run. It writes nothing to the target. |
--yes |
no | false |
Auto-approve trusted actions during apply mode. |
--target <root> |
yes in apply mode | — | Directory the bundle is installed into and launched from. Required unless --plan is used. |
--json |
no | false |
Emit machine-readable JSON. |
Install launches the rig; it does not just unpack it. It extracts the bundle to a temporary directory, validates integrity, and bootstraps the rig. In apply mode, the daemon requires targetRoot, so rig bundle install must be given --target <root> unless you are running with --plan.
For a pod-aware (schema version 2) bundle, apply copies the extracted contents (bundle.yaml, rig.yaml, agents/, culture and docs files) into the target and launches from there, then removes the temporary extraction. So:
- the target becomes the rig root:
agent_refpaths resolve inside it, and a member withcwd: "."(or nocwd) starts in the target; - an absolute member
cwdstays as authored, andrig up --cwd <dir>still overrides every member's cwd; - if the target already has a file with different content at any bundle path (for example its own
rig.yaml), install refuses withtarget_conflictand writes nothing. Identical files are accepted, so reinstalling the same bundle into the same target works. Use an empty or dedicated directory as the target.
Legacy (schema version 1) bundles keep their old behavior: --target is only where packages are installed.
Launch directly
rig up <bundle-path> [--target <root>] [--cwd <dir>]
rig up auto-detects .rigbundle files and routes them through the bundle bootstrap path.
--target <root>is the install target described above (for a schema-version-2 bundle, the directory the bundle is copied into and launched from)- if
--targetis omitted for a.rigbundle, the CLI defaults the install target to the current working directory, so the bundle's files are written there rig upresolves a relative--targetagainst your current directory before sending it, likerig bundle install; with--host,--targetis sent as given and must be a path that exists on that host--cwd <dir>does not change the install target; it only overrides the launched members' working directory for that run
Assembly Process
When rig bundle create runs, the PodBundleAssembler performs these steps:
- Parse and validate the rig spec
- Collect rig-level files:
- Culture file (if
culture_fileis set) - Docs files (if
docsarray is set) — required: missing docs fail assembly - Rig-level startup files
- Pod-level and member-level startup files
- Culture file (if
- For each member's
agent_ref:- Resolve the ref to an agent spec directory
- Copy the agent spec and all its resources (skills, guidance, hooks, startup, runtime resources)
- Recursively resolve and copy imports
- Record the agent entry in the manifest with its hash
- Rewrite the ref to a bundle-relative
local:path
- Write the rewritten rig spec to the staging directory
- Compute integrity — SHA-256 of every file in the staging directory
- Write the manifest (
bundle.yaml) with all entries and integrity - Pack the staging directory into a deterministic tar.gz
Terminal nodes
Members with agent_ref: "builtin:terminal" are bundle-native sentinels. They are not vendored — the runtime handles them directly.
Deduplication
If multiple members reference the same agent spec (same resolved path), the spec is vendored once and all members' refs are rewritten to the same bundle-relative path.
Import resolution
When an agent spec has imports, each import is resolved, vendored into the bundle, and the import refs in the vendored agent.yaml are rewritten to bundle-relative local: paths. Import entries are recorded in the manifest's agent entry.
Validation Rules Summary
Manifest validation (schema version 2)
schema_versionmust be2nameis required non-empty stringversionis required non-empty stringcreated_atis required non-empty stringrig_specis required and must be a safe relative pathagentsmust be an array- Each agent must have
name,path(safe relative), andhash - Integrity
algorithmmust besha256 - Integrity
filesmust be a non-empty map of safe-relative-path → 64-char hex hash
Archive safety (enforced on unpack)
- No symlinks or hardlinks
- No absolute paths
- No
..path traversal - Archive digest must match sibling
.sha256 - Per-file content hashes must match integrity section
Assembly validation
- Rig spec must validate
- All
agent_refpaths must resolve to valid agent specs - All declared
docsfiles must exist on disk (missing docs fail assembly) - Culture file and startup files are collected best-effort (missing = skipped)
Legacy Bundles (Schema Version 1)
Schema version 1 bundles are the pre-reboot format using flat-node rig specs and package-based bundling. They are still supported for backward compatibility but should not be created for new rigs.
Key differences from v2:
schema_version: 1in the manifestpackagesarray instead ofagentsarray- Package entries have
original_sourceinstead oforiginal_ref - No
import_entriesin package entries - Legacy rig spec format (flat nodes, not pods)
Example: Creating and Using a Bundle
Create
# From the rig directory
rig bundle create rig.yaml -o my-team.rigbundle --rig-root . --name my-team --bundle-version 1.0.0
Output:
Bundle created: my-team.rigbundle
Name: my-team v1.0.0
Hash: a1b2c3d4e5f6...
Inspect
rig bundle inspect my-team.rigbundle
Output:
Bundle: my-team v1.0.0
Digest valid: true
Integrity: PASS
Install and launch
cd ~/projects/my-project
rig up /path/to/my-team.rigbundle
Equivalent explicit form:
rig up /path/to/my-team.rigbundle --target ~/projects/my-project
The bundle is extracted to a temporary directory and its integrity is verified. A schema-version-2 bundle is then copied into the target root (refused if the target holds different files at the same paths) and the rig is launched from there, with all agents and resources from the bundle. If you also want agents to launch with a different working directory for that run, pass --cwd <dir> separately.