Skip to main content
The runner separates reviewed structure from deployment-time identity and secrets.
  • polycore.json declares the capability surface and project context.
  • The actions/ directory contains customer-authored capabilities.
  • Runtime variables bind one deployed process to one project and environment.
  • Your deployment resolves credentials through workload identity or secret injection.
Polycore prepares this package with you during early access. This reference exists so engineering and security teams can review exactly what is committed and what remains runtime-only.

Repository layout

polycore-runner
polycore.json
Dockerfile
package.json
Only include folders that the integration needs. Actions are discovered by convention from actions/ beside polycore.json; there is no action-directory setting.

Complete example

polycore.json
Relative file paths resolve from the directory containing polycore.json, not from the process’s current working directory.

Four conventions

The file follows the same four rules throughout, so a family you have not used before behaves the way you would guess.
1

Presence enables reads

"auth": {} exposes the Auth read family. There is no true shorthand: one shape per family means nothing has to ask whether a config is a boolean or an object.
2

`write` is the write grant, and it names the identity

Absent means read-only. "ambient" uses Application Default Credentials. { "keyEnv": "…" } uses a separate service-account key, so the runtime identity can stay read-only at IAM. Everything a grant unlocks is write-hazard and still needs a human approval per call.
3

Every environment binding is a `*Env` field

No variable name is hardcoded in the runner, so you can rename any of them without a code change. Most default to one conventional name; the Firebase project id instead falls back to Google’s own resolution order, because a GCP runtime already populates it under more than one name.
4

Every ceiling lives under `limits`

If a value bounds how much work one call may do, it is in that object and nowhere else.
integrations here means your systems, reached only from inside your environment. It is unrelated to Polycore’s hosted integrations (Notion and friends), which are provider grants the control plane holds.

Configuration fields

object
default:"{}"
The customer systems this runner exposes. Every family is read-only unless it carries a write grant. Omit for a runner that serves only customer-authored actions.

Firebase

object
The Firebase project this runner serves, and which of its services are exposed. The three services are independent grants against one project: a runner may serve document reads without ever exposing the auth directory.
string
The variable holding the GCP project id, when you want to name one. Omit it and the runner uses Google’s own resolution order — FIRESTORE_PROJECT_ID, then GOOGLE_CLOUD_PROJECT, then GCLOUD_PROJECT — which is what GCP runtimes already populate. The explicit variable comes first on purpose: an operator who sets one means it, and it should not lose to whichever project the VM happens to sit in.Name a variable when the runner reads a different Firebase project than the one it runs in, or when your deployment uses its own spelling. Naming one means only that one: there is no quiet fallback behind it.
object
Exposes firestore.* document reads. See Firestore.
string
Path to a build-generated Typesync definition JSON, relative to polycore.json. The runner validates and reads this file locally, and it grounds the agent in your declared schema instead of one inferred from sampled documents.
"ambient" | { keyEnv }
Grants the approval-gated firestore.create / set / update / delete / batchWrite capabilities.
object
Exposes auth.* directory reads. See Firebase Auth.
"ambient" | { keyEnv }
Grants the approval-gated account-administration and action-link capabilities. {keyEnv} lets the runtime service account stay roles/firebaseauth.viewer.
object
Exposes storage.* object reads. See Firebase Storage.
string
default:"FIREBASE_STORAGE_BUCKET"
Where the project’s default bucket name comes from, used whenever a Storage capability names no bucket.
string[]
The buckets in scope. A runtime service account often has object access to buckets unrelated to the product (build artifacts, Terraform state, backups); naming the ones in scope keeps the capability surface narrower than the IAM grant behind it. Absent means every reachable bucket. The default bucket must appear in this list when it is set.
integer
default:"60"
Longest life of a signed read URL. 0 withdraws storage.getSignedUrl entirely, so it is never advertised.
integer
default:"1048576"
Largest object storage.download returns inline. Larger objects need a signed URL.
integer
default:"1048576"
Largest inline object storage.upload accepts, decoded.
integer
default:"1000"
Objects one storage.summarize walk covers before it stops and reports complete: false.
"ambient" | { keyEnv }
Grants the approval-gated storage.delete / copy / move / setMetadata / makePublic / upload capabilities. Writes resolve their bucket through the same allowlist as reads, so a write can never reach a bucket a read could not.

Postgres

object
Exposes postgres.* bounded schema discovery, explain, and parameterized read-only queries. See Postgres.
string
default:"POLYCORE_POSTGRES_URL"
Where the connection string comes from. Point it at a read-only role or replica.
object
Grants postgres.update and postgres.delete. Absent means read-only, as with every other family. Present with no urlEnv means writes go through the read connection; give urlEnv to use a separate write role so the read path stays mutation-incapable at the database. See Postgres writes.
string
Where the write connection string comes from. Omit to reuse integrations.postgres.urlEnv, which is only appropriate when that role already has write access.
object
Ceilings on write review cost, separate from the read limits because they bound what a human can reasonably approve rather than what the database can reasonably serve.proposalTtlMinutes bounds how long a decision stays open, not correctness: every previewed row is pinned to the version it had at preview time, so a row written in the meantime aborts the apply whatever the clock says.
object
Customer-reviewed upper bounds. Every value is a ceiling: a call may request less, never more. Unset ceilings take their defaults.

PostHog and Prometheus

object
Exposes posthog.* read capabilities. host is committed; the project id and API key bind from projectIdEnv (default POSTHOG_PROJECT_ID) and apiKeyEnv (default POSTHOG_PERSONAL_API_KEY).
integer
default:"365"
Longest window the actor-oriented helpers accept. Raw HogQL stays explicit.
object
Exposes prometheus.* read capabilities against baseUrl. auth is { "type": "none" }, { "type": "bearer", "tokenEnv": "…" }, or { "type": "basic", "usernameEnv": "…", "passwordEnv": "…" }. An optional tenantHeader sets a safe header such as X-Scope-OrgID from valueEnv.

Everything else

{ file } | { text }
Agent grounding for this project. { "file": "./context/product.md" } is preferred for anything longer than a line; { "text": "…" } inlines it. Two shapes rather than two sibling keys, so “both were set” is not a state the parser has to reject.
record<string, string>
Optional secret values for customer-authored actions, keyed by the names the actions declare. Missing keys fall back to process.env. Values in the file take precedence over the environment.
object
Optional control-plane URL and enrollment identity. Production deployments normally supply these fields through environment variables instead.
object
Opts the runner into code.execute delegated workloads. It sets the workload image, OCI runtime (runsc by default), container CLI, and maximum CPU, memory, process, and timeout limits.
Do not commit production values under actions.secrets or controlPlane. Their file forms support local evaluation and explicit configuration, but production runner images should receive them from the deployment environment.
sandbox is a preview surface and is absent from standard integrations. Enabling it requires explicit host preparation and security review; it adds an unknown-hazard capability that your policy always holds for human review.
Do not commit production values under secrets or controlPlane. Their file forms support local evaluation and explicit configuration, but production runner images should receive them from the deployment environment.

Runtime identity

These bindings identify the deployed process and its control-plane enrollment:
string
Path to the committed polycore.json. Set this when the runner command does not receive --config <path>.
string
required
The control-plane project namespace this runner serves.
string
required
The runner WebSocket endpoint, using wss:// in production.
string
required
The runner registration provisioned for this project and environment.
secret
required
Authenticates the runner’s join handshake.
secret
required
Lets the runner verify dispatch envelopes signed for its registration.
The environment itself comes from control-plane enrollment. It is not declared in polycore.json and is not selected by capability arguments.

Datastore bindings

Every one of these is the default variable name for a *Env field. Rename any of them in polycore.json rather than working around it.
secret
Required when integrations.postgres is present. Point it at a read-only role or replica and inject it through your secret manager. Renamed with integrations.postgres.urlEnv.

Project context

Project context explains customer-specific facts the fixed Polycore agent prompt should not contain. Keep it concise and operational:
context/product.md
Good context covers:
  • Domain terms and identifiers.
  • Important data-model conventions.
  • Safe interpretations of ambiguous language.
  • Known limits or preconditions that apply across requests.
Do not place secrets, broad copies of database schemas, or one-off query instructions in this file. Query tool descriptions and on-demand schema capabilities should carry platform-specific guidance.

Configuration lifecycle

1

Review

Query families, context changes, and actions are reviewed in your runner repository.
2

Build

The image includes polycore.json, actions, context, and any generated schema artifact.
3

Inject

CI or infrastructure tooling supplies enrollment and execution secrets without rewriting structural config.
4

Deploy

The environment’s long-running runner process starts or restarts.
5

Advertise

On connection, the runner sends the current catalog and project context to the control plane.
There is deliberately no dashboard write path into polycore.json, actions, or project context. A standing authority change remains a code and deployment change.

Environment isolation example

The same runner source can be deployed more than once: Each deployment uses its own runner registration and downstream credentials. The shared source does not collapse those runtime boundaries.