Skip to content

Architecture

Neutron ships as a single container image. When it runs you get one web server, one helper service beside it, and one database. That is the whole moving-parts list.

WHO TALKS TO ITWeb chat@mention on amerge requestAnother programover /mcp

ONE PODAPI — the chromechat, users, approvals, audit, costEngine seamCodex · Claude Agent SDK · OpenCodeCodingcontrollerConnectors7 built inassay-engine, alongsideencrypted vault · cron · durable workflows

gates and the interrupt governor wrap all of the above

WHAT IT WRITES TOPostgreswork · jobs · approvalsaudit · costGitLab / GitHubmerge and pull requests

Each organisation gets its own pod and its own database. There is no shared tenant column.

One image, one database, one helper process. The API is deliberately thin — it holds the chat, the people and the rules, and hands the thinking to whichever engine the instance was configured with.

The four pieces

PieceWhat it does
APIThe web server. Serves the chat UI, holds accounts and roles, records every approval and every cost, and enforces the rules. TypeScript, run by Bun.
Engine seamA thin adapter so neutron does not care which AI runs the conversation. Three are supported. Swapping one for another is configuration, not a rewrite.
ConnectorsThe abilities switched on per instance: encrypted vault, web search, knowledge-base search, schedules, agent self-config, agent administration, and driving peer nodes.
assay-engineA small binary running beside the API. Holds encrypted secrets and runs durable timers and workflows — jobs that survive the pod being killed and restarted.

Persistence is Postgres, reached through typed queries with ordered migrations. That is a deliberate exception to the house default, chosen because the schema is expected to keep growing.

One program, many customers

This is the structural decision that shapes everything else. There is exactly one codebase and one built image. A customer is not a fork or a branch — a customer is a configuration file and a database.

one image, one versionidentical bytes everywhereInstance Aits own instance.yamlits own databaseits own users + agentsits own secretsoptional persona pluginInstance Bdifferent models ondifferent connectors offstricter safety modedifferent login provider— same codeInstance C…and so on

isolation comes from the pod and the database, not from a tenant column in the schema

Configuration, not forks. The cost of this choice is at the bottom of the picture — isolation is physical, so a new customer means new infrastructure, not a new row.

Interchangeable engines

The conversation loop is provided by an engine, and there are three. The codebase is written so that no engine-specific type escapes the adapter folder, which is the enforceable version of “we could switch”.

the rest of neutronengine seamone shape: send a turn, receive eventsnative CodexClaude Agent SDKOpenCode

below the seam, provider-specific code; above it, none — and OpenCode brings any OpenAI-compatible model with it

The seam is a boundary rule as much as an abstraction: engine types are not permitted above the line, so the swap stays cheap instead of becoming a rewrite three years from now.