Skip to content
BasaltDBBasaltDB
Star

Runs

View as Markdown

A run is one job your agent does, with one reason you can read. It is the unit you review, and the unit you undo.

The agent starts a run with run_start and a sentence that says why:

run_start  intent: "Qualify this week's leads"

BasaltDB returns a run id. The agent passes it to every query and write that belongs to the job. If a write arrives without a run id, BasaltDB starts a run of one write for it.

The intent is required and holds up to 500 characters. Write it for a person: someone will read it next to the rows it changed.

Each write also carries its own intent. A write without one is refused:

{ "code": "INTENT_REQUIRED" }

The refusal does not depend on the engine. The guard inside your Postgres checks for the intent too. If an agent finds a way around the engine and writes directly with its own credential, Postgres refuses the write.

For each action in a run, BasaltDB records the reason, the statement, the rows it touched and their old values. It records reads as well. Each read stores the version of the rows the agent saw.

Reads are what make this rule possible: an update to a row that changed after the agent read it is refused with STALE_READ. The agent has to read the row again before it writes. A row the agent never read can still be written. That is called a blind write, and the record marks it.

basalt log --run RUN_ID shows a run as one line per action, with the rows it wrote indented below:

2026-11-15T07:20:47Z  APPLIED  UPDATE basalt_demo.leads          3 rows     9ms  7c3e4f0a-5b1d-4c8e-9a62-0d1f2e3a4b5c  "Qualify leads 1 to 3"
    UPDATE basalt_demo.leads (blind write) {"id":1} score 37 -> 47, status NEW -> QUALIFIED
    UPDATE basalt_demo.leads (blind write) {"id":2} score 74 -> 84, status NEW -> QUALIFIED
    UPDATE basalt_demo.leads (blind write) {"id":3} score 11 -> 21, status NEW -> QUALIFIED

A task groups runs. Pass a taskId to run_start to join a task another agent started, even one from a different vendor. You can undo a whole task at once. See Undo.

  • You read a run’s reason first, then its rows.
  • You undo a whole run at once. A loop of small writes is not blocked, and it all lands in one run.
  • An agent can find its own runs with list_runs, so you can say “undo what you did yesterday on leads”.
  • Rules: what a run may and may not do.
  • The ledger: everything BasaltDB records about each action.
  • MCP tools: run_start, query, write and the others.

BasaltDB · Apache-2.0