Actana

Queries

Reference rows from a workflow or inference call — operations, filters, and sorts.

ScreenshotTable block configured with a filter + sort.

The Table block is how a workflow reads from and writes to Tables. The same query semantics are exposed by the Tables REST API and through the actana_tables skill that the Assistant and Crew agents use.

Operations

The block exposes a single operation parameter — pick one of:

OperationWhat it does
readReturn rows matching a filter. Optional sort, limit, offset.
read-rowReturn a single row by rowId.
insertInsert one row from a data object.
bulk-insertInsert many rows from a rows array.
updateUpdate a single row by rowId with a data patch.
bulk-updateUpdate every row matching a filter with a data patch.
deleteDelete one row by rowId.
bulk-deleteDelete every row matching a filter.

The operation determines which sub-blocks are visible in the UI — rowId is required for the row-scoped operations, filter is required for the bulk operations.

Filters

Filters are evaluated against the JSONB data column. The block accepts two input modes:

  • Builder (basic) — UI filter rows, internally compiled to the same shape as JSON mode.
  • JSON (advanced) — pass a filter object directly. Useful when constructing filters from upstream block output.

A filter is a tree of conditions. A leaf condition is { column, op, value } where op is one of eq, neq, gt, gte, lt, lte, contains, starts_with, ends_with, in, is_null, is_not_null. Branch nodes are { all: [...] } (AND) or { any: [...] } (OR).

{
  "all": [
    { "column": "status", "op": "eq", "value": "active" },
    { "any": [
      { "column": "score", "op": "gt", "value": 80 },
      { "column": "vip", "op": "eq", "value": true }
    ]}
  ]
}

The block converts builder rules to this shape via filterRulesToFilter from lib/table/query-builder/converters.ts.

Sorts

Sorts are an array of { column, direction } entries applied in order. direction is asc or desc. Builder mode emits the same shape via sortRulesToSort.

[
  { "column": "createdAt", "direction": "desc" },
  { "column": "name", "direction": "asc" }
]

Limit + offset

Both are integers passed as block params (the UI accepts strings and the params transformer coerces them at execution time). The block enforces a hard ceiling from TABLE_LIMITS in lib/table/constants.ts.

Referencing block outputs in JSON

When constructing filters or data payloads from another block's output, wrap the reference in quotes:

// ✓ Good
{ "column": "email", "op": "eq", "value": "<signupForm.email>" }

// ✗ Bad — invalid JSON, the parser hint will surface this
{ "column": "email", "op": "eq", "value": <signupForm.email> }

The block's parseJSON helper (in blocks/blocks/table.ts) detects the unquoted-reference pattern and surfaces a specific error message before the run proceeds.

Bulk operations are atomic at the row level — a partial failure in one row does not roll back others. If you need transactional semantics across many rows, build a workflow that runs the operations sequentially and writes a status column.

Source

  • apps/actana/blocks/blocks/table.ts — block definition + JSON parsing
  • apps/actana/lib/table/query-builder/converters.ts — builder → filter/sort shape
  • apps/actana/lib/table/constants.tsTABLE_LIMITS
  • apps/actana/tools/table/types.tsTableQueryResponse
  • apps/actana/app/api/v1/tables/[tableId]/ — REST endpoints

On this page