Skip to main content
Glama

2.2.10-beta.3

A blog you host yourself, and an AI agent can run it for you. No algorithm, no ads, no platform standing between you and your readers. One process. Two SQLite files. No cloud account anywhere in the path. Your name on it, not ours.

Bun Hono SQLite TypeScript React 19 MCP License: PolyForm Noncommercial plus paid hosting

English · Tiếng Việt

quireink.com · Try it · Why this one · Install · Speed · Let an agent write · Changelog · License

demo.quireink.com is the real thing. No sign-up, nothing to fill in. The bar at the bottom jumps between the front page, the list, an article, book mode, light and dark, and the admin. That bar is the only thing added, and it lives outside the code, so the demo is always the latest build.

What it is

A blog you write in and publish from, on a server you rent. This first part is for a reader who is not technical. Everything after it is for whoever sets it up.

It has the usual furniture: a front page, posts, categories, a search box, comments, and a newsletter that goes out when you publish. What it has none of is an algorithm deciding who sees your writing, ads across the middle of it, or a company that can change the rules next year.

Colour, type, size, the shape of the front page, the menu: all of it is a setting in the admin, behind your own sign-in, and all of it works from a phone. Reading comfort is the point of the project, so six palettes in light and dark, four reading fonts, a book mode set in two columns like paper and a five-ink highlighter come with it rather than as themes you go shopping for.

Opening a post costs about 100 KB, a few dozen times lighter than one photo from your phone, so a stranger on a weak signal with an old handset still gets the words almost at once. The table says how that was measured.

To start you need a domain and a rented server, and the cheapest tier is enough. That first setup is a technical job, so ask someone who knows servers or hand it to an agent (Install). After that the writing, the publishing, the look and the stats all live in the admin, and only an upgrade sends you back to a terminal.

The trade is that you keep your own house: nobody backs it up for you, and the blog lives as long as the server you rent. There is a button that downloads the entire blog, but pressing it is your job. A personal blog costs nothing, and you may charge for it too, whether that is running one inside a business or selling hosting where every customer gets their own. Only a modified version used commercially has to ask first (License).

Related MCP server: kontexta

Why this one

An agent can run the blog, not just write in it. The MCP server is built in and goes through the same code the admin does. An assistant drafts, tags, schedules and publishes; it also reads your traffic, counts subscribers without ever seeing an address, sweeps spam into the trash rather than out of existence, recomposes the front page around what people actually read, and takes a snapshot before anything big. Plenty of blogs let a robot post. This one hands it the desk.

Your readers get the pen too. Select a sentence on a post and a bar offers five inks, a pencil underline, a ballpoint ring, a note and the quote, drawn with the site's own hand. Marks anchor to the words rather than to a position, live in the reader's browser, and travel between devices by a twenty-character code rather than an account. It costs a reader 4.5 KB, only on a post, and one switch turns it off.

The reading page is the product. Type, colour, size, spacing and layout are settings, not code. Not one size or colour is written into the reader's stylesheet, and the build fails if somebody puts one there.

Nothing of ours is forced onto your pages. No "powered by" line: the footer is your own line or nothing, and the admin's wordmark and version line each have a switch. The one place the software still names itself is a meta tag a reader never sees.

Against the usual alternatives:

  • Instead of a hosted platform. Your writing is two SQLite files on your own disk. No account, no plan, no export button you have to hope still works in five years.

  • Instead of WordPress. No PHP, no MySQL, no plugins to keep patched. One process, and readers get single-digit kilobytes of JavaScript.

  • Instead of a static site generator. You get a real admin: write, upload a photo, schedule and publish from a laptop or a phone, with search, comments, a newsletter and stats already there. No rebuild, no deploy, no git push to fix a typo.

  • Instead of writing your own. The boring half is done and tested: sign-in with TOTP, sessions, image resizing, feeds, OG images, redirects, an undo for deletes, revisions, backups, importers for WordPress, Ghost, Substack and Medium, eleven languages.

Nothing to deploy and no database to install. Point a domain at one command and you have a blog:

bun src/index.ts

What you get

The part

What it does

🖋️ Writing

A real editor over Markdown: tables, video, footnotes, callouts, mathematics, Spotify. An image dropped in is cut for every screen, described for you if Settings has an AI key, and can hold the column, float, join a gallery or wear a paper mat. Saves as you type, keeps three versions, holds a post until Tuesday

🏠 Front page

The post list, a page you wrote, or a composed front: lead story, picks, a row per category, most read. Works with photographs and with only words. How it works

🎨 Looks

Four of them: plain paper, source code, a newspaper that numbers its own sections, a notebook ruled at your leading. Over that, six palettes in light and dark, four reading fonts or your own. Every size comes from a role, so one change moves the whole page instead of one heading

🖍️ The pen

==text== highlights in five inks, ++text++ underlines in pencil, @@word@@ rings a word in red ballpoint. Strokes grow from a seeded hand that inks unevenly, so no two on a page share a shape, in pigments measured off a real pen box. Any site may link /pen.css and write with your inks

📓 Notebook

Notes and clips as a third kind of writing beside posts and pages, keeping where a passage came from. Speaks IndieAuth, Micropub and Webmention. How it works

💻 Code

Highlighted on the server, so the reader downloads no highlighter. Twenty-one languages, and the names people actually type. A fence naming nothing is guessed at timidly, so program output stays plain

🔍 Reading

Search that answers as you type. A rail with your categories and tags, or the contents of the post. Related posts, reading time, a progress bar. Book mode sets a post in two columns on a desk and one scrolled column on a phone, and keeps your place

📈 Numbers

Analytics without cookies: who read what, how far they got, where they came from, per post as well as per site. Nothing is ever deleted, so the year-by-year table reaches your first reader. Plus an activity log and a trash you can undo

💬 Comments

Readers comment without an account. The page signs its own spam challenge, so no third party sees them; Turnstile takes over only if you add its keys. Sweeping goes to the trash, not into nothing

🔎 Search engines

Sitemap, RSS, robots.txt, llms.txt, and an OG image drawn per post. Rename a slug and the old URL keeps working

📬 Newsletter

Sign-ups with a confirmation email, an issue sent when you publish, a note when a comment gets a reply. Your own SMTP, so there is nothing to sign up for

📚 Series

Write in parts, number them, and every part shows the others

💾 Backups

One button downloads the whole install. Scheduled snapshots stay on the server and are shipped to your own R2 or S3 bucket. Details

📥 Moving in

A WordPress XML, a Ghost JSON, or the ZIP Substack or Medium emailed you; the server works out whose it is. Everything becomes Markdown, dead shortcodes are swept out, old URLs answer with redirects, and the images land in your library

🌍 Languages

Eleven, in the admin and on the site, and one more is one file. No CJK webfont ships, because they run to megabytes, but each of the three names its own face so 直 is drawn the Japanese way on a Japanese site

🔐 Sign-in

Username and password hashed with argon2id, an authenticator code every time, ten recovery codes, and every signed-in device listed with a button to end it. There is a way back in when the password AND the phone are both gone. No Google in the login path

🤖 Assistant

Your own model key in the admin: Claude, GPT, Gemini or DeepSeek. Answers arrive as they are written, conversations are kept, and each carries a receipt of what it cost. It also writes alt text and sorts spam into the trash

⌨️ The admin

⌘K finds any named setting and jumps to it, so it stops mattering which of the seven tabs holds it. The rail's order is yours to drag. Every control is a key with relief: raised means press me, carved means held down. Nine chords in the editor, find and replace among them, in the writing surface and in the Markdown source alike

📱 Phone

Install it to the home screen and it opens like an app

Made for one person, one server, one blog they mean to keep. Not made for a team that needs roles, approvals and an editorial queue. It has one owner on purpose.

One post, four looks, one palette. The look decides shape, type and marks; every colour on all four comes from the palette, so changing it moves all of them together.

Book mode and the dark theme. Neither is a filter dropped over the page; both are the reading typography itself. The fonts ship with Vietnamese and Central European accents included, so the specimen on the left is set properly instead of falling back to whatever the system has.

Mathematics is MathML, laid out by the browser itself: no script, no stylesheet, no font file, so a post with a formula costs a reader nothing over one without. Code is highlighted on the server for the same reason. The lower block named no language, so nothing invented colours for it.

Your readers get a pen

Select a sentence on any post and a small bar offers the five inks, the pencil underline, the ballpoint ring, a note and the quote. The mark is drawn with the site's own hand and anchored to the words rather than to a position, so it survives the author fixing a typo three paragraphs up. It lives in the reader's browser, and nothing is sent anywhere.

Press Keep on every device and the marks travel: by the Google sign-in commenters already have, or by a twenty-character code for anyone who would rather not sign in to anything. The server keeps a hash and one row per page, never an address, and you as the owner see none of it. Send to my notebook opens a page on the reader's own Quire Ink, or any site that speaks Micropub, with the passage and their words already filled in.

It is on from the first install, and one switch turns it off (Settings → Posts → The reader's pen). Try it on the demo.

Speed

Off the network, first visit, nothing cached. It is what a stranger on a phone actually waits for.

Home

A post

Requests

8

9

11 on a post with book mode and comments switched on

Total transferred

100 KB

98 KB

68 KB of that is the fonts

JavaScript

3.8 KB

6.5 KB

written by hand, no framework; +5.1 KB only when book mode and comments are on, +4.5 KB only when readers are given the pen

CSS

11.5 KB

11.5 KB

+11 KB only on a page carrying the pen

Third‑party requests

0

0

no CDN, no font host, no tracker

Coming back

0 bytes

0 bytes

the same page answers 304; a page you have not read yet still costs its HTML

The CSS and JavaScript rows are build artefacts, the same bytes on every install, brotli from the origin since 2.2.5. The totals came off a live site running Vietnamese, Literata to read and JetBrains Mono for the furniture, and they are not a property of the software: fonts are cut per script, so a browser fetches only the ranges your pages use. The pen's stroke shapes ride in two further immutable sheets that board only a page carrying a mark (ADR 0027). An inkless page never pays for them.

Five decisions keep it there, and all five are hard to walk back.

  • Every bundle has a size limit the build enforces. Going over it fails the build, so a feature cannot quietly start costing every reader a little more forever.

  • The page cache is one Map, and any write empties all of it. That is the whole rule, which leaves nothing to get subtly wrong. A miss costs a SQLite read and a render, well under a millisecond.

  • Rendered Markdown is stored under a hash of its input, so nothing ever needs invalidating. A long post went from 383 ms to 1 ms.

  • The fonts are yours, cut down per language, and only the ones a page needs get preloaded. Pinning one variable-font axis took that set from 97.6 KB to 46.2 KB.

  • The fade-in and the progress bar are pure CSS: no script, off the main thread, and an old browser simply shows the text.

None of this is for a benchmark. It is for someone on a four-year-old phone who wanted to read four hundred words.

The admin is built around writing: the list beside the paper, everything else one sheet per page. Palettes, fonts, sizes, layout and the menu are all settings. None of it is code.

This release

2.2.10-beta.3 is the third pre-release before 2.2.10. It runs the demo above and the author's own blog at manhhung.me; the changelog has everything that changed. Its Docker tag is 2.2.10-beta.3 and only that: latest is still 2.2.9, so nobody gets a beta by accident.

What it adds is a look. A published blog can wear one of four now, and which one is the last question setup asks. Newspaper is the one that touches your words: it numbers sections, figures and tables, prints the section over the headline and sets both in a second serif, and those numbers live on the page and nowhere else, so a feed, a newsletter and a copied paragraph stay as they were. Notebook draws the page as a sheet lying on a desk, ruled at the leading your own type settings use. Source code dresses the furniture and leaves the reading column alone. Each is its own stylesheet, linked only by a blog wearing it, so plain paper pays nothing for the other three. The six palettes were rebalanced at the same time, every colour solved for a contrast against its own paper, and a look now carries no colour of its own at all: whatever it puts on the page comes out in the palette you chose and in whatever your reader picks over it. A blog that already exists keeps the colours it has.

And what it does not do. It is a beta, so expect 2.2.10 to still move things. There are four looks and no fifth: a look is a stylesheet in the build rather than something you can write in the admin, so going further is still custom CSS. A look is site-wide, so one post cannot be a newspaper and the next a notebook, and it dresses the published site only, never the admin. The panel that appears once after an upgrade says which version you are now on and links its notes; it does not carry the notes, and they are in English. Two devices marking the same page at once overwrite each other, last save wins. Nothing in the admin shows which passages readers keep most; only the list_mentions MCP tool answers that. Webmention verifies its source and rate-limits, but no spam judgement is wired to it. The Help screens are still English only, a few counts still read "1 words", and every standing limit holds: a NAS and a Kubernetes cluster get no Caddy, the Motion switch is the owner's rather than per-reader, an install that rewrites its own HTML with nginx sub_filter loses the origin's compression and validator, and an origin with no CDN makes a reader on the far side of the planet pay a round trip that saved bytes cannot buy back.

Install

Where can it live? Any of these, and the blog is the same on all of them.

  • A rented VPS, cheapest tier. The one command below, then one more for the certificate (deploy/caddy/setup.sh); or Docker, where the certificate comes with it.

  • A DigitalOcean droplet: paste one file into the droplet-create page and it is serving three minutes after boot. Put your domain in its first editable line and it comes up on HTTPS, certificate issued; leave it empty and it comes up on the droplet's address, with the one command that fixes that written to /root/quire-https.txt (how and why).

  • A NAS in your house: on Unraid search QuireInk in Community Applications; on Synology (DSM 7.2+) paste the compose into Container Manager, and QNAP's Container Station takes the same. No shell on any of them, since the blog prints its claim link to the container log. Step by step, per box.

  • Any machine with Docker: pull quireink/quireink, amd64 and arm64 both. With HTTPS and nothing to schedule, that is docker-compose.image.yml plus the Caddyfile, so two files and no checkout.

  • A Kubernetes cluster: kubectl apply -k deploy/kubernetes on DOKS, EKS, GKE or your own. One pod and one volume, because one blog is one SQLite writer (the manifests, and why they are a StatefulSet).

Two of those do not bring Caddy, and both on purpose. A NAS already has a reverse proxy with its own certificate UI and is already holding ports 80 and 443, so a second one fights it. A Kubernetes cluster terminates TLS at its ingress, the one thing in the cluster that knows about certificates. Everywhere else, the certificate comes with the install.

For the first path you need Bun 1.3 or newer and a machine you can point a domain at. That is the list.

One command, which clones, installs, builds and starts it:

curl -fsSL https://raw.githubusercontent.com/joiha-steven/quireink/main/install.sh | bash

It never uses sudo, never installs Bun behind your back and never touches systemd; it refuses to run as root, and running it again on the same directory updates and rebuilds instead of failing. Settings go in front of bash, on the far side of the pipe:

curl -fsSL https://raw.githubusercontent.com/joiha-steven/quireink/main/install.sh \
  | SITE_URL=https://example.com QUIREINK_DIR=/srv/blog bash

NO_RUN=1 stops it short of starting the blog, and the script itself is 136 readable lines if you would rather look before you pipe.

Or the same thing by hand, which is all it does:

git clone https://github.com/joiha-steven/quireink.git && cd quireink
bun install
bun run build:assets && bun run build:admin     # the islands, then the admin
DATA_DIR=./data SITE_URL=https://example.com bun src/index.ts

Put a reverse proxy with TLS in front of the port, 3000 by default. Then read the log. A blog nobody owns yet prints the link that claims it, every time it starts:

  ┌─────────────────────────────────────────────────────────────────────────┐
  │  This blog has no owner yet. Open the link below to claim it.           │
  └─────────────────────────────────────────────────────────────────────────┘

  https://example.com/setup?token=…

Open it and the rest is a browser: username, email, password, then the QR code for an authenticator and ten recovery codes, once. The token lives in memory, so a restart mints a new one and the old line stops being a secret, and /setup answers 404 the moment an account exists. Prefer the terminal? bun run user create --username <name> --email <address> does the same job.

The whole of setup after the log line. The time zone and the address arrive already filled in, because the browser knows both and both are wrong by default without saying so. What setup does not ask about is the design: palettes, fonts, book mode and the feature switches stay on a dashboard card you can reopen, since nobody can judge them before the site has a single post on it.

The database sets itself up on first boot, so there is no migration step to remember. The full version with systemd, nginx, cache headers, backups and upgrades is in docs/self-host.md.

NOTE

Run from source. That is the whole deployment, and it is what the live site does. There is no compiled binary: bun build --compile leaves out sharp's native module, and a binary that cannot resize an image is not a shipping artefact (ADR 0022).

Pull it. Nothing to clone, no Bun, no build step, on linux/amd64 and linux/arm64:

docker run -d --name quire -p 127.0.0.1:3000:3000 \
  -e SITE_URL=https://example.com \
  -v quire-data:/var/lib/quire/data -v quire-uploads:/var/lib/quire/uploads \
  quireink/quireink:latest
docker logs quire            # prints the link that claims the blog

:latest on purpose: the newest release is the one with the fixes in it. Version tags exist for anyone who wants to move by hand instead. Also on GHCR as ghcr.io/joiha-steven/quireink, the same image from the same run, carrying the same digest, so the two can never drift.

Or build it from this repository, which is what docker-compose.yml does:

cp .env.docker.example .env          # set SITE_URL
docker compose up -d --build
docker compose logs quire            # the claim link, same as above

No docker exec and no interactive terminal anywhere in that, which is the point: a NAS container UI gives you a log panel and no TTY. One service, two volumes, no sidecar. The port listens on 127.0.0.1 only, so a reverse proxy still does TLS.

On a NAS (Synology, QNAP, Unraid), mount real folders and set PUID/PGID to whoever owns them: the container adopts them on first boot and never runs as root. Volumes, ownership and upgrades are in docs/self-host-docker.md.

Give an agent SSH to a fresh server and ask it to set the whole thing up: clone, build, write the systemd unit and the nginx vhost, create your account, hand you back the URL. There is no OAuth client to register and no service to sign up for, so it really can finish the job on its own.

TIP

Uploads have no size limit when you host it yourself, because the browser posts straight to your server. Put a CDN in front for TLS and edge caching, and let it obey thecache-control the app already sends instead of forcing its own.

Let an AI agent write for you (MCP)

Quire Ink has an MCP server built in, so an assistant can draft, edit, tag and publish straight to your live site. No git, no deploy. It goes through the same code the admin does, with the same rules about slugs, revisions and the trash.

  1. Turn it on. Admin → Settings → Server & connections → MCP, then create a token. You see it once, it is hashed after that, and it dies in 180 days.

  2. Point your agent at https://<your-domain>/api/mcp with Authorization: Bearer <token>. OAuth connectors work too.

  3. Ask for a post.

Using the Quire Ink MCP server, write a 600-word post titled
"What I learned shipping a blog with an AI agent", give it the tags
"ai" and "writing", set a friendly excerpt, and publish it.

Writing is half of it. The agent can also read your traffic and compare it to last week, count subscribers without seeing their addresses, sweep spam into the trash, search the whole archive, and tell you whether a newer release is out. It can steward, too: recompose the front page around what people actually read, restyle the site from the curated palettes and fonts, reply to a comment under your name, send the next newsletter issue as a test to you alone, and take a snapshot before anything big. Free-form colour is the one thing it cannot touch, because an agent has no eyes. The agent cookbook collects prompts that do real jobs: a Monday report, a newsletter draft, an archive audit.

The sensitive settings are off limits over MCP, and you stay in charge: revoke the token in the admin and it stops working immediately.

The repository also teaches the agent. Three skills ship in .claude/skills/, so an assistant that has just cloned this repo already knows how to install a blog, run one over MCP, and move an existing blog in from WordPress, Ghost, Substack or Medium. Nothing to install: clone it and ask. What they cover.

Environment variables

These are the only things that live outside the admin.

Variable

Needed

What it does

DATA_DIR

Where quire.db and analytics.db go. Defaults to ./data

SITE_URL

Your public address, used in feeds, OG images and email. Left empty, all of them say http://localhost:3000, so the site still reads fine and only crawlers and mail clients notice. It is deliberately not guessed from the request

STORAGE_LOCAL_DIR

◻️

Where uploads go, served at /uploads. Defaults to ./uploads

PORT

◻️

Defaults to 3000

HOST

◻️

Which interface to listen on. Defaults to 127.0.0.1, right when a reverse proxy sits in front on the same machine. Set 0.0.0.0 when it does not

SETUP_CODE

◻️

Twelve characters or more; then /setup asks for it instead of the log link. For installs where nobody reads a log: cloud-init, a hosting panel

MAX_UPLOAD_MB

◻️

Largest single upload. Defaults to 64, matching the client_max_body_size in the recommended vhost so the two refuse the same file. 0 = no limit

STORAGE_QUOTA_GB

◻️

Largest the uploads folder may grow, counting the smaller copies of each image. Defaults to 5, and an upload that would go past it is refused. 0 = no limit

CRON_SECRET

◻️

Guards /api/cron, which publishes scheduled posts and tidies image variants

CRON_INTERNAL

◻️

0 stops the process running its own maintenance clock, for when you would rather schedule /api/cron yourself. On by default since ADR 0031

PURGE_WEBHOOK_URL

◻️

A URL the blog POSTs to whenever it flushes its own cache, for a CDN that is not Cloudflare (ADR 0033). Normally a setting instead

S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY (+S3_ENDPOINT, S3_REGION, S3_PREFIX)

◻️

An S3-compatible bucket every snapshot is also shipped to (ADR 0035). Normally a setting instead

BACKUP_DIR

◻️

Where snapshots are written. Defaults to <DATA_DIR>/backups (backups)

MCP_OAUTH_SECRET

◻️

Signs MCP OAuth codes. Leave it out and the server makes its own, which is the recommended way

ANALYTICS_TZ

◻️

Default timezone until the owner picks one in Settings → Blog → Timezone, which is the site's whole clock: post dates, month markers, the day a chart starts on. Defaults to UTC

CSP

◻️

A Content-Security-Policy to send on every response. Empty by default, and leave it that way behind the shipped Caddyfile or the documented nginx block: both send one already, and a browser enforces the intersection, so a second could only narrow theirs. Set it where neither is in front, such as a NAS proxy, a PaaS, or a Kubernetes ingress

TRUST_PROXY

◻️

Set to 1 only when the proxy in front reaches you over a PUBLIC address. Rate limits key on the socket address; CF-Connecting-IP/X-Forwarded-For are believed automatically from loopback or a private network

UPDATE_CHECK

◻️

0 stops the one request this software makes on its own: once a day it asks what the newest release is, and by asking is counted as a blog in use. It sends the version you run and four coarse facts, never your address, posts, readers or an exact number. Also a switch in Settings. The whole call

SMTP, Turnstile and CDN credentials go in Settings → Comments & mail and Server & connections, and stay on the server. Your posts live in DATA_DIR and your uploads folder, never in git.

Translations

The interface speaks eleven languages on the reader's side and in the admin: English, Tiếng Việt, Deutsch, 日本語, 简体中文, 한국어, Français, Español, Português (Brasil), Italiano and Русский. The first question setup asks is which one this blog speaks.

Help translate. Every language is a pair of plain files of quoted strings under locales/: locales/<code>.ts is what readers see, locales/admin/<code>.ts what the owner sees. To add a language, copy the two en files, translate, and register the code in locales/langs.ts, src/types.ts and DATE_LOCALE in src/i18n/format.ts. The compiler refuses to build until every key exists, so a half-done translation cannot ship silently. Pull requests welcome, since a native speaker's ear beats ours.

Develop

bun install
bun run build:admin                 # once, and again whenever src/admin changes
bun run dev                         # http://localhost:3000
# the log prints a /setup link to claim it; or: bun run user create --username me --email me@example.com

Nothing is finished until bun run check:all passes. It typechecks, runs the static guards and runs the tests, all offline, with no credentials and no services. Start at CONTRIBUTING.md, which points to the house rules in CLAUDE.md.

Where

What is in it

src/

The whole thing: Bun, Hono, SQLite. How the pieces fit

docs/

How it works and why. docs/README.md indexes it; docs/decisions/ is every decision, including the ones that were reversed

golden/

The rendering contract. One byte of different output fails the build

scripts/checks/

The guards. Register a write route outside the owner-only group and the build stops, same as a hardcoded font size in the reader's stylesheet

What is planned lives with the author's own notes rather than here, because it is one person's intentions for one blog and not a promise to anybody running the software (ADR 0017). What has already shipped is in the changelog.

License

Two different things, and they are not covered by the same terms.

The code here is PolyForm Noncommercial 1.0.0 plus one additional permission. Source-available, not open source. Together they come to one sentence: run it, and charge for running it, as long as the version you run is the one published here.

Noncommercial: everything. Your own blog, a hobby project, study, research, and also charities, schools, public research bodies and government. Read it, change it, host it, fork it, pass it on. Keep the licence text and the Required Notice: line with any copy you give someone.

Commercial: yes, unmodified. Run it for a business, run it for a client, sell hosting where each customer gets their own Quire Ink blog. Four things are asked in return: run a published release with its source unchanged, keep the notices, say your service runs Quire Ink and link back, and sell the service rather than the software. Settings, palettes, fonts and content are not source, so the look of a site is a setting here rather than a fork.

A modified version, used commercially, needs a separate licence. That is the one line the project holds: change the code and then sell it, or run a changed copy as a service, and you have to ask first. Fixing a bug or a security hole in your own deployment is carved out; patch it, and tell the owner within 30 days. Ask by opening an issue or through the owner's GitHub profile.

What you write stays yours. Your posts and images are not covered by the code licence and are not in this repository.

If the project ever goes quiet, it opens. Forty-eight months without a release, and the code as it then stands is also yours under the Apache License 2.0, by a grant already made today. Nobody has to be reachable for that to happen. It is section 6 of the additional permission.

Everything up to and including v2.0.0 was MIT, and stays MIT forever. A licence change does not reach backwards: a copy taken before this one keeps the rights it came with. See ADR 0015.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Local-first markdown vault with a built-in MCP server (streamable HTTP). 16 tools and 2 resources for Claude Code / Desktop / Cursor: read/write/search plus context_for_query, find_orphans, weekly_digest, compare_notes, semantic_outline. Per-folder agent permissions, LanceDB vectors, local Xenova ONNX embedder swappable to Ollama. Single Bun binary. AGPL.
    33
    AGPL 3.0
  • A
    license
    A
    quality
    A
    maintenance
    A local-first MCP server that gives AI coding agents persistent memory and controlled commands. Features a git-backed markdown knowledge vault with FTS5 search, surgical section edits, token-aware context budgeting, and a sandboxed command engine with human approval gates. Works with Claude Code, Cursor, Copilot, Gemini, and more.
    4
    58
    316 npm
    1
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    A private, local-first MCP server that gives any AI long-term memory — its own diary. Zero models, zero network, zero subscription; smarter search than Notion, running entirely on your machine.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Self-hosted MCP server giving AI agents persistent memory — Markdown source of truth, hybrid BM25+embedding search, typed graph relations.
    2
    MIT