Cells
Where a value came from, which run wrote it, and what it cost.
Trace any value in a table back to the run that produced it and the credits it spent. A cell is one row of one column, and it keeps its own status, error, provenance, and write history.
What the grid shows before you click
Open Tables in the sidebar (/tables), then a table (/tables/<table-id-or-slug>). A tool or enrichment cell that never ran shows a grey Not run chip; an AI or formula cell shows its definition label instead. A cell with work in flight shows a status chip instead of a value:
| Chip | Meaning |
|---|---|
Queued | Claimed by a run, not started |
Running | In flight |
Retrying | Failed, still inside its attempt budget |
Rate limited | Provider throttled it; retries continue |
Awaiting callback | Waiting on an async provider response |
Failed | Out of attempts |
Hover the chip for its attempt count and item id. While a run is active, a strip above the grid shows settled/total rows, credits used against the run's ceiling, and a View link to that run.
Open one cell
Double-click the cell or press Enter on it. The Cell details panel opens beside the grid:
- Last run — Status, Attempts (
2 / 3), Completed time, skip reason, and the failure message in red when the last attempt errored. - Result — a plain-language verdict for tool output, such as a verified email or an invalid number.
- Value — the output as an expandable tree. Each field offers Copy value, and Copy reference where the path is referenceable — the
{{column_key.field}}token for formula and AI columns.
An empty cell says so: This cell is empty. Run the column to populate a value. On a waterfall enrichment cell, Expand into result columns fans it into per-provider sub-cells; clicking one opens the same panel headed Waterfall attempt.
Inspect from the terminal
oxygen cells inspect <table> <row-id> <column> --history-limit 25 --jsonRow ids come from oxygen tables query <table> --limit 1 --json — the field is _row_id. You get the value, identity fields for the row, recent history (10 changes by default, cap 50), and a deep_link shaped https://oxygen-agent.com/tables/<table>?cell=<row-id>:<column-key>.
That link opens a dialog: the value, its confidence badge and via <provider> source, a Timeline of provider attempts (Provider, Operation, Detail, Latency), and Recent writes (When, Source, Status, Run). Only enrichment cells have a timeline.
Full history
oxygen cells history <table> <row-id> <column> --limit 100 --json
oxygen rows history <table> <row-id> --jsonEach change carries createdAt, sourceType (api, cli, tool, workflow, system), oldValue, newValue, runId, and runStatus — enough to see that a CRM sync overwrote an AI classification. rows history covers every column on the row and has no web equivalent.
What it cost
The grid prints no per-cell credit number. Two commands do:
oxygen tables preview <table> --include-cell-states --json # cellStates[row][column].billing
oxygen table-runs get <run-id> --json # the run that wrote itbilling reports creditsUsed, creditsSaved, charged, and cacheHit, so a cell served free from cache is distinguishable from one that spent. Pass the runId from any cell change to table-runs get, or open /tables/<table>/runs/<run-id>, which shows Credits used against the run's ceiling. The run list at /tables/<table>/runs is not linked from the grid — reach it by URL, or from a run page's Back to runs.
Rerun one cell
Rerun this cell in the Cell details panel re-executes the executable kinds — ai, tool, enrichment, formula, bind, and lookup. On a paid column the grid's hover button reads Run this cell (uses credits): one click, no dialog, bounded by a one-row ceiling the server derives. The paid kinds (ai, tool, enrichment) mint a durable run; formula, bind, and lookup execute synchronously and mint none. From the CLI, preview first:
oxygen columns run <table> <column> --row-id <row-id> --force --dry-run --json
oxygen columns run <table> <column> --row-id <row-id> --force --approved --max-credits 50 --json--dry-run shows the resolved model, credit estimate, and rendered prompt without spending. --force is what overwrites a cell that already holds a value. oxygen columns rerun is the narrower AI-only path — --dry-run first, then a required --max-credits, plus --from-review-id to thread a message review's feedback into the prompt.
When a cell says the result was lost
Some columns write to something outside Oxygen — a custom HTTP tool column that POSTs to your own API, or a provider enrichment call. When Oxygen dispatches that write and then loses the answer — a timeout, a connection reset, a 5xx, or a lost worker lease — it cannot tell whether the write actually landed at the destination.
Rather than guess, Oxygen stops. The cell fails with custom_http_effect_unknown or worker_step_outcome_unknown and is not retried automatically, because a blind retry could apply the same external write twice — a duplicate charge, a duplicate record, a duplicate email. Because of that, rerunning such a cell is refused with effect_unknown_approval_required until you say what actually happened.
How to resolve it
List what is blocked on a run:
oxygen table-runs effect-unknown <run-id> --jsonEach entry names the row, the column, the error code, the operation and the (secret-redacted) URL that was called, and how many attempts were made — enough to go check the destination yourself.
Open the destination, check whether the write actually landed, then record what you found:
oxygen cells resolve <table> <row-id> <column> --outcome not_appliedThe write never landed. The cell stops counting as ambiguous and can be rerun normally — oxygen columns run <table> <column> --row-id <row-id> --force and the in-app Rerun this cell button both work again.
oxygen cells resolve <table> <row-id> <column> --outcome applied --value '"ok"'The write did land. The cell is marked complete. --value is optional; pass it only to record the value you read off the destination — Oxygen never invents a provider response, a value only ever appears because you supplied one.
Add --note "checked Supabase logs, no row created" to either command to store how you verified it.
In the app
Open the cell. In place of Rerun this cell, the Cell details panel shows a Verify external result section: the reason Oxygen stopped, the operation, method and secret-redacted URL that were sent, and two buttons — Mark as applied (with an optional field for the value you read off the destination) and Mark as not applied, allow rerun. Both ask for confirmation first. After not applied, Rerun this cell comes back.
On the run's page, Retry failed opens a dialog listing every item still awaiting a verdict and requires explicit confirmation before it will re-execute any of them.
From an MCP client
oxygen_table_runs_effect_unknown lists what is awaiting verification on a run, and oxygen_table_cells_resolve records the outcome. Like the CLI, both only read and write Oxygen's own record of what a person verified — neither one calls the destination.
If you are sure re-running is safe anyway
A whole run can be retried at once:
oxygen table-runs retry-failed <run-id> --approved-effect-unknown --jsonThis re-executes every unconfirmed item in the run. Only do this when duplicate external writes are genuinely harmless — an idempotent upsert against a key you control, for example.
Recording an outcome is a note about what a person verified. It never calls the provider.