WBSP client guidelines — what always applies
These hold whatever you are doing. They are here so you never have to
choose to read them. Everything else is loaded by the phase that needs it:
open wbsp-guidelines-digest.md, find the entry for the phase you are in,
and read only what it binds.
- /notes is the mailbox (inbox/ written only by the carrier, outbox/ written only by this project, flat root = archive); /docs is your own internal documentation; /user-docs is user-facing. Never mix them. Files are never renamed and a note is never edited after sending — a correction is a new dated file. (wbsp-client-guidelines.md §1)
- A demo or sandbox talks to nothing outside its own container — no email, third-party API, webhook or outbound data. Gate on WBSP_SAMPLE_MODE, never on a missing key (a key baked in or injected later silently turns real sending back on). Say so in the interface where the feature would have been, keep workers and schedulers inert, and list every outbound path in the demo notes. Logging to stdout is not egress and continues. The full rule is on the ready-for-sandbox-checklist gate page, which the sandbox phase binds. (wbsp-client-guidelines.md §1)
- A demo/sandbox deploy needs NO auth client secrets: the platform injects AUTH_HAP_ISSUER / AUTH_HAP_ID / AUTH_HAP_SECRET / NEXT_PUBLIC_HAP_ENABLED at launch, AFTER your env, overriding anything baked in. Do not declare OIDC client variables under
secrets:for demo, do not put real OR placeholder values in .env.demo (the overlay only overrides keys with the same names, so an app reading its own OIDC_* names boots with the placeholders and login breaks), and never register a per-app client for a demo. The full rule is on the ready-for-sandbox-checklist gate page, which the sandbox phase binds. (wbsp-client-guidelines.md §6) - A green test suite does not mean the application runs. Before reporting it runnable, start it the way its own documentation says and request a plain page or the health endpoint, then read the log: a clean request must produce no error. This catches the faults tests never see — a framework paired with an unsupported peer version, a variable only the server path reads, a native module for the wrong architecture. (wbsp-client-guidelines.md §8)
- A local sign-in bypass is REQUIRED, not optional: three pipeline steps (UI fine-tuning, end-to-end tests, screenshot capture) run unattended and cannot complete a real login. It must be environment-variable gated, active only on dev/compose/standalone with cloud activation made IMPOSSIBLE in code (gate on a loopback address), and NEVER baked into the standalone image, Dockerfile, entrypoint or compose file — the screenshot step enables it at docker run time. The full rule is on the ready-to-test-checklist gate page, which the refine and test phases bind. (wbsp-client-guidelines.md §6)
- A note to another project may contain only one of four things — a question, a boundary report with your own evidence, an answer, or a yes/no with a reason — and may only ask its reader to act inside the reader's own repository. No advice, no suggestions, no comments on another project's code. A note that needs nothing gets no reply. Never paste a secret into a note; reference it by variable name. (wbsp-client-guidelines.md §1)
- All application code lives under /target (or, for a declared monorepo, under root-level source trees); wbsp.yaml and wbsp.Docker live in the repository ROOT, never under /target — a target/wbsp.yaml is silently not found by the tooling. (wbsp-client-guidelines.md §2)
- Authentication failures may redirect; authorization failures must RENDER a page saying the user has no access and who to contact — never a redirect back toward sign-in. A refusal loop is indistinguishable from an outage and gets reported to the platform team as one. A sign-in page that just refreshes is almost always the who-am-I call failing; identity resolution must depend only on the verified token and degrade to the base identity when optional client state is stale. (wbsp-client-guidelines.md §6)
- Destinations never layer. Each deploy reads exactly ONE file,
.env.<destination>, and never falls back to a bare.envor another destination's file. Every key a destination needs must be in its own file. (wbsp-client-guidelines.md §5) - Documents belonging to another project (HAP's endpoint reference and OpenAPI spec above all) reach this wiki as periodic COPIES that can lag the running service by days. An address absent from a copied specification is not evidence the route does not exist: probe the running service — for HAP,
https://hap.wbsp.ai/openapi.json— before concluding two documents disagree, and record the date you observed anything. (wbsp-client-guidelines.md §related-platform-documents) - Every documented command uses the project's OWN declared toolchain — if package.json names
packageManager: pnpm@…, every command in the README, compose file and useful-commands.md is pnpm, not npm. The wrong manager either fails or silently installs a second, divergent lockfile. (wbsp-client-guidelines.md §3) - Every explanation — in conversation, commit messages, user-docs, decision records, status reports — describes behaviour the reader can observe and names NOTHING they would have to open the source to understand: no files, functions, classes, tables, columns, endpoints, status codes or line numbers. Names the reader acts on (URLs, commands, wbsp.yaml/.env keys, env var names) stay. (wbsp-client-guidelines.md §explaining-your-work)
- In a demo or sandbox the
Exititem must NOT forward to HAP's exit endpoint — the visitor arrived on their wbsp.ai session via silent SSO, so ending the HAP session logs them out of the platform they came from. Gate on WBSP_SAMPLE_MODE: omit the item or point it at https://wbsp.ai without calling exit/end-session. The full rule is on the ready-for-sandbox-checklist gate page, which the sandbox phase binds. (wbsp-client-guidelines.md §6) - Never change files that belong to another project, never run git or deploy operations on another project, and never route a question to a team that merely calls the API you are asking about. Write to your own /notes/outbox; the operator or conductor carries it. A note is written, not sent — never report it as delivered. (wbsp-client-guidelines.md §9)
- Never hand-edit a deployed database. Schema and data changes flow only through versioned migrations or the application's own code; direct connections (psql via wbsp db) are for inspection and debugging. Prisma preferred, Drizzle acceptable for performance, TypeORM discouraged — deviations need permission and a documented reason. (wbsp-client-guidelines.md §4)
- Never write DATABASE_* or REDIS_* into env files — they are platform-injected, identically on every destination type. There is no DATABASE_URL or REDIS_URL in a pod; build the client from the discrete variables. (wbsp-client-guidelines.md §4)
- No first-user-wins administrator bootstrap, and no operator SQL to create the first admin. Read BOTH HAP claims —
is_app_adminandis_tenant_adminare independent, always present, and need no scope.falseis authoritative; an ABSENT claim is a fault to investigate, neverfalse. Reconcile existing local admins at HAP before shipping code that trusts the claims, or you demote them on their next sign-in. (wbsp-client-guidelines.md §6) - On
awsthe single unnamed component is routed to container port 8080 REGARDLESS of whatport:says, unlessuse_declared_port: true(which also injects PORT). The local types honourport:. The same config therefore means two things on a laptop and in the cloud. (wbsp-yaml-reference.md) - Provision an ordinary user on first sign-in with the default role; never park a HAP-authenticated user on an 'awaiting access' screen only an operator can clear. Gate privileged actions on the claims, not the front door. (wbsp-client-guidelines.md §6)
- Reply in exactly three bands, in order: 🟢 Done (verified facts), 🟡 Still to do (not the user's), 🔴 What you must do. Every request to the user lives in the red band and nowhere else; if it is empty, say so. (wbsp-client-guidelines.md §explaining-your-work)
- Secrets are declared by reference only in
secrets:; values live only in a git-ignored.env.<destination>. A declared secret with no value FAILS the deploy (fail-closed) — it never deploys silently unset. (wbsp-client-guidelines.md §5) - The application must reach a usable first screen from EMPTY storage with no operator step:
release:runs before the workload on every install against a possibly brand-new database, and migrations alone are not enough — any row a first user must belong to (default workspace, tenant, org, team, role) is created there, idempotently. A schema-only release refuses every user it has just authenticated. (wbsp-client-guidelines.md §4) - Validate the ISSUER, not the audience alone. A HAP client id is unique per tenant only (and may now be chosen by the caller), so a token's
audno longer identifies a tenant or installation; the issuer{hap-url}/t/{tenant}does — check it against your configured AUTH_ISSUER. Never use a client id as a database key, tenant discriminator or filename; use the application's internal uuid. (wbsp-client-guidelines.md §6) demo,sandboxanduniversalare reserved destinations: declaringtype,mode,tenant,clusterorenclaveunder any of them is a hard error — including an empty value and a value that happens to match.demo: {}/universal: {}is the normal shape. A baredemo:followed only by comments parses as null, not an empty map, and is refused. (wbsp-yaml-reference.md)tenant:is declared per destination. A root-leveltenant:is rejected by the parser. (wbsp-yaml-reference.md)- wbsp.yaml must declare
variant: <uuid>(fromwbsp whoami), by convention immediately beforename:. Without it every image-producing deploy is refused. (wbsp-client-guidelines.md §2)