Try the live demo — the whole landing page is interactive. Full docs (EN / 中文): lkrcharon.github.io/patch-mark/docs/
UI feedback for AI coding agents. Point at an element on a preview page, write a comment, and your coding agent gets structured untrusted evidence to verify — selector, element name, position, visible text, and feedback. No more "the button on the left" screenshots.
This is not an annotation library for human review — it's specifically the feedback channel between a human and an AI coding agent.
<script type="module" src="https://unpkg.com/patch-mark"></script>
<patch-mark visible></patch-mark>Click the floating button, hover an element, click to select, write your comment. Annotations persist in localStorage. The visible attribute is off by default on the raw element — enable it on preview/staging only. (patch-mark/react renders visible by default.)
npm install patch-markimport 'patch-mark';
import { createFetchStore } from 'patch-mark';
const tool = document.querySelector('patch-mark')!;
tool.store = createFetchStore({ endpoint: '/api/annotations' });'use client';
import { useMemo } from 'react';
import { PatchMark } from 'patch-mark/react';
import { createFetchStore } from 'patch-mark';
export default function PatchMarkClient() {
const store = useMemo(() => createFetchStore({ endpoint: '/api/annotations' }), []);
return <PatchMark store={store} />;
}Gate it by environment where you render it: {process.env.NODE_ENV !== 'production' && <PatchMarkClient />}.
With a REST store (createFetchStore), agents that speak MCP — Claude Code, Cursor, Codex — can read open annotations without copy-pasting:
{
"mcpServers": {
"patch-mark": {
"command": "npx",
"args": ["-y", "patch-mark-mcp", "--endpoint", "http://localhost:3000/api/annotations"]
}
}
}The default server exposes only list_open_annotations. It labels annotation fields as untrusted user input and supports both legacy MCP 2025-03-26 clients and stateless MCP 2026-07-28 clients. After human approval, opt into the mutating resolver explicitly:
{
"mcpServers": {
"patch-mark-write": {
"command": "npx",
"args": ["-y", "patch-mark-mcp", "--endpoint", "http://localhost:3000/api/annotations", "--allow-resolve"]
}
}
}resolve_annotation then requires a summary, changed files, and checks run. It is never a substitute for review or backend authorization. No MCP? The list panel's handoff bar copies a trust-bounded prompt that treats annotations as data, not instructions.
| Theme | Accent | Works well on |
|---|---|---|
blue (default) |
#0058d0 |
neutral SaaS dashboards |
violet |
#7c3aed |
creative / AI tools |
emerald |
#059669 |
docs, fintech, admin panels |
orange |
#ea580c |
marketing sites |
rose |
#e11d48 |
bold consumer brands |
<patch-mark theme="emerald" visible></patch-mark>Every color token is a CSS custom property — see the theming docs for the full variable table and custom presets.
| Property | Default | Description |
|---|---|---|
store |
createLocalStorageStore() |
Where annotations are persisted/sent |
visible |
false |
Show the launcher (attribute: visible) |
themeName |
'blue' |
Preset theme (attribute: theme) |
pageKey |
current path + query + hash | Stable page identity; set it from a pushState router on route changes |
requireAuth |
false |
Server-validated token session (attribute: require-auth) |
onError |
null |
Error reporter for failed store ops |
Full API reference, REST contract, access control, and framework recipes (Vue, vanilla HTML) are in the docs.
MIT