npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mdinterface

v0.2.1

Published

A live markdown canvas wired to Claude Code. Highlight a passage to set both the context and the scope, ask, and Claude edits exactly that and leaves the rest alone.

Readme

mdinterface

CI License: MIT Node

mdinterface makes editing with Claude precise. A rendered markdown canvas sits beside a live Claude session, bridged by the file on disk. The passage you highlight sets both what Claude sees and what it is allowed to change, so edits stay scoped to what you pointed at instead of sprawling across the document. Ask for a small fix or a full rewrite of that part, and watch just that block change and re-render.

The two panes never talk to each other directly. The file on disk is the interface, and Claude's awareness is wired through its hooks, not by typing into its prompt:

full doc          ──SessionStart hook──▶ in Claude's context from the start
canvas selection  ──file + UserPromptSubmit hook──▶ rides along with each message
Claude Code       ──edits──────────────▶ the file on disk
file watcher      ──content────────────▶ canvas re-render

Setup

cd mdinterface
npm install        # express, ws, node-pty (ships a native helper)

Requires Node 18+ and the claude CLI on your PATH.

If the terminal pane says "Terminal unavailable," node-pty's prebuilt helper lost its executable bit (a common install hiccup). Restore it:

chmod +x node_modules/node-pty/prebuilds/*/spawn-helper

If there's no prebuilt binary for your platform, build it instead (needs Xcode Command Line Tools / build-essential):

npm rebuild node-pty

The rendering and terminal libraries (marked, xterm and its addons, DOMPurify) are bundled in public/vendor/ and served locally, so mdinterface works fully offline — no CDN, no first-load internet requirement.

Run

node server.js path/to/doc.md
# prints a URL like http://localhost:7777/?t=… — open THAT (it carries a session token)

Or start with no file — you get an empty canvas and a file browser; pick a .md and the session begins. The folder of that first document becomes Claude's working directory for the rest of the session, so launch from (or pick within) the project you want Claude to work in:

node server.js
# empty canvas → Browse → pick a doc; Claude starts in that doc's folder

Options:

--port 8000        # different port
--cmd "claude --continue"   # custom launch command (or set MDINTERFACE_CMD)
--help             # usage and exit

Use

  • Select any text in the rendered doc and it becomes ambient context — nothing is typed into the prompt. The selection is mirrored to .claude/mdinterface-selection.txt next to the doc, and a UserPromptSubmit hook (auto-installed into .claude/settings.local.json) silently attaches it to your next message. Give a normal instruction — "tighten this up", "explain this" — and Claude already knows what "this" is. Clear the selection and it stops.
  • Edits apply immediately — Claude changes the file and the canvas re-renders. To take one back, use the Undo button (rolls back the last change) or ask Claude to revert it; in a git repo, every change is also one git diff away.
  • The right pane is the genuine CLI: /commands, plan mode, claude --resume, everything works, because it is claude running in a PTY.
  • When Claude (or anything else — your editor, git checkout) changes the file, only what changed flashes green and updates. Scroll position is preserved.

Notes

  • If claude isn't found, it falls back to your shell so you can debug.
  • Undo = git. Run it in a repo and every accepted change is one git diff away.

Security

mdinterface runs a live shell/Claude session over a local WebSocket, so it is locked down to this machine only:

  • The server binds to 127.0.0.1 (loopback), never reachable from the network.
  • Every request carries a per-launch token (in the URL); the WebSocket also checks the Origin and Host headers, so a website you visit can't connect to it.
  • Rendered markdown HTML is sanitized (DOMPurify) before display.

Still your responsibility:

  • Only open documents you trust. The whole file is fed into Claude's context and an auto-approved canvas_edit tool can write it, so a malicious document is a prompt-injection vector.
  • Single-user machines only. The launch token is written to .claude/mdinterface-runtime.json (mode 600) so the helper process can reach the server. Anyone who can read your files can read that token and drive the session — fine on your own machine, not on a shared host.
  • mdinterface writes into the document's folder: .claude/settings.local.json (hooks + MCP pre-approval), .mcp.json, .claude/mdinterface-selection.txt, and .claude/mdinterface-runtime.json. The shipped .gitignore covers these for mdinterface's own repo; when you point it at a doc in another repo, add them to that repo's .gitignore.

Threat model — how you'd actually get owned

There is essentially one door, and it's a document you didn't write. A remote attacker can't reach the server (loopback bind + per-launch token + WebSocket Origin/Host checks mean a website you visit or someone on your network can't connect — they don't have the token and can't read it cross-origin). So the only way in is to get a file to you and have you open it in the canvas — a contributor's PR, a shared .md, a downloaded doc.

When you open it, the whole file is fed into Claude's context, so any instructions hidden in it (an HTML comment, white-on-white text, or just confident prose) are read as if you'd typed them. From there:

  • The dangerous escalation is Bash, and Bash is not pre-approved — it hits the normal permission prompt. So a poisoned doc degrades to social engineering: it tries to get Claude to propose a benign-looking command (npm install && ./setup.sh) that you approve on autopilot. Approving a command you didn't ask for, with a foreign doc open, is the whole ballgame — that's RCE as you. Don't.
  • Never run the pane in bypass-permissions / "YOLO" mode with an untrusted doc open. That auto-approves Bash, turning the above into a true zero-click RCE on file open.
  • Zero-click, no approval needed (bounded): an injection can still use whatever is already auto-approved — e.g. a WebFetch(domain:…) grant becomes a silent exfiltration channel (doc/selection text smuggled in a URL), and canvas_edit can silently tamper with the doc you're about to publish. Prune auto-approve grants you aren't using.

What an attacker cannot do, by construction: reach you over the network, escape canvas_edit/canvas_open into .claude/ to plant a hook (path-scoped: realpath + extension allow-list + .claude refusal), steal the token via XSS (sanitized, with a plain-text fallback), or read the 600 token file as another user. The boundary that's yours to hold is the first line: treat any document you didn't write as untrusted input, and don't approve commands for it.