Actions and the catalog
Typed provider operations installed with swirls add. Browse the integration catalog, install action blocks, generate them from any API spec, and request new providers.
What it is. An action block declares a typed provider operation: the HTTP transport plus input and output JSON schemas and the OAuth scopes the call needs. Actions never hold credentials; they pair with a connection at run time.
Use it when a workflow or agent calls a third-party API and you want the call typed, scoped, and reviewable in the file instead of hidden in a fetch.
Works with type: integration nodes, connections, and the swirls add CLI command.
The integration catalog
The catalog at swirls.ai/catalog lists every curated action you can install. Today it covers four providers:
| Provider | Actions | Coverage |
|---|---|---|
| Slack | 1 | Post messages to channels, DMs, and conversations. |
| GitHub | 8 | Repos, issues, and pull requests. |
| Linear | 7 | Issues, comments, teams, and viewer. |
| Microsoft Graph | 106 | Mail, calendar, contacts, OneDrive, OneNote, Teams, and SharePoint. |
These are the providers with curated actions today, not the limit of what Swirls can reach. The same brokered OAuth framework supports any provider: Discord and LinkedIn are already brokered for channels, swirls add generates actions from any OpenAPI or GraphQL spec, and self-managed connections cover any API you hold credentials for. See Request a provider below.
Install actions with one command:
swirls add slack # every curated Slack action
swirls add linear create_issue # one Linear action
swirls add microsoft send_mail list_calendar_eventsswirls add writes action blocks to swirls/integrations/<provider>/ and records source, version, and checksum in swirls.lock.json. Override the registry with --registry or SWIRLS_REGISTRY_URL.
Action blocks
Installed actions are ordinary .swirls blocks. You can read them, review them in a PR, and write your own by hand.
action slack_post_message {
label: "Post message"
provider: slack
method: POST
path: "/chat.postMessage"
encoding: form
scopes: ["chat:write"]
input: @json { { "type": "object", "required": ["channel", "text"], "properties": { "channel": { "type": "string" }, "text": { "type": "string" } } } }
output: @json { { "type": "object", "required": ["ok"], "properties": { "ok": { "type": "boolean" } } } }
}| Field | Type | Required | Description |
|---|---|---|---|
provider | identifier | Yes | Must match the bound connection's provider. |
method | identifier | Yes | GET, POST, PUT, DELETE, or PATCH. |
path | string | Yes | Provider API path (leading / optional). Supports {param} substitution from the input. |
encoding | identifier | No | json (default), form, query, or raw. |
document | string | No | GraphQL query or mutation (requires method: POST; not combined with input/output). |
input / output | schema | No | Inline @json, object literal, or a bare schema name. Drives typed params and node output. |
scopes | string array | No | OAuth scopes the action needs. |
label, description | string | No | Display metadata. |
raw encoding sends the content input verbatim as the request body, with an optional contentType input setting the MIME type. The Microsoft Graph file-upload actions use it.
GraphQL actions carry a pre-authored document instead of input and output schemas; the LSP types them from the schema.graphql sidecar that swirls add writes beside the actions.
Using an action in a workflow
A type: integration node names a connection and an action. Deploy inlines the transport and schemas from the action block, so params: and the node output are checked against them.
connection team_slack {
label: "Team Slack"
provider: slack
}
node post_slack {
type: integration
label: "Post to Slack"
connection: team_slack
action: slack_post_message
params: @ts {
return {
channel: context.nodes.root.output.channel,
text: context.nodes.root.output.text,
}
}
}The platform issues a short-lived provider token for the bound account and proxies the call. No provider credentials exist in the file, the vault, or the node. Full node reference: integration nodes.
Any API, not just the catalog
swirls add also accepts a URL. Point it at an OpenAPI or GraphQL spec and it generates the same typed action artifacts the catalog ships:
swirls add https://api.linear.app/graphql --only viewer
swirls add https://petstore.example.com/openapi.jsonURL imports scaffold a connection file once if one is missing. Pair the generated actions with a self-managed connection (base_url plus auth) and the runtime calls your API with credentials from the project vault.
Request a provider
Managed OAuth for a provider we don't broker yet is a request away:
- Declare the connection anyway:
connection my_crm { provider: salesforce }. Validation warns that the provider is not in the catalog but the file still passesswirls doctor. - Deploy with
git pushorswirls deploy. The slot appears on the project's Connections page. - Click Request support on the slot and tell us which scopes or capabilities you need. We prioritize enabling it and follow up by email.
Prefer to talk first? Email [email protected] with the provider name. Self-managed connections work immediately in the meantime, so a request never blocks shipping.
Common mistakes
- Setting
method:orpath:on a node that usesaction:. The action block owns the transport. - Editing installed action files in place and re-running
swirls add. The checksum inswirls.lock.jsontracks the installed version; copy the block out under a new name if you want to customize it. - Combining
documentwithinput/output. GraphQL actions type through theschema.graphqlsidecar, not inline schemas. - Calling the provider with
fetchfrom a code node. Code nodes never see connection credentials; use an integration node.
Further reading
- Connection blocks: the credential slots actions pair with
- Integration nodes: full node reference
- Channels: connections behind chat platforms