Skip to main content
Glama
README.md
# mdreview-service

A containerized markdown review microservice. An agent POSTs markdown, gets back a review URL
for a human, and polls feedback over HTTP. One service handles many reviews, isolated by id.
No per-process spawning, no shared filesystem with the agent.

**Landing page:** [mdreview.space](https://mdreview.space/) (served from
GitHub Pages via `.github/workflows/pages.yml`; source in `web/site/`).

**Docs:** [mdreview.space/docs](https://mdreview.space/docs/): onboarding,
how-to, and troubleshooting, rendered through the service's own markdown renderer (source in
`web/site/docs/`).

## Getting started: hosted or self-hosted

Two ways to use mdreview; pick one.

**1. Hosted (online).** A managed instance runs at **[mdreview.space](https://mdreview.space)** (app at
**[app.mdreview.space](https://app.mdreview.space)**). Sign in with any email address (you get a
one-time link; there is no invite list). Three ways to connect your agent.

*claude.ai custom connector (no token).* In claude.ai open **Settings, Connectors, Add custom
connector** and enter:

```text
https://app.mdreview.space/mcp
```

Claude opens the mdreview sign-in; enter your email, follow the one-time link and approve the
connection on the consent page. It works in claude.ai on the web, Desktop and mobile. Revoke it any
time on the Account page.

*Claude Code plugin.* Inside Claude Code run:

```text
/plugin marketplace add ranawaqas-ai/mdreview-service
/plugin install mdreview@mdreview
```

It prompts for a token (mint one on the Account page after signing in) and keeps it in your keychain.
Plugin updates arrive through `/plugin update`; the wrapper does not update itself inside a plugin.

*Installer.* On the machine running your agent (needs the `claude` CLI + `python3`), with a token from
the Account page:

```sh
curl -fsSL https://mdreview.space/install.sh | MDREVIEW_TOKEN=mdr_xxx sh
```

That fetches the stdlib-only MCP wrapper into `~/.mdreview` and registers it with Claude Code at
user scope; quit and reopen Claude Code and you are connected. Omit `MDREVIEW_TOKEN=…` to be
prompted for it instead. (To wire it up by hand, or for a non-Claude-Code MCP client, see
[MCP server](#mcp-server-optional).)

**2. Self-hosted (local).** Clone and run it yourself (no account, no auth, on `localhost`). See
[Run](#run), then point your agent's MCP `MDREVIEW_BASE` at `http://localhost:8137`. This is the
path if you want everything on your own machine.

Stdlib Python only (tiny image, no pip installs). Self-contained: the marked, Mermaid, KaTeX,
highlight.js, and footnote renderers are vendored and served from `/static`, so the browser needs no
CDN. The viewer renders Markdown the way a Jekyll/MathJax site does: **LaTeX math** (inline `$…$` /
`\(…\)`, display `$$…$$` / `\[…\]`; prose/currency `$` left literal), **Mermaid** diagrams, **GFM
footnotes** (`[^id]` refs → an ordered back-ref section), and **syntax-highlighted** fenced code (a
dual-scheme theme that reads on light and dark panes).

## Run

```bash
make up        # serves on http://localhost:8137
# or:
docker build -f infra/Dockerfile -t mdreview-service .
docker run -d -p 8137:8080 -v mdreview-data:/data mdreview-service
```

`make up` (compose) is the canonical local-docker path; it serves on 8137 and reuses the
named `mdreview-data` volume, so a rebuild/recreate preserves your reviews.

Health check: `curl localhost:8137/healthz` -> `{"ok":true}`.

Feedback and source persist in the `/data` volume across restarts.

### Migrating a legacy hand-run container

If you have an older instance started by hand (`docker run` on a nonstandard port such as
:8139), move it onto the canonical compose flow without losing data: the `mdreview-data`
volume is reused as-is:

```bash
docker rm -f mdreview     # stop the hand-run container (the mdreview-data volume survives)
make up                   # compose recreates it on 8137, mounting the same mdreview-data volume
```

Because the compose volume is now declared with an explicit `name: mdreview-data` (not a
project-prefixed `infra_mdreview-data`), `make up` mounts the very volume your old container
owned. Confirm with `curl localhost:8137/healthz` and check your reviews are still listed.

## The flow

1. Agent: `POST /api/reviews {markdown, title}` -> `{id, review_url, feedback_url, ...}`
2. Agent hands `review_url` to a human.
3. Human opens it, selects text or clicks a paragraph number, types notes (auto-saved).
4. Agent polls `GET /api/reviews/{id}/status` then `GET /api/reviews/{id}/feedback`.
5. Agent applies edits and `PUT /api/reviews/{id}/source {markdown}` -> the human's page
   live-reloads and addressed notes are struck through. Repeat as needed.

## Config (env)

| Var | Default | Meaning |
|---|---|---|
| `PORT` | `8080` | in-container listen port |
| `MDREVIEW_DATA` | `/data` | storage dir (mount a volume) |
| `MDREVIEW_PUBLIC_BASE` | empty | if set (e.g. `https://review.example.com`), `review_url`/`feedback_url` use it; otherwise the request Host header is used |
| `MDREVIEW_ENABLE_LATEX` | off | opt-in: enable the LaTeX paper review mode (see below). Requires the `mdreview-service-latex` image (Tectonic); the default slim image has no LaTeX toolchain |

## Operator guides

The runbooks that used to live here, moved out so this page stays readable:

| Guide | What it covers |
|---|---|
| [HTTP API](docs/operations/api.md) | Every route, request and response shape |
| [MCP server](docs/operations/mcp-server.md) | Running the stdio server, smoke tests |
| [LaTeX paper review](docs/operations/latex-review.md) | Enabling it, templates, the compile loop, the image runbook |
| [Watcher](docs/operations/watcher.md) | The agent watcher, trusted-base mode, containerized runs |
| [Design system](docs/design/design-system-spec.md) | §01-§10, the UI rules that tickets cite |
| [Autonomous runs](docs/process/autonomous-run.md) | How agents ship changes here |

## Notes

- Multi-tenant by id, so concurrent reviews never collide. No auth (intended for trusted /
  local networks); put it behind a reverse proxy with auth if exposing it.
- The dashboard (`/`) and `GET /api/reviews` list **across all reviews**: fine for the
  trusted-network posture, but a reason to keep auth in front when exposed.
- The **MCP wrapper** above was designed in [docs/future-mcp.md](docs/future-mcp.md), kept as its
  design/decision record.
- For agent integration details, see [CLAUDE.md](CLAUDE.md).
- A non-Docker, per-file CLI version lives in `../mdreview` (writes feedback to a file next to
  the source). This service is the networked, multi-session form.

## License

[Apache License 2.0](LICENSE).

## Privacy Policy

The hosted service at app.mdreview.space stores your account email, your reviews and comments, and sign-in security records. It uses no analytics or tracking cookies, does not sell your data and does not use it to train AI models. The full policy, including retention, deletion and third-party services, is at <https://mdreview.space/privacy/>. Questions go to rana.waqas.works@gmail.com. A self-hosted instance keeps all data on your machine.