Learnings: Paperclip Railway deployment (March 2026)
Context: First deployment of Paperclip (agent orchestration app) from the brainforge-platform monorepo to Railway, with custom domain paperclip.brainforge.ai and adapter API keys (e.g. Gemini).
Use these learnings to update skills, playbook, and platform when deploying new services or similar apps.
1. Monorepo deploy: use --path-as-root
- Problem: Pushing the full repo triggered
413 Payload Too Large(huge upload). - Fix: Deploy from repo root with path-as-root so only the app directory is the build context:
railway up apps/paperclip --path-as-root - For skills/playbook: Any “deploy app from monorepo to Railway” flow should document
railway up <app-path> --path-as-root. Add tostandards/03-knowledge/engineering/setup/railway-*.mdor a generic “Railway monorepo deploy” note.
2. Railway Dockerfile constraints
- VOLUME: Railway disallows the
VOLUMEinstruction. Remove it or comment it out; use Railway volumes in the dashboard if persistent storage is needed. - For skills: A “Railway Dockerfile” checklist or skill could include: no
VOLUME, no other banned instructions per current Railway docs.
3. TypeScript in Docker: global augmentation
- Problem:
Express.Requestaugmentation in a separateexpress.d.tswas not applied during the Docker build, soreq.actorfailed in routes even though it worked locally. - Fix: Inline the
declare global { namespace Express { interface Request { actor: ... } } }block into the main entry file (server/src/index.ts) so it’s part of the compiled unit. - Learning: In strict Docker/CI builds, keep critical global type augmentations in a file that is definitely compiled (e.g. entry), or ensure
tsconfiginclude/exclude clearly picks up the.d.tsand the same options as local.
4. Adapter API keys via service env (no UI)
- Observation: Users prefer setting adapter API keys (e.g. Gemini) as service environment variables (e.g. Railway vars) rather than adding more UI.
- Already supported: Paperclip adapters (e.g. Gemini) read
GEMINI_API_KEY/GOOGLE_API_KEYfrom serverprocess.envfor both environment checks and runs. - Action taken: Documented in
apps/paperclip/docs/deploy/environment-variables.md. For other providers (e.g.GOOGLE_AI_STUDIO_GEMINI_API_KEY), document “rename when setting on host” (e.g. set asGEMINI_API_KEYon Railway). - For skills/playbook: When adding a new adapter or provider, document the server env var name(s) in the app’s deploy docs and, if useful, in playbook setup so operators know what to set on Railway/Heroku/etc.
5. Domain strategy: subdomain vs subpath
- Tried first:
platform.brainforge.ai/paperclip(subpath proxy from Platform app). - Switched to:
paperclip.brainforge.ai(dedicated subdomain). - Learning: Subpath requires base-path handling in the app, proxy + auth bypass in the parent app, and more moving parts. For a net-new service, a dedicated subdomain is simpler: no proxy, no base path, healthcheck at
/api/health, and auth (e.g. Better Auth) configured for one origin. - For skills: A “deploy new service with custom domain” skill could default to subdomain and only use subpath when there’s a strong reason (e.g. single-domain requirement).
6. Better Auth: trusted origins
- Problem: Account creation returned 403 when using the Railway URL or custom domain; Better Auth was rejecting the request origin.
- Fix: Set
BETTER_AUTH_TRUSTED_ORIGINS(comma-separated) to include both the Railway default URL and the custom domain, e.g.https://paperclip-production-xxx.up.railway.app,https://paperclip.brainforge.ai. - For skills/playbook: Any app using Better Auth behind a proxy or with multiple domains should document “set
BETTER_AUTH_TRUSTED_ORIGINS(and optionallyPAPERCLIP_ALLOWED_HOSTNAMES/PAPERCLIP_AUTH_PUBLIC_BASE_URL) for all public URLs.”
7. First-time instance setup in production
- Need: Run
paperclip onboardand optionallypaperclip auth bootstrap-ceoinside the live Railway container. - Gotcha: Interactive prompts (e.g. Corepack “Do you want to continue?”) block non-interactive use.
- Fix: Use non-interactive invocations, e.g.
npx --yes pnpm@9.15.4to avoid Corepack prompt when running commands viarailway ssh. - For skills/playbook: Document “first-time instance setup in production” (onboard, bootstrap) and non-interactive CLI patterns so scripts and agents don’t hang.
8. Healthcheck path
- With a root-mounted app (no base path), healthcheck is
/api/health. With a subpath (e.g./paperclip), it would be/paperclip/api/health. SethealthcheckPathinrailway.toml(or Railway service config) to match.
Summary: what to change
| Area | Change |
|---|---|
| Playbook | Add “Monorepo deploy: railway up <path> --path-as-root” to Railway setup docs; add “Better Auth trusted origins” and “first-time instance setup (non-interactive)” for Paperclip or similar apps. |
| Skills | Consider a “deploy net-new service to Railway” skill: path-as-root, env checklist, trusted origins, healthcheck, optional subdomain vs subpath. |
| Platform / Cursor rules | If we add more in-repo services: reference playbook for Railway monorepo deploy and Dockerfile constraints. |
| Paperclip docs | Already updated: env vars (GEMINI_API_KEY, GOOGLE_API_KEY), deploy environment-variables.md. |
Captured 2026-03-17 from Paperclip Railway deployment and post-deploy configuration (custom domain, Gemini key, Better Auth).