mcpField
A
actions

actions

github.com/revosaiMarketing & growth0112 installsUpdated 5d ago
Repository

About actions

A RevOS MCP server skill for inspecting integration actions and diagnosing their runs. It guides agents from run results and organization-specific error instructions to the cause, while limiting unnecessary payload reads.

Key features

  1. 01Inspect action catalogue and details
  2. 02List and inspect action runs
  3. 03Read organization error instructions
  4. 04Trace failures from run results
  5. 05Run an action column when requested

Use cases

  1. 01Find recent failures for a record
  2. 02Explain an action run error
  3. 03Check an action's expected inputs
  4. 04Execute an action column on a row

MCP support

Uses the RevOS MCP server's generic api_read and api_write tools to access actions and runs. It describes the exposed action-run operations and their cautious use.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/revosai/skills --skill actions

After installing, type/actionsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

evals/
evals.json
references/
debug.md
run.md
sync-now.md

Details

From the project README

Actions

Three things share the name, and telling them apart is most of the work:

  • An action is one operation of an integration against one object: "NetSuite upsert customer", "Enrich name". The catalogue is the actions resource; each has an id and an integrationName.
  • An action column is an action wired into a table: which action, its params, and the input mapping that says which of the row's columns feed it. It lives in the table's objectsColumns (the tables skill covers adding and changing one).
  • An action run is one execution of one action column against one row. A run is stored once an attempt finishes, so its status is always COMPLETED or FAILED (the API's enum lists ACTIVE, DELAYED, WAITING too, but no run is saved with them). Runs are kept for 14 days.

You reach them through the RevOS MCP server's generic tools:

CallWhat it does
api_read { "resource": "actions", "params": { "fields": "id,name,integrationName" } }the catalogue; add "onlyUsed": "true" for the ones a table uses
api_read { "resource": "actions", "id": "<action id>" }one action: name, description, integrationName
api_read { "resource": "actions", "id": "<action id>", "method": "errorInstructions" }what this organization wrote about that action's errors
api_read { "resource": "action-runs", "params": { … } }list runs: filter, orderBy, fields, pageSize
api_read { "resource": "action-runs", "id": "<run id>" }one run, with its input and result
api_write { "resource": "action-runs", "data": { "tableId": "…", "columnId": "…" } }run an action column — see references/run.md first

The calls in this skill are complete as written: go straight to them. api_search and api_details are for when one of them is refused, or you need a filter or field this skill doesn't name.

Something failed: start from the run

Most questions here are "why did this fail". Work in levels and stop at the first one that answers the question: a failure whose cause is already named in the run's own result doesn't need the table's schema, and pulling it anyway costs the user a slower answer buried in detail they didn't ask for.

Find the run. The user may hand you a run id straight from the action-run drawer in the UI. More often they name a record — "deal 31415926535", a company, a contact. That id is the row's objectId: a row usually carries the id its record has in the source system. It is not unique: the same record can be a row in several tables, and a row has an action column per action (a sync to NetSuite next to a write-back to HubSpot), each with its own runs. So list the record's newest runs first, without their payloads (one run's input and result can be thousands of tokens):

api_read { "resource": "action-runs",
           "params": { "filter": "objectId == \"<record id>\"",
                       "orderBy": "createdAt desc", "pageSize": 5,
                       "fields": "id,actionId,columnId,modelId,objectName,status,createdAt" } }

Add && modelId == "<table id>" to the filter when you know the table. Then take the newest run of the action column the question is about (modelId, columnId) and read that run by id. If it is COMPLETED, the record is not failing any more: say so. If the runs span several tables or action columns and the request doesn't say which one ("to NetSuite"), name them and ask.

With neither a run id nor a record, list the failures without the payloads:

api_read { "resource": "action-runs",
           "params": { "filter": "status == \"FAILED\" && modelId == \"<table id>\"",
                       "orderBy": "createdAt desc", "pageSize": 10,
                       "fields": "id,actionId,columnId,modelId,objectId,objectName,status,attemptsMade,createdAt" } }

modelId is the table's id. Narrow with columnId or objectId when you know them.

Read the run by id. One call, and it carries the spine as well as both payloads: actionId, columnId, modelId, objectId, objectName, status, attemptsMade, input and result.

Read the organization's error instructions for the run's actionId. This is the next call after the run, every time, however clear the error already looks: api_read on actions with that id and method: "errorInstructions", described below. They often map the error message straight to its cause and fix, and say who fixes it.

Where the error lives. There is no separate error column. result holds the whole run result, a union discriminated by metadata.success. On a failure it carries:

  • metadata.error.message — the message to trust and to quote. When it is a bare HTTP status line ("Request failed with status code 400"), the vendor's own message is in error.details.response.data; quote that;
  • metadata.error.aiMessage — an AI rewording generated automatically when the failure was saved (paid plans, under a daily cap). The table cell shows it, as ❌ <aiMessage>, so error text the user copied from a cell is usually this rewording, not the system's message. Never present it as the system's own error;
  • error — a normalized object with message, code, details, isUnrecoverable and retryAfter.

error.isUnrecoverable: true means the framework stopped retrying: any HTTP 4xx other than 429, input that failed validation, or an action that said so. Re-running unchanged fails the same way; it can work once the cause is fixed.

A large share of failures are fully explained right here — credentials the target system rejected, a permission, a validation message that already names the field and the reason. When result, read together with the organization's instructions, says something the user can act on, that is the answer: quote it, say what to do, stop.

When the id doesn't resolve. api_read by id answers data: null rather than a 404. (The id may also be the run's jobId, which the cell's metadata.jobId carries — both resolve.) A table cell goes on showing a failure long after the run behind it was removed, so an id can name a run older than the 14-day window. Say so and stop — no page of action-runs can contain it. If the user quoted the error text, that text is still worth reading back to them. Then offer what does work: re-run the action and diagnose the fresh failure.

When the run alone doesn't answer — the error is about a value that was missing, empty or malformed, or the user asks where a value should have come from — go on to references/debug.md: the mapping, the lineage, and how to say where the fault is.

The organization's error instructions

Organizations write down what their actions' errors mean and how they are fixed: what a particular NetSuite error really means for them, who fixes what, how a link to their CRM is built. Read them once for each failed run you diagnose, by the run's actionId:

api_read { "resource": "actions", "id": "<the run's actionId>", "method": "errorInstructions" }

It returns three texts, each null when nothing was written:

  • global — applies to every action in this organization;
  • integration — every action of this action's integration;
  • action — this action alone.

They add up rather than override one another: the action-level text assumes you've read the integration-level one.

They are where a convention that makes your obvious recommendation wrong lives. When they give wording, a link format, or an owner for the fix, use theirs. If all three are null, the organization wrote nothing for this action; carry on without them. If the read itself is refused, don't retry: carry on from the run, and say you couldn't read them.

Running an action

Running acts on connected systems — it creates and updates records in the customer's CRM or ERP — so only do it when the user asks, and read references/run.md before the first api_write on action-runs.

Syncing

"Sync" means two things: ingestion, a connection pulling a source system into RevOS ("sync HubSpot"), and activation, an action pushing a row out ("sync this deal to NetSuite"). Ingestion is the connections skill. For one record synced now from an id or a link, check the record in its cube first. Ingest its source only if RevOS doesn't have it or the user just changed it there, then run the action for that one row. Read references/sync-now.md for that.

Adding or changing an action column

That is a change to the table, not to the action: the tables skill, its column reference. The catalogue here tells you which actionId to use and, through the action's description, what input it expects.

Reporting back

Lead with the cause in the user's terms, then what to do about it and who does it. Quote metadata.error.message verbatim when the fix involves a third party — a paraphrased vendor error is worse than useless when the user takes it to that vendor's support. Name the row by objectName, not by id. Don't dump input or result.

Comments

Markdown supported