Skip to content

Data agents

A data agent is a scheduled LLM loop bound to a single database. You give it a natural-language standing goal (“keep the metrics rollup fresh”, “triage new tickets rows and tag them”) and a cadence; it wakes on that cadence, inspects the database, calls tools, optionally fetches the web, and writes rows back. It is the LLM analog of a scheduled query: same per-database, no-central-cron design, but the body is a model with tools instead of a fixed SQL string.

Data agents are a feature, not a plan tier. They drain the same prepaid workspace balance as everything else — requests, rows, and AI tokens.

Each agent’s config lives in the control plane; its execution state lives on the database’s own isolated instance, which owns the schedule. There is no central worker.

  1. On the cadence, the database wakes the agent.
  2. The agent runs a bounded tool-use loop (default 6 rounds per wake, 1–12) against your data, carrying a one-line summary of its previous run as working memory.
  3. Any write the agent makes can pause for human approval (see Approval modes). A queued write fires a push and lands in the same /approve/:token surface as a /v1 approval.
  4. After each wake it records last_status, last_summary, last_rows_read/written, last_rounds, last_duration_ms, and last_error, then re-arms for now + intervalSec.

The agent’s tools each wake: web_search, fetch_url, list_tables, describe_schema, sample_table, validate_sql, explain, run_select, run_write, run_batch, query_log, create_snapshot, list_endpoints / call_endpoint, and ask_human (pause for a person). Mount extra tools from external MCP servers.

A wake that fails doesn’t disable the agent — the next one tries again. An agent parked on an approval skips its schedule until every pending write (or ask_human question) is decided, so it never piles up duplicate proposals.

FieldTypeNotes
namestring1–80 chars.
goalstring1–4000 chars. The standing instruction run each wake.
intervalSecnumberCadence. 60–604800 (1 min – 7 days).
approvalModeauto | destructive | writesDefault destructive. See below.
maxItersnumberTool-executing rounds per wake. 1–12, default 6.
modelstring | nullWorkers AI model id; null uses the platform default.
untilISO 8601 | nullStop instant — past it the agent disables itself.
mcpServersarrayExternal MCP servers to mount as tools (≤4).
enabledbooleanStart running. Default true.

The agent’s own writes can be gated before they execute:

  • auto — fully autonomous, no writes pause.
  • destructive (default) — DROP / DELETE / ALTER / TRUNCATE pause for approval; ordinary INSERT / UPDATE run.
  • writes — every mutation pauses for approval.

A paused write pushes a notification and waits in the approval surface. Approve it from the console, the PerSQL mobile app, or POST /api/approvals/:token/decide; the write then runs server-side through the same auto-snapshot + query-log + pricing pipeline as any other.

Mount up to four external MCP servers as extra tools — the agent can call out to a search index, a ticketing system, or your own MCP worker mid-loop:

{
"mcpServers": [
{ "label": "tickets", "url": "https://mcp.example.com", "headers": { "Authorization": "Bearer …" } }
]
}

headers (call-time auth) is write-only — it is accepted on create / update but never returned. The DTO echoes label and url only.

Four surfaces, same agent. Create / update / delete / run require an admin-role token (or workspace admin in the console); list is open to any read access.

Open a database → the Agents tab → New agent. Fill in the goal, cadence, and approval mode; runs, last summary, and pending approvals show inline.

import { PerSQL } from "@persql/sdk";
const persql = new PerSQL({ token: process.env.PERSQL_TOKEN! }); // admin token
const db = persql.database("acme/metrics");
const agent = await db.agents.create({
name: "rollup-refresher",
goal: "Recompute the daily_revenue rollup from orders for any day that changed since the last run.",
intervalSec: 3600, // hourly
approvalMode: "destructive", // INSERT/UPDATE run; DROP/DELETE pause
maxIters: 6,
});
// Run one cycle now (doesn't shift the schedule):
const ran = await db.agents.run(agent.id);
console.log(ran.lastStatus, ran.lastSummary);
await db.agents.update(agent.id, { intervalSec: 1800 });
const { data } = await db.agents.list();
await db.agents.delete(agent.id);

See the SDK reference and the runnable scheduled data agent recipe.

Terminal window
persql agent create acme/metrics \
--name rollup-refresher \
--goal "Recompute the daily_revenue rollup for any day that changed." \
--interval 1h --approval destructive
persql agent list acme/metrics
persql agent run acme/metrics rollup-refresher # run one cycle now
persql agent delete acme/metrics rollup-refresher

--interval accepts 3600, 30m, 1h, or 1d. Reference an agent by name or id. See the CLI reference.

Any MCP runtime gets list_agents, create_agent, update_agent, delete_agent, and run_agent — drive the same lifecycle from Claude, Cursor, or your own agent.

Two parallel surfaces — cookie-authed for the console, bearer-authed for agents and SDK callers:

MethodConsole (cookie / CLI bearer)Agent (/v1 bearer)
GET/api/namespaces/:ns/databases/:db/agents/v1/db/:ns/:db/agents
POST/api/namespaces/:ns/databases/:db/agents/v1/db/:ns/:db/agents
PATCH/api/namespaces/:ns/databases/:db/agents/:id/v1/db/:ns/:db/agents/:id
DELETE/api/namespaces/:ns/databases/:db/agents/:id/v1/db/:ns/:db/agents/:id
POST/api/namespaces/:ns/databases/:db/agents/:id/run/v1/db/:ns/:db/agents/:id/run

The /v1 mutating routes require an admin-role bearer. A workspace-wide read is also available at GET /api/namespaces/:ns/agents, which aggregates every database’s agents (used by the dashboard “needs attention” view).

  • One bounded loop per wake (default 6 rounds, max 12) — the agent can’t spin forever inside a single cycle.
  • Cadence floor is 60s, ceiling 7 days — same bounds as scheduled queries.
  • Up to four external MCP servers per agent.
  • No per-tier message cap and no per-token throughput cap. Every wake drains the prepaid balance (requests, rows, and AI tokens); when it runs out the agent’s next wake gets a 402 and skips. Top up to resume.
  • A model is non-deterministic: a wake may legitimately do nothing if the goal is already satisfied. last_summary records what it concluded.