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

notionctl

v0.1.4

Published

Security-auditable, zero-dependency command-line interface for Notion, designed to be driven by AI coding agents via shell invocations.

Readme

notionctl

CI npm license node dependencies

The security-first CLI for Notion. Zero dependencies. Fully auditable. Built for AI agents and humans alike.

npm install -g notionctl

Requires Node 18+.

Quick Start

# Option A: OAuth browser login (recommended)
notionctl auth login --client-id <id> --client-secret <secret>

# Option B: Paste an integration token
notionctl auth set

# Option C: Environment variable
export NOTION_TOKEN=ntn_...

# Verify
notionctl whoami

# Go
notionctl search "Q2 Roadmap"
notionctl page get <url-or-id>
notionctl page sync ./prd.md --parent <page-id>

Why notionctl

AI coding agents (Claude Code, Copilot, Cursor) work best when they can read and write your team's Notion knowledge base. MCP servers bridge this gap, but require persistent processes with broad privileges and a larger attack surface.

notionctl is the alternative: one shell command per operation, shell-logged, --dry-run-able, and auditable line by line. Every action an agent takes is a visible terminal invocation.

notionctl vs MCP

| | notionctl | Notion MCP server | |---|---|---| | Token cost | One shell command + one response per operation | Tool schemas, JSON-RPC framing, and capability negotiation all consume context tokens | | Latency | Single process: spawn → HTTP call → exit | Persistent server + JSON-RPC round-trip per call | | Agent context | Agent sees notionctl page get <id> — one line | Agent loads full tool schema list into context window on every session | | Setup | npm i -g notionctl + one token | Server process, config file, client wiring | | Auditability | Every call is a shell command in your terminal log | Operations happen inside an opaque server process | | Security surface | Zero deps, single network file, auditable in an afternoon | Server framework, transitive deps, persistent token in memory |

Security Model

notionctl was designed so that a security team can audit the entire tool in an afternoon.

  • Zero runtime dependencies. The entire codebase is hand-written TypeScript compiled to ES modules. No node_modules. No transitive supply chain risk.
  • Single network file. All outbound traffic goes through src/http.ts, hardcoded to https://api.notion.com. No --api-base flag, no proxy support, no way to redirect the token.
  • Single secrets file. Token access is isolated to src/auth.ts. Tokens live in NOTION_TOKEN or a mode-0600 config file. Tokens never appear in logs, errors, or stdout.
  • Automated security tests. npm run test:security runs grep-based source tree assertions that encode these invariants. They fail the build on drift:
    • Only http.ts calls fetch()
    • Only auth.ts reads the config path
    • No hardcoded token patterns in source
    • No non-Node-builtin imports
    • Only api.notion.com URLs in source
  • Dry-run everything. Every write command supports --dry-run to preview the payload without sending.
  • Content-hashed sync. page sync uses SHA-256 frontmatter hashing with drift detection to prevent accidental overwrites.
  • No telemetry. Zero outbound traffic beyond api.notion.com. Provable: grep -r "https://" src/.

Command Surface

39 commands across 8 categories. Full reference: docs/COMMANDS.md.

Pages

notionctl page get <id>                              # Read as Markdown
notionctl page create --parent <id> --title "X"      # Create from Markdown
notionctl page sync ./doc.md --parent <id>            # Bidirectional sync
notionctl page find-replace <id> --find "v1" --replace "v2"
notionctl page duplicate <id>
notionctl page move <id> --to <parent-id>
notionctl page open <id>                              # Open in browser
notionctl page restore <id>                           # Undelete
notionctl page delete <id> --yes

Databases

notionctl db create --parent <id> --title "Tasks" \
  --prop Status=select:Todo,Doing,Done --prop Due=date
notionctl db query <id> --filter "Status=Done" --sort "Due:desc"
notionctl db schema <id>
notionctl db row create <id> --prop "Name=Ship v2" --prop "Status=Todo"
notionctl db row update <id> --prop "Status=Done"

Filter DSL supports =, >, <, >=, <= across select, number, date, text, checkbox, and multi_select types. For complex filters: --filter-json @filter.json.

Blocks, Files, Comments, Users

notionctl block children <id> --recursive     # Full page subtree
notionctl block append <id> --from patch.md --after <block-id>
notionctl file upload ./screenshot.png --parent <page-id>
notionctl comment add <page-id> --text "LGTM"
notionctl user list

Auth

notionctl auth login --client-id <id> --client-secret <secret>  # OAuth
notionctl auth set [--profile staging]                           # Token from stdin
notionctl auth status                                            # Verify token
notionctl auth doctor                                            # Full diagnostics

Escape Hatch

Any Notion REST endpoint, with the CLI's auth and retry behavior:

notionctl api GET /users/me
notionctl api POST /databases/<id>/query --body @filter.json

Markdown Engine

Bidirectional Markdown conversion with full fidelity:

Read: headings, paragraphs, bullet/numbered/to-do lists (nested), code blocks, tables (GFM), quotes, callouts, toggles, dividers, images, equations, bold, italic, strikethrough, inline code, links.

Write: all of the above. Nested lists use 2-space indentation and produce the corresponding nested block tree in Notion.

Sync with Drift Detection

notionctl page sync ./prd.md --parent <id>   # Creates page, writes notion_id to frontmatter
# ...edit locally...
notionctl page sync ./prd.md                 # Updates only if local content changed

Each sync stores a SHA-256 content hash and timestamp in the file's YAML frontmatter. On subsequent syncs, if someone edited the page in Notion after your last sync, notionctl refuses to overwrite and tells you to fetch the remote version first. Override with --force.

Output Formats

| Context | Default | Override | |---------|---------|----------| | TTY (interactive) | Human-friendly (table, Markdown) | --format json | | Piped (scripts) | JSON | --format table |

All commands support --format md|json|table|csv.

Testing

731 automated tests. Zero test framework dependencies (uses Node.js built-in node:test).

npm test                    # Full suite
npm run test:security       # Security invariant checks

Full test coverage breakdown: docs/TESTING.md.

Inspired By

notionctl was written from scratch, but drew on patterns from:

License

MIT. See LICENSE.

Security Disclosure

See SECURITY.md for the responsible disclosure process.