> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polycore.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Capabilities

> How Polycore represents generic reads and named operations without exposing credentials.

A **capability** is an operation a connected runner makes available through the
Polycore catalog. It has a name, a kind, an input contract, an output contract,
and a hazard classification.

Callers can request capabilities. They do not receive the implementation or the
credential behind them.

## Kind and hazard are different

<Columns cols={2}>
  <Card title="Kind describes shape" icon="shapes">
    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.
  </Card>

  <Card title="Hazard is one policy input" icon="shield-alert">
    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.
  </Card>
</Columns>

Do not infer risk from the name or kind. Hazard describes what a capability can
do, not whether a given invocation needs a human. That second question is your
[access policy](/concepts/approvals-and-audit) to answer.

## 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.

<Columns cols={3}>
  <Card title="Postgres" icon="database" href="/integrations/postgres">
    `postgres.listSchemas`, `postgres.listTables`, `postgres.describe`,
    `postgres.explain`, and `postgres.query` let an agent ground itself and run
    bounded read-only SQL.
  </Card>

  <Card title="Firestore" icon="flame" href="/integrations/firestore">
    Document reads, collection and collection-group queries, server-side
    aggregations, collection discovery, and sampled schema description.
  </Card>

  <Card title="PostHog" icon="chart-no-axes-combined" href="/integrations/posthog">
    Parameterized HogQL, event/property/table/field discovery, behavioral
    segmentation, external ID enrichment, and compact activity timelines.
  </Card>
</Columns>

Every built-in query has a `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.

<Note>
  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.
</Note>

## 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](/integrations/firestore#optional-generic-mutations) ships
`firestore.create`, `firestore.set`, `firestore.update`, `firestore.delete`, and
`firestore.batchWrite`.

[Postgres](/integrations/postgres) ships `postgres.update` and
`postgres.delete`.

Each declares a `write` hazard, so unless your
[access policy](/concepts/approvals-and-audit) 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.

<Note>
  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.
</Note>

## 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:

<ResponseField name="title" type="string">
  A human-readable operation name shown in catalog and approval surfaces.
</ResponseField>

<ResponseField name="description" type="string">
  Concrete guidance that helps a human or agent choose the action correctly.
</ResponseField>

<ResponseField name="hazard" type="&#x22;read&#x22; | &#x22;write&#x22;" default="&#x22;write&#x22;">
  The governance class. Omitting it chooses the safe default, `write`.
</ResponseField>

<ResponseField name="input" type="Zod schema">
  The arguments the caller must supply. Validation happens before `run`.
</ResponseField>

<ResponseField name="output" type="Zod schema">
  The structured result returned to the caller and audit path.
</ResponseField>

<ResponseField name="secrets" type="record">
  The local secret keys the runner may make available to this action.
</ResponseField>

<ResponseField name="run" type="function">
  The implementation that executes on the runner host.
</ResponseField>

The loader derives the action id from its folder path. An action at
`actions/billing/set-plan/action.ts` is advertised as a namespaced catalog
operation; the module does not choose an independent id.

See [Author actions](/authoring/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`.

<Columns cols={2}>
  <Card title="Explicitly enabled" icon="container">
    The runner advertises `code.execute` only when its committed config includes
    a `sandbox` block. It is absent from the standard runner catalog otherwise.
  </Card>

  <Card title="Always reviewed" icon="scan-eye">
    `unknown` never uses inline web self-approval. The control plane creates a
    pending approval for the exact workload specification before execution.
  </Card>
</Columns>

The runner executes an approved workload in a disposable OCI container with a
read-only root filesystem, dropped Linux capabilities, no network unless
requested, and configured CPU, memory, process, and wall-clock limits. Only
requested secret keys are injected, and the workload specification receives a
deterministic digest for audit.

<Warning>
  Delegated workloads are a preview capability and are not part of the default
  first integration. They require explicit sandbox-host preparation and a review
  of the approval presentation, requested secrets, egress, image, and resource
  limits.
</Warning>

## The governance ladder

The key distinction is between **invoking authority once** and **changing the
standing authority**.

<Steps>
  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

<Tip>
  Separate the act from the grant. Runtime approval governs one requested act.
  Code review governs the durable grant represented by the catalog.
</Tip>

## The same catalog across interfaces

Capability metadata is interface-independent:

```mermaid theme={"system"}
flowchart LR
  Catalog["Typed capability catalog"]
  Catalog --> Slack["Slack agent"]
  Catalog --> MCP["MCP clients"]
  Catalog --> Web["Admin dashboards"]
  Slack --> Gate["Policy, approval, audit"]
  MCP --> Gate
  Web --> Gate
```

* 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.

This prevents each interface from becoming a separate, inconsistently governed
integration.

## Design guidance

<AccordionGroup>
  <Accordion title="Use a query for broad reads" icon="search">
    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.
  </Accordion>

  <Accordion title="Use an action for a durable operation" icon="braces">
    Prefer an action when the operation has business rules, needs a stable
    contract, combines systems, should be easy to reuse, or can change state.
  </Accordion>

  <Accordion title="Keep outputs bounded" icon="scan-line">
    Return the minimum fields needed by the caller. Aggregate in the datastore,
    cap lists, redact sensitive fields, and make truncation explicit.
  </Accordion>

  <Accordion title="Make descriptions operational" icon="text">
    State when the capability should be used, important preconditions, what it
    changes, and how failures should be handled. Avoid relying on hidden domain
    knowledge.
  </Accordion>
</AccordionGroup>
