The most powerful command-line interface for Notion — built for AI agents first, humans too.
notion-cli-agent is designed to be used by AI agents that need to read and write Notion workspaces — natural language queries, batch operations, --llm output mode, workspace introspection, and more. Works great for humans too.
npm install -g notion-cli-agent
export NOTION_TOKEN="ntn_your_token_here"
# Full quick reference (read this first)
notion quickstartThis repo ships AgentSkills-compatible skill files in the skills/ directory. Skills use progressive disclosure: the core SKILL.md is small enough to live in your agent's context window, and detailed reference files (filters.md, batch-patterns.md, workflows.md) are loaded on demand.
skills/
├── notion-onboarding/ ← run first: maps your workspace to a state file
└── notion-cli-agent/ ← core CLI skill + references
Recommended setup for agents:
- Install skills in your agent framework (see
skills/README.md) - Run the
notion-onboardingskill once — it discovers your databases (tasks, projects, OKRs, home page) and saves them to~/.config/notion/workspace.json - All subsequent tasks use the mapped IDs automatically — no more looking up database IDs
--llmmode — compact, structured output optimized for agent consumptionnotion find— natural language → Notion filters in one commandnotion batch— multiple operations in a single shell call (minimize tool calls)notion ai prompt— generates a database-specific prompt for the agentnotion inspect context— full schema + examples + command reference in one shot- No rate-limit boilerplate, no SDK setup, shell-composable
- Search — Find pages and databases across your workspace
- Pages — Create, read, update, archive pages with full property support
- Databases — Query with filters, create schemas, manage entries
- Blocks — Add and manage page content (paragraphs, headings, lists, code, etc.)
- Comments — Read and create comments on pages
- Users — List workspace users and integrations
- Smart Queries — Natural language queries translated to Notion filters
- Batch Operations — Execute multiple operations in one command
- Agent Prompts — Generate optimal prompts for AI agents to work with databases
- Summarize — Get concise page summaries
- Extract — Pull structured data from page content
- Export to Obsidian — Pages and databases with YAML frontmatter
- Import from Obsidian — Import vault notes to Notion
- CSV & Markdown import — Bulk import from files
- Statistics — Database metrics, breakdowns by property
- Timeline — Activity visualization over time
- Health Check — Database integrity scoring
- Validation — Find missing fields, overdue items, stale entries
- Workspace Sync — Cache databases locally, use names instead of UUIDs everywhere
- Templates — Save and reuse page structures
- Backup — Full database backup to JSON/Markdown
- Duplicate — Clone pages and entire databases
- Relations — Manage links, find backlinks, visualize graphs
- Bulk Operations — Update or archive hundreds of entries at once
npm install -g notion-cli-agent# Clone the repository
git clone https://github.com/Balneario-de-Cofrentes/notion-cli-agent.git
cd notion-cli-agent
# Install dependencies
pnpm install
# Build
pnpm build
# Link globally
pnpm link --global- Node.js 20+
- A Notion integration token (create one here)
- Go to notion.so/my-integrations
- Click "New integration"
- Give it a name and select capabilities
- Copy the token (starts with
ntn_orsecret_)
# Option 1: Environment variable (recommended)
export NOTION_TOKEN="ntn_your_token_here"
# Option 2: Pass directly
notion --token "ntn_xxx" search "query"Important: Your integration can only access pages explicitly shared with it.
- Open any page or database in Notion
- Click "..." menu → "Connect to" → Select your integration
Sync your workspace to use database names instead of UUIDs:
# Cache all accessible databases locally
notion sync
# List cached databases
notion list
notion list --json # For scripts
notion list --ids-only # One ID per line
# Now use names anywhere you'd use a database UUID
notion db query "Tasks" --limit 5
notion find "Tasks" "overdue assigned to me"
notion validate health "Projects"
notion stats overview "OKRs"All database commands accept both UUIDs and names. Name resolution uses case-insensitive matching with substring fallback. If a name is ambiguous, the CLI shows candidates and asks you to be more specific.
# Search across workspace
notion search "project plan"
notion search "meeting" --type page
notion search "" --type database # List all databases
# Exact lookup in a known database (deterministic)
notion db query <db_id> --title "Known Page" --json
# Filtered search (best-effort — Notion search is fuzzy)
notion search "keyword" --db <db_id> --exact --first --json
notion search "task" --db <db_id> # Filter by parent database
# Get page info
notion page get <page_id>
notion page get <page_id> --content # Include blocks
# Create page in database
notion page create --parent <db_id> --title "New Task"
notion page create --parent <db_id> --title "Bug Fix" \
--prop "Status=Todo" \
--prop "Priority=High"
notion page create --parent <db_id> --title "Meeting Notes" --icon 📝
# Update page
notion page update <page_id> --prop "Status:status=Done"
notion page update <page_id> --title "New Title"
notion page update <page_id> --icon 🚀
notion page update <page_id> --clear-prop "Assignee" # Type-aware clear
# Archive page
notion page archive <page_id># Export database as CSV
notion db query <db_id> --csv > tasks.csv
# Tab-separated (paste into spreadsheets)
notion db query <db_id> --tsv | pbcopy
# Just IDs for piping into other commands
notion db query <db_id> --filter "Status=Done" --ids-only | \
xargs -I {} notion page archive {}
# Count search results
notion search "bugs" --ids-only | wc -l| Flag | Commands | Description |
|---|---|---|
--json / -j |
all | Raw JSON |
--llm |
most | Compact agent-friendly output |
--csv |
db query, find |
CSV with headers |
--tsv |
db query, find |
Tab-separated |
--ids-only |
db query, search, find |
One ID per line |
Read, write, and surgically edit page content as Markdown.
# Read page content as Markdown (uses native Notion markdown API)
notion page read <page_id>
notion page read <page_id> --blocks # Legacy: fetch blocks and convert client-side
notion page read <page_id> --json # Raw block JSON output
notion page read <page_id> -o page.md # Write to file
# Write Markdown content into a page
notion page write <page_id> -f content.md
echo "# Hello" | notion page write <page_id>
notion page write <page_id> -f doc.md --replace # Replace all content (destructive)
# Surgical block-level editing
notion page edit <page_id> --at 3 --delete 2 # Delete 2 blocks at index 3
notion page edit <page_id> --at 5 --markdown "New paragraph" # Insert at index 5
notion page edit <page_id> --at 0 --delete 1 --file new.md # Replace first block
notion page edit <page_id> --dry-run --at 3 --delete 1 # Preview without changesTranslate natural language into Notion filters:
# Find overdue tasks
notion find "overdue tasks" -d <db_id>
# Find unassigned items in progress
notion find "in progress unassigned" -d <db_id>
# Find high priority pending items
notion find "urgent pending" -d <db_id>
# See what filter was generated
notion find "tareas vencidas" -d <db_id> --explainSupported patterns:
- Status:
done,in progress,todo,pending,hecho,en marcha - Assignment:
unassigned,sin asignar - Dates:
overdue,vencidas,today,this week - Priority:
urgent,high priority,importante
Execute multiple operations in one command — perfect for AI agents to minimize tool calls:
# Preview what would happen
notion batch --dry-run --data '[
{"op": "get", "type": "page", "id": "abc123"},
{"op": "create", "type": "page", "parent": "db_id", "data": {...}},
{"op": "update", "type": "page", "id": "xyz789", "data": {...}}
]'
# Execute with LLM-friendly output
notion batch --llm --data '[...]'
# Read from file
notion batch -f operations.jsonSupported operations:
| Op | Types | Description |
|---|---|---|
get |
page, database, block | Retrieve by ID |
create |
page, database | Create new |
update |
page, database, block | Modify |
delete |
page, block | Archive/delete |
query |
database | Query with filters |
append |
block | Add children |
Create optimal prompts for AI agents to work with a specific database:
notion ai prompt <database_id>Output includes:
- Database schema with all properties
- Valid values for select/status fields (exact spelling matters!)
- Example entries
- Common operations with correct syntax
- Warnings about property naming (e.g., "Title is called 'Título', not 'Name'")
Get concise summaries for quick understanding:
notion ai summarize <page_id>
# Output:
# Project Plan Q1
# Last edited: 2 days ago
# Blocks: 45
# Properties:
# - Status: In Progress
# - Owner: Juan
# Sections:
# - Overview
# - Timeline
# - Resources
# Todos: 8/12 completedPull specific data points from page content:
notion ai extract <page_id> --schema "email,phone,company,date"
# Output:
{
"email": "contact@example.com",
"phone": "+34 612 345 678",
"company": "Acme Corp",
"date": "2024-03-15"
}Get command suggestions based on natural language:
notion ai suggest <db_id> "quiero ver las tareas completadas esta semana"
# Outputs:
# notion find "hecho" -d <db_id>
# notion db query <db_id> --filter-prop "Status" --filter-value "Hecho" --filter-prop-type statusExport a single page:
notion export page <page_id> --obsidian -o my-note.mdExport entire database to vault:
notion export db <database_id> --vault ~/obsidian-vault --folder notion-tasksWith full page content:
notion export db <db_id> --vault ~/vault --contentExported files include:
---
notion_id: "abc123..."
notion_url: "https://notion.so/..."
created: 2024-01-15
updated: 2024-02-01
status: "In Progress"
priority: "High"
tags:
- "project"
- "q1"
---
# Page Title
Content here...Import vault to database:
notion import obsidian ~/my-vault --to <database_id>
notion import obsidian ~/my-vault --to <db_id> --folder specific-folder
notion import obsidian ~/my-vault --to <db_id> --content # Include page contentImport CSV:
notion import csv data.csv --to <database_id>
notion import csv tasks.csv --to <db_id> --title-column "Task Name"Import Markdown file:
notion import markdown document.md --to <page_id>
notion import markdown doc.md --to <page_id> --replace # Replace existing contentnotion stats overview <database_id>
# Output:
# 📊 Database: Tasks
# Total entries: 342
#
# Status:
# Done 124 (36%) ████████
# In Progress 89 (26%) ██████
# Todo 78 (23%) █████
# Blocked 51 (15%) ███
#
# Priority:
# High 45 (13%) ███
# Medium 187 (55%) ███████████
# Low 110 (32%) ███████notion stats timeline <database_id> --days 14
# 2024-02-01 (Thu) 12 ████████████
# 2024-01-31 (Wed) 8 ████████
# 2024-01-30 (Tue) 15 ███████████████
# ...notion validate check <database_id> \
--required "Assignee,Deadline" \
--check-dates \
--check-stale 30 \
--fix
# Output:
# ⚠️ MISSING REQUIRED (23)
# - Task ABC: Missing required property: Assignee
# - Task XYZ: Missing required property: Deadline
# Fix: notion page update <id> --prop "Assignee=..."
#
# ⚠️ OVERDUE (8)
# - Old task: Overdue: deadline was 2024-01-15
#
# ℹ️ STALE (5)
# - Stuck item: Not updated in 45 days (status: In Progress)
#
# 📊 Health Score: 72/100notion validate lint <database_id>
# ✅ Empty titles: OK
# ⚠️ "In Progress" for >30 days: 5 found
# Total issues: 5notion validate health <database_id>
# 📊 Health Report: Tasks
# ════════════════════════════════════════
# Health Score: 78/100 🟡
# ════════════════════════════════════════
#
# 📈 Activity (last 7 days): 34/100 entries (34%)
# ✅ Completion rate: 65%
# 📝 Average fill rate: 82%
#
# Property fill rates:
# ✅ Title ██████████ 100%
# ✅ Status ██████████ 100%
# ⚠️ Assignee ████████░░ 77%
# ❌ Tags ██░░░░░░░░ 15%# Backup to JSON
notion backup <database_id> -o ./backups/tasks
# Backup to Markdown
notion backup <db_id> -o ./backups --format markdown
# Include page content
notion backup <db_id> -o ./backups --content
# Incremental backup (only changed entries)
notion backup <db_id> -o ./backups --incrementalOutput structure:
backups/
├── schema.json # Database schema
├── index.json # Entry index
├── .backup-meta.json # Backup metadata
└── pages/
├── Task_One_abc123.json
├── Task_Two_def456.json
└── ...
# Find duplicate pages by title
notion dedup <db_id>
# Include near-duplicates (strips copy/draft suffixes)
notion dedup <db_id> --fuzzy
# Archive duplicates, keep the page with most content
notion dedup <db_id> --fix --strategy keep-largest --yes
# Keep newest or oldest
notion dedup <db_id> --fix --strategy keep-newest --yes
notion dedup <db_id> --fix --strategy keep-oldest --yes
# Preview first (default when --fix without --yes)
notion dedup <db_id> --fix --strategy keep-largestDiscover what pages link to a specific page:
notion relations backlinks <page_id>
# 📎 Direct Relations:
# Project Alpha
# └─ via property: Related Tasks
#
# Sprint 23
# └─ via property: Tasks
#
# 📝 Potential Mentions:
# Meeting Notes Jan 15
# Weekly Report# Create relation
notion relations link <source_id> <target_id> --property "Related"
# Bidirectional linking
notion relations link <page1> <page2> --property "Related" --bidirectional
# Remove relation
notion relations unlink <source_id> <target_id> --property "Related"# Text format
notion relations graph <page_id> --depth 2
# DOT format (for Graphviz)
notion relations graph <page_id> --format dot > graph.dot
dot -Tpng graph.dot -o graph.png
# JSON format
notion relations graph <page_id> --format jsonnotion template save <page_id> --name "weekly-report" --description "Weekly team report"notion template list
# 📄 weekly-report
# Blocks: 15
# Description: Weekly team report
#
# 📄 meeting-notes
# Blocks: 8notion template use "weekly-report" --parent <db_id> --title "Report Week 5"notion template show "weekly-report" # View details
notion template delete "weekly-report" # RemoveUpdate multiple entries at once:
# Preview first
notion bulk update <db_id> --where "Status=Todo" --set "Status=In Progress" --dry-run
# Execute
notion bulk update <db_id> --where "Status=Todo" --set "Status=In Progress" --yesArchive entries matching a condition:
# Archive completed items older than 2024
notion bulk archive <db_id> --where "Status=Done" --dry-run
notion bulk archive <db_id> --where "Status=Done" --yesWhere clause syntax:
- Equals:
Property=Value - Multiple conditions:
Status=Done,Priority=Low
notion inspect workspace
notion inspect ws --compact # Just names and IDsnotion inspect schema <database_id>
notion inspect schema <db_id> --llm # Optimized for AI consumptionnotion inspect context <database_id>
# Outputs comprehensive context including:
# - Schema with all properties and valid values
# - Example entries
# - Quick command referenceFor operations not covered by other commands:
# GET request
notion api GET "pages/<page_id>"
# POST with body
notion api POST "search" --data '{"query": "test"}'
# With query parameters
notion api GET "users" --query "page_size=5"When setting properties with --prop, the CLI auto-detects types:
| Value Format | Detected Type | Example |
|---|---|---|
| Plain text | select | --prop "Status=Done" |
true/false |
checkbox | --prop "Active=true" |
| Numbers | number | --prop "Count=42" |
YYYY-MM-DD |
date | --prop "Due=2024-12-31" |
| URL | url | --prop "Link=https://..." |
--prop "Contact=a@b.com" |
||
| Comma-separated | multi_select | --prop "Tags=bug,urgent" |
Type hints — Force a specific property type with Key:type=Value:
# Status properties (vs auto-detected select)
notion page update <id> --prop "Status:status=Done"
# Rich text instead of select
notion page update <id> --prop "Notes:rich_text=Some notes"
# People by user ID
notion page update <id> --prop "Assignee:people=user-id-here"For database queries with non-select properties:
notion db query <db_id> \
--filter-prop "Status" \
--filter-type equals \
--filter-value "Done" \
--filter-prop-type status # Required for status typeRun as an MCP tool server for agent frameworks (Claude Code, Cursor, VS Code):
notion --mcpConfigure in Claude Code (settings.json):
{
"mcpServers": {
"notion": {
"command": "notion",
"args": ["--mcp"],
"env": { "NOTION_TOKEN": "ntn_your_token" }
}
}
}Exposes 14 tools: search, page_get, page_create, page_update, db_query, db_schema, block_children, block_append, find, batch, inspect_workspace, comment_create, validate_health, dedup.
| Category | Commands |
|---|---|
| Search | search |
| Pages | page get, page create, page update, page archive, page read, page write, page edit, page property |
| Databases | db get, db query, db create, db update |
| Blocks | block get, block list, block append, block update, block delete |
| Comments | comment list, comment create, comment get |
| Users | user me, user list, user get |
| Export | export page, export db |
| Import | import obsidian, import csv, import markdown |
| AI | ai summarize, ai extract, ai prompt, ai suggest |
| Find | find |
| Bulk | bulk update, bulk archive |
| Validate | validate check, validate lint, validate health |
| Stats | stats overview, stats timeline |
| Backup | backup |
| Templates | template list, template save, template use, template show, template delete |
| Duplicate | duplicate page, duplicate schema, duplicate db |
| Relations | relations backlinks, relations link, relations unlink, relations graph |
| Inspect | inspect workspace, inspect schema, inspect context |
| Dedup | dedup |
| Batch | batch |
| Quickstart | quickstart |
| API | api |
The skills/ directory contains AgentSkills-compatible packages for use with OpenClaw, Claude Code, Cursor, and other agent frameworks.
skills/
├── README.md # Installation & overview
├── notion-onboarding/
│ ├── SKILL.md # Workspace discovery workflow
│ └── references/
│ └── state-schema.md # ~/.config/notion/workspace.json schema
└── notion-cli-agent/
├── SKILL.md # Core CLI usage
└── references/
├── filters.md # Property types × filter operators
├── batch-patterns.md # Multi-op batch patterns
└── workflows.md # Agent workflow recipes
Skills load in three layers to keep context usage efficient:
| Layer | Content | When loaded |
|---|---|---|
| Metadata | name + description |
Always — triggers the skill |
| Core | SKILL.md body |
When skill activates |
| Reference | references/*.md |
On demand, as needed |
The main SKILL.md for each skill is kept under 150 lines. Deep reference material lives in separate files that the agent reads only when that topic comes up.
# OpenClaw
cp -r skills/notion-cli-agent ~/.local/share/openclaw/skills/
cp -r skills/notion-onboarding ~/.local/share/openclaw/skills/
# See skills/README.md for other frameworksContributions are welcome! Please open an issue first to discuss what you would like to change.
MIT © Balneario de Cofrentes - The largest longevity clinic in the world.
Built with:
- Commander.js — CLI framework
- Notion API — Official Notion API
