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

backstep

v0.1.20

Published

Undo for everything your agents touch: an MCP proxy that makes agent actions reversible.

Readme

Backstep

Undo for everything your agents touch. Backstep sits between your agent (Claude Code, Cursor, any MCP client) and the MCP servers it uses. Before a tool changes something, Backstep saves a way back. When an agent goes wrong, you undo the action, or the whole run, from a dashboard.

  • Files: every path a tool is about to touch is copied first. Writes, edits, deletes, creates and moves all roll back.
  • Postgres: INSERT/UPDATE/DELETE/TRUNCATE snapshot the table first. DROP TABLE never really drops: the table is moved to a backstep_trash schema with its indexes, constraints and sequences, so undo brings it back exactly. CREATE TABLE is undone by dropping the new table.
  • Shell commands Claude runs: before each one, the project folder is saved into a hidden git history under ~/.backstep/trees, along with the project's own branches, HEAD and staged files. rm, git reset --hard, scripts that rewrite files and new branches all roll back. Commands that only read are skipped.
  • Supabase: execute_sql and apply_migration snapshot the tables they change, over a connection to the project's database. Backstep never connects it on its own: when Claude Code opens a project that uses Supabase and isn't connected, it asks (Connect, Not now, or Don't ask for this project). Connect uses a connection string in the project's .env files, the local supabase start database, or a Supabase sign-in (supabase login, SUPABASE_ACCESS_TOKEN, or an access token you give Backstep once), with which the project gets a temporary database login that Backstep renews as it runs out. You can also ask Claude to "connect Backstep to Supabase" any time. Deleted rows, dropped tables and migrations, including the migration's history row, all come back. Works for the claude.ai Supabase connector and a local Supabase MCP server alike.
  • Firebase: before a change, Backstep reads what's there through the Firebase MCP server itself, and undoes through it too, so there's nothing to set up. Firestore documents updated, deleted or added; Realtime Database writes; Remote Config publishes (rolled back to the version before); and users enabled or disabled.
  • claude.ai connectors and servers Claude Code signs in to: Backstep can't sit in front of these, so the Claude Code mod watches their calls instead. Calls with an undo rule are undone through Claude Code's own connection.
  • Notion (the claude.ai connector, or Notion's own MCP server): built in, nothing to set up. Pages and rows Claude creates, duplicates or databases it makes go to Notion's Trash on undo; pages it deletes come back from Trash; an edit (content, properties, icon, cover) is undone by writing back the page as the mod read it just before; moved pages go back where each came from. A page too big to read whole, or a result Backstep can't read the new pages from, is recorded and marked not undoable rather than guessed at.
  • Database commands Claude runs (supabase db push, supabase migration up, supabase db reset, psql, prisma migrate, drizzle-kit push, seed scripts…): in a project whose Supabase database is connected, the whole database is noted before the command runs, and ctrl+u puts it back in one transaction: rows, new tables dropped, dropped or altered tables rebuilt with their constraints, indexes, foreign keys, row level security policies, triggers and grants, sequence counters, and the migration history. Copies sit in a backstep schema in the same database; the newest 10 per database are kept. On a very big database it keeps every table's structure and the migration history, and rows smallest-table-first up to a budget (BACKSTEP_DB_SNAPSHOT_MB, default 250); undo names any table whose rows it couldn't bring back. Functions, views, types and extensions aren't restored.
  • Supabase through its web API (curl to /rest/v1, seed and app scripts using supabase-js): Backstep finds Supabase projects in the folder Claude Code opened or a level or two below, and the first time Claude is about to change one that isn't connected, it asks before the command runs. Connect uses the project's own SUPABASE_URL and service role key from its .env, no password: every table's rows are saved on this machine before each such command (smallest first, up to the size budget), and ctrl+u removes rows added since and writes back the old ones. Table changes need the database itself connected (password or access token).
  • Any Postgres database (Neon, Railway, Render, AWS, a local one) named in the project's .env (DATABASE_URL and the like): Backstep asks once, then saves the whole database before Claude's database commands (psql, prisma migrate, drizzle-kit push, seed and app scripts) and puts it back on undo, the same way as Supabase.
  • SQLite files in the project (dev.db, *.sqlite), git-ignored ones included: copied before commands that could change them and restored on undo; a database file made since is removed.
  • Firebase data changed outside its MCP server (firebase firestore:delete, firebase database:set, firebase-admin scripts, curl to Firestore): Backstep asks once and connects with the project's service account key (or gcloud's application default login). Before such a command, Firestore's documents (top-level collections first, then subcollections, up to the size budget) and the Realtime Database are saved; undo deletes documents added since, writes back changed or deleted ones, and puts the Realtime Database back.
  • Code Claude pushed: ctrl+u rewinds the commits locally, then asks whether to undo them on GitHub (or any remote) too. Yes pushes one new commit that undoes Claude's, made in a temporary worktree: no force push, no rewritten history, so it works on protected branches and for teammates who already pulled. Newer commits that clash, or a rewritten branch, stop it. A branch Claude created is deleted instead, if nobody has added to it. It uses the project's own git sign-in, so there's nothing to connect.
  • Things Claude makes on GitHub with gh (a repository, an issue, a pull request, a release): after undo, Backstep asks whether to take each one away there too (delete the repository or release, close the pull request, delete or close the issue), using your own gh sign-in. Deleting a repository needs gh's delete_repo permission; if it's missing, Backstep says how to grant it.
  • Things that can't be undone (sending email, payments, deploys, ALTER TABLE…) run as normal and are marked in the journal, so you know what an undo didn't cover.
  • Anything else, by rule: a rules file maps a tool to its opposite (create_issue → close the issue, send_message → retract it), filled in from the call and its result. See Undo rules.
  • Conflicts: undoing an action first undoes any later action that touched the same file or table, so nothing gets silently thrown away.

Install

npx backstep setup

This installs Backstep, adds its Claude Code mod, binds ctrl+u to undo everything Claude did in its last turn, and puts the MCP servers you've already added to Claude Code behind Backstep, so their changes can be undone too. Databases (Supabase, Postgres, Firebase) aren't touched at setup: the first time Claude goes to change one, Backstep asks whether to connect it. Restart Claude Code afterwards. Needs Node 22.13+ and Claude Code.

Servers in a repo's shared .mcp.json that you've approved get a wrapped copy for that project only; the repo's file is never edited. Remote servers that Claude Code signs in to stay as they are, and the mod watches their calls instead. Servers you add later are wrapped the next time Claude Code starts. backstep unwrap puts every server back the way it was and stops new ones being wrapped.

Uninstall

In Claude Code, type /uninstall-backstep, or just ask Claude to uninstall Backstep. From a terminal: backstep uninstall (or npx backstep uninstall).

It asks first, then takes away everything Backstep set up: your MCP servers go back to their own commands, the database copies Backstep saved are dropped (and its backstep schema, only if that leaves it empty), the undo key comes out of Claude Code's keybindings, the plugin is removed, and ~/.backstep (history, snapshots, saved connections) is deleted. Nothing you undid or kept changes. Restart Claude Code to finish.

Try it

npm install
npm run demo     # throwaway Postgres on :5544 with a customers table; prints the claude mcp add line
npm run ui       # dashboard at http://localhost:4747

Then ask Claude to drop the customers table, and press Undo in the dashboard.

Wrap any MCP server

backstep wrap --name files -- npx -y @modelcontextprotocol/server-filesystem ~/project
backstep wrap --name db --pg "$DATABASE_URL" -- npx -y some-postgres-mcp-server
backstep wrap --name github --url https://api.githubcopilot.com/mcp/ \
  --header 'Authorization: Bearer ${GITHUB_TOKEN}' --rules examples/rules.json

With Claude Code: claude mcp add files -- backstep wrap --name files -- <the server command>.

| Option | | |---|---| | --name | label in the dashboard | | --url <url> | wrap a remote MCP server (Streamable HTTP, falls back to SSE) | | --header "K: V" | header for the remote server, repeatable. ${VAR} is read from the environment so tokens stay out of config files | | --rules <file> | undo rules (or set BACKSTEP_RULES) | | --pg <url> | the Postgres database the wrapped server writes to. Enables database undo. Without it, SQL writes are recorded but can't be undone. |

The undo key is ctrl+u (not ctrl+z: Claude Code suspends itself on ctrl+z in a terminal before anything else sees the key, so it can't be used). The first press asks "Undo Claude's last turn?" above the prompt and a second press within 5 seconds undoes, so a stray press does nothing. Change the key whenever you like: ask Claude ("change my Backstep undo key to ctrl+q"), or run backstep key ctrl+q. The line above the prompt is always there, even with nothing to undo, because the key only reaches Backstep while it's on screen; otherwise a press would do nothing.

Backstep checks npm for a newer version as each Claude Code session starts and asks before updating (Update, Not now, or Skip this version; backstep update does it by hand, BACKSTEP_UPDATE_CHECK=0 turns the check off).

Other commands: backstep ui, backstep log, backstep undo <action-id>, backstep undo --run <run-id>, backstep connect [supabase|firebase] (connects what the project uses, the same as asking Claude), backstep disconnect supabase <ref>.

In Claude Code you can just ask: "connect Backstep to everything I use". Supabase is connected from the project's settings (or the connection string you paste), and when the project uses Firebase but Claude can't reach it yet, Firebase's MCP server is added behind Backstep.

During development, run node src/cli.ts … (Node 24 runs the TypeScript directly). npm run build compiles to dist/.

Undo rules

For tools Backstep can't snapshot, a rule names the tool that undoes them. {{args.x}} comes from the original call; {{result.x}} comes from its result (structured content, or the text parsed as JSON).

{ "rules": [
  { "server": "github", "tool": "create_issue",
    "inverse": { "tool": "update_issue",
                 "args": { "owner": "{{args.owner}}", "repo": "{{args.repo}}",
                           "issue_number": "{{result.number}}", "state": "closed" } } }
] }

server is optional and matches --name. For claude.ai connectors and servers Claude Code signs in to, put rules in ~/.backstep/rules.json; server is the name as it appears in tool names (claude_ai_Notion), and pressing ctrl+u runs the opposite call through Claude Code. A rule overrides the built-in guess, so a send_message with a retract rule is undoable. The undo runs through a live backstep wrap of that server; if none is running, the dashboard tells you to start it, and any running copy with the same --name picks up the request. examples/rules.json has GitHub rules as a starting point. Check the tool and argument names against your server's version.

How it decides

Each call is classified before it runs (src/classify.ts):

  1. Undo rules match first, then Firebase tools.
  2. SQL (an argument like sql/query that reads like SQL): judged by the statements, not the tool name. Reads pass through.
  3. Reads: readOnlyHint, or names like get_*, list_*, read_*, search_*.
  4. Irreversible: names like send_*, pay, deploy, execute_command, or destructiveHint/openWorldHint with nothing to snapshot. These run and are marked, not undone.
  5. Paths: arguments named path, source, destination… get file snapshots.
  6. Anything else is recorded as a write with no undo.

Everything is journaled to ~/.backstep/journal.db (SQLite, mode 0600; override with BACKSTEP_HOME). File snapshots live in ~/.backstep/snapshots/, Postgres snapshots in the backstep schema of your database.

Known limits (MVP)

  • ALTER TABLE, writing CTEs, TRUNCATE … CASCADE, functions and other DDL run but aren't undone.
  • Table snapshots are full copies, capped at ~1M rows; changes to bigger tables aren't undoable. Files are capped at 50 MB per call.
  • Supabase changes need the database connected. Without it they run as normal and the Claude Code mod says once to ask Claude to connect it. The connection string is kept in ~/.backstep/connections.json (mode 0600).
  • Firebase undo needs the Firebase server running behind Backstep (it is after setup). Custom claims on users, Storage, Cloud Messaging and deploys aren't undone. Firestore undo puts the whole document back, so a change someone else made to it in between is lost too.
  • Google's own Firestore MCP server, connected with sign-in, is watched rather than wrapped, so its changes aren't undone yet.
  • Undoing a table restore runs DELETE and then re-inserts rows, so foreign keys from other tables pointing at deleted rows can block it. The undo then fails cleanly inside a transaction.
  • --pg must point at the same database the wrapped server uses.
  • The dashboard only accepts requests from this machine. The journal stores the --pg URL so undo works later.
  • Remote servers that need an OAuth login can't be wrapped; they're watched from Claude Code instead, so their undo works with ctrl+u but not from the dashboard.
  • Shell snapshots cover the project folder (the git repository, or the folder Claude Code runs in). Files outside it, and ignored folders like node_modules, aren't saved: undo restores package.json and the lockfile, and you re-run the install.
  • Shell commands are judged before they run by what they look like, so a script that pushes or deploys from inside is snapshotted, not held.

Telemetry

backstep setup sends one anonymous install event, Claude Code with the Backstep mod sends one active event a day, and backstep uninstall sends one uninstall event. Each carries a random id made on your machine (~/.backstep/install-id), the Backstep version, your OS and CPU type, and the Node major version. Nothing else: no paths, commands, server names, IP-based location, or anything from the journal. The code is src/telemetry.ts.

Turn it off with BACKSTEP_TELEMETRY=0, or the standard DO_NOT_TRACK=1.

Tests

npm test

Runs the official filesystem MCP server and a SQL MCP server on PGlite through the real proxy, plus a remote HTTP server that requires an API key. Then it checks undo, conflict chains, undo rules and dashboard request checks. Supabase is checked against a real Postgres (PGlite), through both the connector path and the proxy, and Firebase against a stand-in server with the real tool names.

Landing page

site/index.html is a static page with no build step. Open it directly, or deploy the folder with vercel deploy site. Set ACCESS_EMAIL at the top of its script before it goes live; until then the early-access form says access opens soon.