
Security News
Deno Goes the Way of the Dinosaur
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.
A dev-only toolbar for Astro and Next.js sites: pinned page comments Claude Code can read and answer, spacing/size/type inspectors in design px, a layout grid, breakpoint canvas and device preview.
Note it. Mend it. Pin a comment on any element of a live site, at the screen width it breaks; your coding agent — Claude Code, Codex, Cursor, Gemini CLI, Copilot or any other — takes the comment, fixes the code and says what it changed; a person confirms the fix with a tick. For design studios, their teams and their clients.
This package is the bar people comment with and the notemend CLI and MCP server agents
work the queue with. The threads live in the Notemend cabinet at
app.notemend.com, shared by everyone in a project — or, with
no account, in feedback/comments.json in your repo. Docs:
app.notemend.com/docs.
npx notemend init # asks which agents you use and wires each one
npx notemend login # shows a code; allow it in the cabinet
npx notemend link <project-id>
Then ask your agent for the open comments. It takes one (notemend start), fixes it and
resolves it with a note (notemend done); the comment waits, marked, until a person
confirms it on the site or in the cabinet.
Webflow, Shopify, WordPress, Framer, a live Next or Astro site: the cabinet's Install tab hands out one line for the site's custom code,
<script src="https://app.notemend.com/bar.js" data-project="<project-id>" defer></script>
and the whole bar — comments, grid, spacing, size and type inspectors, breakpoints,
devices — runs on the live site. A visitor sees nothing: the bar wakes only for people in
the project, once they open the site with ?notemend (the cabinet's "Open site", the
link you send a client) and sign in once on that browser. Their session stays with the
cabinet, in a hidden frame of its own — the site's scripts never hold a token. The
cabinet's Preview tab shows the site at desktop, tablet or mobile width with the bar
in it. The pages menu comes from the site's sitemap.xml and the pages that already have
threads.
bar.js is src/hosted.ts bundled by the cabinet's build (web/scripts/build-bar.mjs);
its endpoints are the dev server's, served by the cabinet (src/hosting.mjs) as whoever
is signed in, so the database's rules decide what they may read and write.
The queue is a CLI any agent that runs commands can work, an MCP server for agents that take tools, and a Claude Code plugin. Whichever you use, a comment reaches the agent with its page, element, width, device, thread, screenshots and what the page logged (console errors and failed requests, secrets masked), quoted as what people wrote — never as instructions — and only the comments meant for the agent.
npx notemend open comments for the agent
npx notemend all including resolved ones and those given to people
npx notemend start <id> [--force] take it before fixing: the thread shows the agent is on it,
and another agent is refused (--force takes it anyway)
npx notemend reply <id> "..." answer in the thread (also: note)
npx notemend done <id> "..." [--shot] resolve as the agent, with a note (stays marked until a
person confirms); --shot files a picture after the fix
npx notemend reopen <id>
npx notemend rm <id> delete the thread and its screenshots
npx notemend shot <id> ["note"] [--before] [--url <dev server>] a picture of the element at the comment's
width (Playwright); a note goes in the thread as the agent's reply
npx notemend watch [--timeout <min>] [--start | --stop] turbo: wait for a comment for the agent, print it, exit
npx notemend prune [--dry] local store: move resolved threads to feedback/archive/
npx notemend digest | count short forms for the agents' hooks (--format claude|codex|gemini|cursor)
npx notemend mcp the same queue as an MCP server (stdio)
npx notemend init [--yes] [--ci] [--agents=<list>] [--force] set a project up (hooks, config; --ci adds the workflow)
npx notemend login [--code] | whoami | logout | link [<project-id>] | unlink
npx notemend --as <agent> … sign as codex, gemini, cursor, copilot… (default: Claude)
npx notemend --version | --help
NOTEMEND_URL is the dev server for screenshots when there is no --url; NOTEMEND_KEY
and NOTEMEND_PROJECT are for an agent on its own (below).
The root is the nearest directory with a package.json above the working directory, or
--root <dir>. The panel numbers threads per page and breakpoint (#4); the CLI prints
both that and the file-wide id: #4 (id 10). prune keeps a local store readable:
resolved threads and their screenshots move to feedback/archive/, and the numbering
carries on. Nothing is deleted.
npx notemend login # shows a code and opens the cabinet — allow the same code there
npx notemend link # a new project named after the site (package.json name and homepage)
npx notemend link <project-id> # or an existing one — the id is under Install in the cabinet
login works over SSH and in containers too — nothing listens on your computer; open the
link on any machine where you are signed in. login --code signs in with the six-digit
code the cabinet emails instead. The terminal gets a session of its own, so signing out in
one never signs out the other. link writes .notemend.json; commit it and the whole
team files into the same project. whoami says who you are and where comments go;
unlink and logout undo.
init asks which agents you use (or --agents=claude,codex,cursor) and wires each the
way it reads context:
| Agent | What init writes | What it reads |
|---|---|---|
| Claude Code | .claude/settings.json hooks | digest at session start, count on each prompt |
| Codex | .codex/hooks.json (+ codex_hooks = true in .codex/config.toml) | the same, as plain text |
| Gemini CLI | .gemini/settings.json hooks, GEMINI.md | the same, as hookSpecificOutput.additionalContext JSON |
| Cursor | .cursor/hooks.json (sessionStart) | digest as additional_context |
| Copilot, Windsurf, Amp, … | a block in AGENTS.md | how to list, take, answer and close threads |
An agent signs what it writes: threads show Codex, Gemini or Cursor rather than Claude.
Gemini CLI, Codex and Cursor are recognised from their environment; any other passes
--as <agent> (npx notemend reply 3 "…" --as copilot).
npx notemend mcp serves the queue over stdio: list_comments, start, reply,
resolve, reopen and screenshot (before, and a note that goes in the thread as a reply). Each runs the CLI above, so the cloud, agent keys
and sign-in work as they do there; replies are signed with the client's own name. It is in
the MCP Registry as io.github.zharkodv-cmd/notemend.
One click: Add to Cursor, Add to VS Code and the Claude Desktop bundle are on app.notemend.com/docs/mcp. By hand:
codex mcp add notemend -- npx -y notemend@latest mcp
claude mcp add notemend -- npx -y notemend@latest mcp
{ "mcpServers": { "notemend": { "command": "npx", "args": ["-y", "notemend@latest", "mcp", "--root", "/path/to/site"] } } }
The hooks and the tools in one, no init needed for Claude Code:
/plugin marketplace add https://app.notemend.com/claude/marketplace.json
/plugin install notemend@notemend
Its files are in plugin/; npm run pack puts them at the package root, and
npm run mcpb rebuilds the Claude Desktop bundle (web/public/notemend.mcpb) after a pack.
A project's settings make agent keys (shown once, kept only as a hash). With one as
NOTEMEND_KEY, the CLI needs no sign-in: it lists the project's threads and takes,
answers and closes them as the agent — nothing else. npx notemend init --ci writes
.github/workflows/notemend.yml: every hour (or by hand) it asks for the agent's threads
and, when there are some, runs Claude Code's GitHub Action to fix them on a branch, close
each with what it changed, and open a pull request. It needs the repository secrets
NOTEMEND_KEY and ANTHROPIC_API_KEY, and .notemend.json committed. A person still
merges, and confirms each fix on the live site.
Review a site the way you review a design file:
.container / .grid.C comments, ⇧C panel, R resolved, G grid,
P/S/T/O/B inspectors, E Sanity, 1–9 breakpoints, D devices, [ ] pages, \ hide
the bar, ? the list (also behind the keyboard button). Physical keys, so any layout works;
never while you type; inside the canvas too.| Control | |
|---|---|
| Pages | jump to any page. Chips show comment counts, one per breakpoint and status, in the six status colours: new, in progress, to review (an agent's fix, or Needs review), waiting, accepted, and resolved while resolved threads are shown |
| Grid | the layout grid overlay |
| Spacing / Size / Type / Colour / Border | inspectors, one at a time. Hold Alt to measure the parent |
| Sanity | hides Sanity's visual-editing overlay (only with sanity: true) |
| Comment | comment mode: click anything to pin a note. The badge counts open threads |
| Panel | the list of this page's threads at this breakpoint |
| Resolved | shows or hides resolved threads, on the page and in the menu |
| Breakpoints | open the canvas at a band. The widest band is your own window |
| Device | Preview: a real screen with its browser. DevTools: the canvas at a device's size. Comments work in both |
| Tab on top of the bar | folds the bar below the window edge and back |
Keys: Esc closes a menu, then the note you are writing, then the open thread, then comment mode. Enter sends, Shift+Enter is a new line. Double-click a canvas handle to snap to the band's edge.
Everything the bar remembers (modes, canvas width, a half-typed comment) is in
localStorage, per browser.
For Astro and Next.js projects the same bar runs under astro dev / next dev — with no
account, comments stay in feedback/comments.json and screenshots in feedback/images/;
linked, they go to the project. Nothing of it reaches a build.
npm i -D notemend
npx notemend init
init reads the project and asks only what it cannot read:
src/pages (Astro) or app/ (Next), named from its
<title> or metadata.title, grouped by folder; dynamic routes are listed as examples
for you to fill in;It writes notemend.config.mjs, wires the bar in (Astro: notemend() in astro.config;
Next: see below) where it is not there yet, and touches nothing else.
npx notemend init --yes takes every default.
Without init, integrations: [notemend()] in astro.config.mjs is enough: four default
breakpoints, pages grouped by folder.
After upgrading, stop and start astro dev. Astro's own restart (on a config change)
runs in the same Node process, which keeps the old server half of the bar loaded while
the browser half is already new.
App Router, Next 15.3 or later, Turbopack or webpack. Next has no integrations, so
init writes three small pieces instead:
// instrumentation-client.ts — loads the bar; a build drops the import with the branch
if (process.env.NODE_ENV === 'development') import('notemend/client');
// app/%5F%5Fdevbar/[...path]/route.ts — the /__devbar/ endpoints (`%5F` is how a Next
// folder serves a segment that starts with `_`); outside `next dev` it answers 404
export { GET, POST, PATCH, DELETE } from 'notemend/next';
// next.config.ts — the bar ships as TypeScript, which Next compiles from node_modules
// only when told
const nextConfig: NextConfig = { transpilePackages: ['notemend'] };
(src/app and src/instrumentation-client.ts in a project that keeps its code in src/.)
An existing instrumentation-client gets the line appended; a next.config init cannot
edit safely is left alone with a note of what to add.
A proxy.ts (middleware.ts before Next 16) that guards every route — a login wall —
must let /__devbar/ through, or the bar cannot load its config:
export const config = { matcher: ['/((?!__devbar|_next/static|_next/image|favicon.ico).*)'] };
There is no enabled switch under Next: to keep the bar out of a Playwright run, add
your own condition to the instrumentation-client line.
Everything lives in notemend.config.mjs at the project root — named exports or one
default object. It is re-read on every page load: edit, refresh, no restart.
// notemend.config.mjs
export const breakpoints = [
{ id: 'desktop', label: 'Desktop', min: 992, max: Infinity, ideal: 1440 },
{ id: 'tablet', label: 'Tablet', min: 768, max: 991, ideal: 834 },
{ id: 'landscape', label: 'Mobile landscape', min: 480, max: 767, ideal: 667 },
{ id: 'portrait', label: 'Mobile portrait', min: 0, max: 479, ideal: 390 },
];
// route → [name, group]. Unlisted pages still appear, named by <title>.
// A number in front of a name only orders the rows: '1.2. About' reads as 'About'.
export const pages = {
'/': ['Home', 'Main'],
'/blog/hello-world': ['Blog post', 'Blog'], // an address a dynamic route serves
};
export const groups = ['Main', 'Blog']; // menu order; unlisted pages land in the last
export const grid = { container: 'container', grid: 'grid', columns: 12 };
export const sanity = true; // Sanity overlay toggle
export const ignore = ['.my-dev-nav']; // selectors the inspectors skip
export const devices = [/* … */]; // the device shelf, see below
export const zIndex = 2000000020; // the bar's base layer
| Key | Default | |
|---|---|---|
breakpoints | the four above | id, label, min, max (Infinity for the widest), ideal (canvas width), optional icon (SVG paths, 20×20) |
pages | from src/pages / app/ | route → [name, group] |
groups | by folder | group order |
grid | container / grid / 12 | classes of your own layout the overlay reuses |
devices | the eight above | the preview shelf: { id, label, group, w, h, shell, browser, note? } — shell: island home punch tablet macbook laptop monitor; browser: safari-ios chrome-android safari-ipad safari-mac chrome-windows; note is the row's tooltip. An older (mitka) config gave a device a frame picture; such an entry is skipped with a warning |
sanity | false | show the Sanity overlay toggle. Sanity's visual editing takes any iframe for Studio's Presentation and swallows clicks on CMS text there — in the canvas, tabs and buttons stop working. Skip its island inside the bar's frame: window.frameElement?.closest('.dt-frame') |
shortcuts | true | single-key shortcuts and their list in the bar; false for a site with letter keys of its own (a video player) |
ignore | [] | selectors the inspectors and comment picker skip |
zIndex | 2000000020 | above Astro's dev toolbar and any app modal |
Under Astro the same keys can be passed to notemend({ … }) in astro.config, where they
win over the file. enabled only works there: notemend({ enabled: process.env.CI !== 'true' }) keeps
the bar out of, say, a Playwright run.
Installed from a repo the build machine cannot reach (an optionalDependency on a
private GitHub repo), import it behind a catch so a missing package never breaks the
build — init writes it this way when it finds notemend under optionalDependencies:
const notemend = await import('notemend').then((m) => m.default).catch(() => null);
export default defineConfig({ integrations: [...(notemend ? [notemend()] : [])] });
astro dev and serves its
endpoints under /__devbar/ from Vite middleware. Under astro build it does nothing.
Under Next the same endpoints are a route handler, and the script waits for React to
hydrate <html> before it touches it — an attribute set earlier is a hydration error.<Link>, anything built on pushState) keeps the bar
and moves it to the new page: its threads, its drafts, its row in the menu.postMessage.<dialog>s: while one is open, the bar moves into
a popover host inside it (top layer, not inert) and back out when it closes./__devbar/comments from another origin are refused — any site open in the
same browser could otherwise post a "comment" an agent would read as a task.vh/svh/lvh unit is the iframe's height (on the phone 100vh is the taller,
bars-folded one), hover/pointer media queries answer for your mouse,
env(safe-area-inset-*) is 0, and the pixel ratio is your screen's. The badge says
which page size you are looking at; the bars button switches to the folded one.src/client/devices.ts.src/integration.mjs the Astro integration
src/next.mjs the Next.js route handler (notemend/next)
src/server/middleware.mjs /__devbar/* endpoints, notemend.config.mjs loading
src/hosted.ts bar.js: the bar as one script for any site, signed in through the cabinet
src/hosting.mjs the same endpoints as the cabinet serves them to bar.js (notemend/hosting)
src/store/ comments.json store, tags, statuses, thread helpers — shared by CLI, server, browser
src/store/cloud.mjs the store in the cabinet's database, the CLI's session, `notemend login`
src/presets.mjs the preview shelf, default breakpoints, switcher icons
src/client/ the bar: markup.ts builds the DOM, run.ts is the behaviour, notemend.css
src/client/devices.ts the preview devices: bodies as SVG, status bars and browsers as HTML
bin/notemend.mjs the CLI; bin/init.mjs is `notemend init`; bin/mcp.mjs the MCP server over it
tools/ pack.mjs (the minified package for npm), mcpb.mjs (the Claude Desktop bundle),
sync-devtools-devices.mjs (Chrome's device list)
npm test runs the selftest (store, CLI, init, the endpoints). To work on the bar, point
a test project at your checkout — "notemend": "file:../notemend" — and restart its dev server
after changing anything outside src/client/. Turbopack will not compile a linked package
that lives outside the project, so for a Next test project install a packed copy
(npm pack, then npm i -D ../notemend/notemend-x.y.z.tgz) instead.
Proprietary — see LICENSE: you may install and run the package only to use Notemend. The DevTools device list (src/devtools-devices.mjs, regenerated by
tools/sync-devtools-devices.mjs) comes from Chrome DevTools and keeps its BSD licence
notice (© The Chromium Authors).
FAQs
A dev-only toolbar for Astro and Next.js sites: pinned page comments Claude Code can read and answer, spacing/size/type inspectors in design px, a layout grid, breakpoint canvas and device preview.
The npm package notemend receives a total of 647 weekly downloads. As such, notemend popularity was classified as not popular.
We found that notemend demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.

Security News
Anthropic’s free OSS Scanner uses Mythos and other Claude models to find open source vulnerabilities and send maintainers reports with proposed fixes.

Security News
On Front Lines’ Early Adopters: CISO podcast, Andrew Becherer shares lessons from Datadog, weighs the long-term costs of AI-built tools, and explains how founders can actually gain a CISO’s trust.