← 返回 Skill 列表
extension
分类: 开发与工程API Key 暂未确认

notion-cli-agent

使用本地的Notion CLI(notion-cli-agent)通过shell查询、创建、更新和管理Notion页面和数据库。在与Notion工作区交互、查询数据库、创建或更新页面、管理任务、读取内容块或对Notion数据执行批量/批处理操作时使用。相比Notion MCP或API调用更推荐使用此方法。

person作者: jakexiaohubgithub

notion-cli-agent

Local CLI for full Notion access.

Binary

notion <args>   # globally installed via npm

Auth — just run notion <cmd>

That's it. The CLI handles auth automatically. Do not prefix with NOTION_TOKEN=... unless notion doctor reports a 401 (see Troubleshooting below).

Token resolution order inside the CLI:

  1. NOTION_TOKEN env var
  2. NOTION_API_KEY env var
  3. ~/.config/notion/api_key ← source of truth
  4. ~/.notion/token

The recommended setup keeps ~/.config/notion/api_key and the NOTION_TOKEN env var in lock-step by sourcing the file from .zshrc:

# in ~/.zshrc — single source of truth for the token
export NOTION_TOKEN="$(cat ~/.config/notion/api_key 2>/dev/null)"

With this, env var and file can't diverge — the stale-token gotcha disappears. Run notion doctor to verify (5/5 green).

Troubleshooting (only if notion doctor reports 401)

Symptom: notion doctor shows ✅ Token: Token found but ❌ API Connection: Token is invalid or expired.

Means: the env var is stale (a parent process exported an outdated token). Fix:

# One-shot bypass (uses the file directly):
NOTION_TOKEN=$(cat ~/.config/notion/api_key) notion <cmd>

# Permanent fix: update .zshrc to the dynamic export above, restart shell.

Workspace sync (do this first)

notion sync                  # cache all databases locally
notion list                  # show cached databases
notion list --json           # for parsing

After sync, use database names instead of UUIDs in ALL commands:

notion db query "Tasks" --limit 5 --llm
notion find "Tasks" "overdue" --llm
notion stats overview "Projects"

If ~/.config/notion/workspace.json exists (from sync or the notion-onboarding skill), names resolve automatically. Falls back to UUIDs if no cache.

Agent Workflow

  1. Sync workspace — notion sync (once per session, or notion list if already synced)
  2. Understand schema — notion inspect context "Tasks" or notion inspect schema "Tasks" --llm
  3. Query deterministically first — prefer db query --title, search --exact --db --first, or --llm over fuzzy workspace-wide search when you know the target DB
  4. Write with --dry-run first on bulk/batch ops, then confirm with user

Core Commands

Discover

notion sync                                     # cache databases for name lookup
notion list                                     # show cached databases
notion inspect ws --compact                     # all databases, names + ids
notion inspect schema "Tasks" --llm             # property types + valid values
notion inspect context "Tasks"                  # workflow context + examples
notion ai prompt "Tasks"                        # DB-specific agent instructions

Users & guests

notion user list                                # members + bots + cached guests
notion user resolve-guests                      # discover guests, cache them
notion user get <user_id>                        # works for guests too (by id)

Guests are NOT in notion user list. Notion's GET /v1/users returns only members and bots — guests are invisible — so you can't list them or look up their id to assign them. Run notion user resolve-guests once: it walks search results, reads every page's created_by/last_edited_by, resolves the unknown ids via GET /v1/users/{id}, and caches the guests in ~/.config/notion/guests.json. After that, user list shows them flagged [guest], and you can assign them in --prop "Field:people=…" by email or name (see Property type hints). notion sync also fishes guests as a side effect.

Query

# Exact lookup in a known DB (deterministic — uses database query API)
notion db query "Tasks" --title "Known Page" --json
notion db query "Tasks" --limit 20 --llm                   # compact output

# Fuzzy search (workspace-wide, best-effort — Notion may miss long titles)
notion search "keyword" --limit 10
notion search "keyword" --db <db_id> --llm                 # filter by parent DB
notion search "short title" --exact --first --json         # best-effort exact match

# Natural language
notion find "overdue tasks unassigned" -d <db_id> --llm
notion find "high priority" -d <db_id> --explain           # preview filter, don't run

For exact lookup by title in a known DB, always use db query --title — not search --exact. Notion's search API is fuzzy and may miss pages with long or common-word titles.

Read pages

notion page get <page_id>                       # properties
notion page get <page_id> --content             # + content blocks
notion page get <page_id> --json                # raw JSON
notion page read <page_id>                      # content as Markdown (native API, 1 call)
notion page read <page_id> --blocks             # legacy block-by-block conversion
notion page read <page_id> -o page.md           # save to file
notion ai summarize <page_id>                   # concise summary
notion ai extract <page_id> --schema "email,phone,date"

Write pages

notion page create --parent <db_id> --title "Task Name"
notion page create --parent <db_id> --title "Task" --prop "Status:status=Todo" --prop "Priority:select=High"
notion page update <page_id> --prop "Status:status=Done"
notion page update <page_id> --clear-prop "Assignee"       # type-aware clear
notion page update <page_id> --clear-prop "Tags" --clear-prop "Deadline"
notion page write <page_id> -f content.md                  # write Markdown to page
notion page write <page_id> -f doc.md --replace            # replace all content
notion page edit <page_id> --at 3 --delete 2               # surgical block editing
notion page edit <page_id> --at 5 --markdown "New text"    # insert at position

Add blocks

notion block append <page_id> --text "Paragraph"
notion block append <page_id> --heading2 "Section" --bullet "Item 1" --bullet "Item 2"
notion block append <page_id> --todo "Action item"

Files & attachments

<source> = local path, public URL, or an existing file_upload ID.

notion file attach <page_id> shot.png                      # upload + append (type auto-detected)
notion file attach <page_id> a.pdf b.png --caption "Q3"
notion file upload shot.png                                # upload only → prints the ID
notion block append <page_id> --text "See below" --image shot.png
notion page update <page_id> --icon logo.png --cover https://example.com/hero.jpg
notion page update <page_id> --attach "Attachments=spec.pdf,diagram.png"
notion comment create --page <page_id> -t "Screenshot" --attach shot.png   # max 3

URL imports need a filename with an extension. If the URL ends in a bare ID: notion file import <url> --content-type image/jpeg → reuse the printed ID as the source.

Batch (minimize tool calls)

notion batch --dry-run --data '[
  {"op":"get","type":"page","id":"<page_id>"},
  {"op":"create","type":"page","parent":"<db_id>","data":{"title":"New"}},
  {"op":"update","type":"page","id":"<page_id2>","data":{"Status":"Done"}}
]'
notion batch --llm --data '[...]'               # execute

Bulk & maintenance

notion bulk update <db_id> --where "Status=Todo" --set "Status=In Progress" --dry-run
notion stats overview <db_id>
notion validate check <db_id> --check-dates --check-stale 30
notion dedup <db_id>                                       # find duplicate pages
notion dedup <db_id> --fuzzy                               # include near-duplicates
notion dedup <db_id> --fix --strategy keep-largest --yes   # archive duplicates

Output flags

| Flag | Use for | |------|---------| | --llm | Compact, structured output for agents (search, db query, find, batch, inspect schema/context, stats overview, relations backlinks) | | --json / -j | Raw JSON for parsing | | --csv | CSV with headers (db query, find) | | --tsv | Tab-separated (db query, find) | | --ids-only | One ID per line for piping (db query, search, find) | | (default) | Human-readable |

Property type filters

--filter-prop-type is required for non-text properties:

notion db query <db_id> \
  --filter-prop "Status" --filter-type equals \
  --filter-value "Done" --filter-prop-type status

Types: status · select · multi_select · number · date · checkbox · people · relation

See references/filters.md for full operator reference.

Property type hints for --prop

Auto-detection treats plain strings as select. Use Key:type=Value to force a type:

notion page update <id> --prop "Status:status=Done"    # status, not select
notion page update <id> --prop "Notes:rich_text=Text"   # rich_text, not select
notion page update <id> --prop "Owner:people=<user_id>" # people (by id)
notion page update <id> --prop "Owner:people=ana@x.com" # people by email (member or guest)
notion page update <id> --prop "Owner:people=Ana Pérez" # people by name (case-insensitive)

For people=, a value that isn't a UUID is resolved against members (live list) plus the guests cache: exact email first, then case-insensitive name. Run notion user resolve-guests first so guests are resolvable. Unresolvable values pass through unchanged.

Rules

  • Property values are usually case-sensitive — verify exact status/select values with inspect context
  • Property names are matched more flexibly in 0.10.0 (resolvePropertyName() is case-insensitive and whitespace-tolerant), but still prefer the real schema labels for reliability
  • Title property name varies per DB ("Name", "Título", "Task" — check state or schema)
  • Prefer db query --title "..." or search --db <id> --exact --first when you know the DB; avoid fuzzy search for operational updates
  • Use --clear-prop instead of fake empty values like Owner:people= or Tags=
  • --dry-run before any bulk/batch write
  • Confirm with user before destructive bulk operations

References

  • references/filters.md — all property types × filter operators with examples
  • references/batch-patterns.md — batch workflows (multi-update, bulk status sweep, multi-get)
  • references/workflows.md — agent workflow recipes (task triage, weekly review, project sync)

Self-help

notion quickstart          # full quick reference
notion <command> --help    # per-command help
notion ai suggest <db_id> "what I want to do"