A writing assistant that learns how you write, then tells you where a draft has stopped sounding like you.
It also checks that your citations exist and actually say what you claim they say. And when a draft was written with AI, it can rewrite it in your voice, with a local model trained on your own writing, then check the result against the draft.
Built by an academic, for academic writing: papers, grant proposals, chapters, reports.
Runs on Claude Code today. It is not tied to Claude, though: almost everything it knows lives in plain-English files that any capable model can follow, so it can be adapted to OpenAI, Gemini or a local model. See Using a different AI model below, or docs/PORTING.md for the detail.
You do not have to follow the setup by hand. Claude Code can install and configure marginalia for you, because this repo explains its own structure.
git clone https://github.com/xkiwilabs/marginalia.git
cd marginalia
claudeThen paste this:
This repo is marginalia, a writing toolkit that installs as Claude Code skills.
Read README.md and content/paths.md, then set it up for me:
run ./install.sh, and tell me what to do next to teach it my voice.
I have published papers and grants I can point you at.
Claude reads the repo, installs the skills, and walks you through building your voice profile from your own work, including converting your PDFs and Word files. Answer its questions as they come.
That is the whole setup. Everything below explains what is happening and what to do when something goes wrong. Skip to Using it once the profile is built, or read on if you would rather do it yourself.
If you use AI to help with writing, your prose drifts. Not dramatically, and not in ways you notice while you are inside the document. It gets smoother, flatter and more generic. Sentences shorten. Certain words creep in: delve, crucial, robust, underscore. Your actual voice, the thing that made the writing recognisably yours, quietly leaks out.
The other problem is citations. AI-assisted drafts contain references that do not exist, references with the wrong year, and references that are real but do not support the claim attached to them.
marginalia checks for both. It is a critic, not a ghostwriter: it tells you what it found and you decide what to do. It never edits your files without showing you exactly what it wants to change and waiting for you to say yes.
The unusual part is what it compares against. Most writing tools measure you against generic "good writing" rules. marginalia measures you against your own published work. If you write long, clause-dense sentences, it will not tell you to shorten them. It will tell you when a draft has stopped doing what you normally do.
Part of that comparison is counting. Models build sentences differently from people: a narrower spread of sentence lengths, more trailing -ing clauses (", revealing a clear pattern"), fewer agentless passives, more lists of three. marginalia measures each of these in your published work and marks a draft only where it falls outside your own range. They are measures of drift from your voice, not a test of whether AI was used. Declaring AI use is up to you, and nothing here hides it.
You need three things. If you already have them, skip to Install.
On a Mac, press Cmd + Space, type Terminal, press Enter. A window opens where
you type commands. That is all a terminal is.
On Windows, use Windows Terminal or PowerShell.
Throughout this guide, anything in a box like this is something you type or paste into that window, then press Enter:
echo hellomarginalia runs inside Claude Code, Anthropic's assistant for the terminal. It needs a Claude account on a paid plan.
Would rather not use Claude? You do not have to. marginalia's actual content is a set of written procedures, not code tied to one provider, and ten of its twelve procedure files need no changes at all to run elsewhere. Adapting it to OpenAI, Gemini, another agentic CLI, or a local model is a real option and is documented in Using a different AI model and docs/PORTING.md — in most cases you can just clone this repo and ask your own coding agent to adapt it, which takes minutes rather than an afternoon. The rest of this guide assumes Claude Code, because that is what works today with no extra effort.
Install instructions: https://docs.claude.com/en/docs/claude-code/overview
To check it worked:
claude --versionA version number means you are set. "Command not found" means it is not installed yet.
Almost certainly already on your machine. Check:
python3 --versionIf you see Python 3.something, you are done. Otherwise install it from
https://www.python.org/downloads/.
Only needed if your published work is in PDF or Word format, which it probably is.
On a Mac, first install Homebrew (a tool for installing other tools) from https://brew.sh, then:
brew install pandoc popplerpandoc reads Word documents. poppler reads PDFs. Without them marginalia
still runs, but only sees plain text and Markdown files.
Step 1. Open your terminal and pick where to put it. Your home folder is fine:
cd ~Step 2. Download marginalia:
git clone https://github.com/xkiwilabs/marginalia.git
cd marginalia(git clone downloads a copy of this project. cd moves you into the folder it
just created.)
Step 3. Install it into Claude Code:
./install.shYou should see a list of green ticks ending in "Done."
Step 4. Restart Claude Code, or start a new session.
To check it worked, start Claude Code and type /marginalia. It should be
recognised as a command.
What just happened? The installer created shortcuts from Claude Code's settings folder to this project. Claude Code now knows about seven new abilities, called skills, plus a
/marginaliacommand. They are shortcuts rather than copies, so updating this project updates what Claude Code uses, automatically.
marginalia starts out knowing nothing about you. Until you finish this section it can still catch generic AI-sounding writing, but it cannot tell you when something does not sound like you, because it has never seen your writing.
Budget about ten minutes, most of it the computer working.
mkdir -p ~/.marginalia/examples/papers
mkdir -p ~/.marginalia/examples/grants
mkdir -p ~/.marginalia/examples/otherThis creates a hidden folder in your home directory. That is deliberate: it sits outside the marginalia project folder, so your writing is never caught up in anything you later share or publish.
Copy in things you have actually published or been funded for. PDFs and Word files are fine.
cp ~/Documents/my-papers/*.pdf ~/.marginalia/examples/papers/Or drag the files in using Finder. To open that folder in Finder:
open ~/.marginalia/examplesThis step matters more than anything else in this guide. marginalia will learn to imitate whatever you put here.
- Do add: published papers, funded applications, book chapters, anything peer-reviewed or written entirely by you.
- Do not add: drafts, anything written with AI help, anything you are not happy with.
Feed it AI-assisted drafts and it will faithfully learn the drift as though it were your voice, then defend that drift in every future review.
How many? Three or more per category gives a solid profile. One or two works but gets marked low-confidence. An empty category is fine.
Start Claude Code inside the marginalia folder:
cd ~/marginalia
claudeThen type:
/marginalia extract-style --genre=all
This reads every document and works out how you write: typical sentence length, which words you reach for, how you bring in citations, how you build a paragraph, how you handle an objection. It takes a few minutes and reports what it found.
Then, back in the terminal:
python3 tools/prose_metrics.py --emit-baseline
python3 tools/move_index.py build --genre papers
python3 tools/prose_metrics.py --emit-voice-reference \
--reference-docs "grants=$HOME/.marginalia/examples/grants/*.md"The first measures the numbers, such as your average sentence length and
punctuation rates. They become the yardstick a review compares a draft against.
The second merges the paragraph tags extraction wrote into a retrieval index, so
that when you ask for a Discussion opener, write has five of your own
Discussion openers in front of it. Run it once per genre you extracted.
The third records your own range on the drift measures, from the paragraphs of
papers you led (first or senior author) and from your grants as whole documents.
A review marks a draft only where it falls outside that range.
/marginalia calibrate --genre=papers
This is a test, and worth the five minutes. It takes a passage of your own writing, hides it, rebuilds it from the profile alone, then compares its attempt against what you actually wrote. If the profile is wrong, this is where you find out, and it proposes fixes.
Do not skip this. A profile nobody has tested is a guess.
Start Claude Code in the folder where your document lives, then:
/marginalia review my-paper.md
You get a report of what it found: AI-sounding words, structural tics, places the draft has drifted from your usual style, each with a line number and a suggested fix. Your file is not touched.
It also marks passages a capable reader new to your method could not follow, and suggests a fix in your own style, never by simplifying. In documentation, it checks the commands, options, defaults and numbers the text gives against the repository it sits in.
Add --genre=grants for a grant application, since the register differs.
/marginalia cite my-paper.md
Checks every citation at four levels: does it exist, is the venue reputable, does the source actually support your claim, and is there a better source. This one takes a while, because it searches academic databases for each reference.
/marginalia cite my-paper.tex --deep
The deep mode is for a document about to go out. It checks every place you cite a
work, each on its own, against the work's full text wherever a free copy exists,
and gives the page and section where the support is. It checks each record for a
retraction, a correction or an expression of concern, and gives each reference a
DOI link and a link to a free full text. Where your sentence goes further than the
source, it proposes the smallest change that makes it true, which apply then
offers you one by one. It reads LaTeX and Markdown citation keys directly, and
several files at once, such as a book's chapters. It costs about ten times the
quick check, so it tells you its estimate before it starts.
/marginalia apply my-paper.md.marginalia/2026-05-15-1142-review.md
Walks through the report's suggestions. It shows a before-and-after for every change and waits for your approval. Mechanical fixes are grouped; anything needing judgement comes to you one at a time.
/marginalia write "draft an abstract about coordination dynamics"
You can also just ask Claude for writing help normally, in any session. It notices and applies your voice profile without being asked.
/marginalia rewrite ai-draft.md
For text drafted with AI that you want in your own voice. A local model trained on your writing rebuilds it paragraph by paragraph, and a guard regenerates any paragraph that loses a citation, adds a number or invents a name. A review then checks the result against the draft. It restores dropped points and fixes errors and unclear passages, changing only the sentences that need it, and keeps each section no more than 10% longer than the draft's.
The result comes back in the draft's own format: Markdown, LaTeX, HTML, or a Word document with every change as a tracked change. A page in your browser shows the draft beside the result, with deleted words in red and added words in green. Nothing is written until you have seen the diff and said yes.
It needs a voice model of your own; see
Your own voice model. Without one, rewrite uses Claude
instead and says so. That still revises the draft toward your voice, but a model
trained on your writing rebuilds the sentences themselves, which is where most of
the drift sits.
--only="Introduction" rewrites only the named sections, for a document that
is partly your own.
| Command | What it does |
|---|---|
/marginalia review <file> |
Check a draft for drift |
/marginalia cite <file> |
Verify citations |
/marginalia cite <file> --deep |
Check every use of every citation against the full text |
/marginalia full <file> |
Both at once |
/marginalia apply <report> |
Apply edits, with your approval |
/marginalia write "<task>" |
Draft in your voice |
/marginalia rewrite <file> |
Rewrite an AI draft in your voice |
/marginalia extract-style |
Build or rebuild your profile |
/marginalia calibrate |
Test that the profile sounds like you |
/marginalia refine |
Improve your voice, not just enforce it |
/marginalia adapt --to=blog |
Guess a profile for a format you have not written in yet |
/marginalia clean |
Delete old reports |
Works directly with .md, .txt, .tex and .mdx. PDFs and Word files are
converted automatically, though conversion is imperfect for figures, complex
tables and multi-column layouts. rewrite also reads Word (.docx) and HTML
directly, and writes its result back in the same format.
Optional, and only for rewrite and for drafting new text with write.
Everything else works without it.
A voice model is an open-weight base model with a small LoRA adapter trained on your own published writing. It runs on your own machine, a Mac with Apple Silicon, through MLX, so unpublished work never leaves it. Pick a base model that fits your machine's memory.
marginalia does not train the model for you. Train the adapter with
mlx_lm.lora on pairs that teach it to turn AI-shaped text into your paragraphs.
For each paragraph of your published work, have a local model write rough notes
from it, then a polished AI paragraph from the notes alone. The pairs are AI
paragraph to your paragraph, and notes to your paragraph, each under the matching
prompt in tools/voice_guard.py, word for word, because those are the prompts
rewrite sends. Hold some paragraphs out, and try the model on them before you
trust it.
Then register it in ~/.marginalia/models/models.json:
{"default": "voice", "python": "~/.marginalia/venv/bin/python",
"models": {"voice": {"base": "<Hugging Face id or local path>",
"adapter": "<the adapter's folder>",
"mem_gb": 48, "genres": ["papers", "grants"]}}}python is a Python with mlx-lm installed, mem_gb caps the memory the model
may use, and genres lists what it was trained on. Check it with:
python3 tools/voice_model.py statusThe adapter encodes your writing, unpublished work included. Treat it like your profile: keep it out of any shared repo, and never give it to someone else.
Two locations, kept deliberately apart.
| What | Where | Why |
|---|---|---|
| The tool | ~/marginalia/ |
Shared. Anyone can have a copy. |
| Your writing and profile | ~/.marginalia/ |
Private. Yours alone. |
Your profile is not a list of abstract rules. It contains actual sentences from your papers, because that is what lets it reproduce your voice rather than merely describe it. It may quote unpublished work.
That is why it lives outside the project folder, and why this repository refuses to track profiles even if you put one there. If you fork this project or push changes anywhere, check what you are about to publish.
The same goes for baselines.json, the file of measured numbers. It describes
one person's writing. Using someone else's would silently compare your prose to
their voice, with nothing visible to tell you it was happening.
/marginalia is not recognised. Restart Claude Code. If it still fails, run
./install.sh again from the marginalia folder and read the output for errors.
"No base style available." The profile has not been built yet. See Teaching it your voice.
"command not found: python3" Python is not installed. See Before you start.
A PDF produced nothing. It is probably a scan rather than text. Run it
through OCR first (ocrmypdf works well), or find a text version.
It flags things that are genuinely your style. The profile is missing
something. Add a note to the ## Manual overrides section at the bottom of the
relevant file in ~/.marginalia/styles/. Anything written there outranks
everything the tool worked out by itself, and survives every rebuild.
It flags nothing on a document you know is bad. Check the report header for which profile files were loaded. If it says none, the profile is not being found.
Everything looks wrong after I added new work. Rebuild all three parts, not just one:
/marginalia extract-style --genre=all
python3 tools/prose_metrics.py --emit-baseline
python3 tools/move_index.py build --genre papers
python3 tools/prose_metrics.py --emit-voice-reference \
--reference-docs "grants=$HOME/.marginalia/examples/grants/*.md"(write warns when the move index is older than the corpus; that warning means
the last command is due.)
Terms this guide could not entirely avoid.
- Terminal — the window where you type commands.
- Claude Code — Anthropic's assistant that runs in your terminal. marginalia is an add-on for it.
- Skill — an ability you add to Claude Code. marginalia installs eight.
- Repository (repo) — a project folder, usually shared through GitHub.
- Clone — download your own copy of a repository.
- Corpus — your collection of published writing, the thing the profile is learned from.
- Profile — the description of how you write, kept in
~/.marginalia/styles/. - Genre — a category of writing with its own register:
papers,grants,business,devdocs, or any label you invent. - Baseline — the measured numbers from your corpus, used to judge a draft.
- AI-drift — the flattening that creeps in when AI helps with writing.
- Voice model — an open-weight model fine-tuned on your own writing, which
rewriteuses to rebuild a draft's sentences. - Register — how formal a kind of writing is. A grant and a blog post differ in register.
Reference: how citation checking works
Tier 1 — Existence and accuracy. Cheap, always run. Searches Crossref, Semantic Scholar and Google Scholar; verifies author, year, title and venue; returns a DOI. Catches the most common AI failure: invented citations, and real ones with the wrong year or first author.
Tier 2 — Source reputability. Cheap, default on. Checks whether the venue is peer-reviewed and indexed, flags likely predatory journals, and flags preprints cited without a preprint qualifier. A flag means the venue is worth a look, not that the citation is wrong.
Tier 3 — Claim–source match. Expensive, default on. Reads the source's abstract and, where open-access, key passages of the full text, then compares what your sentence claims against what the source actually argues. Flags overgeneralised, directionally wrong and domain-mismatched claims. Deliberately cautious: it would rather raise a defensible question than stay quiet about a real mismatch, so expect to dismiss some.
Tier 4 — Better sources. Advisory only. Looks for the original empirical source when you have cited a review, and for newer meta-analyses or replications. Never blocks anything.
Deep mode (--deep). Tiers 1 and 3 in depth, for every use rather than the
first. Each use gets a verdict (supported, partly, not supported, could not check),
what was read (full text, abstract, web page or book preview), and where in the
source the support is. Numbers, the direction of an effect, the population, who
found what, and quotations are checked exactly; loose paraphrase is not flagged.
Where only an abstract could be read, the report says what to look for in a
library copy. The searches never send your email address or any other personal
detail to any service, and use free, legal copies only.
Reference: genres
papers, grants and other are the starting set, but you can invent any
label. Two have handling built in.
devdocs — READMEs, code comments, changelogs. Most academic rules do not
transfer. Short sentences and imperatives are correct here rather than voice
loss. What carries over is the AI-slop word list and the structural tics, because
a README goes wrong the same way a grant does. Colons and semicolons are listed
one by one where they sit inside a sentence, rather than compared as a rate,
because Markdown structure inflates the rate. And the review checks the doc's
commands, options, defaults and numbers against the code.
business — partner terms, letters of intent, investor memos. The reader is
a counterparty rather than a student, so the characteristic failure is explaining
something they already know.
Reference: how it is built
A portable content layer holds all the procedure and vocabulary; a runtime layer
wraps it. Today that runtime is Claude Code skills plus a router command. Nothing
in content/ has to change to add another.
Alongside it is a small tools/ layer, deliberately code rather than written
instructions. Everything else here is a judgement task, which is what a language
model following a protocol is good at. Counting is not. So Python tools count
sentence lengths, punctuation rates and the drift measures against your measured
baselines. Others segment and retrieve your paragraphs, run and guard the voice
model, carry text in and out of LaTeX, HTML and Word, build the comparison
page, and gather every citation for the deep check. The tools count and locate; the protocols judge.
marginalia/
├── content/ # every protocol, and the AI-drift catalogue
│ ├── paths.md # where profiles and corpus are found
│ └── styles/
│ └── template.md # the schema; real profiles are never tracked
├── tools/ # Python: counters, retrieval, the voice model, formats, the page
├── claude-code/ # the runtime: 8 skills + the /marginalia command
├── examples/ # your corpus, if you keep it here instead
└── tests/ # unit tests for tools/, and fixture documents with known problems
Contributor guidance is in CLAUDE.md.
Reference: known limitations
- Suggested word swaps are sometimes ungrammatical in context. "delve into" becomes "examine into". The safety net is the diff you approve, not the suggestion. Read it.
- Real but obscure citations can be flagged as invented. A reference that does not surface in the major databases within the search budget lands in the "no match" bucket. Expect this for older monographs, grey literature and niche venues.
- Tier 3 over-flags by design. Calibrated to raise a question rather than to minimise questions.
- Predatory-venue detection is rough. A curated list plus open signals.
- Converted PDFs and Word files lose things. Figures, complex tables, multi-column layouts.
- Baselines go stale. They reflect your corpus as of the last rebuild.
- A profile is only as good as the corpus. Feed it AI-assisted drafts and it learns the drift as your voice.
- English only.
marginalia runs on Claude Code, but it is not a Claude program. Almost everything it knows lives in ordinary Markdown files that describe how to review writing. Any model capable of following them can do the job.
Of the sixteen procedure files, twelve need no changes at all. Four name
Claude Code tools, and only for citation checking. rewrite also needs the voice
model, which runs under MLX on Apple Silicon whatever runtime drives it.
You do not have to port anything by hand. Clone this repo, open your own coding agent in the folder (Codex CLI, Gemini CLI, Cursor, Aider, Cline, whichever you use) and paste this:
This repo is marginalia, a writing-review toolkit. It currently runs as
Claude Code skills, but its actual logic is plain-Markdown protocols in
content/ that any model can follow.
Read docs/PORTING.md first, then content/paths.md and
content/review-protocol.md.
Set it up to run here, in this tool. Start with `review` only: ignore
citation checking for now. Then run a review on tests/fixtures/ai-drift-sample.md
and tell me how many of the six planted problems you found.
The agent reads the porting notes, works out what its own harness needs, and drives the protocol. Reviewing usually works within a few minutes, and the fixture gives you a real score rather than a vague impression: six planted problems, so six is the target.
Citation checking takes longer, because it needs web search and fetching wired up. Budget an afternoon for an adapter covering everything.
Do the fixture check first. If the model finds two of six, no amount of adapter work will fix that, and you have found out cheaply.
docs/PORTING.md has the full detail: what a replacement runtime must provide, how much context each operation needs (measured, not guessed), three routes to get there, and an honest account of what a local model can and cannot do. Short version: reviewing and writing port well; citation checking needs internet access, which is a network problem rather than a model one.
marginalia was built by one academic to solve his own problem: AI-drift and weakly-grounded citations creeping into his manuscripts and grant proposals. It has been in daily use on real papers, grants, presentations and documentation since mid-2026.
It is shared because people asked for a copy, not because it is a polished product. Expect rough edges. Issues and pull requests are welcome, and so are questions from people new to this kind of tool.
MIT. Use it, change it, share it. See LICENSE.