SUPPORT_EMAIL |
where the support digest goes (else every admin and support address) |
NVM_DIR |
the nvm installation directory (~/.nvm by default), used when the platformkit CLI restarts under Node 22 because npm run dev started with another Node version |
PLATFORMKIT_SITE_<NAME>_GIT_URL |
the HTTPS, SSH, or local Git URL used by platformkit sites fetch when --url is omitted; uppercase the site name and replace hyphens with underscores |
PLATFORMKIT_GITHUB_TOKEN (else GITHUB_TOKEN / GH_TOKEN) |
authenticates managed site fetches and updates for private GitHub HTTPS remotes. Git receives it through temporary process configuration (GIT_CONFIG_COUNT is adjusted internally); do not set that variable yourself. The URL and local site registry never contain the token |
UNSPLASH_ACCESS_KEY |
the admin offers an Unsplash tab on every picture field; unset, the library is the only source and no tab is drawn. A free key from unsplash.com/developers; the server holds it, never the browser |
REDDIT_USER_AGENT |
optional Reddit API identification string; the generic kit value is used when unset |
LINKEDIN_API_VERSION |
optional LinkedIn API version; the adapter uses its supported default when unset |
SHARE_FONT |
optional font family for generated share-card images; defaults to Newsreader |
FORMS_WEBHOOK_SECRET |
the key a form's webhook deliveries are signed with (X-Form-Signature); else derived from the service key |
PUBLIC_FUNCTIONS_URL, VITE_PUBLIC_FUNCTIONS_URL |
the functions on the site's own domain (https://<site>/v1), with the host's rewrite; off by default |
VITE_AUTH_MAGIC_LINK, VITE_AUTH_GOOGLE |
the extra sign-in methods (Google also needs the provider enabled in Supabase) |
IN_BROWSER_TTS |
false switches the person's in-browser voice off for everyone |
LOCKDOWN_MODE |
1 closes the built site to everyone but the staff |
CONTENT_STORE |
cloud selects row-backed content: the admin function serves the production CMS, rows are exported before build, and the content API reads rows; with a connected repository, publishing writes back and rebuilds, while without one rows are the sole source. Otherwise the build uses the resolved deployment.content setting. The CLI and deploy pass that resolved value into the browser build; a backend site registering admin.models is refused if it would compile file-backed content. Read by the build and inlined into the bundle under its exact name; invalid values are refused |
VITE_SUPABASE_STUDIO_URL |
the local Studio's address, linked from the admin |
VITE_BANK_SHEET |
a site with an instrument: swap the statement bank from a Google Sheet without a release |
MATRIX_API_TEST |
0 skips the Matrix lane’s live half, as the other API lanes are skipped |
MATRIX_FN_URL |
where that lane looks for the served function; the local stack’s address by default |
SOCIAL_TEST_MAILPIT_URL |
the social invitation integration test’s local Mailpit URL; defaults to the stack’s Mailpit port |
TTS=1 |
the deploy speaks what is missing (hours) and mirrors the weights |
PRINT_BUILD=1 |
explicitly enables the deploy's printed-edition render and upload step; unset or any other value skips it. This does not disable printer-credential checks for published print offers or change local print commands. When skipped, the cover image in each book's markdown cover field shows beneath any unavailable generated print art |
TTS_VOICE, TTS_STEPS, TTS_SPEED, TTS_THREADS, TTS_BITRATE |
the voice and its settings (a change renames every recording) |
TTS_COMMIT=1 / local, TTS_GITHUB_TOKEN (else GITHUB_TOKEN / GH_TOKEN), TTS_COMMIT_BRANCH, TTS_COMMIT_NAME, TTS_COMMIT_EMAIL |
a tts run commits and pushes its store; a build box's token; the committer it signs as |
TTS_GAP |
the silence between spoken pieces, in seconds |
FFMPEG |
a path to ffmpeg, when not the machine's or ffmpeg-static |
SUPABASE_URL |
the project url for the tts script's uploads (else VITE_SUPABASE_URL) |
APP_URL |
the functions' side of the app's origin: platformkit dev writes it into the functions' env for the run; the deploy sets it from VITE_APP_URL |
SITE_URL |
the site's public address for the prerender's absolute links, when content/site.md sets none |
PRINT_COMMIT=1 / local, PRINT_GITHUB_TOKEN / GITHUB_TOKEN |
a title made at the printer committed back |
PLATFORMKIT_ALLOW_DESTRUCTIVE=1 |
for one run: a plan that loses data is applied, and the log says so |
SCHEMA_TEST=0 |
skips the schema test in platformkit test |
SQL_COLUMNS=0 |
skips the column guard (every column a SQL function names, against the kit's and the site's declarations read as one) in platformkit test; it needs no database |
PLATFORMKIT_SKIP_STATIC_LANE=1 |
skips the static lane — a site with no backend built, served and walked with the console and the network watched. It is the slow one (a real build per fixture), and skipping it is reported at the end of the run rather than passing quietly, since a shape nothing exercises is a shape that rots |
PLATFORMKIT_SHARE_STACK=1 |
runs the share sidecar check against a real compose stack — a Playwright image and a compose build, so it is out of the default run; without it the nginx config is still checked both ways (with a sidecar and without) and the skip says what went unchecked |
PLATFORMKIT_SKIP_CLOUD_LANE=1 |
skips the cloud lane — the publish cycle over rows against a local stack. It skips itself when no stack is up, and either way says which shape went uncovered |
POLICY_TEST=0 |
skips the policies test (who may read what, against the local stack's seed) in platformkit test; it skips itself when the stack is down |
ENCRYPTION_TEST=0 |
skips the encryption test (what a sealed message leaves in the row and in the index, and that the seal is one-way) in platformkit test; it skips itself when the stack is down |
ANALYTICS_TEST=0 |
skips the database half of the analytics test (the channel rule, the audience partition, recirculation, right now, the channels over the seed) in platformkit test; the arrival parser is still checked; it skips itself when the stack is down |
INTERACTION_URL |
where the interaction lane (build/interaction.test.mjs) finds the site to use — a browser that types into the palette, sends a line from the support widget, answers a diagnostic screen and opens the bag, with the console watched. Default http://localhost:5173; --url overrides it. With nothing serving there the lane skips loudly rather than passing |
BROWSER_WAIT_MS |
the floor on every browser timeout in the repository, set on each context by build/browser.mjs. Default 60000. Playwright’s own default is 30000 and applies to any call given no explicit budget, so a file that writes 60 on the waits it thought about still ran the rest at 30 — and under load those are the ones that fail. One number, and it is a minimum: a call that needs longer still passes its own |
INTERACTION_WAIT_MS |
how long the interaction lane waits for any condition before giving up. Default 60000 — generous on purpose, since the lane drives a real browser while the rest of the suite loads the same machine, and a timeout tuned to an idle laptop makes it fail for reasons that have nothing to do with the site |
CONTENT_API_TEST=0 |
skips the content index test (every published entry rendered, an unpublished one absent, the ids stable) in platformkit test |
FORMS_API_TEST=0 |
skips the Forms API test (the shapes, the official client against the served function, the webhooks, the embed) in platformkit test |
FORMS_API_SHOTS |
a directory the Forms API test writes its embed screenshot into (none by default) |
SCHEDULING_API_TEST=0 |
skips the Scheduling API test (the shapes, cal.js pointed at the site, the judge, the webhooks, cal.com's embed) in platformkit test |
RECOMMENDATIONS_TEST=0 |
skips the recommendations test (what somebody is interested in, against the local stack: a re-tagged piece changing it with nothing re-run, a partial read counting, a purchase outweighing browsing) in platformkit test; it skips itself when the stack is down |
REWRITES_TEST=0 |
skips the rewrites test (the nginx instance in Docker against the local stack) in platformkit test; it skips itself when Docker or the stack is down |
SCHEDULING_API_SHOTS |
a directory the Scheduling API test writes its embed screenshots into (none by default) |
STOREFRONT_API_TEST=0 |
skips the Store API test (the products and the schema, the official client against the served function, the cart, the checkout url followed) in platformkit test |
PROMO_TEST=0 |
skips the discount-budget test (a limit counted in the database, and ten checkouts racing for three remaining uses) in platformkit test; it skips itself when the stack is down, naming what it did not cover |
INVENTORY_TEST=0 |
skips the stock test (the decrement racing two connections for the last unit, reservations, a refund putting the count back) in platformkit test; it skips itself when the stack is down, naming what it did not cover |
ORDERS_TEST=0 |
skips the orders test (the transactions summing to the total and refused at the write, fulfilment and payment derived rather than stored, an edit raising the version, stock coming back on received and never on requested) in platformkit test; it skips itself when the stack is down, naming what it did not cover |
STOREFRONT_API_SHOTS |
a directory the Store API test writes the handoff page's screenshots into (none by default) |
SUPPORT_API_TEST=0 |
skips the Support API test (the shapes, the Client and Application APIs, the webhooks, the snippet) in platformkit test |
SUPPORT_API_SHOTS |
a directory the Support API test writes the snippet's screenshots into (none by default) |
SDK_TEST=0 |
skips the analytics script's test (the built file loaded in a headless page against the served ingest door: PostHog's surface, the size, a page view, identify, an opted-out page, PostHog's snippet) in platformkit test; it skips itself when the stack is down |
FUNNELS_TEST=0 |
skips the funnel analytics test (the journey and the conversions against the local stack's seed, the unsubscribe link against the served function) in platformkit test; it skips itself when the stack is down |
WEBHOOKS_TEST=0 |
skips the shipped-subscriptions test (declared, pushed, a secret from the environment, one made by hand untouched) in platformkit test; it skips itself when the stack is down |
WH_TEST_SECRET |
set by that test alone, to prove a secret reaches a subscription from the environment and never from the file; nothing else reads it |
SPACES_TEST=0 |
skips the spaces' database test (the fill sweep, the isolation, the counters against a walk, the cursor, the live topic) in platformkit test; it skips itself when the stack is down |
NETWORK_TEST=0 |
skips the network's database tests (the audiences, a reply never wider than its post, blocks and mutes, the timeline, moderation — and the community's one notification list) in platformkit test; it skips itself when the stack is down |
ATPROTO_TEST=0 |
skips the atproto test (the network as an atproto server, driven by Bluesky's own client against the served function) in platformkit test; it skips itself when the function is not served |
ATPROTO_INTEROP_TEST=0, ATPROTO_PLC_PORT |
skip the federation's interop test; the port its PLC directory listens on (2582, and its app view the next) — it skips itself when the function does not federate |
COPILOT_TEST=0 |
skips what a person told an assistant being theirs (the policies, the recall floor, the deletion) in platformkit test; it skips itself when the stack is down |
COPILOT_TTS_URL, COPILOT_TTS_KEY |
an OpenAI-shaped /v1/audio/speech the site is heard in instead of the kit's own voice. The key stays here and never reaches the browser; with neither set the page speaks for itself |
COPILOT_TTS_MODEL, COPILOT_TTS_VOICE |
which model and voice that endpoint is asked for (tts-1, alloy) |
COPILOT_TURN_MS |
maximum time the Copilot completion function waits for one turn; defaults to 60 seconds |
COPILOT_BASE_URL |
optional LiveKit worker completion base URL; if unset, the worker uses APP_URL plus /v1 |
COMMUNITY_TEST=0 |
skips the community's database test (the three kinds in one instance, invitations, moderating and inviting as grants, the four acts, the mute as a fence) in platformkit test; it skips itself when the stack is down |
AWARDS_TEST=0 |
skips the achievements and traits database test (the event stream awarding a badge when its rule is met and not before, and a client able neither to award itself one nor to read what the site believes about it) in platformkit test; it skips itself when the stack is down |
AGENT_TEST=0 |
skips the agent loop's database test (a run answered, a worker killed mid-run and picked up by another, a cancel that stops a tool before it runs, a budget that holds) in platformkit test; it skips itself when the stack or the functions are down |
AGENTS_LIVE=1 |
bots may buy thinking. Without it nothing reaches a vendor whatever keys are set, because a key in the environment is not consent to spend money on bots; the rule is in the provider rather than in a variable somebody remembers |
PLATFORMKIT_AGENT_MOCK=1 |
every bot answers from a script instead of a model, so nothing is bought. A run that carries a script is never bought anyway, whatever this says |
AGENT_API_KEY |
where bots buy their thinking; OPENAI_API_KEY is used when it is unset. With neither, bots answer from the mock |
AGENT_API_BASE |
an OpenAI-shaped endpoint other than OpenAI's — Azure, Groq, Together, OpenRouter, vLLM, Ollama. Defaults to https://api.openai.com/v1 |
AGENT_MODEL |
the model a bot uses when its own file does not name one |
ANTHROPIC_API_KEY |
a SECOND provider, tried when the first fails for a reason of its own — no credits, a bad key, a rate limit, their server down. A malformed request is not retried: it fails the same way everywhere |
ANTHROPIC_MODEL |
what the fallback uses. It uses its OWN model, never the one asked for: a model is a provider's own word, and sending gpt-4o-mini to Anthropic is a second failure rather than a fallback |
ANTHROPIC_API_BASE |
somewhere other than https://api.anthropic.com |
AGENT_PROVIDERS |
the order, by name (anthropic,openai). Anything not named is left out. Default: the OpenAI-shaped one, then Anthropic |
AGENT_MAX_TOKENS |
the longest answer Anthropic may give (its API requires a limit; 4096 by default) |
DESK_TEST=0 |
skips the staff desk's database test (three sources in one list, each answered where it lives, and nothing of anyone's disclosed to somebody) in platformkit test; it skips itself when the stack is down |
COMMENTS_TEST=0 |
skips the comments' database test (who is held and who is not, the flagged word beating trust, what an approval writes down, the embed's three declarations) in platformkit test; it skips itself when the stack is down |
PEOPLE_TEST=0 |
skips the People panel's database test (every account, one person's whole picture, and never the last administrator away) in platformkit test; it skips itself when the stack is down |
PAYOUTS_TEST=0 |
skips the ledger's database test (the sweep run twice, the delay, and a refund either side of the window) in platformkit test; it skips itself when the stack is down |
HOLDS_TEST=0 |
skips the holds test (nobody's time taken twice: the hold written with the booking, two at the same instant, a group holding its host once) in platformkit test; it skips itself when the stack is down |
TEAMS_TEST=0 |
skips the teams membership test (the rule filling a team, an invitation surviving a change to the rule, a membership that is not a directory) in platformkit test; it skips itself when the stack is down |
PROVIDERS_TEST=0 |
skips the stack half of the providers test (a signed version frozen, who is owed the new one, an offering theirs and never deleted, failing to sign stopping selling and nothing else) in platformkit test; the pure half still runs, and it skips itself when the stack is down |
HUDDLE_LIVE=0 |
skips the two-browser call in the huddle test (the rest of it still runs); it skips itself when no dev server answers |
HUDDLE_APP |
where that two-browser call looks for the site, when it is not http://localhost:5173 |
HUDDLE_ROOM |
the room it opens, as a path (/spaces/<space>/<channel>); by default the site's staff space and its general |
PLATFORMKIT_ICONS_ALL=1 |
the icons step writes every Lucide glyph, not only the ones the pages name (the dev server does this by itself, so the builder's palette is whole) |
OPENAI_API_KEY, REPLICATE_API_TOKEN, COMPANION_MODEL, COMPANION_THINKING |
the enrichment's model |
PRERENDER=0, SHARE_IMAGES=0, PLAYWRIGHT_CHROMIUM_PATH |
the build without the prerender or the images; a browser of your own |
DEPLOY=1 |
what lets deploy.mjs run at all |