Public beta · free while it lasts · MIT

Your content model is a file. Everything else is generated.

One TypeScript declaration becomes Postgres tables, an editor, a REST and GraphQL API, and a permission set the AI assistant has to obey. It runs on your own Postgres, under MIT, with nothing locked away.

npx create-apograph-app my-cms
Latest release
0.5.2
7 Sept 2026
Packages on npm, one version
60
Published together under @apograph
Permission keys, one catalogue
34
Checked in the API, for every caller — the AI included
Protocols, one content model
3
REST, GraphQL and MCP, from the same tokens and rules

One permission check

Everyone knocks on the same door

An editor in the admin, the AI assistant, an agent over MCP and a script with an API token all reach content through one guard, in the API, on every route. None of them holds a permission the person behind them does not.

  • The assistant cannot do more than you can

    Every run holds exactly the permissions of the person using it. Give it to someone with read-only access and they get a read-only assistant — a property a unit test asserts, not a promise.

  • It asks before it changes anything

    A write it has not been allowed stops the run and shows you the call. Allow once, allow for this chat, or refuse. Publishing is never something it can do at all.

  • Outside agents get the same door

    Apograph is an MCP server. An agent connects with an API token and works through the same permission-checked tools, so there is one policy to review, not two.

  • You decide which model it uses

    Claude, any OpenAI-compatible endpoint, or a model inside your own network so nothing leaves it. Switching is a setting, and the whole feature is off until you switch it on.

How the assistant makes a change

Translate the autumn campaign page into German

  • Read “Autumn campaign”
  • Checked existing translations — none for German

Create translation

“Autumn campaign” · German

Allow once Allow for this chat Don’t allow

Nothing is written until you pick. Permission granted here lasts for this conversation only, and every attempt is recorded — including the ones that were refused.

What you get

Everything included, from day one

No modules to buy and no add-ons to wait for. Four groups, and every feature in the MIT core.

Create

Model it, write it, translate it, and find it again.

Ship

Get it live, keep every version, serve it anywhere.

Run

Who may do what, where, and what happened.

Build

AI in the product, agents outside it, and your own code in both.

Every feature, one page each

Plugins

An Apograph deployment is its plugin list

There is barely a core. Everything the product does — content, media, translation, the assistant, webhooks — is a plugin on the same public contract your own code uses, registered in the same two arrays.

  • Create
  • Ship
  • Run
  • Build
  • Every deployment

Two arrays in your app decide what the API serves and what the admin renders. Remove a cell and that capability is gone, with no dead code behind it; add your own on the same contract and it sits in the same list. Each cell links to that plugin's page.

Webhooks

Your stack hears about it

A storefront rebuilds, a search index re-crawls, a cache purges. Register a URL, say which workspaces, events and content types it cares about, and every matching change arrives as a signed POST — from a queue, never from inside the transaction that made it.

  1. A write commits the event lands in the same transaction
  2. The queue takes it one row per endpoint that matched
  3. A worker delivers HMAC-signed, with a stable event id
  4. Your endpoint answers 2xx and does the work
  • Signed and deduplicated

    Every delivery carries an HMAC signature and an event id. Verify one, dedupe on the other, and a retry can never apply twice.

  • Retried on a ladder

    Ten seconds, a minute, five, thirty, two hours, six. A receiver that is down for the afternoon still gets its afternoon.

  • Filtered, not firehosed

    Workspaces × event kinds × content types. An empty set means everything — including the workspace you create next month.

How webhooks work

Who it is for

Three teams that outgrew a hosted CMS

  • An agency with eleven clients

    One installation, eleven workspaces, each with its own content, members and dashboard. A client’s editor never sees another client’s work, and the eleventh workspace costs what the first did.

  • A brand in six markets

    One row per language, shared fields written once, a fallback chain when a translation is missing, and an assistant that drafts the German while the editor reviews the French.

  • An organisation with a security review

    Content in its own Postgres, files on its own disks, single sign-on it can enforce, an activity log of who changed what, four eyes on anything that goes live, and an AI that provably holds no permission of its own.

Straight answers

The questions teams ask first

Answered plainly, in a sentence or two.

Is it really free?

Yes, and free means production — no time limit, no watermark, no licence key, and no cap on people, workspaces, records, API calls or bandwidth. Every feature on this site is in the MIT core and none of them is paid-only. A plan buys support with a response time and a licence agreement, never a capability. The pricing page says exactly that.

How many people can we add?

As many as you like, on every plan — there is no seat count and nothing to buy per user, so invite everyone who touches content. A paid plan covers one organisation, however many people and installations it has.

Where does our content live?

In your own PostgreSQL database, on your own infrastructure, with your files on your own disks. You can query it, back it up and take it with you at any time.

Can non-technical people use it?

Yes. Writers, editors and translators do everything in the admin: creating, editing, translating, uploading and publishing. No one needs to touch code to do their job.

Can we work in more than one language?

Yes. Translation is built in, not an add-on. Each language is a full version of the story, and fields that should read the same everywhere only need writing once.

Can we require somebody else to approve before publishing?

Yes, and per content type rather than for the whole CMS. Switch protection on for a type and entries of that kind need a set number of approvals before they can go live, from somebody other than whoever wrote the version being published. An approval is bound to that version, so editing afterwards asks for it again, and an administrator who overrides the rule leaves a row in the activity log saying so.

What can the AI assistant see?

Only what the person using it can see. It holds exactly that person’s permissions, and it asks for approval in the conversation before it changes anything.

What do we need to run it?

PostgreSQL 16 and Node.js 22. There is nothing else to install and nothing else to keep running — no search cluster, no message broker, no cache. Webhook delivery and the alarm sweep run inside the API process, against your own database.

Ten minutes to a published entry

One command scaffolds the app, the database and the admin. The quick start takes it from there.

npx create-apograph-app my-cms