standards
Dedicated instancesIntroduction

Dedicated instances

Run the same SDK, CLI and MCP against an API host reserved for your organisation.


Standards is hosted at api.standards.new. On request, we run an instance on isolated servers dedicated to one organisation. Nothing else changes: the same SDK, the same CLI, the same MCP surface, under a hostname of yours.

The only setting that moves is baseUrl:

import { createStandards } from "@standards/client";

const standards = createStandards({
  // https://api.standards.new/v1 on the shared host; your own hostname on a dedicated instance.
  baseUrl: process.env.STANDARDS_API_URL!,
  apiKey: process.env.STANDARDS_API_KEY!,
});

The CLI stores one profile per instance: standards login --name production --url <your hostname>, then --instance production on any command. An MCP client uses the same /mcp path under your hostname.

When to ask

  • Data residency: your records must stay in a region or on servers of your choosing.
  • Compliance: an audit requires isolation from other tenants.
  • Volume: a sustained workload you would rather size on its own servers.
  • Custom connectors: integrations that only make sense inside your network.

To discuss one, book a demo below. Once your instance runs, [email protected] is its operations contact.

The sections below are for whoever operates the instance: the settings, variables and upgrade steps it runs on.

Public files are served at {PUBLIC_FILES_URL}/{fileId}. Without PUBLIC_FILES_URL, the base is ${API_URL}/public/files.

  • Point it at the API directly, or at a CDN in front of the API. Pointing it at the web app's /api/v1 rewrite sends every anonymous hit through your Next server.
  • Choose it before the first public upload. Rich text stores the absolute link: if the base changes, the old one must keep routing to the API.
  • Serve user uploads from a registrable domain of their own, not the app's: it keeps cookies apart and keeps what users upload away from the app's Safe Browsing reputation.

Webhook URLs

An instance publishes trigger webhook URLs under ${API_URL}/hooks by default. To publish them on another domain, set WEBHOOK_PUBLIC_URL and restart the API; the API still builds every webhookUrl itself, so callers keep reading it from the trigger.

Cross-origin headers

When the web app and the API sit on different origins, the API's CORS configuration must expose the x-stndrds-protocol response header: the app reads it to ask open tabs to reload after an upgrade, and a header the browser hides never triggers that prompt.

Session revocation

A dedicated instance verifies session access tokens the way standards.new does: it checks each token's signature locally against the auth project's keys, with no network call per request. An access token issued before a sign-out therefore keeps reaching the API until it expires, about 1 hour.

VerificationAfter sign-out, a stolen access token works forCost
Local signature check (default)up to its expiry, about 1 hournone per request
Ask the auth server, remember a valid answer for 30 sat most 30 secondsone auth call per token every 30 seconds

When revocation must take effect within seconds, ask for the second mode, or for a shorter access-token lifetime.

In-app news

Your workspace shows short announcements about new features: a banner when you arrive, a small marker next to the place a feature lives, and a "What's new" window with the full article. They come from https://news.standards.new, which your instance reads every 30 minutes. Your instance only shows announcements for the version it runs and for features your role can use. What you have already seen is remembered in your browser. Links to the public blog are hidden unless your instance shows them, so announcements stay inside your workspace.

Images in an article load in the browser straight from Standards' public file host (https://stndrds.io/f/…). If your instance sends a strict img-src Content Security Policy, allow that host, or articles show the images' descriptions instead.

A dedicated instance can:

  • turn announcements off entirely, so no outbound request is ever made;
  • read them from a mirror over https instead of news.standards.new;
  • show links to the public blog, or to your own copy of it.

Ask us to apply any of these when your instance is set up.

Meeting recording

A deployment records meetings through the Standards meeting relay. Set these variables and restart the API:

VariableMeaning
STANDARDS_MEETINGS_KEYThe deployment's key on the relay, issued by Standards. Absent → no bot joins any meeting.
API_URLThe API's public base URL, as the internet reaches it (https://api.example.com/v1). Required with STANDARDS_MEETINGS_KEY: the API refuses to start without it, because the relay calls this URL back.

The relay sends a bot to each meeting the workspace policy records, then notifies the deployment at {API_URL}/meetings/transcripts/webhook/standards when the transcript is ready. The deployment reads the transcript from the relay and stores it; the relay keeps nothing. Recordings are processed in the EU and deleted by the vendor after 24 hours.

Memory

Memory learns observed practices from each person's activity: a digest of the last 30 days, built every Monday at 03:00 UTC for every workspace. There is nothing to configure. To compute a digest at once instead of waiting for Monday, run standards memory activity (see the CLI).

Search index

Search runs on Meilisearch (version 1.53 or later). Each workspace has a record index, and the instance has one mail index. Both are built from PostgreSQL, so they can always be rebuilt.

Memory. Set MEILI_MAX_INDEXING_MEMORY on the Meilisearch container to about half of the container's memory limit (for example 2GiB on a 4 GiB container). Left unset, Meilisearch sizes indexing from the host's memory and can exceed the container limit during a build, which gets it killed.

The build at deploy. The first start of a release that changes the index layout builds the new indexes in the background: the mail index first, then each workspace's record index, smallest workspace first. Nothing needs to be run. The current indexes keep answering while a build runs. Until a workspace's record index exists, searches inside an object answer from PostgreSQL on record labels, without a total, and global search re-checks every hit in PostgreSQL. Mail received during the mail build shows in search a few minutes late. Builds run one workspace at a time on each Meilisearch host, smallest first: on an instance shared by many workspaces, the largest ones answer from PostgreSQL until every build before theirs is done. Note the 95th percentile of search latency before the deploy so you can compare it afterwards.

Rebuilding. standards search reindex (see the CLI) builds a workspace's record index beside the current one and replaces it in one step. There is no empty window. standards search reindex --emails --rebuild --yes does the same for the instance's mail index, from the stored mail of every workspace, but only to recover it: it is accepted while the mail index is not built or its email indexer stopped on an uncertain write (restart the workers once it is swapped in), and refused (HTTP 409) on a healthy one. Mail delivered by the previous release's workers during a rolling deploy is handed back to the indexer after the swap, so it reaches the new index.

Rolling back. Each switch deletes the index it replaces, so an earlier release finds none of the new indexes. After redeploying it, run standards search reindex for each workspace on that release. For mail, delete the emails index first, then run standards search reindex --emails for each workspace. Search is incomplete until the rebuilds finish. To deploy the newer release again later, first delete every <prefix>-<workspace>-records_v2 and …records_v2__staging index in Meilisearch: they stopped receiving writes during the rollback, and the newer release would answer from them instead of building new ones.

Task queue. Meilisearch keeps every finished task. The API deletes the ones older than 24 hours, which stops the task database from growing but does not shrink its file. To give the space back once, after the first purge, enable the compaction route and compact the task queue, then restart Meilisearch once the compaction has finished:

curl -X PATCH -H "Authorization: Bearer $MEILI_MASTER_KEY" -H 'Content-Type: application/json' \
  "$MEILI_HOST/experimental-features" --data '{"taskQueueCompactionRoute": true}'
curl -X POST -H "Authorization: Bearer $MEILI_MASTER_KEY" "$MEILI_HOST/tasks/compact"

Restart only once the compaction task has succeeded: GET $MEILI_HOST/tasks?types=taskQueueCompaction shows it succeeded.

The API also compacts an index by itself when at least 30 % of its file, and at least 200 MiB, is waste.

Environments

Environments and the agent sandbox run on Vercel Sandbox machines. Set one variable and restart the API and the workers:

VariableMeaning
VERCEL_SANDBOX<token>@<teamId>/<projectId>: the Vercel project both the agent sandbox and the environments use. The project must hold the agent image standards:default. Absent → agents have no sandbox, only the Standards default environment is listed, and creating an environment answers 503 with CONFIGURATION_REQUIRED.

A custom Standards environment's snapshot is built by the environments and read by the agent sandbox, and a snapshot resolves only inside its own project: the API refuses to start (CONFIGURATION_REQUIRED) when the two are configured with different projects.

The environment terminal talks to the machine directly over a WebSocket on *.vercel.run. If your app sets a Content Security Policy, add wss://*.vercel.run to connect-src, or the terminal stays blank.

Cloud browsers

Cloud browsers run at Kernel (kernel.sh), on the deployment's own Kernel account. Set these variables and restart the API and the workers:

VariableMeaning
KERNEL_API_KEYThe Kernel API key. Absent → no cloud browsers: no agent is offered browser_launch or a cloud browser grant, Settings → Execution → Browsers is hidden, and /browser-profiles and /cloud-browsers answer 503 with CONFIGURATION_REQUIRED.
KERNEL_EXTENSION_NAMEThe name under which the Standards browser extension was uploaded to Kernel (standards-ext-<version>). Required with KERNEL_API_KEY: the API refuses to start without it.
KERNEL_REGIONOptional: us-east, eu-west or ap-southeast. Passed to Kernel only when set; Kernel then starts browsers in us-east. Choosing a region needs Kernel's Start-Up plan. Even in eu-west, Kernel gives no data-residency guarantee.
API_URLThe browser extension inside each Kernel browser connects back to this URL's origin, so it must be reachable from the internet.

Every agent browser loads the Standards browser extension: upload the extension build to Kernel once per release, under the name set in KERNEL_EXTENSION_NAME. Loading a custom extension needs Kernel's Start-Up plan; the Developer plan stores a single extension, so a test and a production deployment sharing one Kernel account overwrite each other's.

The live view is an iframe served by Kernel. If your app sets a Content Security Policy, add https://*.onkernel.com:8443 and https://*.kernel.sh:8443 to frame-src, or the live view and the preparation window stay blank.

Upgrading to resource access grants

The release that lets a private agent be shared (see Sharing) renames the table that holds who else can open a private record. The previous image reads that table on every read of a record by a person, so from the moment the migration commits until the new image serves, any instance of the previous image fails those reads. The upgrade is stop-the-world, in one short maintenance window:

Stop every API and worker instance of the old image.

Apply the migrations (pnpm db:migrate, or your own migrator).

Start the new image.

The migration is one-way. Rolling back to the previous image needs the SQL at the head of the migration 20261009100000_resource_access_grants, run by hand in one transaction while the API is stopped.

GitHub and Slack connectors

Create a GitHub App and a Slack App for the deployment before enabling their cards in workspace settings. Configure the API and workers with the same credentials. A provider is enabled only when its entire variable family is present; partial configuration refuses startup.

VariableMeaning
CONNECTORS_GITHUB_APP_IDNumeric GitHub App ID.
CONNECTORS_GITHUB_SLUGApp slug from its GitHub installation URL.
CONNECTORS_GITHUB_PRIVATE_KEYFull PEM private key used to sign server requests. Preserve its newlines.
CONNECTORS_GITHUB_CLIENT_ID, CONNECTORS_GITHUB_CLIENT_SECRETApp OAuth credentials for each person's GitHub account.
CONNECTORS_GITHUB_WEBHOOK_SECRETSecret configured on the GitHub App's webhook.
CONNECTORS_SLACK_CLIENT_ID, CONNECTORS_SLACK_CLIENT_SECRETSlack OAuth credentials.
CONNECTORS_SLACK_SIGNING_SECRETSlack signing secret used to verify incoming events.
CONNECTORS_APP_URLWeb app URL used by “Open in Standards” links; defaults to APP_URL.

Both OAuth providers use {API_URL}/connectors/oauth/callback, unless CONNECTORS_REDIRECT_URI overrides it. The GitHub App's Setup URL is {API_URL}/connectors/oauth/github/installation; set the OAuth callback separately, and leave automatic authorization during installation off so the signed installation association can complete first. Enable expiring user access tokens. GitHub webhook delivery goes to {API_URL}/connectors/events/github. Enable write permissions for contents, pull requests, issues, actions, workflows and projects; read permissions for checks and metadata. Subscribe to pull_request, pull_request_review, pull_request_review_comment, issues, issue_comment, commit_comment, push, create, delete, release, workflow_run, check_run, check_suite, projects_v2_item, discussion, discussion_comment, star, fork and repository, alongside installation lifecycle events and user authorization revocation. Enable discussion and organization project permissions when using those event families.

Slack events go to {API_URL}/connectors/events/slack. Import the versioned slack-app-manifest.json supplied with the deployment, replace its example API URLs, and verify the request URL in Slack's App Manifest settings. Its fixed bot scopes support reading, sending, reactions, files and assistant activity; Standards agent grants control which actions an agent can use. No user token is requested. Token rotation is enabled. For new apps the manifest uses agent_view, following the current Slack manifest reference; existing apps should review the irreversible transition from the older assistant view before importing it.

Keep the original request bytes at both event endpoints: signature checks cannot verify a JSON body that a proxy parses and serializes again. Slack's challenge is answered after signature verification. Network enrichment and agent runs happen after the event is durably accepted, so the endpoint can acknowledge promptly.

GitHub installation credentials stay on the server. A sandbox receives the pinned author's personal GitHub token; that token can access every App installation available to that account. Selecting an installation in Standards does not confine the token to that installation. Each person must link their own account. Uninstalling a provider disconnects retained grants and triggers; deleting its connection in Standards removes dependent grants and triggers.

See it on your own data

Book a 30-minute demo with the team: cal.com/team/andyoucreate/introduction-30, or write to [email protected].

Next steps

  • SDK: createStandards and its options.
  • CLI: instance profiles and --instance.
  • MCP: connect Claude Code, Codex or Cursor to your host.
  • Book a demo