Tools

Read Database

Let the agent run SELECT queries against your application database through a read-only connection.

Introduction

The Read Database tool runs ad-hoc SQL against your application database through a connection that is read-only at the database layer. Writes don't get blocked by the tool — they get rejected by the database itself, because the connection has no grants (MySQL and Postgres) or is opened in read-only mode (SQLite).

When enabled, the tool also injects your schema (tables, columns, foreign keys) into the agent's system prompt, so the agent can write joins without guessing column names.

It's disabled by default.

How Read-Only Is Enforced

The enforcement is at the connection level, not at the tool level. There is no SQL parsing or write-statement allowlist.

  • MySQL and Postgres — the tool uses a separate database user whose only grant is SELECT on your schema. Even if the agent emits UPDATE, the DB rejects it with a permission error.
  • SQLite — the tool opens the same file in read-only mode (file:/path?mode=ro) and re-asserts PRAGMA query_only = ON before every query, so writes through the main file or any ATTACH-ed database are blocked.

This means the trust boundary lives where you can audit it (SHOW GRANTS, the SQLite PRAGMA) rather than in PHP code the agent could in principle talk its way around.

Enabling Read Database

Run the wizard:

php artisan laraclaw:setup-read-database

It detects your default DB driver and:

  • MySQL, MariaDB, Postgres — prints the CREATE USER / GRANT SELECT SQL you'll need to run as a DB admin, then prompts for the read-only username and password and verifies the connection actually has read access.
  • SQLite — flips the env flag. No credentials needed; the same file is opened in read-only mode.
  • Other drivers — disables the tool.

You can also set the env vars directly:

LARACLAW_READ_DATABASE_ENABLED=true
LARACLAW_READ_DATABASE_USERNAME=laraclaw_reader
LARACLAW_READ_DATABASE_PASSWORD=...
LARACLAW_READ_DATABASE_TIMEOUT_SECONDS=10

Running Queries

ParameterRequiredDescription
queryYesA single SQL SELECT statement

The result is returned as a JSON array of rows. A trailing semicolon is stripped. On failure, the response is {"error": "..."} so the agent can see what went wrong and try again.

Output Limits

Results are capped at 500 rows. If the cursor returns more, the response is wrapped:

{
  "rows": [...],
  "truncated": true,
  "note": "Result exceeded 500 rows; add LIMIT or refine the query to see the rest."
}

The note nudges the agent toward adding a LIMIT clause rather than blindly retrying.

Query Timeouts

A per-query timeout is set on every call:

  • MySQL and MariaDBSET SESSION MAX_EXECUTION_TIME
  • PostgresSET statement_timeout
  • SQLite — no equivalent; falls back to PHP's request time limit

The default is 10 seconds. Set LARACLAW_READ_DATABASE_TIMEOUT_SECONDS=0 to disable.

Schema in the Prompt

When the tool is enabled, the agent's system prompt is appended with a description of your schema:

  • SQLite — every CREATE TABLE / CREATE INDEX from sqlite_master.
  • MySQL and MariaDBSHOW CREATE TABLE for every table.
  • Postgres — column and foreign key metadata as JSON (there is no single SHOW CREATE TABLE equivalent).

The snapshot is cached for one hour. After running migrations, clear the cache to refresh:

php artisan cache:forget laraclaw:read_database:schema

Security Considerations

!NOTE Read Database is the narrower alternative to Tinker. If all you need is "let the agent answer questions about my data", enable this and leave Tinker off — it has a much tighter blast radius.

  • The agent can read everything the read-only user can read. Audit your grants. If laraclaw_reader can see the payment_methods table, the agent can too.
  • Inbound messages can influence prompts. Anyone who can DM the bot can in principle convince the agent to run a query. Trust your trusted senders.
  • Set LARACLAW_LOG_AGENT_REQUESTS=true to keep an audit trail of every query the agent has run.
  • Self-describing schemas help. A users.last_login_at column will be queried correctly far more often than users.lla.
Copyright © 2026