← Changelog

First Client Stack Live: Twenty CRM for reach-edu on Railway

The per-client self-host pattern stopped being a spec today — Reach University has its own Twenty CRM, its own database, its own project, and the first real record landed through the API within the hour.

· Michael Staton · with Claude Code on Claude Fable 5

First Client Stack Live: Twenty CRM for reach-edu on Railway

Why Care?

Self-hosting a CRM for someone else is easy to do once and hard to do repeatably. This repo exists to make it repeatable — one playbook serving managed clients now and, eventually, ~140 FullStackVC firms as a take-it-and-go guide. Today the playbook ran for real: Reach University (reach-edu) is live on its own Twenty CRM, deployed to its own Railway project with zero shared infrastructure, executed phase-by-phase from the [[../context-v/specs/Per-Client-Stack-Deployment-Spec-Twenty-First|deployment spec]] with a verification gate at every step.

What's New?

  • A reach-edu Railway project running twentycrm/twenty:v2.24.1 (released the same day we deployed it): twenty-server, twenty-worker, twenty-postgres (own volume), twenty-redis (noeviction), and a twenty-storage bucket for file attachments.

  • A client-agnostic runbook at docs/twenty/setup.md — the procedure palmer-ai (client #2) will be deployed from, verbatim.

  • The first real record — Reach Capital — created through Twenty's REST API and verified with a filtered read-back.

  • A verified no-terminal onboarding path: the deployed instance is MCP authorization-spec compliant (OAuth discovery + dynamic client registration, probed live). A stakeholder adds one URL as a Claude custom connector, logs in with their own Twenty account, and their AI can work their CRM — desktop and mobile, no API keys, no config files.

  • Client-scoped agent context is born: client-stacks/reach-edu/ now carries a context-v/agent-skills/twenty-interface/ skill — auth, the instance's own OpenAPI schema (Twenty's API is metadata-driven, so the schema is per-instance), and a proven write recipe.

How it went — the deltas worth keeping

No template existed worth trusting: Railway has eight community Twenty templates, zero verified, and Twenty's own docs endorse Docker Compose only. So we deployed the official image directly, mirroring upstream's compose file. Three findings now encoded in the runbook:

  1. Railway healthchecks probe the port named in PORT — Twenty only reads NODE_PORT, so the first deploy failed its healthcheck after 4m52s. Fix: set both.

  2. Storage must be S3 (a Railway bucket): upstream shares a local volume between server and worker, which Railway services can't do.

  3. APP_SECRET is dead; long live ENCRYPTION_KEY — upstream moved on, and the spec's variable list was already stale on deploy day. The grep-the-source doctrine earned its keep.

Database and redis URLs are wired as Railway reference variables, so the postgres password lives in exactly one place and the canvas shows the dependency graph.

What's Next

palmer-ai (client #2) gets the identical stack, executed from the runbook rather than from memory — every divergence is a pattern bug to record. Then backups with a real restore drill, and the first terminal-poor stakeholder onboarded through the OAuth connector path.

Files changed

  • docs/twenty/setup.md
  • context-v/specs/Per-Client-Stack-Deployment-Spec-Twenty-First.md
  • client-stacks/reach-edu/ (gitignored operational files)