v2.0.1 on npm · Apache 2.0

The CMS that moves into your repo.

Content that never leaves home — no database, no hosted backend, no export step. Just MDX and YAML, versioned in the git repo you already have.

$ npm install cimisy
Star on GitHub

No separate app. No hosted service. No content that lives anywhere but your repo.

The premise

The standard CMS trade: hand over your content, get an editor back.

cimisy keeps the editor and refuses the trade. Everything a hosted CMS asks you to give up stays exactly where it already is.

Their database

Your repo

Content is MDX + YAML frontmatter, committed to the repo you already have — local disk in development, real commits on GitHub in production.

Their login

Your domain

The editor mounts at /admin inside your own app's deploy — no second app, no separate account for your teammates.

Their export feature

Nothing to export

Leaving is deleting a config file and two routes. What remains is a normal Next.js app with normal files — because that's all it ever was.

How it works

One package, one config, two routes.

1

Install, then describe your content

A typed cimisy.config.ts declares collections and fields. That file is the whole content model — versioned, reviewable, greppable.

// cimisy.config.ts
import { config, collection, fields } from 'cimisy'
 
export default config({
  collections: {
    blog: collection({
      path: 'content/blog/*',
      fields: {
        title: fields.text({ required: true }),
        body: fields.mdx(),
      },
    }),
  },
})
2

Mount two route files

One API route, one admin page — inside the Next.js app you already deploy. There is no third thing to run, host, or pay for.

// app/api/cimisy/[...route]/route.ts
export { GET, POST } from 'cimisy/next/route'
 
// app/admin/[[...cimisy]]/page.tsx
export { default } from 'cimisy/next/admin'
3

Open /admin and write

Local disk while you develop; commits, branches, and pull requests on GitHub once you ship. Same config, same editor, higher stakes.

$ next dev
▸ ready on http://localhost:3000
$ open http://localhost:3000/admin

The editor

A real editor for people who will never touch a terminal.

A block editor with a slash menu, image upload with a media picker, and live preview via Next.js Draft Mode. When a non-admin hits submit, their draft becomes a branch and a pull request — they never have to know.

cimisy/blog/shipping-v1
editorA

Title

Shipping v1

Seven milestones, each demoed live before the next one started. Here's what made the cut, and what we deliberately left to GitHub.

Every draft in cimisy is a branch. Reviews happen where reviews already happen

/  Type to insert a block
Paragraph
HHeading
<>Code
Image
!Callout
Draft Mode previewdraft

/blog/shipping-v1

Shipping v1

Seven milestones, each demoed live before the next one started. Here's what made the cut, and what we deliberately left to GitHub.

Every draft in cimisy is a branch. Reviews happen where reviews already happen

cimisy/ana/blog/shipping-v1PR #42 opened

Blocks, not raw markdown

Paragraph, heading, code, image, callout — each block declares how it round-trips to clean, human-readable MDX.

Drafts become pull requests

Non-admin saves land on a deterministic branch with an auto-opened PR. Repeated saves update the same PR — review happens on GitHub or in the admin, whichever the reviewer prefers.

Preview before it's real

Next.js Draft Mode renders the draft branch on your actual site, side by side with the editor — no rebuild, no staging environment.

Security

It holds write access to your repo. It's built like it knows that.

No adjectives here — mechanisms. Each claim below maps to code and tests in THREAT_MODEL.md, written down before v1 shipped, not after.

Server-side RBAC

adminpublishereditorviewer

Every read, write, and delete passes one centralized permission check before storage is touched. Deny by default; a forged client-side role has zero effect — there's a regression test for exactly that.

Strict MDX allowlist

import · export · {expressions} · unregistered JSX · spread attrs — rejected

Content is validated as an AST on both write and read, so a hand-edited malicious file on disk is rejected too — against a permanent corpus of 24 attack fixtures.

Format-sniffed uploads

Files are checked for what they actually are, not what their extension claims. PNG, JPEG, GIF, and WEBP only — no SVG — capped at 5MB. Link URLs are scheme-validated at multiple independent layers.

A threat model you can read

Assets, trust boundaries, and specific attack scenarios — each mapped to the code and tests that mitigate it. SECURITY.md · THREAT_MODEL.md

The contrast

cimisy vs. the hosted default

A hosted CMS
cimisy
Where content lives
Their database, behind their API
Your repo, as MDX/YAML files
If you cancel
You need an export feature, if one exists
Nothing happens — it was already yours
How non-devs edit
A separate app, a separate login
The same domain your app already runs on
The security model
Trust their infrastructure
Server-side RBAC + a content allowlist you can read yourself
What you run
Their service, plus your app
Just your app
The pricing model
Seats, rows, API calls
Whatever your repo already costs you

Other git-based CMSes keep your files in your repo too. The difference is everything around that fact: server-side roles, a validated content pipeline, drafts as real pull requests, and a written threat model — inside your own app, not a hosted editor pointing at it.

Questions, answered plainly

Is it really no lock-in?+

Content is MDX + YAML frontmatter in your own repo. Remove the config file and two route files, and what's left is a normal Next.js app with normal content. There is no export step because the content was never stored anywhere else.

Does it need a database?+

No. Local disk in development; the GitHub API (commits, branches, pull requests) in production. Your git history is the version history.

Can non-technical teammates use it?+

Yes — that's most of the point. They sign in on your app's own domain, write in a block editor, and hit submit. The branch and pull request happen behind the scenes; they never touch git or GitHub directly.

How does review work?+

Direct-publish roles commit straight to the default branch. Everyone else's drafts land on a per-user branch with an auto-opened PR. Approval and merging are GitHub's own PR review and branch protection — deliberately not reimplemented.

What does it cost?+

The package is Apache 2.0 licensed. There's no hosted service to pay for — it runs inside your app's existing deploy, against the repo you already have.

What stack does it require?+

An existing Next.js app. Storage is local disk in development and a GitHub App integration in production — setup for the GitHub App is a documented, one-time walkthrough.