Kind and hazard are different
Kind describes shape
A
query is a generic read transport supplied by the runner. An action is
a named unit of work (customer-authored, or a built-in generic write such as
firestore.delete). An optional code capability runs a delegated workload
in a disposable runner-side sandbox.Hazard is one policy input
Each capability declares a
hazard: what it is capable of. With no policy
written it is the whole decision, and unknown delegated code always waits
for human review.Generic queries
Queries cover broad read surfaces without requiring one function per question. The caller supplies the specific SQL statement, collection filter, or document path at request time.Postgres
postgres.listSchemas, postgres.listTables, postgres.describe,
postgres.explain, and postgres.query let an agent ground itself and run
bounded read-only SQL.Firestore
Document reads, collection and collection-group queries, server-side
aggregations, collection discovery, and sampled schema description.
PostHog
Parameterized HogQL, event/property/table/field discovery, behavioral
segmentation, external ID enrichment, and compact activity timelines.
read hazard. The runner also constrains how it
talks to the downstream system:
- Postgres statements execute inside a read-only transaction with a statement timeout and row cap.
- Firestore tools call read methods only.
- PostHog accepts only query/read endpoints; results, actor sets, and timelines are bounded before they return to the control plane.
- The credential should also be read-only, giving you an independent downstream enforcement layer.
Generic does not mean unlimited. Inputs are schema-validated, outputs are
bounded, and the runner’s credential and network reach still define the
accessible data.
Generic mutations
A mutation is the write-side twin of a query: also generic, also built in, with the caller naming the target at request time. Firestore shipsfirestore.create, firestore.set, firestore.update, firestore.delete, and
firestore.batchWrite.
Postgres ships postgres.update and
postgres.delete.
Each declares a write hazard, so unless your
access policy says otherwise, the control plane
holds the request until a human approves that exact call with those exact
arguments. A typed mutation is narrower and easier to review than a delegated
program that could touch anything, which is why routine one-off changes belong
here rather than in a sandboxed workload.
The two Postgres mutations differ from the rest in one way worth knowing: a SQL
predicate does not name its rows until it is evaluated, so these preview
themselves first. The statement is rewritten into a read that reports exactly
which rows would change, and the apply then changes only those rows. That is
what lets a policy decide on the consequence of a statement rather than on its
text.
Mutations are off unless the runner config grants the family a write credential,
which is a separate identity from the read path. That keeps the read
credential mutation-incapable and makes granting write authority an explicit,
reviewable act rather than a side effect of enabling reads.
Mutations address documents by path, never by filter. A filtered set would
only be resolved after approval, so nobody could review what they approved.
Read the paths first, then propose them explicitly.
Named actions
Actions are source-controlled TypeScript modules for stable operations such as producing an account summary, changing a plan, or triggering an internal workflow. An action declares:string
A human-readable operation name shown in catalog and approval surfaces.
string
Concrete guidance that helps a human or agent choose the action correctly.
"read" | "write"
default:"\"write\""
The governance class. Omitting it chooses the safe default,
write.Zod schema
The arguments the caller must supply. Validation happens before
run.Zod schema
The structured result returned to the caller and audit path.
record
The local secret keys the runner may make available to this action.
function
The implementation that executes on the runner host.
actions/billing/set-plan/action.ts is advertised as a namespaced catalog
operation; the module does not choose an independent id.
See Author actions for a complete example.
Delegated workloads
code.execute is an opt-in escape hatch for work that does not fit an existing
query or action. It has capability kind code and hazard unknown.
Explicitly enabled
The runner advertises
code.execute only when its committed config includes
a sandbox block. It is absent from the standard runner catalog otherwise.Always reviewed
unknown never uses inline web self-approval. The control plane creates a
pending approval for the exact workload specification before execution.The governance ladder
The key distinction is between invoking authority once and changing the standing authority.1
Ad hoc query
An agent composes a request through a generic query. The runner’s
constrained implementation and scoped credential bound what it can touch,
and the caller’s policy clears this class of request to return without a
human approval.
2
Approved invocation
A caller invokes an existing action that the policy holds for approval. The
control plane creates an approval record. Depending on the interface and the
caller’s role, that decision is either pending for a human or recorded
inline for an authenticated web owner or admin.
3
Reviewed delegated workload
An enabled runner may receive a
code.execute specification. Its unknown
hazard always creates a pending review, even where a direct web action could
otherwise use inline owner or admin approval.4
Catalog change
Adding a new action, widening an input schema, changing its credential
needs, or enabling another query family changes standing authority. That
change is reviewed in your repository and reaches the runner through your
deployment process.
The same catalog across interfaces
Capability metadata is interface-independent:- An agent discovers the schema as tool metadata.
- A dashboard binds fields and buttons to the same schema.
- An approval surface renders the same capability and arguments.
- The audit record names the same capability regardless of caller.
Design guidance
Use a query for broad reads
Use a query for broad reads
Prefer a built-in query when the operation is side-effect-free and the agent
can choose the specific projection, filter, or aggregation at request time.
Use an action for a durable operation
Use an action for a durable operation
Prefer an action when the operation has business rules, needs a stable
contract, combines systems, should be easy to reuse, or can change state.
Keep outputs bounded
Keep outputs bounded
Return the minimum fields needed by the caller. Aggregate in the datastore,
cap lists, redact sensitive fields, and make truncation explicit.
Make descriptions operational
Make descriptions operational
State when the capability should be used, important preconditions, what it
changes, and how failures should be handled. Avoid relying on hidden domain
knowledge.

