The official marketplace for Expanso skills: complete jobs for the data work
you are asked to build, plus single-purpose pipeline skills, for OpenClaw,
Claude and any MCP-compatible AI assistant. All open source; the live count
per category is in catalog.json.
These eight jobs were each run end to end on 2026-09-18 with
expanso-edge v2.1.21 and their output counted at the destination. Each
lives in skills/jobs/ with its job spec, a README with
dependency setup and output checks, the sample inputs used, and a
skill.yaml proof block recording where it ran and what was not proved.
The dated, sanitized run record with the Cloud job and execution ids is
skills/jobs/PROOF-2026-09-18.md.
| Job | Proven | Directory |
|---|---|---|
| RSS feed engine | Cloud + local; live NASA and BBC feeds; fetch-error guard local only; items must carry a stable, non-empty <guid> (GUID-less feeds unsupported, untested) |
rss-feed-engine |
| Data migration engine (batch) | Cloud + local | data-migration-engine |
| Notification engine | Cloud + local, to a local test receiver only | notification-engine |
| RAG: fetch, chunk, embed, store, search | Cloud + local; Ollama + Qdrant; URL-based chunk id local only | rag-embed-retrieve |
| Webhook fan-out | Local only | webhook-fan-out |
| Log reduction | Local only | log-reduction |
| Sensor telemetry over MQTT | Local only; synthetic publisher | sensor-telemetry-mqtt |
| CI test fixtures | Local only | ci-fixtures |
"Cloud" means submitted to an Expanso Cloud workspace and executed by one
operator-registered node chosen by label, with the job's dependencies on
that host; it is not a hosted runner. "Local" means a local-mode node only.
Each job spec has the same structure as the job that ran; only the values
listed in its header comment differ, and long mappings are rewrapped. Four
changes are newer than the runs and were not re-run on Cloud: the RSS
fetch-error guard, the RAG URL-based chunk id and the migration's signed
balance formula (each validated on a local-mode node only), and restart_policy: never on the bounded jobs.
Not proven, and not published as working jobs:
live X (Twitter) ingestion, change data capture, delivery into Slack or
email, and the native qdrant output (the RAG job writes through Qdrant's
REST API instead). The first five nodes are free.
Readiness: these skills are published pipeline definitions. Except where a skill's own README states otherwise, they have not been confirmed by an end-to-end run on current Expanso Cloud. See Pipeline shape & readiness and Known issues before depending on one.
Expanso Skills are portable data processing pipeline definitions. A skill is a job spec: you submit it to your Expanso Cloud control plane, and the scheduler assigns it to an edge node you own and control.
What that means in practice:
- Your infrastructure runs the work - pipelines execute on your own edge nodes, not on Expanso's servers.
- Credentials resolve on the node that runs the pipeline - they are read from
that node's environment and are not embedded in the pipeline definition.
This is not the same as "credentials never leave your machine". A skill that
calls a third-party API (OpenAI, Slack, Gmail, ...) transmits its credential to
that provider, along with whatever data you send it. Only skills whose
skill.yamlhas adependenciesblock (text-summarizeand the eight jobs) have been audited for what leaves the host; for any other skill, check its pipeline's components rather than relying on its README. - Some skills run without network egress; many do not. Only skills whose components are entirely local are offline-capable. Any skill listing a third-party API component is not offline. Check the skill, not this page.
- Are composable - chain skills together for complex workflows.
Each skill includes:
skill.yaml- Metadata, inputs/outputs, credentialspipeline-cli.yaml- Standalone CLI pipelinepipeline-mcp.yaml- MCP server integrationtest/test.yaml- Automated tests
# Install Expanso Edge (the node agent)
curl -fsSL https://get.expanso.io/edge/install.sh | bash
expanso-edge version
# Install Expanso CLI (for job management)
curl -fsSL https://get.expanso.io/cli/install.sh | bash
expanso-cli versionBoth tools take a version subcommand. There is no --version flag.
Skills run as Cloud-scheduled jobs, so the binaries alone are not enough. You need a control-plane profile and at least one connected node.
# Endpoint and API key come from https://cloud.expanso.io
expanso-cli profile save my-network \
--endpoint https://YOUR-NETWORK.us2.cloud.expanso.io:9010 \
--api-key exp_ak_YOUR_KEY --select
# On the machine that should run the work:
expanso-edge bootstrap --token YOUR_BOOTSTRAP_TOKEN
expanso-edge run
# The node must show up as connected before anything can be scheduled
expanso-cli node listStart with json-pretty's Cloud variant. It needs no credentials, sends
nothing off the host, and generates its own bounded input, so a remote node can
run it with no further setup.
# Clone the marketplace
git clone https://github.com/expanso-io/skills.expanso.io.git
cd skills.expanso.io
# Validate locally, no control plane needed
expanso-edge validate skills/transforms/json-pretty/pipeline-cloud.yaml
expanso-cli job validate skills/transforms/json-pretty/pipeline-cloud.yaml --offline
# Submit to your control plane; the scheduler assigns it to a matching node
expanso-cli job deploy skills/transforms/json-pretty/pipeline-cloud.yaml
# Confirm it actually ran
expanso-cli job describe json-pretty-cloud
expanso-cli job logs json-pretty-cloudOr straight from the marketplace, without cloning:
curl -fsSL -O https://skills.expanso.io/json-pretty/pipeline-cloud.yaml
expanso-cli job deploy pipeline-cloud.yamlValidation and deployment both passing does not mean the pipeline ran. See Confirm it actually ran.
Why pipeline-cloud.yaml and not pipeline-cli.yaml? The -cli variant
reads stdin, which a Cloud-scheduled node cannot receive from your terminal.
See Providing input.
plugin/ is a Claude plugin that teaches Claude this workflow:
find a proven job, write the job spec, run both validators, deploy, and confirm
execution. It works in claude.ai, Cowork and Claude Code.
# Claude Code
/plugin marketplace add expanso-io/skills.expanso.io
/plugin install expanso@expansoOn claude.ai, add it from Customize > Plugins > Add > Add marketplace with
this repository's URL. See plugin/README.md for what it
does and what it sends.
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"expanso-pipelines": {
"command": "npx",
"args": ["@expanso/mcp-pipelines"]
}
}
}This MCP server provides tools to validate, create, and deploy Expanso pipelines directly from Claude.
Complete jobs, each run end to end. See If you are asked to build....
End-to-end automation combining multiple services.
| Skill | Description |
|---|---|
morning-briefing |
Daily briefing with calendar, weather, news, tasks |
email-triage |
AI-powered email classification and routing |
stripe-reports |
Automated Stripe analytics and reports |
devops-monitor |
Infrastructure monitoring and alerting |
jira-automate |
Jira/Confluence workflow automation |
todoist-automate |
Task management automation |
seo-pipeline |
SEO analysis and optimization |
| View all... |
AI-powered processing for text, images, audio, and video.
| Skill | Description |
|---|---|
text-embed |
Generate embeddings for RAG/semantic search |
text-summarize |
Summarize long documents |
text-translate |
Multi-language translation |
image-analyze |
Vision AI for image understanding |
audio-transcribe |
Speech-to-text transcription |
meeting-notes |
Transcribe and summarize meetings |
| View all... |
Integration connectors for SaaS services and messaging platforms.
| Skill | Description |
|---|---|
slack-read |
Read Slack channel messages via the Slack Web API |
gmail-read |
Read Gmail messages via the Gmail API |
webhook-receive |
Receive and verify webhook events from any service |
Security, compliance, and cryptographic operations.
| Skill | Description |
|---|---|
cve-scan |
Scan SBOM for vulnerabilities |
pii-detect |
Detect PII in text |
pii-redact |
Redact sensitive information |
sign-envelope |
Cryptographically sign data |
secrets-scan |
Detect leaked secrets |
sbom-generate |
Generate software bill of materials |
access-gate |
Deny-by-default permission gateway for agent access |
data-fence |
Field-level filtering to limit agent data exposure |
| View all... |
Data transformation, parsing, and format conversion.
| Skill | Description |
|---|---|
json-* |
10 JSON manipulation skills |
array-* |
15 array operation skills |
string-* |
10 string manipulation skills |
text-* |
12 text processing skills |
date-* |
4 date/time skills |
math-* |
8 mathematical operations |
| View all... |
General utilities and helper functions.
| Skill | Description |
|---|---|
uuid-generate |
Generate UUIDs |
email-validate |
Validate email addresses |
mime-type |
Detect file MIME types |
image-dimensions |
Get image dimensions |
retry-wrapper |
Add retry logic to operations |
| View all... |
Each skill follows this structure:
skill-name/
├── skill.yaml # Skill metadata
├── pipeline-cli.yaml # CLI pipeline definition
├── pipeline-mcp.yaml # MCP server pipeline
├── README.md # Documentation
└── test/
├── test.yaml # Test definitions
└── fixtures/ # Test data
name: text-summarize
version: 1.0.0
description: Summarize long documents using AI
credentials:
- name: OPENAI_API_KEY
required: false # Not required if using Ollama
description: OpenAI API key
inputs:
- name: text
type: string
required: true
description: Text to summarize
- name: max_length
type: integer
default: 100
description: Maximum summary length
outputs:
- name: summary
type: string
description: Summarized text
backends:
- name: openai
type: remote
requires: [OPENAI_API_KEY]
- name: ollama
type: local
models: [llama3.2, mistral]This matters, because earlier versions of this README got it wrong:
expanso-edge runstarts the node agent. It connects to your control plane, registers the node, and executes jobs the scheduler assigns to it. Its--config/-cflag takes agent configuration files. Passing a pipeline to it does not run that pipeline.expanso-edge validate FILE...validates pipeline configs locally, offline. It reads stdin when given-or no file.expanso-cli job deploy FILEsubmits a job spec to the control plane.
There is no supported expanso-edge run <pipeline> form. Execution goes through
the control plane.
# Validate one or more pipeline configs, no control plane required
expanso-edge validate skills/ai/text-summarize/pipeline-cli.yaml
# Validate from stdin
cat skills/ai/text-summarize/pipeline-cli.yaml | expanso-edge validate -
# Validate the job spec client-side
expanso-cli job validate skills/ai/text-summarize/pipeline-cli.yaml --offlineLocal validation checks pipeline syntax, structure and component types. It does not run the orchestrator's submission validation, and it does not prove the pipeline will execute. See Known issues.
# Submit; the scheduler assigns it to nodes matching the job's selector
expanso-cli job deploy skills/ai/text-summarize/pipeline-cli.yaml
# Preview without submitting
expanso-cli job deploy skills/ai/text-summarize/pipeline-cli.yaml --dry-run
# Deploy straight from the marketplace over stdin
curl -fsSL https://skills.expanso.io/text-summarize/pipeline-cli.yaml \
| expanso-cli job deploy -expanso-cli job deploy takes a local file path, or - for stdin. It does
not fetch an HTTPS URL: passing one fails with
failed to read job specification file. Download first, or pipe via stdin.
A successful deploy means the control plane stored the job. Assignment and execution happen afterwards, asynchronously, and can still fail.
expanso-cli job describe <job-name> # job state
expanso-cli execution list --job-id <job-id> # per-node executions
expanso-cli job logs <job-name> # realtime logsA job whose state is degraded has been assigned but is failing at runtime.
Note the flag is --job-id; --job-name and --job are not accepted.
Many skills in this repository declare a stdin input. A stdin input cannot
receive your terminal's input once the job is scheduled onto a remote node --
the node's process has no connection to your shell. stdin skills are usable
only where the pipeline runs attached to a process you control.
For a Cloud-scheduled job, use an input the node can reach on its own, for
example file (a path on the node), http_server, generate, or a message
queue or object-store input. See Known issues.
Skills with pipeline-mcp.yaml are shaped as HTTP endpoints, using an
http_server input and a sync_response output. They are intended to be served
by a node running that pipeline.
The MCP endpoint's advertised address and its operational status have not
been verified for this release. Treat pipeline-mcp.yaml as a definition, not a
running service.
uv run -s scripts/test-skills.py --report /tmp/test-report.jsonThe harness defaults to:
- Reusing cached passing results when inputs and pipelines are unchanged
- Rerunning failed tests up to 3 total attempts
If you have a locally built or pre-release binary, point the harness at it:
EXPANSO_CLI_BIN=/path/to/expanso-cli \
EXPANSO_EDGE_BIN=/path/to/expanso-edge \
uv run -s scripts/test-skills.py --report /tmp/test-report.jsonUseful flags:
--no-cacheto force a full run--no-rerun-failedto disable retries--max-reruns 3to change attempts per test
Credentials are referenced by environment variable from the pipeline definition and are never embedded in it:
export OPENAI_API_KEY=sk-...
export SLACK_WEBHOOK=https://hooks.slack.com/...Two things this does not mean:
- It is not "credentials never leave your machine". A skill that calls a
third-party API sends its credential to that provider.
text-summarizeauthenticates to the OpenAI API withOPENAI_API_KEY;slack-readauthenticates to Slack;gmail-readauthenticates to Google. What is true is that the credential is not sent to Expanso Cloud and is not stored in the pipeline file. - The variable must exist on whichever node runs the pipeline, not on the
machine you ran
expanso-cli job deployfrom. For a Cloud-scheduled job that is the edge node's environment. Exporting it in your own shell does not make it available to a remote node.
Each skill's skill.yaml lists the credentials it references. Only skills with a
dependencies block in skill.yaml (text-summarize and the jobs) have been audited
for what leaves the host, and the catalog publishes that block. For any other
skill, check the pipeline's components: any third-party API component sends its
credential and your data to that provider.
Every row is at its true label. No row is verified-executed. A row may only
be promoted by a dated run record on current Expanso Cloud carrying pinned
versions, control-plane identifiers, and a downstream receipt. Component
availability alone does not promote a row: it establishes that the component
exists, not that the shape runs.
Component availability below was confirmed on 2026-09-17 against the Expanso MCP
documentation server's list_components (236 components) and cross-checked
against live docs.expanso.io component pages.
| # | Pipeline shape | Readiness | Components | Notes |
|---|---|---|---|---|
| 1 | stdin -> mapping -> stdout |
drafted-unverified |
present, Stable | stdin has no input path on a Cloud-scheduled node |
| 2 | http_server -> mapping -> sync_response (MCP) |
drafted-unverified |
present, Stable | endpoint operation unverified |
| 3 | Kafka source -> mapping -> sink | drafted-unverified |
kafka, kafka_franz present, Stable |
never run end to end |
| 4 | input -> mapping -> Kafka sink | drafted-unverified |
kafka output present, Stable |
never run end to end |
| 5 | input -> mapping -> Postgres sink | drafted-unverified |
sql_insert, sql_raw present, Stable |
never run end to end |
| 6 | input -> mapping -> Iceberg sink | not-supported |
no Iceberg component exists | see below |
| 7 | input -> mapping -> object-store sink | drafted-unverified |
aws_s3 present, Stable |
never run end to end |
| 8 | sensor / industrial telemetry -> mapping -> sink | drafted-unverified |
mqtt input present, Stable |
never run end to end |
Row 6 is not-supported, not drafted-unverified. A case-insensitive search
of the full component listing for iceberg, delta, lakehouse and hudi
returns no match, and docs.expanso.io/components/outputs/iceberg/ returns 404.
parquet_encode exists, but writing Parquet into an object store is not an
Iceberg table commit: no catalog registration, no snapshot, no manifest write.
drafted-unverified would imply the shape might work as written; the evidence
contradicts that. This is a demotion on evidence.
Component presence was established against a documentation component listing. It does not establish behavior in a Cloud-managed execution context, which is unproven for every row.
Open items affecting published skills, recorded rather than silently patched.
This distinction matters more than any count, so it is stated first:
| Command | Question it answers | Used by |
|---|---|---|
expanso-cli job validate --offline |
Is this a well-formed job spec? | the repository CI gate |
expanso-edge validate |
Is the inner pipeline config valid? | validation-report.json |
The first does not check component configuration. A pipeline can be accepted
as a job spec and still be rejected by the strict validator for unknown
component fields, bloblang arity errors or wrong value types. In
validation-report.json those two answers are recorded separately, as
job_spec_accepted and validates; a substantial number of skills are
job_spec_accepted: true and validates: false.
A green CI run therefore does not mean the catalog is semantically valid. It means every file was accepted as a job spec.
Settled, offline evidence: expanso-edge validate at v2.1.21 rejects at
least one published pipeline variant (pipeline-cli.yaml, pipeline-mcp.yaml,
pipeline-cloud.yaml, or a recipe's pipeline.yaml) of a number of skills.
Every variant is validated separately. A skill is labelled invalid-does-not-validate in
validation-report.json
if any of its variants is rejected, and is excluded from any "ready"
promotion.
The report is the only source for which skills and how many. Counts and the affected list are deliberately not repeated here, because prose copies go stale silently while the report is drift-checked:
uv run -s scripts/validate-skills.py # regenerate
uv run -s scripts/validate-skills.py --check # fails if the report is staleFor the cli/mcp skills, two causes account for nearly all of them:
Missing required field 'tools'inopenai_chat_completion. The component schema at v2.1.21 requires atoolsfield. Addingtools: [](no tool calling) was verified to satisfy the validator. This repair has been applied only to both pipelines of the promotedtext-summarizeskill; the rest are left untouched and labelled, so the fix can be applied deliberately rather than swept across the catalog.- Bloblang mapping syntax errors, plus one file
(
email-triage/pipeline-cli.yaml) that is not valid YAML at all.
Some skills have both causes, one per variant.
Recipes (skills/recipes/*/pipeline.yaml) fail for different reasons, mostly
component-configuration errors:
- Unknown component fields, such as
max_retries,batching,backoff,compression,storage_classortime_partitioning. - Unknown processors:
try,catchandjson_documentsare not components at v2.1.21. - Wrong value types, where a string (often an env interpolation) is given
for a numeric field such as a rate limit
countorbatching.count. - Bloblang errors, including
letinside an expression-positionif/else/matchbody and wrong method arity.
All 177 published skills carry it. In exploratory testing against Expanso
Cloud v2.1.21 it was rejected at runtime with
codec was not recognised: json_object, while both validators passed and the
deploy succeeded; removing the key (stdout: {}) ran correctly in the same
test. This has not been confirmed on an intended test workspace, so the catalog
has not been changed. Newly authored files here use stdout: {}. If a job
reaches degraded state, suspect its output codec.
A pipeline can pass both validators, be accepted by the control plane, and still
fail when a node runs it. The codec issue above is exactly that. Always check
job describe and execution list --job-id.
See Providing input. Skills whose only input is stdin have
no delivery path on a remote node.
pipeline-mcp.yaml files are definitions. Their advertised endpoint and its
operational status are unverified for this release.
catalog.json carries a generated timestamp of 2026-02-24. Its contents were
checked and are accurate: 177 skills, exactly matching the skills on disk, with
no additions or omissions. The timestamp is stale metadata, not stale data.
We welcome contributions! See CONTRIBUTING.md for guidelines.
-
Use the template:
cp -r _template skills/category/my-new-skill
-
Update
skill.yamlwith your skill metadata -
Implement the pipeline in
pipeline-cli.yamlandpipeline-mcp.yaml -
Add tests in
test/test.yaml -
Submit a PR!
- Keep skills focused and single-purpose
- Support both remote (OpenAI) and local (Ollama) backends when possible
- Include comprehensive tests
- Document all inputs, outputs, and credentials
- Follow naming conventions:
category-action(e.g.,text-summarize,json-validate)
The marketplace provides a JSON catalog for programmatic access:
# Full catalog with all metadata
curl https://skills.expanso.io/catalog.json
# Minimal catalog (just names and categories)
curl https://skills.expanso.io/catalog-minimal.json
# Per-skill validation status and readiness labels
curl https://skills.expanso.io/validation-report.json
# Agent-oriented summary of the invocation and dependency contracts
curl https://skills.expanso.io/llms.txtvalidation-report.json is generated by scripts/validate-skills.py and records
what the local validator says about every published pipeline, with the tool
version it was produced against:
uv run -s scripts/validate-skills.py # regenerate
uv run -s scripts/validate-skills.py --check # fail if results driftedIts readiness vocabulary caps at validated-not-executed. Nothing reaches
verified-executed without a dated Expanso Cloud run record. The report itself
carries the current totals and the validator version they were produced against;
they are not duplicated in this prose -- see Known issues.
{
"version": "1.0.0",
"total_skills": 177,
"categories": {
"ai": {
"description": "AI-powered skills...",
"skill_count": 23,
"tags": ["ai", "ml", "llm"]
}
},
"skills": {
"text-summarize": {
"name": "text-summarize",
"version": "1.0.0",
"description": "Summarize long documents",
"category": "ai",
"credentials": [...],
"inputs": [...],
"outputs": [...],
"backends": ["openai", "ollama"],
"tags": ["ai", "local", "openai", "remote", "text"],
"dependencies": {"offline_capable": false, "...": "..."}
}
}
}dependencies is copied verbatim from skill.yaml and is present only for
audited skills. The offline tag is set only when a skill declares
dependencies.offline_capable: true, or declares only local backends.
docs/js/analytics.js sends browser page views and clicks on
skills.expanso.io to Expanso's PostHog project through web.t.expanso.io, with
the same privacy defaults as docs.expanso.io. The site loads no other
analytics: scripts/check-site-tags.py fails the build if the retired Google
Tag Manager container or the old ph.expanso.io proxy comes back.
It only sees visitors whose browser runs the script. It does NOT show
whether pages are indexed, whether agents fetch llms.txt or pipeline
files directly, whether install.sh runs, or whether any skill is deployed
or executed. Those need request logs or Cloud-side data, which this site
does not collect.
MIT License - see LICENSE for details.
Built with love by Expanso