Docs
Data

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:

ChipMeaning
QueuedClaimed by a run, not started
RunningIn flight
RetryingFailed, still inside its attempt budget
Rate limitedProvider throttled it; retries continue
Awaiting callbackWaiting on an async provider response
FailedOut of attempts
BlockedAn earlier step on the row failed, so this one never started
Credit capThe 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 --json

Row 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> --json

Each 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 it

billing 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 --json

Rerun 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> --json

Each 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_applied

The 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 --json

This 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.

On this page