# Reading and changing: use the read-only tools to read (https://lazyfrog.dev/docs/guide/reading-and-changing-use-the-read-only-tools-to-read)

{/* Generated by scripts/generate-docs.ts from services/gateway/src/guide.md. Do not edit. */}

Every tool that both reads and changes things has a read-only twin that carries only its reads.
Use the twin whenever you only want to look: it changes nothing, so your AI app never has to ask
the user before it (a tool that can change things is asked about every time, and an AI app running
without approvals refuses it). The tools that change things still answer the old read actions for
now, marked deprecated; don't rely on that. `deploy` (`preflight` and `publish` alike) is one of
those tools: in an app that refuses tools needing approval it can't run until the user approves
it, so ask the user to approve it (or to run it in a client that asks) instead of retrying.
A `status` read never fails because something isn't set up yet (Stripe, email, a domain): it says
so and names the next step (`payments` `connect`, the portal page, `domain` `add`); an error from
one is a real error.

| To read | Use (read-only) | Instead of |
|---|---|---|
| the user's projects, one project, its app info, its exports | `project_read` (`list`, `get`, `about`, `exports`) | `project list` / `get` / `about` / `exports` |
| a background job's status and output | `job_read` (`get`) | `job get` |
| the plan, the look | `plan_read`, `look_read` (`get`) | `plan get`, `look get` |
| git status, history, changes, the remote | `git_read` (`status`, `log`, `diff`, `remote_show`) | `git status` / `log` / `diff` / `remote_show` |
| the names of the secrets | `secrets_read` (`list`) | `secrets list` |
| routing rules, form submissions | `routing_read` (`get`), `forms_read` (`list`) | `routing get`, `forms list` |
| email and AI gateway settings, the Stripe connection | `email_read`, `ai_read`, `payments_read` | `email status`, `ai settings`, `payments status` |
| images in the project, stock photos | `images_read` (`view`, `stock`, `status`) | `images view` / `stock` / `status` |
| SQL results | `db_read` (a read-only transaction: a statement that writes is refused) | `db_query` for a SELECT |
| a page of the running app | `http_get` (GET, HEAD, OPTIONS) | `http_request` for a GET (deprecated; it takes only POST, PUT, PATCH and DELETE from 2027-01-26) |
| the support requests | `support_read` (`list`, `get`) | `support list` / `get` |
| whether a message to a customer was sent | `message_read` (`status`, `list`) | `message status` / `list` |
| whether domain names are free, a domain's records as public DNS sees them | `domain_read` (`check`, `status`) | `domain check` / `status` |

Already read-only: `fs_read`, `fs_list`, `fs_search`, `logs_tail`, `service_status`, `db_schema`,
`snapshot_list`, `deploy_list`, `domain_list`, `usage_get`, `account`, `preview_screenshot`,
`design_check`, `project_scan`. There is no read-only `exec`: to look at files use `fs_read`,
`fs_list` and `fs_search`, and `git_read` for the repository. The tools that change things keep
their names; whatever changes or deletes something (`project` delete, `secrets` delete, `snapshot`
restore, `domain` remove, `deploy` publish, `db_query` writes) is asked about by your AI app.
