EXTENSION MANIFEST
The extension manifest is a YAML file named manifest.yaml that declares the
contents and metadata of a swamp extension. It is the input to
swamp extension push, which packages and publishes the extension to the
registry.
manifestVersion: 1
name: "@myorg/deploy-tools"
version: "2026.04.07.1"
description: "Deployment automation models and workflows"
models:
- ec2_instance.ts
- security_group.ts
workflows:
- deploy_stack.yaml
reports:
- cost_summary.ts
additionalFiles:
- README.md
platforms:
- darwin-aarch64
- linux-x86_64
labels:
- aws
- deployment
dependencies:
- "@myorg/aws-core"
releaseNotes: "Added security group model"Required Fields
manifestVersion
Schema version for the manifest format.
| Property | Value |
|---|---|
| Type | integer |
| Required | Yes |
| Value | 1 |
The only supported value is 1. A manifest missing this field or using an
unsupported version is rejected.
name
Scoped extension name.
| Property | Value |
|---|---|
| Type | string |
| Required | Yes |
| Pattern | @[a-z0-9_-]+/[a-z0-9_-]+(/[a-z0-9_-]+)* |
| Examples | @myorg/deploy, @swamp/aws/ec2, @acme/monitoring |
The name has two parts separated by /:
- Collective — the
@-prefixed namespace (e.g.,@myorg). Must match the authenticated user's collective when pushing. - Name — one or more
/-separated segments (e.g.,deploy,aws/ec2,aws/accessanalyzer/analyzer).
All segments must be lowercase and may contain letters, digits, hyphens, and underscores.
The collectives @swamp and @si are reserved for built-in extensions.
All content types within the extension (model types, vault types, workflow names, driver types, datastore types, report names) must use the same collective prefix as the extension name. This is enforced during push.
version
Extension version in CalVer format.
| Property | Value |
|---|---|
| Type | string |
| Required | Yes |
| Format | YYYY.MM.DD.MICRO (e.g., 2026.04.07.1) |
The date components must represent a valid calendar date (month 01-12, day valid
for the given month and year including leap years). The micro counter is a
non-negative integer that allows multiple versions per day and resets for each
new date. In practice, swamp extension version starts the counter at 1.
The registry enforces unique name+version tuples. Use
swamp extension version --manifest manifest.yaml to query the latest published
version and compute the next CalVer version.
Content Arrays (at least one required)
The manifest must include at least one of models, workflows, vaults,
drivers, datastores, reports, or skills with at least one entry. A
manifest with none of these is rejected.
Content Fields
All content fields are arrays of relative file paths. Every path must be
relative and downward-only — paths containing .. components or starting
with / are rejected.
models
TypeScript model entry-point files.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No (but see content requirement above) |
| Default | [] |
| Resolved to | extensions/models/ (or modelsDir from .swamp.yaml) by default — see Path Resolution for the paths.base: manifest opt-in |
models:
- ec2_instance.ts
- aws/s3/bucket.tsOnly list entry-point files. Local imports (e.g., ./helpers.ts) are
auto-resolved recursively and included in the archive. Each entry point is
bundled into a standalone JavaScript file for the registry.
workflows
YAML workflow files.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No (but see content requirement above) |
| Default | [] |
| Resolved to | workflows/ first, then extensions/workflows/ (or workflowsDir) |
workflows:
- deploy_stack.yaml
- namespace-debug/workflow.yamlWorkflow files are resolved by checking the indexer symlinks directory
(workflows/) first, then the extension workflows directory. Models referenced
by workflows are auto-resolved and included in the archive.
vaults
TypeScript vault entry-point files.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No (but see content requirement above) |
| Default | [] |
| Resolved to | extensions/vaults/ (or vaultsDir from .swamp.yaml) by default — see Path Resolution for the paths.base: manifest opt-in |
drivers
TypeScript driver entry-point files.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No (but see content requirement above) |
| Default | [] |
| Resolved to | extensions/drivers/ (or driversDir from .swamp.yaml) by default — see Path Resolution for the paths.base: manifest opt-in |
datastores
TypeScript datastore entry-point files.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No (but see content requirement above) |
| Default | [] |
| Resolved to | extensions/datastores/ (or datastoresDir from .swamp.yaml) by default — see Path Resolution for the paths.base: manifest opt-in |
reports
TypeScript report entry-point files.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No (but see content requirement above) |
| Default | [] |
| Resolved to | extensions/reports/ (or reportsDir from .swamp.yaml) by default — see Path Resolution for the paths.base: manifest opt-in |
For vaults, drivers, datastores, and reports, the same rules as models apply:
only list entry-point files, local imports are auto-resolved, and each entry
point is bundled.
skills
AI coding tool skill directories to include in the extension.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No (but see content requirement above) |
| Default | [] |
| Resolved to | Tool skill directory (e.g., .claude/skills/ for claude tool) |
skills:
- swamp-deploy
- deploy-checklistEach entry is a skill directory name, resolved from the project-local skill directory first, then the global skill directory. The tool determines which directory is used:
| Tool | Skill Directory |
|---|---|
| Claude | .claude/skills/ |
| Cursor | .cursor/skills/ |
| Opencode | .agents/skills/ |
| Codex | .agents/skills/ |
| Kiro | .kiro/skills/ |
Each skill directory must contain a SKILL.md file with YAML frontmatter
declaring name and description. Skills are passive markdown guidance
documents — swamp registers metadata at install time but never executes them.
Skill file limits:
| Limit | Value |
|---|---|
| Individual file size | 500 KB |
| Total skill content | 2 MB |
A skills-only extension (no models, workflows, or other code) is valid. This
enables distributing organizational guidance separately from the integrations
they build on. Use dependencies to declare which model extension the skills
are designed for.
Optional Metadata Fields
description
Human-readable description of the extension.
| Property | Value |
|---|---|
| Type | string |
| Required | No |
| Default | None |
repository
URL of the extension's source repository.
| Property | Value |
|---|---|
| Type | string |
| Required | No |
| Default | None |
| Format | Valid URL |
repository: "https://github.com/myorg/swamp-deploy-tools"Must be a valid URL. Invalid URLs are rejected during validation.
releaseNotes
Per-version release notes.
| Property | Value |
|---|---|
| Type | string |
| Required | No |
| Default | None |
| Max length | 5000 characters |
Can also be provided via the --release-notes flag on swamp extension push,
which overrides the manifest value.
platforms
Platform identifiers the extension supports.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No |
| Default | [] |
| Values | Non-empty strings (e.g., darwin-aarch64) |
platforms:
- darwin-aarch64
- linux-x86_64Informational only — displayed during pull. Not enforced at install time.
labels
Categorization labels for registry search and filtering.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No |
| Default | [] |
| Values | Non-empty strings (e.g., aws, kubernetes) |
labels:
- aws
- kubernetes
- securitydependencies
Other extensions this extension depends on.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No |
| Default | [] |
| Format | Each entry must contain a / (e.g., @collective/name) |
dependencies:
- "@myorg/aws-core"
- "@myorg/network"Dependencies are pulled automatically when the extension is installed. Maximum dependency resolution depth is 10 to prevent circular loops.
paths
Path resolution mode for content and supplementary file fields.
| Property | Value |
|---|---|
| Type | object |
| Required | No |
| Default | { base: "typedDir" } |
| Fields | base: "typedDir" or "manifest" |
paths:
base: manifestA manifest with no paths field uses the typedDir mode. Unknown values for
paths.base are rejected at parse time. Unknown keys inside paths are
rejected at parse time. See Path Resolution for the
resolution rules under each mode and the fields each mode affects.
Supplementary File Fields
include
TypeScript files to include alongside models without bundling.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No |
| Default | [] |
| Resolved to | extensions/models/ (or modelsDir from .swamp.yaml) by default — see Path Resolution for the paths.base: manifest opt-in |
include:
- helpers/scan_ports.tsInclude files are copied to the archive's models/ directory but are not
bundled or quality-checked. They are intended for helper scripts executed via
Deno.Command subprocess rather than imported directly. At runtime, the loader
skips files that do not declare the expected named export.
additionalFiles
Non-code files to include in the extension.
| Property | Value |
|---|---|
| Type | string[] |
| Required | No |
| Default | [] |
| Resolved to | Relative to the manifest file location |
additionalFiles:
- README.md
- templates/config.txtAdditional files are stored under files/ in the archive, preserving their
relative paths. Pulled extensions retain the same files/ subdirectory under
.swamp/pulled-extensions/<name>/.
Path Safety
All file paths in content, supplementary, and include fields are validated:
- Must be relative (must not start with
/) - Must not contain
..components (e.g.,../../workflows/file.yaml) - Must not contain backslash traversal (e.g.,
..\file.ts)
Paths that fail these checks are rejected during both schema validation and file resolution.
Path Resolution
The paths.base field selects the directory models, vaults, drivers,
datastores, reports, include, and additionalFiles resolve against during
push. The archive layout under each typed-key directory mirrors the manifest
entries verbatim under the active mode.
| Mode | Typed keys resolve relative to | additionalFiles resolves relative to |
|---|---|---|
typedDir (default) |
Configured directory (modelsDir, vaultsDir, etc., from .swamp.yaml or environment override) |
Manifest's own directory |
manifest |
Manifest's own directory | Manifest's own directory |
A manifest with no paths field uses the typedDir mode. The mode does not
apply to workflows or skills — both keep their own multi-base resolution
independent of paths.base.
The on-wire manifest written into the archive carries the paths field only
when the mode is non-default. A typedDir push omits the field; the on-wire
byte content of the manifest is unchanged from manifests authored without the
field.
Mode comparison
The same extension expressed under both modes produces the same archive contents, with different source layouts:
paths.base: typedDir (default) — manifest at the repository root, source
under the configured extensions/<typed>/ directory:
extensions/models/echo.ts
extensions/models/utils/helper.ts
manifest.yaml
README.mdmanifestVersion: 1
name: "@me/my-ext"
version: "2026.04.29.1"
models:
- echo.ts
- utils/helper.ts
additionalFiles:
- README.mdpaths.base: manifest — each extension is a self-contained directory under
the configured typed directory; manifest sits beside its source:
extensions/models/my-ext/echo.ts
extensions/models/my-ext/utils/helper.ts
extensions/models/my-ext/manifest.yaml
extensions/models/my-ext/README.mdmanifestVersion: 1
name: "@me/my-ext"
version: "2026.04.29.1"
paths:
base: manifest
models:
- echo.ts
- utils/helper.ts
additionalFiles:
- README.mdIn both cases the resulting archive contains extension/models/echo.ts,
extension/models/utils/helper.ts, and extension/files/README.md.
Push Checks
Extensions are analyzed for safety and quality before push. All checks run in a single pass.
Safety Checks (hard errors — block push)
| Check | Limit |
|---|---|
| File count | 150 files maximum |
| Individual file size | 1 MB maximum |
| Total extension size | 10 MB maximum |
| Allowed file types | .ts, .json, .md, .yaml, .yml, .txt |
| Hidden files | Not allowed (names starting with .) |
| Symlinks | Not allowed |
| Code injection | eval() and new Function() are rejected |
Safety Warnings (prompt user)
| Check | Threshold |
|---|---|
| Long lines | Lines with more than 500 non-whitespace chars |
| Base64-like strings | 100+ consecutive base64 characters |
| Subprocess spawning | Deno.Command() usage |
Quality Checks (hard errors — block push)
| Check | Requirement |
|---|---|
| Dynamic imports | import() calls are rejected (use static imports) |
| Formatting | TypeScript files must pass deno fmt --check |
| Linting | TypeScript files must pass deno lint |
Quality checks use the project's deno.json configuration when present,
otherwise default rules.
Validation Summary
| Rule | Error message |
|---|---|
Missing manifestVersion |
"Extension manifest is missing 'manifestVersion'. Add 'manifestVersion: 1' to your manifest." |
Unsupported manifestVersion |
"Unsupported manifest version: N. Only version 1 is supported." |
| Unscoped name | "Extension name must be scoped: @collective/name (lowercase, alphanumeric, hyphens, underscores, additional /segments allowed)" |
| Invalid CalVer version | "Version must be valid CalVer format: YYYY.MM.DD.MICRO" |
| No content arrays | "Extension must include at least one model, workflow, vault, driver, datastore, report, or skill" |
Dependency without / |
"Dependencies must include a slash (e.g., @collective/name)" |
| Invalid repository URL | "Invalid url" |
| Unsafe path (traversal) | "Path must be relative and must not contain '..' components or start with '/'" |
Unknown paths.base value |
Zod enum rejection — accepted values are typedDir and manifest |
Unknown key inside paths |
Zod strict-object rejection — only base is permitted |
Complete Examples
Default mode (paths.base: typedDir)
A manifest using all available fields with content under the configured typed directories:
manifestVersion: 1
name: "@myorg/deploy-suite"
version: "2026.04.07.1"
description: "Full deployment automation with models, workflows, and reporting"
repository: "https://github.com/myorg/swamp-deploy-suite"
models:
- ec2_instance.ts
- security_group.ts
- aws/s3/bucket.ts
workflows:
- deploy_stack.yaml
vaults:
- secrets_manager.ts
drivers:
- docker_driver.ts
datastores:
- s3_datastore.ts
reports:
- cost_summary.ts
skills:
- swamp-deploy
include:
- helpers/scan_ports.ts
additionalFiles:
- README.md
- templates/config.txt
platforms:
- darwin-aarch64
- linux-x86_64
labels:
- aws
- deployment
- security
dependencies:
- "@myorg/aws-core"
- "@myorg/network"
releaseNotes: "Added S3 bucket model and cost reporting"Source layout for the example above:
extensions/models/ec2_instance.ts
extensions/models/security_group.ts
extensions/models/aws/s3/bucket.ts
extensions/models/helpers/scan_ports.ts
extensions/vaults/secrets_manager.ts
extensions/drivers/docker_driver.ts
extensions/datastores/s3_datastore.ts
extensions/reports/cost_summary.ts
workflows/deploy_stack.yaml
.claude/skills/swamp-deploy/
manifest.yaml
README.md
templates/config.txtPer-extension-subdir layout (paths.base: manifest)
The same extension expressed with manifest, source, and supplementary files in a single directory:
manifestVersion: 1
name: "@myorg/deploy-suite"
version: "2026.04.07.1"
description: "Full deployment automation with models, workflows, and reporting"
repository: "https://github.com/myorg/swamp-deploy-suite"
paths:
base: manifest
models:
- ec2_instance.ts
- security_group.ts
- aws/s3/bucket.ts
include:
- helpers/scan_ports.ts
additionalFiles:
- README.md
- templates/config.txt
platforms:
- darwin-aarch64
- linux-x86_64
labels:
- aws
- deployment
- security
dependencies:
- "@myorg/aws-core"
- "@myorg/network"
releaseNotes: "Added S3 bucket model and cost reporting"Source layout for the example above:
extensions/models/deploy-suite/ec2_instance.ts
extensions/models/deploy-suite/security_group.ts
extensions/models/deploy-suite/aws/s3/bucket.ts
extensions/models/deploy-suite/helpers/scan_ports.ts
extensions/models/deploy-suite/manifest.yaml
extensions/models/deploy-suite/README.md
extensions/models/deploy-suite/templates/config.txtworkflows, vaults, drivers, datastores, reports, and skills keep
their own resolution rules (workflows fall back from the indexer dir to the
extension workflows dir; skills look up project-local then global) and are
omitted here for the same-layout comparison. They can still be combined with
paths.base: manifest when the rest of the content lives beside the manifest.
Import Resolution
Extension source files can use any Deno-compatible import — npm:, jsr:, or
https:. All three are resolved and inlined by the bundler identically. zod
is the sole externalization exception: it is not inlined so that extensions
share the same zod instance as swamp (required for schema instanceof checks).
| Specifier form | Example | Resolution |
|---|---|---|
npm: |
npm:lodash-es@4.17.21 |
Inlined into the bundle |
jsr: |
jsr:@std/assert@1.0.0 |
Inlined into the bundle |
https: |
https://deno.land/std@0.224.0/async/delay.ts |
Inlined into the bundle |
| Bare | from "zod" |
Requires a deno.json import map or a package.json with node_modules |
Bare specifiers are only supported when the extension lives inside a project
that has a deno.json or package.json — the push command walks up from the
manifest directory to the repo root to discover one. deno.json takes priority
over package.json.
Dynamic import() calls are not supported. All imports must be static top-level
imports.
Archive Structure
When pushed, the extension is packaged as a gzipped tar archive:
extension/
manifest.yaml
models/
ec2_instance.ts
security_group.ts
aws/s3/bucket.ts
helpers/scan_ports.ts # from include
bundles/
ec2_instance.js
security_group.js
aws/s3/bucket.js
workflows/
deploy_stack.yaml
vaults/
secrets_manager.ts
vault-bundles/
secrets_manager.js
drivers/
docker_driver.ts
driver-bundles/
docker_driver.js
datastores/
s3_datastore.ts
datastore-bundles/
s3_datastore.js
reports/
cost_summary.ts
report-bundles/
cost_summary.js
skills/
swamp-deploy/
SKILL.md
references/
deploy-steps.md
files/
README.md
templates/config.txtSource TypeScript files preserve their relative directory structure. Local imports are resolved recursively and included alongside entry points. Each entry point is compiled into a JavaScript bundle with zod externalized.
Related
- Model Definitions — YAML schema for model definitions referenced by extensions
- Workflows — YAML schema for workflow files included in extensions
- Vaults — vault types and configuration
- Repository Configuration —
directory overrides (
modelsDir,workflowsDir, etc.) and trust settings that affect extension resolution