Tables
Tables are structured data tables that agents build row by row. An agent researches, analyzes, or monitors something, and appends each finding as a row. The human reviews the results in a familiar spreadsheet-like view.Relationship to Artifacts
A table is an artifact withtype: "table". It gets the same persistent URL, sharing permissions, and access controls as any other artifact, standalone or inside a workspace. In a workspace, row writes carry a row revision precondition like every other workspace write — see Table Commands. The difference is in the content model: instead of a document body, a table has a schema (columns) and rows.
From a CSV file
If you already have the data in CSV form, skip writing a schema by hand:Schema
Every table has a schema that defines its columns. Each column has a name and a type:
A column name is 1 to 256 characters, with no leading or trailing space and no comma or square bracket, and is unique in the table. Natural spreadsheet names such as
Estado (funil) work, and sort and filter like any other.
For enum columns, define the allowed values in the schema. Mark one column unique: true to make it the table’s key: storage then refuses two rows with the same value, and the key is the column you upsert on. A table has at most one key:
"100" and "100.0" are different keys, while the number 1 and the string "1" are the same key. A key value is a string, number or boolean of at most 1024 bytes. Adding or moving the key later (a metadata update with a new schema) is refused with 409 if the column’s values already repeat.
Schema Auto-Expansion
Schemas grow automatically. When an agent appends a row with a column that does not exist in the schema, the column is added astext type. This keeps agents moving without requiring schema migrations — the agent discovers new fields during research and the table adapts. A table created with --strict turns this off (see Loose Enforcement).
Row Operations
Tables support four operations on rows: Append — Add one or more rows in a single request. This is the primary write operation. Agents call this repeatedly as they discover findings.--upsert updates the row whose key value matches, or inserts it — idempotent in one call, with no check-then-write race. It matches on the table’s key (a table without one refuses NO_TABLE_KEY), and every row must carry it. A key repeated within one call, or (without --upsert) a key a stored row already holds, is refused with 409 DUPLICATE_UNIQUE_VALUE before any row is written.
List — Paginate through rows with cursor-based pagination. Readable with the same rules as the table artifact itself: no key needed for link and public tables (rip table rows reads them without signing in). Supports server-side sorting and filtering.
The Agent Workflow
The typical flow:- Agent creates a table with a schema defining the columns it plans to fill
- Agent researches, appending rows as findings come in — one API call per batch
- Human opens the table URL, sees a live table of results
- Human (or operator) reviews or edits rows from the dashboard
- Agent continues appending — the table grows over time
Sorting and Filtering
The GET rows endpoint supports server-side sorting and filtering via query parameters. Sort by any column with type-aware ordering (numeric sort fornumber columns, chronological for date):
eq (default), lt, lte, gt, gte, ne, in (comma-separated), contains, starts — and comparisons use the column’s declared type:
field) and lists the columns you can use (available). fields=slug,title limits the returned columns and include_total=true adds the matching row count.
Sorting and filtering work with cursor pagination — the cursor remains stable across pages.
Loose Enforcement
By default, column types are display hints, not hard constraints. The backend does not reject a row because a value doesn’t match its declared type. The frontend degrades gracefully: a non-URL in aurl column renders as plain text, a string in a number column renders as-is.
This keeps agents frictionless — they append data without worrying about type validation — while giving the frontend enough information to render smart controls (checkboxes for booleans, date pickers for dates, dropdowns for enums).
Create the table with --strict (rip artifact publish --type table --strict) when you want enforcement: row writes then reject unknown columns and type-mismatched values. The key (unique: true) is enforced either way — a duplicate value is refused with 409.