Skip to main content

MarkAI

CI PyPI Python Downloads License: MIT Local-first

Reviewing a document is easy. Getting the review applied is the part that wastes your afternoon. You read a thesis, a spec or a set of docs, and you leave forty comments — a wrong figure reference in §3.2, a paragraph that contradicts the previous chapter, a term that should be spelled the same way everywhere. Then the real work starts: every one of those comments has to be carried back into the source by hand. And that is exactly the work an AI coding agent could do for you — except no annotation tool will hand the notes over. Word comments live inside the .docx. PDF annotations live inside the PDF. Google Docs suggestions live inside Google. You can read them one at a time and retype each into a chat window, which is slower than just fixing the document yourself.

MarkAI is the missing export step. You annotate the document the way you always have — click a word, select a phrase, type a note — and MarkAI writes the whole review out as a compact JSON file built for an agent to consume: what to change, where it is (Chapter 3 / 3.3 Chunking and pre-processing) and the exact quoted text to find it by. Point your agent at the file, let it apply the fixes, and it flips each note to done in a companion status file that MarkAI reads back — so the notes panel in front of you empties itself as the work lands. Review in a UI made for reading; let the agent do the typing.


How it works

   you                          MarkAI                        your AI agent
    │                              │                                │
    │  click / select → note       │                                │
    ├─────────────────────────────►│                                │
    │                              │  <doc>.notes.json              │
    │                              ├───────────────────────────────►│
    │                              │       (source folder)          │  applies each
    │                              │                                │  note to the
    │                              │  <doc>.notes_status.json       │  real source
    │   notes flip to "done"       │◄───────────────────────────────┤
    │◄─────────────────────────────┤        status: done            │

Link a document to a source folder — the directory where the actual source of that document lives — and MarkAI keeps two files there in sync on every change:

  • <doc>.notes.json — the review itself.
  • <doc>.notes_status.json — id/status pairs the agent writes back as it applies each note.

No source folder? Use Export notes… in the toolbar and pick either the notes file alone or a zip containing the same pair, and hand it to the agent yourself.

The export format

Deliberately terse — a document full of notes should not eat an agent's context window:

{
  "document": "Master Thesis",
  "notes": [
    {
      "id": "9f3c1e7a4b6d40f2a1c8e5d2b7093f14",
      "status": "pending",
      "note": "This contradicts the definition given in 2.1 — pick one and use it everywhere.",
      "location": "Chapter 3 / 3.3 Chunking and pre-processing",
      "quote": "chunks are split on token boundaries"
    }
  ]
}

location is the full heading path (root → leaf), not just the nearest heading, so an agent can find the right section even when a phrase repeats across a long document. quote is the selected text verbatim, or a few words either side of the anchor for a single-point note.

The status file the agent writes back is just as small:

{
  "instructions": "For each note you have applied to the source, set its status to 'done'. MarkAI reads this file back and reflects the status in its UI.",
  "notes": [{ "id": "9f3c1e7a4b6d40f2a1c8e5d2b7093f14", "status": "done" }]
}

Features

  • Markdown, PDF and DOCX in one reader, with the same annotation model across all three.
  • Precise anchoring. Click a word or select a phrase; notes are anchored to the exact character offsets, not just "somewhere in this paragraph" — markers and highlights land on the glyphs.
  • PDF that behaves like a PDF reader. Real text selection (pdf.js's own text layer), a chapter outline read from the PDF's bookmarks, and zoom that responds instantly at any page count: the page resizes on the spot and canvases re-render in the background, nearest to the viewport first. / +, a fine-grained slider popover (40–400 %), Fit-width presets, and Ctrl/Cmd + wheel.
  • Chapter outline on the left as a collapsible tree, starting closed, with a Collapse-all button, a Locate button that expands and scrolls to wherever you currently are, a jump-to-page control for PDFs, and a chapter-snap rail beside the content for quick or precise navigation.
  • Notes panel on the right grouped by chapter (collapsible), with in-panel search and a selection mode for bulk mark-done / mark-pending / delete.
  • Per-chapter review tracking — an opt-in toggle tints each chapter by whether you've marked it not reviewed / just read / reviewed, so you can track progress through a long document.
  • Reading theme — a day/night switch plus a reading filter (sepia, more to come), applied to the document itself (PDF included) via the toolbar, alongside search/export/zoom.
  • Configurable quote length (Settings → Reading): long selection quotes are shortened to a few words at each end past a character limit you choose, in both the popover and exported notes.
  • Two-way sync. Notes are written to the source folder on every change; statuses your agent writes back are pulled in on a 5 s poll, on demand via Refresh, and before every note edit.
  • Drag & drop upload anywhere on the library page.
  • Settings page for your account (change password, current one required) and AI-provider configuration.
  • Local-first: a single Flask process and one SQLite file. Nothing leaves your machine.

Quick start

Requires Python 3.10+. With uv installed, there is nothing to clone and nothing to set up:

uvx markai

That downloads MarkAI into a throwaway environment, starts it on http://localhost:8765 and opens your browser. To keep it installed instead:

uv tool install markai     # or: pipx install markai
markai

A fresh install comes with an account ready to use, and the login page shows it to you:

Email Password
admin@markai.local markai

Change it under Settings → Change password (the hint on the login page disappears as soon as you do), or create your own account instead. Everything is stored in your own SQLite file, on your own machine.

Forgot your password?

There is no email to send a reset link to, so recovery happens from a terminal on the same machine:

markai reset-password

It lists the accounts in your database and sets a new password for the one you choose.

Options

markai --port 9000        # a specific port (fails loudly if it's taken)
markai --data-dir ~/notes # where the database and uploads live
markai --no-browser       # don't open a browser window

MarkAI binds to 127.0.0.1 only, so nothing outside your machine can reach it. Everything it stores lives in one directory — %LOCALAPPDATA%\MarkAI on Windows, ~/Library/Application Support/MarkAI on macOS, ~/.local/share/MarkAI on Linux — holding app.db, uploads/ and a session key generated on first run. Delete that directory to reset the app; back it up to keep your notes. MARKAI_DATA_DIR overrides the location.

From a checkout

git clone https://github.com/follen99/MarkAI && cd MarkAI
python -m venv .venv
.venv/bin/python -m pip install -e .        # Windows: .venv/Scripts/python
.venv/bin/python run.py                     # dev server on :5000, data in ./data

Using it with an AI agent

  1. In the library, click Source folder on a document and enter the path where its source lives (e.g. the repo folder containing the .md file, or the LaTeX project behind the PDF).
  2. Annotate. Every note rewrites <doc>.notes.json and <doc>.notes_status.json in that folder.
  3. Tell your agent something like:

    Read thesis-4.notes.json. For each note with status: "pending", find the spot using location and quote, apply the change described in note, then set that note's status to "done" in thesis-4.notes_status.json.

  4. Watch the notes move from Pending to Done in the panel as the agent works.

Tech

Flask, SQLite (plain sqlite3, no ORM), server-rendered Jinja templates, and vanilla JS/CSS — no build step, no frontend framework. PDF rendering and interaction are entirely client-side via pdf.js (3.11.174, bundled with the package rather than pulled from a CDN, so MarkAI works with no network at all); the server just streams the raw bytes. Markdown is parsed with markdown, DOCX with python-docx. Serving is handled by waitress.

CLAUDE.md in the repository root is the deep architecture document — how notes are anchored, why the PDF text layer works the way it does, and which fallbacks are load-bearing. Read it before changing anything non-trivial.

Status and limitations

This is a working single-user local tool, built to be deployable later but not deployed yet:

  • Built for localhost. There is no CSRF protection and AI-provider API keys are stored in plaintext, so don't put this on a public host — --host 0.0.0.0 exists but exposes your documents to anyone who can reach the machine.
  • No password recovery and no email verification, by design.
  • The "Resolve with AI" button is an intentional stub (app/ai/): provider settings can be saved, but the in-app resolve endpoint returns 501. The export/agent loop above is the supported path.
  • Paragraph grouping in PDFs is a heuristic (column-aware, but still not real structure); unusual layouts (tables, rotated text) can still group oddly.
  • Cross-page PDF selections are rejected rather than silently truncated.

Contributing

python tests/smoke_test.py runs the end-to-end check (it installs nothing, but expects MarkAI to be installed — pip install -e . first). CI runs it on Linux, macOS and Windows against a freshly built wheel, for every pull request against master.

Releases are driven by the version number rather than by hand-pushed tags: bump __version__ in markai/__init__.py inside your branch, and merging to master builds, tests, publishes to PyPI and tags the release automatically. Merge a branch that didn't touch __version__ and nothing is published, so day-to-day work never ships a release by accident.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

markai-0.4.4.tar.gz (3.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

markai-0.4.4-py3-none-any.whl (3.2 MB view details)

Uploaded Python 3

File details

Details for the file markai-0.4.4.tar.gz.

File metadata

  • Download URL: markai-0.4.4.tar.gz
  • Upload date:
  • Size: 3.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for markai-0.4.4.tar.gz
Algorithm Hash digest
SHA256 e505df8e52e77b8b5d15390f7ba7304cb4e77092cda62845d53037091d3d116b
MD5 f6f861c85977f237fcda05f85ab05c9c
BLAKE2b-256 c128874d5f1d7ba4828e88303946f6f3fb6f77d036f03913568132ff4a675ce7

See more details on using hashes here.

Provenance

The following attestation bundles were made for markai-0.4.4.tar.gz:

Publisher: publish.yml on follen99/MarkAI

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file markai-0.4.4-py3-none-any.whl.

File metadata

  • Download URL: markai-0.4.4-py3-none-any.whl
  • Upload date:
  • Size: 3.2 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for markai-0.4.4-py3-none-any.whl
Algorithm Hash digest
SHA256 07a33d0a0b8083fbe23f6b6b217ab659849e6e838583e2e7695483e1a2e19fb8
MD5 07cd8fbdd071281d91fd546445e330f9
BLAKE2b-256 7a258480a9c4b7d462de1a0d9c8a956eeb490949c3ddc9fcf1630058de17f899

See more details on using hashes here.

Provenance

The following attestation bundles were made for markai-0.4.4-py3-none-any.whl:

Publisher: publish.yml on follen99/MarkAI

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.4.4 This release

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page