Clay routines — create a routine from an existing function/workflow, then run a saved routine that exists in this workspace. Use when the user asks to create/register a routine, or to run, execute, or trigger a function, workflow, or routine (by name or id), pass it inputs, or check the results/status of a run. For building a new workflow, use the workflows entry-point skill instead.
Installs into .claude/skills of the current project.
Are you the author of Routines?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/clay-run-routines)
---
name: routines
description: Clay routines — create a routine from an existing function/workflow, then run a saved routine that exists in this workspace. Use when the user asks to create/register a routine, or to run, execute, or trigger a function, workflow, or routine (by name or id), pass it inputs, or check the results/status of a run. For building a new workflow, use the workflows entry-point skill instead.
---
# Running Clay routines
A **routine** is the runnable unit in Clay: a saved **function** or **workflow** that
already exists in this workspace. This skill is about _running_ an existing routine and
getting its results — not building one.
- To **build or edit** a workflow, use the workflows entry-point skill.
- If no existing routine matches a request for custom Claygent or LLM work, use the
`/workflows-claygent` skill to build and run it.
- To **query data** out of a Clay table, use the tables entry-point skill.
- To **find the records** to run a routine over, use the `searches` skill for net-new people
or companies, or the `audiences` skill for members of a saved audience, then feed the
results in here.
- To **write people or companies into Audiences**, run a routine whose underlying
workflow contains `upsert-audiences-record` (for example, to persist Search results).
Items pipe in the same as other runs, using `workflow:<id>` instead of `function:<id>`.
If no such workflow exists, build it via the `workflows` skill's
`audiences.md`, then `clay routines create workflow`.
- To run a routine **over HTTP** from a service or app (not a one-off shell task), use
the `public-api` skill.
Routines run **asynchronously**: you start a run, then poll for results.
## 1. Find the routine
Don't assume a routine id. List what exists and match the user's request to one:
```bash
clay routines list # routines in this workspace
clay routines get <id> # full config and input schema
```
`clay routines list` is **paginated** — a workspace can have far more routines than one
page. Page through with `--cursor` until the response has no `cursor` before concluding a
routine doesn't exist. Each routine carries a `source` field in the response — `list` has no
filter flag, so filter client-side (e.g. `| jq '.data | map(select(.source == "managed"))'`).
`managed` routines are Clay's built-in enrichers
(emails, domains, firmographics) and should be your first choice for standard enrichment;
`custom` are workspace-built. Decide by **input schema**, not name — e.g. the managed
**Work Email** routine needs Full Name + Company Name + Company Domain, so resolve the
domain first with the managed **Company Domain** routine when you only have a company name.
`clay routines get <id>` is important before running: it shows the routine's **input
schema** so you know exactly which fields each item needs.
### Link the user to the underlying function or workflow
Whenever you show the user a routine — from `clay routines list` or `clay routines get` —
give them a link to open its underlying object in the Clay app so they can inspect or edit
it. This matters most in a headless environment (Claude Code, Cursor, a shell) where the
user has no Clay tab open.
A routine id encodes the object it wraps: `function:<tableId>` wraps a table,
`workflow:<workflowId>` wraps a workflow. Split off the id after the `:` and combine it
with the workspace id (`clay whoami | jq -r '.workspace.id'`) to build the link:
- **Function** (`function:<tableId>`) → `https://app.clay.com/workspaces/<workspaceId>/tables/<tableId>`
- **Workflow** (`workflow:<workflowId>`) → `https://app.clay.com/workspaces/<workspaceId>/terracotta/tc-workflows/<workflowId>`
For **function** routines, both `list` and `get` return a `source` (`managed` for a
Clay-managed default function, `custom` for one built in this workspace) and, for custom
functions, a `createdBy` (`{ id, name, email }`; `null` for managed ones). Use these to tell
the user which functions are Clay-managed vs. their team's own, and who authored a custom
one — e.g. group them by `source`, or note the author when disambiguating similar functions.
### Create a routine from an existing function or workflow
If no routine exists yet for a function (a table) or a workflow, expose it as a runnable
routine with `create`. This registers the underlying object as a routine.
```bash
clay routines create function <tableId> --name "My contact routine" --entity-type contact
clay routines create workflow <workflowId> --name "My workflow routine"
```
- `type` is `function` or `workflow`; `objectId` is the table id (function) or workflow id.
- `--name` is **required** for both types.
- `--entity-type` (`contact` or `company`) is **required** for function routines and rejected
for workflow routines.
- The routine id is built from the type and object id, e.g. `function:t_abc`.
Use `clay routines update <id>` to change a routine's name, description, or entity-type
later. See `clay routines create --help` / `clay routines update --help` for the full flags
and JSON shape.
## 2. Check the cost and your balance before running
Before starting a run, inspect its estimate and the workspace balance internally. Follow
the shared cost policy in `workflows-discover-actions/cost-and-budget.md` for disclosure and confirmation; ordinary authorized
runs do not need a cost-only check-in. `clay routines get <id>` includes a per-item estimate;
`clay credits balance` returns the remaining balance.
```bash
clay routines get function:t_abc123 | jq '.estimatedCreditCost'
clay credits balance | jq '{ balance, actionExecutionBalance }'
```
There are **two independent budgets**, and a run needs enough of each:
- `estimatedCreditCost.perRun` is charged against the data-credit `balance`.
- `estimatedCreditCost.actionExecution` (when supplied) is charged against the separate
`actionExecutionBalance` on action-execution pricing plans. A workspace can have plenty
of `balance` but no action executions left — enough of one budget does not cover the other.
A missing or null `actionExecution` does not identify the plan: it means the workspace is
on legacy billing **or** the estimate carries no priced action executions. Whether
`clay credits balance` returns `actionExecutionBalance` is what tells the plans apart —
present means action-execution pricing, absent means legacy.
For how to read the balance and how the cost fields work, see the help text:
```bash
clay credits balance --help
```
Only multiply per-item costs when they apply to the configured execution and all relevant
execution counts are known. Workflow estimates count nodes once and can omit branching
and fan-out; `containsVariablePricing: false` does not establish completeness. Do not turn
an incomplete base estimate into a total, even by labeling it approximate.
If a supported estimated total for **either**
budget exceeds its matching balance — `perRun × items > balance`, or
`actionExecution × items > actionExecutionBalance` — stop and tell the user instead of
starting a run that will only partially complete.
Undefined, null, incomplete, or inapplicable costs are unknown, not free. If asked, explain
that the total cannot be reliably estimated; otherwise continue within the authorized scope.
### Running low? Share a top-up link
When supported pricing shows insufficient balance, or a real billing failure occurs, read the
`credits-quotas-plans` skill and follow it for CLI top-up, auto top-up, and
billing UI options.
## 3. Run it
Start an async run, passing inputs per item:
```bash
clay routines runs start <id> # see --help for how to pass items/inputs
```
- A single inline run takes **1-100 items**; each item is a set of `inputs` matching the
routine's input schema.
- For larger sets, routines support a **batch** run over an uploaded JSONL file.
Run `clay routines runs start --help` for the exact flags, the input/JSON shape, and how
to supply items.
## 4. Get the results
Runs are asynchronous. Prefer a single blocking call with `--wait` instead of hand-rolling a
poll loop:
```bash
clay routines runs get <run-id> --wait 60 # poll until complete / validation_failed / processing_failed, or 60s
clay routines runs get <run-id> --bulk --wait 60 # same for a bulk run (skip the inline probe)
clay routines runs get <run-id> --wait # poll until complete / validation_failed / processing_failed (no budget)
clay routines runs get <run-id> # single request (may still be in_progress)
clay routines runs get <run-id> --bulk # look up as a bulk run (bare flag, no value)
clay routines runs list # recent runs and their statuses
```
Check `.status` on the JSON before treating the run as done. With bare `--wait`, the command
blocks until `complete`, `validation_failed`, or `processing_failed`. With `--wait <seconds>`, if the budget expires
while still `in_progress`, the command exits 0 with that latest status — do not assume success.
Prefer a bounded `--wait <seconds>` for bulk runs: a bulk run that was stopped keeps reporting
`in_progress`, so bare `--wait` can wait forever.
Every response carries a `mode` of `inline` or `bulk`, and so does the output of
`runs start`. When it is `bulk`, pass `--bulk` on `runs get` so the run is looked up directly.
If you don't know the mode — a run id you were handed, or one from `runs list`, which does not
report it — omit `--bulk`; the response tells you the mode.
A completed bulk run reports a `resultUrl` rather than inline `data`. That URL is short-lived
(minutes) — download it promptly, and re-run `runs get --bulk` to mint a fresh one rather
than reusing a stale link. Results stay retrievable for about a day after the run finishes,
after which the id stops resolving.
Per-item results come back with a status (`complete` / `failed`) and either a `result`
or an `error`.
`clay routines runs get` returns a single page of inline results. Since an inline run
has at most 100 items, `--limit 100` returns every result in one page. If you use a
smaller page size, the response includes a top-level `cursor` when more results remain —
pass it back via `--cursor` to fetch the next page.
## Authoritative details
```bash
clay routines --help
clay routines <cmd> --help
```