# What is diachron? diachron is a web framework for TypeScript and Node.js. It uses a Go-based master process that handles file watching, building, process management, and request proxying. The application code is TypeScript running on Express.js. If you're joining a project that uses diachron, this document will orient you. ## Why diachron exists diachron was built around a few frustrations with mainstream web frameworks: - **No dev/prod split.** Most frameworks behave differently in development and production. diachron doesn't. The master process watches files, rebuilds, and manages workers the same way everywhere. There is no `NODE_ENV`. - **Managed tooling.** Node.js, pnpm, and other tools are downloaded and pinned to exact versions inside the project. You don't install them system-wide. Everyone on the team runs the same binaries. - **PostgreSQL, directly.** No ORM, no database abstraction layer. You write SQL (via Kysely for type safety) and talk to PostgreSQL. If you need MySQL or SQLite support, this is not the framework for you. - **Debuggability over magic.** Everything is explicit and inspectable. Logging and observability are first-class concerns, not afterthoughts. diachron is inspired by the [Taking PHP Seriously](https://slack.engineering/taking-php-seriously/) essay from Slack Engineering. It's designed for small to medium systems (what we call "Ring 0 and Ring 1") -- not heavy-compliance or banking-scale applications. ## How it works When you run `./master`, the following happens: 1. The Go master process starts and watches your TypeScript source files. 2. It builds the backend using `@vercel/ncc`, producing a single bundled JS file. 3. It starts one or more Node.js worker processes running your Express app. 4. It proxies HTTP requests from port 8080 to the workers. 5. When you edit a source file, it rebuilds and restarts the workers automatically. 6. If a worker crashes, it restarts automatically. There is no separate "dev server" or "hot module replacement." The master process is the only way to run the application. ## Project structure A diachron project looks like this: ``` . ├── DIACHRON.md # This file (framework overview for newcomers) ├── master/ # Go master process (framework-owned) ├── logger/ # Go logging service (framework-owned) ├── diachron/ # Managed binaries, shims, framework library │ ├── AGENTS.md # Guide for AI coding agents │ ├── binaries/ # Downloaded Node.js, pnpm (gitignored) │ ├── cmd.d/ # Commands available via ./cmd │ ├── shims/ # Wrappers that use managed binaries │ └── ... ├── backend/ # Your application code │ ├── app.ts # Entry point │ ├── routes.ts # Route definitions │ ├── handlers.ts # Route handlers │ ├── services.ts # Service layer │ ├── types.ts # Application types │ ├── config.ts # Application configuration │ └── diachron/ # Framework library code (framework-owned) ├── cmd # Run managed commands (./cmd pnpm install, etc.) ├── develop # Development-only commands (./develop reset-db, etc.) ├── mgmt # Management commands safe for production ├── sync.sh # Install/update all dependencies ├── master # The compiled master binary (after sync) └── docker-compose.yml ``` ### File ownership There are two owners of files in a diachron project: - **You own** everything in `backend/` (except `backend/diachron/`), plus `docker-compose.yml`, `package.json`, and anything else you create. - **The framework owns** `master/`, `logger/`, `diachron/`, `backend/diachron/`, and the top-level scripts (`cmd`, `develop`, `mgmt`, `sync.sh`, `check.sh`). Don't modify framework-owned files unless you need to. This separation keeps framework upgrades clean. If you do need to change framework files (especially early on, there are rough edges), you can extract your changes as a patch: ```bash ./diff-upstream.sh # full diff against upstream ./diff-upstream.sh --stat # just list changed files ``` This diffs every file in `file-list` against the upstream ref recorded in `.diachron-version`. When you do change framework files, make each change in its own commit with a clear message explaining what the change is and why it's needed. Mixing framework fixes with application work in a single commit makes it much harder to upstream later. A clean history of discrete, well-explained framework commits is the easiest thing to turn into contributions. ## Getting started ```bash # Install dependencies and build the master process ./sync.sh # Start the application ./master ``` The app will be available at `http://localhost:8080`. You need Linux or macOS on x86_64. For the full stack (database, Redis, etc.), you also need `docker compose`. ## The command system diachron has three types of commands, separated by intent and safety: - **`./cmd `** -- Run managed tools (node, pnpm, tsx, etc.). These use the project's pinned versions, not whatever is installed on your system. ```bash ./cmd pnpm install ./cmd pnpm test ``` - **`./mgmt `** -- Management commands that are safe to run in production. Migrations, user management, that sort of thing. ```bash ./mgmt migrate ./mgmt add-user ``` - **`./develop `** -- Development commands that may be destructive. Database resets, fixture loading, etc. These are gated in production. ```bash ./develop reset-db ./develop db # Open a database shell ``` The rule of thumb: if you'd run it at 3am while tired and worried, it's a `mgmt` command. If it destroys data on purpose, it's a `develop` command. ## Key concepts ### Call and Result diachron wraps Express's `Request` and `Response` in its own types called `Call` and `Result`. This avoids shadowing and keeps the framework's interface distinct from Express internals. Your handlers receive a `Call` and return a `Result`. ### Routes Routes are defined as data (arrays of `Route` objects in `routes.ts`), not through decorators or method chaining. The framework processes them into Express handlers. ### No environment variables for behavior There is no `NODE_ENV`, no `DEBUG`, no mode switching. Configuration that must vary between deployments (database URLs, secrets) lives in configuration files, but the application's behavior doesn't branch on environment. ## Further reading - `README.md` -- Project introduction and requirements - `diachron/AGENTS.md` -- Guide for AI coding agents - `docs/` -- Design documents and philosophy - `docs/commands.md` -- Detailed explanation of the command system - `docs/concentric-circles.md` -- What diachron is (and isn't) designed for