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 empty AI cell shows AI definition and a Function column Function call instead. An empty formula cell shows nothing: formulas compute whenever the cell is read, so there is nothing to run. A cell with work in flight, or one a run stopped, 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 |
Blocked | An earlier step on the row failed, so this one never started |
Credit cap | The run's credit ceiling was reached first; the row was not run or billed |
Hover the chip for its attempt count and item id, and for a failure, the reason. When you run a column on selected rows or on all rows, the confirmation carries a View run link; the grid itself doesn't announce the run. Cells fill in as it works, and a warning appears above the grid only when processing is delayed.
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 No 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.
A Function column's panel is headed Function call. It names the Function, with a View Functions link, then shows the call's status, the credits it used, a View run link, the outputs it returned (or This call wrote no outputs.), and the columns it wrote them to (Written to …).
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
Apart from a Function call's panel, 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.
When the credit cap stops a run
A run never spends past its --max-credits ceiling. Rows it could not afford stay unrun and unbilled: their cells show Credit cap, and the panel says Not run — the run's credit cap was reached. This row was not billed. The run is then reported as needing review, not as a success: oxygen table-runs get <run-id> --json shows user_status: "needs_review", credit_limit_skipped (the rows the cap stopped), a user_message such as The 300-credit cap was reached: 4 rows ran and 16 did not, and the next_best_action. To finish, raise the ceiling and run the column again without --force. Filled cells are skipped, so no row is billed twice:
oxygen columns run <table> <column> --all --background --approved --max-credits 1500 --jsonRerun one cell
Rerun this cell in the Cell details panel (Run this cell while it is empty) re-executes ai, research, tool, enrichment, bind, and lookup cells, and an empty cell in one of those columns also gets a run button in the grid; on a paid column it reads Run this cell (uses credits): one click, no dialog, bounded by a one-row ceiling the server derives. Formula cells have no run button: every read computes them from their inputs. The paid kinds (ai, research, tool, enrichment) mint a durable run; 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 model tier, 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.