Notion — Printing Press CLI
Prerequisites: Install the CLI
This skill drives the
binary.
You must verify the CLI is installed before invoking any command from this skill. If it is missing, install it first:
- Install via the Printing Press installer:
bash
npx -y @mvanhorn/printing-press install notion --cli-only
- Verify:
- Ensure (or ) is on .
If the
install fails (no Node, offline, etc.), fall back to a direct Go install (requires Go 1.26.3 or newer):
bash
go install github.com/mvanhorn/printing-press-library/library/productivity/notion/cmd/notion-pp-cli@latest
If
reports "command not found" after install, the install step did not put the binary on
. Do not proceed with skill commands until verification succeeds.
notion-pp-cli syncs your Notion workspace into a local SQLite store and exposes commands for page and block management, stale page detection, and change tracking. Works offline and ships a full MCP server.
When to Use This CLI
Use notion-pp-cli when you need to manage Notion pages and blocks from the terminal, detect stale pages, or track what changed since a given time. Run
once to populate the local store, then
and
work offline. Not a substitute for the Notion web UI for day-to-day editing.
Unique Capabilities
These capabilities aren't available in any other tool for this API.
Agent-native plumbing
-
— Show everything in the workspace added, edited, or deleted since your last sync or a given timestamp.
Use at the start of an agent session to orient on what has changed before taking action.
bash
notion-pp-cli changed --since 2h --json
Local state that compounds
-
— List pages and records not edited in N days, filterable by database, parent, or tag.
Use to identify dead pages before workspace cleanup or to flag deliverables overdue for review.
bash
notion-pp-cli stale --days 30 --db ProjectDB --agent
Command Reference
blocks — Block endpoints
notion-pp-cli blocks delete
— Delete a block
notion-pp-cli blocks query-meeting-notes
— Query meeting notes
- — Get a block by ID
notion-pp-cli blocks update
— Update a block
notion-pp-cli blocks children list
— List children of a block or page
notion-pp-cli blocks children append
— Append blocks to a page or block
comments — Comment endpoints
notion-pp-cli comments create-a
— Create a comment
notion-pp-cli comments delete-a
— Delete a comment
notion-pp-cli comments list
— List comments
notion-pp-cli comments retrieve
— Retrieve a comment
notion-pp-cli comments update-a
— Update a comment
custom-emojis — Custom emoji endpoints
notion-pp-cli custom-emojis
— List custom emojis
data-sources — Data source endpoints
notion-pp-cli data-sources create-a-database
— Create a data source
notion-pp-cli data-sources retrieve-a
— Retrieve a data source
notion-pp-cli data-sources update-a
— Update a data source
databases — Database endpoints
notion-pp-cli databases query <database_id>
— Query records in a database with optional filter/sort
notion-pp-cli databases create
— Create a database
notion-pp-cli databases retrieve
— Retrieve a database
notion-pp-cli databases update
— Update a database
file-uploads — File upload endpoints
notion-pp-cli file-uploads create-file
— Create a file upload
notion-pp-cli file-uploads list
— List file uploads
notion-pp-cli file-uploads retrieve
— Retrieve a file upload
notion-search — Manage notion search
notion-pp-cli notion-search
— Search by title
oauth — OAuth endpoints (basic authentication)
notion-pp-cli oauth create-a-token
— Exchange an authorization code for an access and refresh token
notion-pp-cli oauth introspect-token
— Introspect a token
notion-pp-cli oauth revoke-token
— Revoke a token
pages — Page endpoints
notion-pp-cli pages update
— Update a page
notion-pp-cli pages create
— Create a page
- — Get a page by ID
- — Move a page
notion-pp-cli pages markdown export
— Export a page as markdown
users — User endpoints
- — List all users
notion-pp-cli users get-self
— Retrieve your token's bot user
notion-pp-cli users get-userid
— Retrieve a user
views — View endpoints
notion-pp-cli views create
— Create a view
notion-pp-cli views delete
— Delete a view
- — List views
notion-pp-cli views retrieve-a
— Retrieve a view
notion-pp-cli views update-a
— Update a view
sync pages — Sync all pages and databases to local SQLite
- — Sync all pages and databases via search API (run before stale/changed)
notion-pp-cli sync pages --full
— Full resync from scratch
notion-pp-cli sync pages --type database
— Sync databases only
Finding the right command
When you know what you want to do but not which command does it, ask the CLI directly:
bash
notion-pp-cli which "<capability in your own words>"
resolves a natural-language capability query to the best matching command from this CLI's curated feature index. Exit code
means at least one match; exit code
means no confident match — fall back to
or use a narrower query.
Recipes
Morning triage: what changed overnight
bash
notion-pp-cli changed --since 8h --json
Show everything edited in the last 8 hours — use at session start to orient before taking action.
Find stale pages before cleanup
bash
notion-pp-cli stale --days 30 --json --select id,title,days_since_edit,last_edited_time
Pages untouched for 30+ days, sorted oldest-first. The Notion UI has no equivalent filter across multiple workspaces.
Export a page as markdown
bash
notion-pp-cli pages markdown export <page-id>
Fetches the page content as markdown via the native Notion markdown endpoint — no conversion needed.
Read block children of a page
bash
notion-pp-cli blocks children list <page-id> --json --select id,type
List all top-level blocks on a page with their types and IDs.
Auth Setup
Requires a Notion Internal Integration token. Create one at notion.so/my-integrations, share your top-level pages with it, then set
(or
) in your environment.
First-run setup:
bash
notion-pp-cli doctor # verify auth
notion-pp-cli sync pages # sync all pages + databases (~15k pages, takes 2-3 min)
notion-pp-cli stale --days 30 # now works
notion-pp-cli changed --since 24h
Agent Mode
Add
to any command. Expands to:
--json --compact --no-input --no-color --yes
.
-
Pipeable — JSON on stdout, errors on stderr
-
Filterable —
keeps a subset of fields. Dotted paths descend into nested structures; arrays traverse element-wise. Critical for keeping context small on verbose APIs:
bash
notion-pp-cli comments list --block-id 550e8400-e29b-41d4-a716-446655440000 --agent --select id,name,status
-
Previewable —
shows the request without sending
-
Offline-friendly — sync/search commands can use the local SQLite store when available
-
Non-interactive — never prompts, every input is a flag
-
Explicit retries — use
only when an already-existing create should count as success, and
only when a missing delete target should count as success
Response envelope
Commands that read from the local store or the API wrap output in a provenance envelope:
json
{
"meta": {"source": "live" | "local", "synced_at": "...", "reason": "..."},
"results": <data>
}
Parse
for data and
to know whether it's live or local. A human-readable
summary is printed to stderr only when stdout is a terminal — piped/agent consumers get pure JSON on stdout.
Agent Feedback
When you (or the agent) notice something off about this CLI, record it:
notion-pp-cli feedback "the --since flag is inclusive but docs say exclusive"
notion-pp-cli feedback --stdin < notes.txt
notion-pp-cli feedback list --json --limit 10
Entries are stored locally at
~/.notion-pp-cli/feedback.jsonl
. They are never POSTed unless
is set AND either
is passed or
NOTION_FEEDBACK_AUTO_SEND=true
. Default behavior is local-only.
Write what surprised you, not a bug report. Short, specific, one line: that is the part that compounds.
Output Delivery
Every command accepts
. The output goes to the named sink in addition to (or instead of) stdout, so agents can route command results without hand-piping. Three sinks are supported:
| Sink | Effect |
|---|
| Default; write to stdout only |
| Atomically write output to (tmp + rename) |
| POST the output body to the URL ( or when ) |
Unknown schemes are refused with a structured error naming the supported set. Webhook failures return non-zero and log the URL + HTTP status on stderr.
Named Profiles
A profile is a saved set of flag values, reused across invocations. Use it when a scheduled agent calls the same command every run with the same configuration - HeyGen's "Beacon" pattern.
notion-pp-cli profile save briefing --json
notion-pp-cli --profile briefing comments list --block-id 550e8400-e29b-41d4-a716-446655440000
notion-pp-cli profile list --json
notion-pp-cli profile show briefing
notion-pp-cli profile delete briefing --yes
Explicit flags always win over profile values; profile values win over defaults.
lists all available profiles under
so introspecting agents discover them at runtime.
Exit Codes
| Code | Meaning |
|---|
| 0 | Success |
| 2 | Usage error (wrong arguments) |
| 3 | Resource not found |
| 4 | Authentication required |
| 5 | API error (upstream issue) |
| 7 | Rate limited (wait and retry) |
| 10 | Config error |
Argument Parsing
- Empty, , or → show output
- Starts with → ends with → MCP installation; otherwise → see Prerequisites above
- Anything else → Direct Use (execute as CLI command with )
MCP Server Installation
- Install the MCP server:
bash
go install github.com/mvanhorn/printing-press-library/library/productivity/notion/cmd/notion-pp-mcp@latest
- Register with Claude Code:
bash
claude mcp add notion-pp-mcp -- notion-pp-mcp
- Verify:
Direct Use
- Check if installed:
If not found, offer to install (see Prerequisites at the top of this skill).
- Match the user query to the best command from the Unique Capabilities and Command Reference above.
- Execute with the flag:
bash
notion-pp-cli <command> [subcommand] [args] --agent
- If ambiguous, drill into subcommand help:
notion-pp-cli <command> --help
.