Skip to content

About

Learns how you write from your own published work, then flags where a draft has drifted. Also verifies citations. A critic, not a ghostwriter.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Latest commit

 

History

9 Commits

Folders and files

Repository files navigation

marginalia

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.


Already have Claude Code? Start here

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
claude

Then 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.


The problem it solves

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.


Before you start

You need three things. If you already have them, skip to Install.

1. A terminal

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 hello

2. Claude Code

marginalia 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 --version

A version number means you are set. "Command not found" means it is not installed yet.

3. Python 3

Almost certainly already on your machine. Check:

python3 --version

If you see Python 3.something, you are done. Otherwise install it from https://www.python.org/downloads/.

Optional, depending on your files

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 poppler

pandoc reads Word documents. poppler reads PDFs. Without them marginalia still runs, but only sees plain text and Markdown files.


Install

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.sh

You 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 /marginalia command. They are shortcuts rather than copies, so updating this project updates what Claude Code uses, automatically.


Teaching it your voice

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.

Step 1: Make a folder for your writing

mkdir -p ~/.marginalia/examples/papers
mkdir -p ~/.marginalia/examples/grants
mkdir -p ~/.marginalia/examples/other

This 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.

Step 2: Add your published work

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/examples

This 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.

Step 3: Build the profile

Start Claude Code inside the marginalia folder:

cd ~/marginalia
claude

Then 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.

Step 4: Check that it worked

/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.


Using it

Start Claude Code in the folder where your document lives, then:

Review a draft

/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.

Check the citations

/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.

Apply the suggested edits

/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.

Write something new in your voice

/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.

Rewrite an AI draft in your voice

/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.

Everything else

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

File types

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.


Your own voice model

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 status

The 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.


Where your files live, and why

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.


When something goes wrong

/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.)


Glossary

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 rewrite uses 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.

Using a different AI model

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.

The quickest way to find out

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.

Where this came from

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.

License

MIT. Use it, change it, share it. See LICENSE.

About

Learns how you write from your own published work, then flags where a draft has drifted. Also verifies citations. A critic, not a ghostwriter.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages