Bundle Structure
Reference for the three resources that make up a bundle — the bundle itself, its assets, and its published versions. Each section lists the fields you see in API responses.
How the Resources Relate
A bundle is a named container you create. You add assets (text files) to it. When ready, you publish a version — an immutable snapshot of all current assets.
- Create a bundle with a unique slug in your namespace.
- Add one or more assets — each is a text file at a logical path.
- Publish a version to freeze the current assets into a snapshot that consumers can resolve.
For the full lifecycle, see the Bundles overview.
Entity Reference
Bundle
The top-level container you create to hold related assets. Each bundle is identified by a slug unique within its namespace.
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUID | PK, auto-generated | Unique identifier |
namespace | string | max 40 chars, NOT NULL | Owning namespace |
slug | string | max 100 chars, unique per namespace | URL-safe, CLI-friendly identifier |
name | string | max 255 chars, NOT NULL | Human-readable display name |
description | string | null | max 1000 chars | Optional longer description |
visibility | string | NOT NULL, default private | One of private, workspace, or public. Default private. |
created_at | datetime | NOT NULL, UTC | Creation timestamp |
updated_at | datetime | null | UTC | Last modification timestamp |
deleted_at | datetime | null | UTC | Soft-delete timestamp |
BundleAsset
A single text file you add to a bundle. Each asset has a logical path that must be unique within the bundle. You classify it with an asset type — see Asset Types.
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUID | PK, auto-generated | Unique identifier |
bundle_id | UUID | FK, NOT NULL | Parent bundle |
asset_type | string | max 50 chars, NOT NULL | Classification label (free-form, not an enum). See Asset Types. |
logical_path | string | max 500 chars, unique per bundle | Filesystem-like path, e.g. prompts/summarize.md |
content_text | string | NOT NULL, max 512 KB | The asset body (text only) |
content_sha256 | string | 64 chars (hex), NOT NULL | SHA-256 hash of content_text, computed on write |
created_at | datetime | NOT NULL, UTC | Creation timestamp |
updated_at | datetime | null | UTC | Last modification timestamp |
deleted_at | datetime | null | UTC | Soft-delete timestamp |
BundleVersion
A frozen snapshot created when you publish a bundle. Once published, contents cannot change. See Publishing for the full workflow.
| Field | Type | Constraints | Description |
|---|---|---|---|
id | UUID | PK, auto-generated | Unique identifier |
bundle_id | UUID | FK, NOT NULL | Parent bundle |
version | string | max 50 chars, unique per bundle | Semver-style version string |
state | string | NOT NULL, default published | Either published or yanked. Default published. |
oci_ref | string | null | — | Full OCI reference, e.g. registry/namespace/slug:1.0.0. See Publishing > OCI Integration. |
oci_digest | string | null | max 100 chars | OCI content digest. See Publishing > OCI Integration. |
manifest_json | object | null | JSONB | Frozen manifest at publish time. See Publishing > Manifest Schema. |
published_by | string | null | max 255 chars | Actor who published (user ID or API key label) |
yanked_by | string | null | max 255 chars | Actor who yanked |
yanked_at | datetime | null | UTC | When the version was yanked |
yank_reason | string | null | max 500 chars | Human-readable reason for yanking |
created_at | datetime | NOT NULL, UTC | Publish timestamp |
deleted_at | datetime | null | UTC | Soft-delete timestamp |
Enums
Visibility
| Value | Description |
|---|---|
"private" | Only the creating user or API key can access |
"workspace" | All workspace members can access |
"public" | Anyone can resolve and download (no auth required) |
Version State
| Value | Description |
|---|---|
"published" | Active — included in resolution |
"yanked" | Withdrawn — excluded from resolution |
Limits and Constraints
| Limit | Value |
|---|---|
| Max asset content size | 524,288 bytes (512 KB) |
| Max assets per bundle | 200 |
| Max slug length | 100 characters |
| Max name length | 255 characters |
| Max description length | 1,000 characters |
| Max version string length | 50 characters |
| Max asset type length | 50 characters |
| Max logical path length | 500 characters |
| Max yank reason length | 500 characters |
Guarantees
The platform enforces these rules. The API returns an error if any are violated.
- Slug unique per namespace — you cannot create two bundles with the same slug in
the same namespace. The API returns a
409 Conflict. - Logical path unique per bundle — you cannot add two assets with the same
logical path to the same bundle. The API returns a
409 Conflict. - Version unique per bundle — you cannot publish two versions with the same
version string in the same bundle. The API returns a
409 Conflict. - Empty bundles cannot be published — a bundle must have at least one asset
before you can publish a version. The API returns a
422 Unprocessable Entity. - Published versions are immutable — once created, a version's manifest, content
hashes, and version string cannot be modified. The only allowed state transition is
published → yanked.
Design Rationale
Why are assets restricted to text content?
Text enables deterministic diffing, transparent auditing, and simple integrity verification via SHA-256 hashing. Binary blobs would complicate content-addressable storage, make diffs opaque, and introduce encoding ambiguities. If binary assets are needed in the future, they can be added as a separate asset type with different storage semantics.