Automations and playbooks
Make work repeatable. A playbook is the work you can run again, an automation decides when it runs, and capabilities are the tools both use.
Three pieces compose every repeatable process on a pod:
| Piece | Answers | What it is |
|---|---|---|
| Capability | With what? | A tool the pod can run: a verb such as "send an email" or "search the web". |
| Playbook (a template in the apps) | What? | The reusable work: a goal, optional stages and acceptance criteria. Each run is a session that an agent works on. |
| Automation | When? | A trigger (an event, a schedule, an incoming webhook or a manual start) and a flow of steps. A step can call a verb or start a playbook. |
Keep them apart: an automation should not hold the work itself, and a playbook should not decide when it runs.
Playbooks
A playbook needs a name and a goalTemplate. It can also declare:
params: inputs asked for when it runs, referenced in the goal as{name}(for exampleAnalyze competitors for {market}). An undeclared name, or{{name}}, is refused.stages: ordered steps, each with akey, anameand acategory(backlog,planned,started,paused,completedorcanceled), and optionally a gate where a person must say yes.criteria: binary statements every run is graded against.- a subject kind: the kind of record it runs on, such as a company or a lead.
Create one
- Your agent: ask for it.
synap_create_playbookfiles it as a proposal you approve. An agent can also turn a session that went well into a playbook withsynap_promote_session_to_playbook. - The API:
POST /api/hub/playbookswithname,goalTemplateandworkspaceId, plus any ofdescription,stages,params,criteriaandsubjectProfile(for example{ "profileSlug": "company" }). See Playbooks in the Hub REST API. - A template: workspaces from the marketplace bring their own playbooks.
Run one
synap playbook run "<name or id>" --subject <entityId> --param market=EuropeYour agent runs one with synap_run_playbook, and the API with POST /api/hub/playbooks/{id}/run (subjectId,
params, workspaceId). A run creates a session and hands it to the playbook's executor. It can come back:
| Status | Meaning |
|---|---|
running | It started. |
draft | An agent launched it: it waits in your sessions until you accept it. |
proposed | A rule or a limit asks you first. |
blocked | Nothing ran: the playbook uses verbs that are not turned on yet. The answer names them. |
skipped | Nothing ran, for the reason in message (for example, the record's last run failed recently). |
Let a goal run on its own
A playbook can declare workers: what starts it by itself. Your agent turns one on for a goal with
synap_enable_worker, named by its trigger: schedule:<cron> (for example schedule:0 9 * * 1, every Monday at
09:00 UTC), enters_status:<status> (when a record enters that status), count:<status> (when enough records are in
it) or created. Its mode says whether each run asks you first (propose, the default) or just runs (run).
Automations
Triggers
| Trigger | Fires | Settings (triggerConfig) |
|---|---|---|
event | When something happens on the pod | eventPattern, such as entity.create.completed or entity.*, and optional filters on the event's data, such as { "profileSlug": "company" } |
cron | On a schedule | expression, a 5-field cron expression such as 0 9 * * MON |
webhook | When an outside service posts to the pod | webhookSource: { "name": … }, an inbound webhook source a pod admin created. See Import your data. |
manual | When you start it | none |
Match events in the .completed phase: it fires for every change that lands, whether it ran directly or was
approved. The .validated phase fires only for changes that went through a proposal.
Filters compare values exactly, or with $eq, $ne, $in, $gt, $gte, $lt and $lte. A record's properties
are flat in the event data: filter on score, not properties.score.
The flow
The flow is a set of nodes joined by edges. It starts at its trigger node. The steps you will use most:
| Step | Does |
|---|---|
output | An action: a notification, a record created or updated, a role attached, a relation, a webhook call, a channel message, or a session update |
condition, switch | Branch on a value |
fetch | Call a URL |
transform, compute | Reshape or compute values |
query, entity_read, related_entities | Read records |
loop | Repeat steps for each item |
capability | Run a verb (its verbId must exist on your pod) |
skill | Run a skill by ID |
playbook_run | Start a run of a playbook, by playbookId or playbookName. This is how an automation starts a session. |
sub_automation | Run another automation |
Text in a step can use the trigger and earlier steps: {{trigger.payload.subjectId}} (the record the event is about),
{{trigger.payload.data.title}}, {{steps.<nodeId>.output}}. The full reference, with every step type and its
fields, is served by your pod:
synap automation schema # or GET /api/hub/automations/schemaCreate and manage one
- Your agent:
synap_create_automation. It is always a proposal; once approved, the automation is live. An agent's automation must also carry a short contract of what it reads, stores and does (metadata.dataContract, below), or it is refused. - The API:
POST /api/hub/automations/createwithname,triggerType,triggerConfig,flowDefinition,workspaceIdandstatus(draftby default, oractive). See Automations in the Hub REST API.
synap automation list
synap automation describe <id>
synap automation enable <id> # make it live
synap automation disable <id> # pause itTo run one now, outside its trigger: synap_trigger_automation for an agent, or
POST /api/hub/automations/{automationId}/trigger. A run is not a proposal, but every write its steps make goes
through the same governance as any other write.
Example: research every new company
This puts the three pieces together: when a company is added to your pod, start a research session on it, in which an agent can use the search capability you installed.
Install the tool. Install a web search capability from the marketplace and turn it on, then check the name of its search verb:
synap capability add
synap capability listCreate the playbook (the work). With a key that has the hub-protocol.write scope:
curl -X POST https://pod.example.com/api/hub/playbooks \
-H "Authorization: Bearer $SYNAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "<workspace id>",
"name": "Research a company",
"goalTemplate": "Research this company on the web and record what it does, who runs it and recent news",
"subjectProfile": { "profileSlug": "company" }
}'The automation below refers to the playbook by name, so the playbook must exist first. If an agent created it, approve its proposal before the next step.
Create the automation (when). It listens for new company records and starts a run of the playbook on each one:
curl -X POST https://pod.example.com/api/hub/automations/create \
-H "Authorization: Bearer $SYNAP_API_KEY" \
-H "Content-Type: application/json" \
-d @research-new-companies.json{
"workspaceId": "<workspace id>",
"name": "Research new companies",
"triggerType": "event",
"triggerConfig": {
"eventPattern": "entity.create.completed",
"filters": { "profileSlug": "company" }
},
"status": "active",
"flowDefinition": {
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"position": { "x": 0, "y": 0 },
"data": {
"triggerType": "event",
"label": "A company is added",
"config": { "eventPattern": "entity.create.completed" }
}
},
{
"id": "run-1",
"type": "playbook_run",
"position": { "x": 0, "y": 200 },
"data": { "label": "Research it", "playbookName": "Research a company" }
}
],
"edges": [{ "id": "e1", "source": "trigger-1", "target": "run-1" }]
},
"metadata": {
"dataContract": {
"version": 1,
"mode": "react",
"gets": [
{
"id": "new-company",
"label": "A company is added to the pod",
"nodeIds": ["trigger-1"],
"origin": "synap",
"event": "entity.create.completed"
}
],
"stores": [],
"reacts": [
{ "id": "research", "label": "Start a research session on it", "nodeIds": ["run-1"], "kind": "process" }
]
}
}
}The dataContract is required only when an agent creates the automation; it is harmless otherwise. Its mode must
match its sections: react has reacts and no stores, ingest the opposite, ingest_and_react both. Every
nodeIds entry must name a node of the flow.
Try it. Add a company. The run's session is about the new record (the automation passes the record the event is about as the session's subject), and the agent working on it can use the capabilities your pod has, under the same governance as any other agent run.
To call the search verb directly from the flow instead of leaving it to the agent, add a capability step with
verbId set to the verb's name and an inputMapping such as { "query": "{{trigger.payload.data.title}}" }.
Related
- Capabilities
- Validation policy
- Event catalog
- Webhooks, for the pod to call your URL when something changes
Capabilities
What a capability is, how to see what your pod has, install and run one from an app, an agent or the API, and make your own.
Import your data
Every way to bring data into a pod (files, notes, connected accounts, webhooks and your own scripts) and which of them you review before anything lands.