Add a New Standalone App
⚠️ This is the INFRA-MECHANICS appendix, not the full process. The canonical onboarding SOP — infrastructure and citizenship (spine, registry, governance, staffing, Definition of Done) — isUse this runbook when onboarding a brand-new Factory app that is not one of the original 6 apps (wordis-bond, cypher-healing, prime-self, ijustus, the-calling, neighbor-aid). New apps use a standalone per-app workflow pattern rather than the bulk scripts (app-onboarding.md. Start there. Known-stale: several workflows referenced below (create-hyperdrive.yml,scaffold-*.yml,setup-*-secrets.yml) no longer exist; use the scripts inpackages/deploy/scripts/directly. Librarian #1975 owns the refresh.
setup-all-apps.mjs, scaffold-all-apps.yml).
Rate Limiter ID Registry
Each app gets a unique Cloudflare rate limiter namespace ID. IDs are integers; never reuse one.
Next available ID: 1022
⚠️ Rate-limit bindings go under wranglerAllocate separate ids per environment so a misconfigured staging worker cannot exhaust the prod rate-limit budget. Update this table every time a new app or environment is added.unsafe.bindingswithtype: "ratelimit"— the top-levelrate_limiterskey is silently dropped (“unexpected field”) and binds nothing (the-calling#43).
Prerequisites
Before starting:- Neon project created for this app
- Connection string stored as a GitHub Secret in
Latimer-Woods-Tech/factory:{APP_UPPER}_CONNECTION_STRING- Example: app
xico-city→ secretMEXXICO_CITY_CONNECTION_STRING
- Example: app
-
CF_API_TOKENset in Factory GitHub Secrets -
GH_PAT(classic PAT withrepo+read:packages) set in Factory GitHub Secrets - GitHub repo created:
gh repo create Latimer-Woods-Tech/{app} --private
Step 1 — Add App to Factory Scripts
Edit three files inpackages/deploy/scripts/:
1a. create-hyperdrive.mjs
Add an entry to the CONFIGS array:
1b. write-schema.mjs
Add a schema entry to the SCHEMAS object with the app’s canonical Drizzle ORM schema.
1c. add-app-deps.mjs
Add an entry specifying which @latimer-woods-tech/* packages the app uses beyond the defaults:
Step 2 — Update create-hyperdrive.yml
In .github/workflows/create-hyperdrive.yml, add:
-
Env var in the
Create Hyperdrive instancesstep: -
Store step (even though it will fail with 403 — the log still captures the UUID):
Step 3 — Create Standalone Workflow Files
Create two new files in.github/workflows/:
scaffold-{app}.yml
Copy scaffold-xpelevator.yml and replace all occurrences of xpelevator with {app}, then:
- Set the correct rate limiter ID (from the registry above)
- Leave
--hyperdrive-idas a placeholder ("REPLACE_AFTER_STEP_4") until Step 4
setup-{app}-secrets.yml
Copy setup-xpelevator-secrets.yml and replace all occurrences of xpelevator with {app}.
- The JWT secret references
JWT_SECRET_{APP_UPPER}— add this to Factory GitHub Secrets before running - The Sentry DSN references
SENTRY_DSN_{APP_UPPER}— add this to Factory GitHub Secrets before running
Step 4 — Commit, Push, Create Hyperdrive
Step 5 — Extract Hyperdrive UUID from Logs
The “Store” step will fail with 403 (expected — see lessons-learned.md). Get the UUID from the successful “Create” step:- Hard-code the UUID in
scaffold-{app}.yml - Store it as a Factory secret:
- Commit and push the updated scaffold workflow
Step 6 — Add Required Secrets to Factory
Before running the scaffold and secrets workflows, ensure these exist inLatimer-Woods-Tech/factory GitHub Secrets:
Generate JWT secret:
Step 7 — Run Scaffold and Secrets Workflows
Step 8 — Update This Registry
Add the new app and its rate limiter ID to the registry table at the top of this file. Commit the update.Checklist Summary
- Rate limiter ID reserved (next available: 1012+)
- Neon connection string in Factory Secrets as
{APP_UPPER}_CONNECTION_STRING - GitHub repo created:
Latimer-Woods-Tech/{app} -
create-hyperdrive.mjsupdated -
write-schema.mjsupdated with canonical Drizzle schema -
add-app-deps.mjsupdated with app-specific package deps -
create-hyperdrive.ymlupdated with new env var + store step -
scaffold-{app}.ymlcreated -
setup-{app}-secrets.ymlcreated - All changes committed and pushed
-
create-hyperdrive.ymlworkflow triggered; UUID extracted from logs - UUID hard-coded in scaffold workflow + stored as
HYPERDRIVE_{APP_UPPER}secret -
JWT_SECRET_{APP_UPPER}added to Factory Secrets -
SENTRY_DSN_{APP_UPPER}added to Factory Secrets -
scaffold-{app}.ymlworkflow run successfully -
setup-{app}-secrets.ymlworkflow run successfully - Rate limiter registry table updated in this file
- Update
github-secrets-and-tokens.mdto include new app in the app list - Create
.github/repo-contexts/{app}/CLAUDE.mdwith the repo’s standing orders (stack, hard constraints, surfaces, commit format). The CIvalidatejob will fail until this file exists — see coh or humandesign for examples.