Linear OpenCode webhook + Railway production (web)
Date: 2026-04-15
This runbook ties together the Brainforge Platform Linear OAuth app, the Forge host platform.brainforge.ai (no www), and Railway service web (production).
Preconditions
- 1Password CLI:
op signin(vault: Brainforge Platform Team, item: Brainforge Platform Linear App). - Railway CLI:
railway loginand access to project brainforge-platform. - Linear workspace admin for installing / re-authorizing the app.
1) Linear — webhook URL (must be public DNS)
In Linear → Settings → API → Applications → Brainforge Platform → Webhooks:
- Webhook URL must be exactly:
https://platform.brainforge.ai/api/brainforge/linear/opencode-webhook
Do not use www.platform.brainforge.ai (NXDOMAIN unless DNS is added).
- Enable webhook categories needed for agents (at minimum Agent session / equivalent wording in Linear’s UI).
Copy the Webhook signing secret shown in Linear into 1Password (same secure note is fine: Signing Secret: / Webhook Secret: lines).
2) Railway — which service
Production Forge runs on Railway service web (custom domain platform.brainforge.ai).
From repo:
cd apps/platform
railway link -e production # if needed
railway service link web
railway statusYou should see Service: web.
Canonical URL for Linear OAuth (redirect_uri)
Linear returns Invalid redirect_uri if the authorize request uses a callback origin that is not exactly listed under the OAuth app’s Callback URLs.
Set on service web (production):
railway variable set -s web -e production NEXT_PUBLIC_BASE_URL=https://platform.brainforge.aiThe Forge OAuth routes prefer NEXT_PUBLIC_BASE_URL over the request Host, so opening the flow via www (or another alias) still sends redirect_uri=https://platform.brainforge.ai/api/brainforge/linear/oauth/callback, matching the usual Linear registration.
3) Railway — set the signing secret from 1Password
Automated (recommended):
cd apps/platform
python3 scripts/sync-linear-opencode-webhook-secret-to-railway.pyManual alternative (avoid pasting secrets into chat logs):
cd apps/platform
railway service link web
op read "op://Brainforge Platform Team/Brainforge Platform Linear App/notesPlain" | … # do not commit command history with secrets
railway variable set -s web -e production BRAINFORGE_PLATFORM_LINEAR_APP_OPENCODE_WEBHOOK_SECRET --stdinAfter changing variables, redeploy web if Railway did not auto-deploy.
4) Forge — re-authorize OAuth (agent scopes)
A workspace admin opens (no www):
https://platform.brainforge.ai/api/brainforge/linear/oauth/authorize
Complete consent so Linear grants actor=app and app:assignable / app:mentionable (see merged platform authorize route).
Auth middleware: these GET routes must be reachable without a Forge Supabase session (admins may not be logged into The Forge). The platform middleware allows unauthenticated access to /api/brainforge/linear/oauth/authorize and /api/brainforge/linear/oauth/callback specifically for this flow.
5) Smoke check
- Delegate an issue to the Brainforge Platform app in Linear.
railway logs -s web -e productionand look for[Linear OpenCode Webhook]/ insert errors.
References
- Linear Agents + scopes: https://linear.app/developers/agents#actor-and-scopes
- Platform route:
apps/platform/src/app/api/brainforge/linear/opencode-webhook/route.ts - Env:
BRAINFORGE_PLATFORM_LINEAR_APP_OPENCODE_WEBHOOK_SECRET(seeapps/platform/src/lib/linearOpenCodeWebhookSecret.ts)