HOW SWAMP WORKS
Swamp is an adaptive automation framework designed to be operated by AI agents. It decomposes automation into a small set of composable primitives: models, workflows, vaults, extensions, skills, and a data layer — also known as The Swamp. Each primitive does one thing. What matters is how they fit together.
Models are the unit of work
A model has two halves: a type and a definition. The type is reusable logic written in TypeScript — it defines methods, input and output schemas, and execution behaviour for interacting with an external system. The definition is configuration written in YAML — it fills in the specifics for one particular use of that type.
This separation matters because the two halves change for different reasons. A
type like @tutorial/http-check defines what it means to check an HTTP
endpoint: send a GET, measure latency, record status. Three definitions —
check-swamp-club, check-example, check-dead — each point that same type at
a different URL with different timeouts. The type is code; the definitions are
data. Because definitions are plain structured data, an agent can produce one
using only its general reasoning ability — it writes YAML that conforms to the
type's schema, and the type handles execution.
Every method execution produces versioned, immutable data artifacts. Running
check-example's check method writes a result resource:
{ "status": 200, "latency": 176, "ok": true }This data is stored in .swamp, versioned automatically, and queryable. Any
subsequent operation can look up what previous operations produced. See
Models, Types, and Methods for
why the separation works the way it does.
Workflows wire models together
A workflow is a DAG of jobs, where each job contains steps that run model methods. Jobs execute in dependency order. Steps within a job run in parallel.
Workflows become useful through data chaining — a step can reference the output
of a previous step using CEL expressions. In the
tutorial's health-check workflow, the
summarize job reads from the checks that ran in the previous job:
data.latest("check-swamp-club", "result").attributes.statusThat expression reaches into the stored data from check-swamp-club and
extracts the HTTP status code. The output of one model becomes the input of
another through typed, validated references. If the data doesn't exist yet
(because a dependency hasn't run), the expression fails loudly rather than
passing through a blank value.
This means workflows don't just sequence actions — they compose data flows.
Workflows can also nest: a step can invoke another workflow instead of a model
method, passing inputs down. A manual_approval step can suspend a run until
someone approves it (see
Understanding Workflow Suspension),
and steps can run on remote machines via workers (see
Remote Execution).
Vaults keep secrets out of the data path
The data flow described above has a problem: some values are sensitive, and they
shouldn't be stored in plaintext YAML or versioned alongside the data they help
produce. Vaults provide a separate path for secrets. Model definitions and
workflows reference secrets by name rather than by value, and Swamp resolves
those references at runtime — not when the definition is created or the workflow
is planned, but when the step actually executes. This means secrets are never
frozen into YAML files, never written to .swamp data, and never cached between
runs. When a model's schema marks a field as sensitive, Swamp redirects that
value into vault storage automatically, so secrets never persist in the data
layer either.
The tutorial's health monitor checks public URLs that need no authentication — but the moment an endpoint requires an API token, that token belongs in a vault rather than in the model definition. Storing Secrets walks through adding one.
There's a design tension between solo developers, who need secrets to work without external infrastructure, and teams, who need secrets to live in managed systems (AWS Secrets Manager, 1Password, and the like). Vaults resolve this through swappable providers: a local encryption provider works out of the box, while provider-backed vaults delegate to external secret management. Because a vault provider is one of the things an extension can package, the vault system is open-ended.
Extensions package reusable model types
When no built-in model type exists for a task, someone writes one. The
tutorial's @tutorial/http-check is an extension model — a TypeScript file in
extensions/models/ that exports a type definition with Zod schemas for inputs
and outputs, and an execute function for each method.
Extensions aren't limited to models. They can also package vault providers
(custom secret backends), datastores (custom backends for .swamp data), and
reports. A single extension manifest bundles whichever of these it needs,
versioned with CalVer, and published to a registry.
The registry exists so that no single person or team needs to build every
integration. Someone writes a model type for their own use, publishes it, and
anyone else can install it.
Publish an Extension shows how to take
@tutorial/http-check from a local file to a community package. Trust is
deliberately narrow: only the first-party swamp collective is trusted by
default, and any other collective must be trusted explicitly. Belonging to a
collective grants the ability to publish its extensions, not consent to install
them automatically — so membership alone does not make a collective trusted.
Skills teach agents how to use Swamp
None of this works if the agent doesn't know how to use it. Skills are the bridge between Swamp's capabilities and an agent's ability to exercise them.
A skill is a markdown document — not executable code — that teaches an agent how
to work with Swamp. Rather than shipping a separate skill for each topic area,
Swamp consolidates guidance into a single swamp skill that acts as a gateway.
When an operative says "create a workflow," the agent loads the skill, which
routes to the relevant guidance internally — the right CLI commands, the right
YAML structure, the validation steps, the common pitfalls. A second skill,
swamp-getting-started, handles onboarding as a dedicated path.
Because the interface is markdown rather than a plugin API, any agent that can read and follow instructions can use Swamp. The agent uses its general reasoning abilities to apply the skill's instructions to the operative's specific situation.
Data querying ties it all together
Every model execution, every workflow run, every step produces data. Swamp stores this data with rich metadata: which model produced it, which spec it belongs to, tags from the model and workflow, a version number, a timestamp.
The data query system uses CEL (Common Expression Language) to filter across all stored data. After running the tutorial's health-check workflow twice, a single query finds every check that failed:
swamp data query 'attributes.ok == false'Only check-dead appears — the query matched across every model in the repo.
Projection with --select extracts specific fields from matching records.
Data querying serves two audiences. For humans, it's an inspection tool — what
did the last run produce? What's the current state of my infrastructure? For
agents and models, it's a composition mechanism. Extension models can call
context.queryData() from within their execute functions to find and process
data from other models. Models can also invoke other models directly via
context.runModel() when they need to orchestrate sub-model execution and act
on the result mid-method. Workflow expressions can use data.query() to
conditionally branch based on what exists in the datastore.
The data layer also manages lifecycle. Resources have lifetimes (ephemeral, job, workflow, duration, infinite) and garbage collection policies. Old versions get cleaned up automatically. Data can be renamed with forward references so that refactoring names doesn't break existing workflows. The system is designed for data to accumulate and be useful, not to become debt.
The composition
These primitives compose in a specific pattern:
- A skill teaches an agent what Swamp can do and how to do it
- The agent creates model definitions from existing types, or writes extension models when no type exists
- The agent wires models into workflows with data chaining expressions
- Vault expressions supply secrets at runtime, keeping sensitive values out of configuration files and stored data
- Each execution produces versioned data that's queryable and referenceable
- Data queries feed into future decisions — by humans inspecting results, by agents reasoning about state, or by models reading each other's output
- When a model needs to orchestrate another model's execution mid-method,
context.runModel()enables direct model-to-model invocation — bounded by dependency declarations, depth limits, and vault isolation (see Models, Types, and Methods)
Several properties of the system support this composition. Model definitions and workflows are YAML files committed to git, so they're reviewable and versioned alongside the code they automate. Data is immutable and versioned, so you can always see what happened. Schemas are validated at creation time and execution time, so type mismatches surface early. Extensions are published and versioned, so teams can share and build on each other's work.
To build this yourself, start with Your First Automation.