Agent Workflows
Use these workflows when an agent needs to validate Postgres behavior without assuming a framework.
ttlMinutes values in these examples are positive minutes. Omit the field to
use the profile default; 0 and negative values are rejected with
invalid_ttl.
Direct SQL Schema Change
- Create a sandbox.
{
"tool": "create_database",
"arguments": {
"nameHint": "billing status check",
"ttlMinutes": 45,
"owner": "agent-session"
}
}
- Apply SQL directly.
{
"tool": "run_sql",
"arguments": {
"databaseId": "<databaseId>",
"sql": "CREATE TABLE accounts(id serial PRIMARY KEY, email text UNIQUE);"
}
}
- Inspect the schema.
{
"tool": "describe_schema",
"arguments": {
"databaseId": "<databaseId>"
}
}
- Delete the sandbox when finished.
{
"tool": "delete_database",
"arguments": {
"databaseId": "<databaseId>"
}
}
Before/After Diff
Use the full schema_digest response as baseDigest; a checksum string alone
cannot compute a diff.
{
"tool": "schema_digest",
"arguments": {
"databaseId": "<databaseId>"
}
}
{
"tool": "schema_diff",
"arguments": {
"databaseId": "<databaseId>",
"baseDigest": {
"databaseId": "<databaseId>",
"databaseName": "<databaseName>",
"digestVersion": 3,
"checksum": "<checksum>",
"relationCounts": {
"tables": 0,
"partitionedTables": 0,
"views": 0,
"materializedViews": 0,
"foreignTables": 0,
"other": 0
},
"columnCount": 0,
"constraintCount": 0,
"indexCount": 0,
"extensionCount": 0,
"tables": [],
"extensions": []
}
}
}
For a compact stored baseline, prefer snapshots:
{
"tool": "create_schema_snapshot",
"arguments": {
"databaseId": "<databaseId>",
"snapshotName": "before_change",
"notes": "baseline before repo command"
}
}
{
"tool": "diff_schema_snapshot",
"arguments": {
"databaseId": "<databaseId>",
"snapshotName": "before_change"
}
}
Row-Limited Reads
run_sql returns explicit row metadata:
{
"tool": "run_sql",
"arguments": {
"databaseId": "<databaseId>",
"readonly": true,
"rowLimit": 2,
"sql": "SELECT * FROM accounts ORDER BY id"
}
}
Use returnedRowCount, affectedRowCount, totalRowCountKnown, and
truncated for result-size and mutation checks. For multi-statement SQL, read
the ordered resultSets array when you need each statement’s result; top-level
rows mirrors the last row-returning statement. resultSets uses 1-based
statementIndex values, applies rowLimit independently to each
row-returning result set, and serializes each row-returning statement with the
same typed rules as a single-statement query.
Repo Command Validation
Use run_repo_command when the repo already has a script. Use
validate_schema_change when the agent needs the schema diff.
{
"tool": "validate_schema_change",
"arguments": {
"repoPath": "/absolute/path/to/repo",
"nameHint": "validate repo schema change",
"ttlMinutes": 45,
"owner": "agent-session",
"command": ["npm", "run", "migrate"]
}
}
Commands run with repoPath as current directory and receive DATABASE_URL,
PGSANDBOX_DATABASE_URL, and libpq PG* variables for the sandbox. PGSandbox
does not add an implicit shell, and it rejects shell wrappers and indirect
launchers such as ["bash", "-lc", "..."], ["sh", "-c", "..."], env, and
sudo. Pass direct argv such as ["npm", "run", "migrate"],
["psql", "-v", "ON_ERROR_STOP=1", "-f", "migrations/schema.sql"], or
["psql", "-Atc", "SELECT current_database(), current_user"]. For multi-step
workflows, prefer a repo/package script that can be invoked directly, or split
the work into separate tool calls.
Templates And Clone
Create a reusable local template from a sandbox:
{
"tool": "create_template_from_sandbox",
"arguments": {
"databaseId": "<databaseId>",
"templateName": "seeded_accounts",
"createdBy": "agent-session"
}
}
Restore it into a new sandbox:
{
"tool": "create_sandbox_from_template",
"arguments": {
"templateName": "seeded_accounts",
"nameHint": "replay bug",
"ttlMinutes": 45,
"owner": "agent-session"
}
}
For external sources, use clone_database with schemaOnly when data is not
needed. Do not paste production URLs into issue trackers, Rowset rows, or logs.
Cleanup And Diagnostics
List or clean up one profile by default:
{
"tool": "list_databases",
"arguments": {
"owner": "agent-session"
}
}
Use all-version scope deliberately:
{
"tool": "cleanup_expired",
"arguments": {
"includeAllVersions": true,
"dryRun": true
}
}
Use MCP doctor when shell access is unavailable:
{
"tool": "doctor",
"arguments": {}
}
Error Handling
Branch on stable error.code and error.category, not prose. Common SQL
repair cases include:
undefined_columnorundefined_table: calldescribe_schemaor check identifiers.syntax_error: revise SQL;doctoris not the first recovery step.readonly_violation: retry withreadonly: falseonly when mutation is intended.constraint_violation: inspect the constraint and adjust input.statement_timeoutorlock_timeout: reduce scope or retry after the conflicting operation ends.
Creation tools return connectionStringRedacted and connectionStringsRedacted
for summaries, task trackers, and logs. Use
connectionStringsRedacted.localContainer only as a safe hint that a
Dockerized local app should use the container variant.
get_connection_string also returns only redacted values by default. Pass
includeCredentials: true only when a command or database client needs the
actual credential-bearing URL. For Dockerized app services running on the same
machine as PGSandbox, pass connectionStrings.localContainer as DATABASE_URL.
Docker Desktop supports host.docker.internal automatically; on Linux Docker,
add extra_hosts: ["host.docker.internal:host-gateway"] to the service. Do not
echo raw connection values into chat, logs, PR comments, issues, or durable
datasets.