Running vibld yourself
Settings and secrets
Checked against the product on
Two kinds of value. A var is public: it ships in the Worker’s wrangler.jsonc and is meant to be read. A secret is set out of band, with wrangler secret put, and never committed. Everything here is the builder’s unless it says otherwise; apps/web/.env.example lists the builder’s secrets with the shape of each.
For a copy of your own, scripts/self-host.mjs writes the names, CLERK_FRONTEND_API_URL, VIBLD_PROVIDER and VIBLD_MODEL from a settings file, and drops VIBLD_MODEL unless you give one, so the provider’s default answers. See Deploying.
Secrets
Each is optional: unset means the feature it unlocks reports itself unavailable, never that anything opens up.
ANTHROPIC_API_KEY,DEEPSEEK_API_KEYorOPENAI_API_KEY. Any one makes generation available, and so does a local model (below); without any, generation refuses. Setting more than one makes each of those providers’ models available to choose from, within whateverVIBLD_MODEL_POLICYbelow allows.VIBLD_LOCAL_API_KEY: only for a local model server started with an API key.VIBLD_PLATFORM_ADMINS, comma-separated email addresses. Each is matched against the verified email in the caller’s Clerk session. An admin is always past the invite gate and gets the admin panel. Unset means no admins, and on a deployment that is not open, nobody at all can generate.CLERK_SECRET_KEY. Not needed for sign-in, which verifies sessions against public keys. It powers the admin tools that talk to Clerk: approving an invited address in Clerk, looking an account up by email for credit grants, banning, and deleting the sign-in account when an account is purged. Each of those says so when the key is missing.PREVIEW_INTERNAL_SECRET, shared with the sandbox Worker. Both sides must carry the same value.PUBLISH_INTERNAL_SECRET, shared with the publish Worker. Deliberately a different value from the one above: a leak of one must not compromise the other. Publishing needs both, because the sandbox builds what the publish Worker serves.STRIPE_SECRET_KEYandSTRIPE_WEBHOOK_SECRET, only if you are charging.VIBLD_MODEL_POLICY, JSON naming which models each identity may use. A secret rather than a var because it names people. Absent means no policy: everyone may use whatever the deployment can serve. Where billing is configured, a Free account is held to GPT-6 Luna whatever the policy grants, so a deployment that charges needs a key that serves it for its Free accounts to build at all.
The GitHub App’s five values (VIBLD_GITHUB_APP_ID, VIBLD_GITHUB_PRIVATE_KEY, VIBLD_GITHUB_CLIENT_ID, VIBLD_GITHUB_CLIENT_SECRET, VIBLD_GITHUB_WEBHOOK_SECRET) are secrets too. Without the webhook secret, pushing still works but /api/github/webhook answers 503, so a merged pull request goes on being shown as open. The private key is a PEM file that downloads once; it belongs in a secret store and nowhere else. They come from a GitHub App of your own, and the builder looks up that App’s installation page from the App ID and key; the repository’s README, under “Pushing to GitHub”, has the steps.
SUPABASE_OAUTH_CLIENT_ID and SUPABASE_OAUTH_CLIENT_SECRET, secrets, are your own Supabase OAuth app, made at supabase.com/dashboard/org/_/apps with the redirect URL https://<your app host>/api/supabase/callback. With both, the Keys tab offers Connect Supabase, so an owner signs in to Supabase and picks a project instead of pasting an access token. Without them the paste still works.
Sign-in
CLERK_FRONTEND_API_URL, a var: your Clerk instance’s Frontend API URL. A public identifier, not a secret. It is both the issuer the Worker matches tokens against and the base it fetches the signing keys from. The shipped value is vibld’s own.VITE_CLERK_PUBLISHABLE_KEY, a build variable rather than a Worker secret: Vite inlines it into the interface when you build. Locally it goes inapps/web/.env.local, not in.dev.vars. (vibld’s own deploy stores it as a secret calledCLERK_PUBLISHABLE_KEYand passes it to the build under this name.) Without it the interface has no sign-in, and every request it makes is refused.
The invite gate
VIBLD_ACCESS_MODE decides who may use the deployment once signed in. Only the exact string open lets every signed-in account in. Anything else, including unset, OPEN and open with a trailing space, keeps the gate shut to all but platform admins and the addresses they invite. It is not in the shipped wrangler.jsonc, so a fresh deployment is closed. vibld’s own deploy sets it as a secret; a var works the same.
Vars you have to set
VIBLD_PROVIDER:anthropic,deepseek,openaiorlocal, the provider that answers when no model is named. Set it rather than relying on which key is present. Any other value is an error.VIBLD_LOCAL_BASE_URLandVIBLD_LOCAL_MODEL: a model on a server of your own, such as Ollama, LM Studio or llama.cpp. The first is the server’s OpenAI-compatible address, ending in/v1, and the second the model’s name there. Both are needed. The builder offers it as “Local: ” and its name, and it costs nothing against anybody’s allowance. A Worker on Cloudflare reaches only the public internet, so the server has to be reachable from there; under Docker it can be on your own machine. Give the model a context window of 32,768 tokens or more.VIBLD_MODEL: the default model, which beatsVIBLD_PROVIDERwhen set. The shippedwrangler.jsoncsetsVIBLD_PROVIDERtoopenaiand this togpt-6-sol. If your keys cannot serve the model named here, a build that does not pick a model is refused with a message saying why, rather than run on some other model. A model picked in the builder that your keys do serve still runs. Set this to a model your key serves, or delete it to get the provider’s default. On the command line, a setVIBLD_MODELpicks the provider outright.
Vars that bound spend
VIBLD_ACCOUNT_DAILY_MICRO_USD: what the whole deployment may spend per UTC day, across every account. This is the one that stops a compromised account spending the month. The shipped default is a starting point, not a measured figure.VIBLD_FREE_MONTHLY_MICRO_USD: the Free tier’s monthly allowance, $1 unless set. With billing configured, a Free account has it once it saves a card no other account saved first, or pays for a plan or a top-up. Set it only to change that figure. Paid tiers are not configurable here, since their included spend is fixed by the price table rather than by an operator.VIBLD_FREE_TRIAL_MICRO_USD: with billing configured, what a Free account without the monthly allowance may spend, once: $0.20 unless set, and 0 means nothing until the account has the allowance. Without billing it does not apply.VIBLD_FREE_DAILY_MICRO_USD: Free runs’ share of the deployment’s daily ceiling, $10 unless set: free use takes at most that much, and the rest stays for paying accounts. A Free account’s run paid from top-up credit does not count against it. Like the trial, it applies only with billing configured.VIBLD_FREE_PREVIEW_DAILY_MINUTES, on the preview Worker: after how many minutes in a day a Free account’s sandbox previews stop starting, 120 unless set. A preview already running finishes, so a day can run over by one preview (at most 30 minutes). Like the other Free limits, it applies only with billing configured.VIBLD_MAX_IN_FLIGHT: concurrent runs per user.VIBLD_SIGNUP_CREDIT_USD_CENTSandVIBLD_SIGNUP_CREDIT_FROM: an optional one-time grant for a new account (0 cents, off, unless set), and the instant from which accounts count as new. The second has no default: any default early enough to catch new accounts would also catch every existing one. The grant waits for a card saved through Stripe, so it needs billing configured and the Stripe webhook subscribed tocheckout.session.completedorsetup_intent.succeeded; without Stripe nobody gets it.
Your own domains
PREVIEW_HOSTNAME, on the sandbox Worker: the domain previews and share links are minted under. It has to match that Worker’s wildcard route. Unset, previews report themselves not configured.PUBLISH_HOSTNAME, on the publish Worker and on the builder: the domain published sites are served under, and the address a project shows for its site. Both default tovibld-preview.dev, so set both. Published sites share the preview domain: the sandbox Worker hands the publish Worker every host that is not a preview or a share.VIBLD_REFERRAL_ORIGIN: where a referral link points. Unset, it is your builder’s own address.
The other two Workers’ secrets
- The sandbox Worker carries
PREVIEW_INTERNAL_SECRET(the builder’s value) andPREVIEW_SHARE_SECRET, which signs share links. A third, separate value that only the sandbox holds: without it, sharing reports itself not configured. - The publish Worker carries
PUBLISH_INTERNAL_SECRET(the builder’s value).
RESEND_API_KEY turns on one email: a nightly warning when the DeepSeek balance is below VIBLD_DEEPSEEK_BALANCE_ALERT_USD (default 10). It goes to VIBLD_ALERT_EMAIL from VIBLD_ALERT_FROM, whose defaults are vibld’s own addresses, so set both. The From address has to be on a domain your Resend account can send from.
Vars you should probably leave alone
VIBLD_USD_MICRO_PER_INPUT_TOKEN and VIBLD_USD_MICRO_PER_OUTPUT_TOKEN override the running model’s own rate. Set them only if the built-in rate for your model is wrong. Pinning one provider’s prices while running another’s model has already ceilinged every run here at roughly forty times its real cost, turning a budget of forty generations a day into two.
VIBLD_REPLAY_QUERY_BUDGET: the D1 queries the nightly billing pass may spend in one invocation. Unset means 40, which fits the Workers free plan’s limit of 50. The shippedwrangler.jsoncsets 500, sized for Workers Paid. Above your plan’s limit, the pass fails at the same point every night.VIBLD_STREAM_KEEPALIVE_MS: milliseconds between keepalives on the generation stream. Default 10000; a value outside 1000 to 60000 is ignored.