@jordancoin/notioncli 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -423
- package/TECHNICAL.md +125 -0
- package/bin/notion.js +925 -814
- package/lib/config.js +68 -0
- package/lib/filters.js +213 -0
- package/lib/format.js +225 -0
- package/lib/helpers.js +9 -334
- package/lib/markdown.js +347 -0
- package/package.json +1 -1
- package/skill/SKILL.md +44 -10
- package/skill/marketplace.json +2 -2
- package/test/unit.test.js +392 -0
- package/test/debug-parent.js +0 -32
- package/test/live-relations-test.js +0 -309
package/README.md
CHANGED
|
@@ -2,96 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@jordancoin/notioncli)
|
|
4
4
|
[](https://github.com/JordanCoin/notioncli/actions/workflows/ci.yml)
|
|
5
|
-
[](https://codecov.io/gh/JordanCoin/notioncli)
|
|
6
5
|
[](https://opensource.org/licenses/MIT)
|
|
7
6
|
[](https://nodejs.org/)
|
|
8
7
|
|
|
9
|
-
A
|
|
10
|
-
|
|
11
|
-
**No more copy-pasting UUIDs.** Set up aliases once, then just type `notion query tasks` or `notion add projects --prop "Name=Ship it"`.
|
|
8
|
+
A CLI for the Notion API. Aliases instead of UUIDs, property names as flags, full CRUD. Built for humans and AI agents.
|
|
12
9
|
|
|
13
10
|
```bash
|
|
14
11
|
npm install -g @jordancoin/notioncli
|
|
15
12
|
```
|
|
16
13
|
|
|
17
|
-
## Quick Start
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
# 1. One command to set up
|
|
21
|
-
notion init --key ntn_your_api_key_here
|
|
22
|
-
|
|
23
|
-
# That's it. Aliases are created automatically:
|
|
24
|
-
# ✅ projects → Project Tracker
|
|
25
|
-
# ✅ reading-list → Reading List
|
|
26
|
-
# ✅ meetings → Meeting Notes
|
|
27
|
-
|
|
28
|
-
# 2. Start using them immediately
|
|
29
|
-
notion query projects
|
|
30
|
-
notion add projects --prop "Name=Ship it" --prop "Status=Todo"
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Zero UUIDs. One command. You're ready to go.
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## What's New
|
|
38
|
-
|
|
39
|
-
### v1.2 — Multi-Workspace, Database Management & File Uploads
|
|
40
|
-
|
|
41
|
-
- 🏢 **Multi-workspace** — Named profiles for multiple Notion accounts (`workspace add/use/list/remove`, `--workspace` flag)
|
|
42
|
-
- 🤖 **`me`** — Show integration/bot identity and owner
|
|
43
|
-
- 📦 **`move`** — Move pages between databases by alias
|
|
44
|
-
- 📋 **`templates`** — List page templates available for a database
|
|
45
|
-
- 🏗️ **`db-create`** — Create new databases with custom property schemas
|
|
46
|
-
- ✏️ **`db-update`** — Add/remove columns, rename databases
|
|
47
|
-
- 📎 **`upload`** — Upload files to pages (MIME-aware, supports images/docs/text)
|
|
48
|
-
- 🔍 **`props`** — Quick page property inspector (cleaner than `get` for debugging)
|
|
49
|
-
- 🐛 **Fixed** canonical `database_id` resolution for the 2025 dual-ID system
|
|
50
|
-
|
|
51
|
-
### v1.1 — Relations, Rollups & Blocks
|
|
52
|
-
|
|
53
|
-
- 🔗 **Relations** — `get` resolves linked page titles automatically. New `notion relations` command for exploring connected pages.
|
|
54
|
-
- 📊 **Rollups** — Numbers, dates, and arrays are parsed into readable values. No more raw JSON blobs.
|
|
55
|
-
- 🧱 **Blocks CRUD** — Edit and delete blocks directly with `block-edit` and `block-delete`. Use `--ids` flag on `blocks` for precise targeting.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## Notion as a Graph
|
|
60
|
-
|
|
61
|
-
Notion databases don't live in isolation — they're connected by relations and rollups. notioncli treats your workspace as a **graph of linked pages**:
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
$ notion get tasks --filter "Name=Ship v1.1"
|
|
65
|
-
Properties:
|
|
66
|
-
Name: Ship v1.1
|
|
67
|
-
Status: Active
|
|
68
|
-
Project: Launch CLI ← relation resolved to title
|
|
69
|
-
Task Count: 3 ← rollup parsed to number
|
|
70
|
-
|
|
71
|
-
$ notion relations tasks --filter "Name=Ship v1.1"
|
|
72
|
-
Project: 1 linked page
|
|
73
|
-
id │ title │ url
|
|
74
|
-
──────────┼────────────┼──────────────────────
|
|
75
|
-
302903e2… │ Launch CLI │ https://notion.so/...
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Relations resolve to human-readable titles. Rollups return real values. Blocks can be queried, edited, and deleted directly. This makes it possible to explore, automate, and reason about complex workspaces entirely from the CLI.
|
|
79
|
-
|
|
80
14
|
---
|
|
81
15
|
|
|
82
16
|
## Setup
|
|
83
17
|
|
|
84
18
|
### 1. Create a Notion Integration
|
|
85
19
|
|
|
86
|
-
|
|
87
|
-
2. Click **"New integration"**
|
|
88
|
-
3. Give it a name (e.g. "My CLI")
|
|
89
|
-
4. Copy the API key (starts with `ntn_`)
|
|
20
|
+
Go to [notion.so/profile/integrations](https://www.notion.so/profile/integrations) → **New integration** → copy the API key (`ntn_...`)
|
|
90
21
|
|
|
91
22
|
### 2. Share Your Databases
|
|
92
23
|
|
|
93
|
-
In Notion, open each database
|
|
94
|
-
- Click the **•••** menu → **Connections** → Add your integration
|
|
24
|
+
In Notion, open each database → **•••** menu → **Connections** → add your integration.
|
|
95
25
|
|
|
96
26
|
### 3. Initialize
|
|
97
27
|
|
|
@@ -99,441 +29,199 @@ In Notion, open each database you want to access:
|
|
|
99
29
|
notion init --key ntn_your_api_key_here
|
|
100
30
|
```
|
|
101
31
|
|
|
102
|
-
This saves your key, discovers all shared databases, and **creates aliases automatically**:
|
|
103
|
-
|
|
104
32
|
```
|
|
105
|
-
✅ API key saved
|
|
33
|
+
✅ API key saved
|
|
106
34
|
|
|
107
35
|
Found 3 databases:
|
|
36
|
+
✅ project-tracker → Project Tracker
|
|
37
|
+
✅ reading-list → Reading List
|
|
38
|
+
✅ meeting-notes → Meeting Notes
|
|
108
39
|
|
|
109
|
-
|
|
110
|
-
✅ reading-list → Reading List
|
|
111
|
-
✅ meeting-notes → Meeting Notes
|
|
112
|
-
|
|
113
|
-
3 aliases saved automatically.
|
|
114
|
-
|
|
115
|
-
Ready! Try:
|
|
116
|
-
notion query project-tracker
|
|
117
|
-
notion add project-tracker --prop "Name=Hello World"
|
|
40
|
+
3 aliases saved. Try: notion query project-tracker
|
|
118
41
|
```
|
|
119
42
|
|
|
120
|
-
|
|
43
|
+
Aliases are created automatically from database names. Rename them anytime:
|
|
121
44
|
|
|
122
45
|
```bash
|
|
123
46
|
notion alias rename project-tracker projects
|
|
124
|
-
notion alias rename reading-list reads
|
|
125
47
|
```
|
|
126
48
|
|
|
127
|
-
> **Alternative:** Skip `init` and set an environment variable:
|
|
128
|
-
> ```bash
|
|
129
|
-
> export NOTION_API_KEY=ntn_your_api_key
|
|
130
|
-
> ```
|
|
131
|
-
|
|
132
49
|
---
|
|
133
50
|
|
|
134
51
|
## Commands
|
|
135
52
|
|
|
136
|
-
|
|
53
|
+
| Command | Description | Example |
|
|
54
|
+
|---------|-------------|---------|
|
|
55
|
+
| `query` | Query a database | `notion query projects --filter Status=Active` |
|
|
56
|
+
| `add` | Create a page | `notion add projects --name "Ship it" --status "Todo"` |
|
|
57
|
+
| `update` | Update a page | `notion update projects --filter "Name=Ship it" --status "Done"` |
|
|
58
|
+
| `delete` | Archive a page | `notion delete projects --filter "Name=Old task"` |
|
|
59
|
+
| `get` | View page details | `notion get projects --filter "Name=Ship it"` |
|
|
60
|
+
| `props` | Quick property view | `notion props projects --filter "Name=Ship it"` |
|
|
61
|
+
| `blocks` | View page content | `notion blocks projects --filter "Name=Ship it" --ids` |
|
|
62
|
+
| `block-edit` | Edit a block | `notion block-edit <block-id> "New text"` |
|
|
63
|
+
| `block-delete` | Delete a block | `notion block-delete <block-id>` |
|
|
64
|
+
| `append` | Add content to a page | `notion append projects "Update: shipped!" --filter "Name=Ship it"` |
|
|
65
|
+
| `search` | Search everything | `notion search "meeting"` |
|
|
66
|
+
| `dbs` | List all databases | `notion dbs` |
|
|
67
|
+
| `relations` | Explore linked pages | `notion relations tasks --filter "Name=Ship it"` |
|
|
68
|
+
| `comments` | View page comments | `notion comments tasks --filter "Name=Ship it"` |
|
|
69
|
+
| `comment` | Add a comment | `notion comment tasks "Done! 🚀" --filter "Name=Ship it"` |
|
|
70
|
+
| `users` | List workspace users | `notion users` |
|
|
71
|
+
| `me` | Show bot identity | `notion me` |
|
|
72
|
+
| `move` | Move page between DBs | `notion move tasks --filter "Name=Done" --to archive` |
|
|
73
|
+
| `templates` | List DB templates | `notion templates projects` |
|
|
74
|
+
| `db-create` | Create a database | `notion db-create <parent-id> "Tasks" --prop "Name:title"` |
|
|
75
|
+
| `db-update` | Update DB schema | `notion db-update projects --add-prop "Rating:number"` |
|
|
76
|
+
| `upload` | Upload file to page | `notion upload tasks --filter "Name=Ship it" ./file.png` |
|
|
77
|
+
| `import` | Import file as pages | `notion import projects ./data.csv` |
|
|
78
|
+
| `export` | Export page as markdown | `notion export projects --filter "Name=Ship it"` |
|
|
79
|
+
| `alias` | Manage aliases | `notion alias list` |
|
|
80
|
+
| `workspace` | Manage workspaces | `notion workspace list` |
|
|
137
81
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
$ notion query projects
|
|
142
|
-
Date │ Name │ Status │ Priority
|
|
143
|
-
───────────┼─────────────────┼────────┼──────────
|
|
144
|
-
2026-02-09 │ Launch CLI │ Active │ High
|
|
145
|
-
2026-02-08 │ Write Docs │ Active │ Medium
|
|
146
|
-
2026-02-07 │ Design Landing │ Done │ Low
|
|
82
|
+
---
|
|
147
83
|
|
|
148
|
-
|
|
149
|
-
```
|
|
84
|
+
## Examples
|
|
150
85
|
|
|
151
|
-
|
|
86
|
+
### Query with filters and sorting
|
|
152
87
|
|
|
153
88
|
```
|
|
154
89
|
$ notion query projects --filter Status=Active --sort Date:desc --limit 5
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### `notion add` — Add a Page
|
|
158
|
-
|
|
159
|
-
```
|
|
160
|
-
$ notion add projects --prop "Name=New Feature" --prop "Status=Todo" --prop "Date=2026-02-10"
|
|
161
|
-
✅ Created page: a1b2c3d4-...
|
|
162
|
-
URL: https://www.notion.so/...
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
Properties are matched **case-insensitively** against the database schema. No need to memorize exact field names.
|
|
166
|
-
|
|
167
|
-
**Supported types:** title, rich_text, number, select, multi_select, date, checkbox, url, email, phone_number, status.
|
|
168
|
-
|
|
169
|
-
### `notion update` — Update a Page
|
|
170
|
-
|
|
171
|
-
By page ID:
|
|
172
|
-
```
|
|
173
|
-
$ notion update a1b2c3d4-5678-90ab-cdef-1234567890ab --prop "Status=Done" --prop "Priority=Low"
|
|
174
|
-
✅ Updated page: a1b2c3d4-...
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
By alias + filter (no UUIDs needed):
|
|
178
|
-
```
|
|
179
|
-
$ notion update workouts --filter "Name=LEGS #5" --prop "Notes=Great session"
|
|
180
|
-
✅ Updated page: a1b2c3d4-...
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### `notion delete` — Delete (Archive) a Page
|
|
184
|
-
|
|
185
|
-
```
|
|
186
|
-
$ notion delete workouts --filter "Date=2026-02-09"
|
|
187
|
-
🗑️ Archived page: a1b2c3d4-...
|
|
188
|
-
(Restore it from the trash in Notion if needed)
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### `notion get` — View Page Details
|
|
192
|
-
|
|
193
|
-
Relations are **automatically resolved** to linked page titles:
|
|
194
|
-
|
|
195
|
-
```
|
|
196
|
-
$ notion get tasks --filter "Name=Implement relations"
|
|
197
|
-
Page: a1b2c3d4-5678-90ab-cdef-1234567890ab
|
|
198
|
-
URL: https://www.notion.so/...
|
|
199
|
-
Created: 2026-02-10T14:30:00.000Z
|
|
200
|
-
Updated: 2026-02-10T14:30:00.000Z
|
|
201
|
-
|
|
202
|
-
Properties:
|
|
203
|
-
Name: Implement relations
|
|
204
|
-
Project: Build CLI ← resolved title, not a UUID
|
|
205
|
-
Done: ✓
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### `notion relations` — Explore Connections
|
|
209
|
-
|
|
210
|
-
See what a page is linked to, with resolved titles and URLs:
|
|
211
|
-
|
|
212
|
-
```
|
|
213
|
-
$ notion relations tasks --filter "Name=Implement relations"
|
|
214
|
-
Project: 1 linked page
|
|
215
|
-
id │ title │ url
|
|
216
|
-
──────────┼───────────┼──────────────────────
|
|
217
|
-
302903e2… │ Build CLI │ https://notion.so/...
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### `notion blocks` — View & Edit Page Content
|
|
221
|
-
|
|
222
|
-
View blocks with optional IDs for targeting:
|
|
223
|
-
|
|
224
|
-
```
|
|
225
|
-
$ notion blocks tasks --filter "Name=Ship v1.1" --ids
|
|
226
|
-
[a1b2c3d4] # Project Overview
|
|
227
|
-
[e5f67890] This is the main project page.
|
|
228
|
-
[abcd1234] • First task
|
|
229
|
-
[efgh5678] ☑ Completed item
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
In v1.1+, blocks are fully editable and deletable — not just readable:
|
|
233
|
-
|
|
234
|
-
```
|
|
235
|
-
$ notion block-edit a1b2c3d4-5678-90ab-cdef-1234567890ab "Updated heading text"
|
|
236
|
-
✅ Updated heading_1 block: a1b2c3d4…
|
|
237
|
-
|
|
238
|
-
$ notion block-delete a1b2c3d4-5678-90ab-cdef-1234567890ab
|
|
239
|
-
🗑️ Deleted block: a1b2c3d4…
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
Use `notion blocks --ids` to list block IDs for precise edits.
|
|
243
|
-
|
|
244
|
-
### `notion append` — Add Content to a Page
|
|
245
|
-
|
|
246
|
-
```
|
|
247
|
-
$ notion append tasks "Status update: phase 1 complete" --filter "Name=Ship feature"
|
|
248
|
-
✅ Appended text block to page a1b2c3d4-...
|
|
249
|
-
```
|
|
250
90
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
id │ title │ url
|
|
256
|
-
─────────────────────────────────────┼──────────────────┼──────────────
|
|
257
|
-
a1b2c3d4-e5f6-7890-abcd-ef1234567890 │ Project Tracker │ https://...
|
|
258
|
-
f9e8d7c6-b5a4-3210-fedc-ba0987654321 │ Reading List │ https://...
|
|
91
|
+
Date │ Name │ Status │ Priority
|
|
92
|
+
───────────┼─────────────────┼────────┼──────────
|
|
93
|
+
2026-02-09 │ Launch CLI │ Active │ High
|
|
94
|
+
2026-02-08 │ Write Docs │ Active │ Medium
|
|
259
95
|
|
|
260
96
|
2 results
|
|
261
97
|
```
|
|
262
98
|
|
|
263
|
-
###
|
|
264
|
-
|
|
265
|
-
```
|
|
266
|
-
$ notion search "meeting"
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### `notion users` / `notion user <id>` — Workspace Users
|
|
99
|
+
### Rich filter operators
|
|
270
100
|
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
```
|
|
278
|
-
$ notion comments tasks --filter "Name=Ship feature"
|
|
279
|
-
$ notion comment tasks "Shipped! 🚀" --filter "Name=Ship feature"
|
|
280
|
-
```
|
|
101
|
+
```bash
|
|
102
|
+
# Comparison operators
|
|
103
|
+
notion query tasks --filter "Priority>3"
|
|
104
|
+
notion query tasks --filter "Count>=10"
|
|
105
|
+
notion query tasks --filter "Status!=Draft"
|
|
281
106
|
|
|
282
|
-
|
|
107
|
+
# Multiple filters (AND)
|
|
108
|
+
notion query tasks --filter Status=Active --filter Priority=High
|
|
283
109
|
|
|
110
|
+
# Relative dates
|
|
111
|
+
notion query tasks --filter "Due=today"
|
|
112
|
+
notion query tasks --filter "Created>=last_week"
|
|
284
113
|
```
|
|
285
|
-
$ notion me
|
|
286
|
-
Bot: Stargazer
|
|
287
|
-
ID: 8fd93059-5e54-44a5-8efd-800069da9497
|
|
288
|
-
Type: bot
|
|
289
|
-
Owner: Workspace
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### `notion props` — Quick Property Inspector
|
|
293
|
-
|
|
294
|
-
A fast way to inspect a single page's properties:
|
|
295
114
|
|
|
296
|
-
|
|
297
|
-
$ notion props tasks --filter "Name=Ship v1.1"
|
|
298
|
-
Page: a1b2c3d4-5678-90ab-cdef-1234567890ab
|
|
299
|
-
URL: https://www.notion.so/...
|
|
300
|
-
Name: Ship v1.1
|
|
301
|
-
Status: Done
|
|
302
|
-
Priority: High
|
|
303
|
-
Date: 2026-02-09
|
|
304
|
-
```
|
|
115
|
+
### Dynamic property flags
|
|
305
116
|
|
|
306
|
-
|
|
117
|
+
Property names from your database schema become CLI flags automatically:
|
|
307
118
|
|
|
308
119
|
```bash
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
120
|
+
# Instead of --prop "Name=Ship it" --prop "Status=Done":
|
|
121
|
+
notion add projects --name "Ship it" --status "Done" --priority "High"
|
|
122
|
+
notion update projects --filter "Name=Ship it" --status "Complete"
|
|
312
123
|
```
|
|
313
124
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
### `notion templates` — List Database Templates
|
|
125
|
+
### Import data
|
|
317
126
|
|
|
318
127
|
```bash
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
a1b2c3d4… │ Project Template │ https://notion.so/...
|
|
323
|
-
```
|
|
128
|
+
# CSV or JSON → database pages
|
|
129
|
+
notion import projects ./tasks.csv
|
|
130
|
+
notion import projects ./data.json
|
|
324
131
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
```bash
|
|
328
|
-
$ notion db-create <parent-page-id> "My New DB" --prop "Name:title" --prop "Status:select" --prop "Priority:number"
|
|
329
|
-
✅ Created database: a1b2c3d4…
|
|
330
|
-
Title: My New DB
|
|
331
|
-
Properties: Name, Status, Priority
|
|
132
|
+
# Markdown → page with content blocks
|
|
133
|
+
notion add projects --name "My Notes" --from notes.md
|
|
332
134
|
```
|
|
333
135
|
|
|
334
|
-
###
|
|
335
|
-
|
|
336
|
-
Add or remove columns, rename databases:
|
|
136
|
+
### Export content
|
|
337
137
|
|
|
338
138
|
```bash
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
$ notion db-update projects --remove-prop "Old Column"
|
|
344
|
-
✅ Updated database: a1b2c3d4…
|
|
345
|
-
Removed: Old Column
|
|
346
|
-
|
|
347
|
-
$ notion db-update projects --title "Renamed Projects"
|
|
348
|
-
✅ Updated database: a1b2c3d4…
|
|
349
|
-
Title: Renamed Projects
|
|
139
|
+
# Page content → markdown
|
|
140
|
+
notion export projects --filter "Name=Ship it"
|
|
141
|
+
# Outputs: # Ship it\n\nPage content as markdown...
|
|
350
142
|
```
|
|
351
143
|
|
|
352
|
-
###
|
|
144
|
+
### View page details (relations auto-resolved)
|
|
353
145
|
|
|
354
|
-
```bash
|
|
355
|
-
$ notion upload tasks --filter "Name=Ship feature" ./screenshot.png
|
|
356
|
-
✅ Uploaded: screenshot.png (142.3 KB)
|
|
357
|
-
Page: a1b2c3d4…
|
|
358
146
|
```
|
|
147
|
+
$ notion get tasks --filter "Name=Implement relations"
|
|
359
148
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
### `notion alias` — Manage Aliases
|
|
363
|
-
|
|
364
|
-
Aliases are created automatically by `notion init`, but you can manage them:
|
|
149
|
+
Page: a1b2c3d4-5678-90ab-cdef-1234567890ab
|
|
150
|
+
URL: https://www.notion.so/...
|
|
365
151
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
152
|
+
Properties:
|
|
153
|
+
Name: Implement relations
|
|
154
|
+
Project: Build CLI ← relation resolved to title
|
|
155
|
+
Done: ✓
|
|
156
|
+
Task Count: 3 ← rollup parsed to number
|
|
371
157
|
```
|
|
372
158
|
|
|
373
|
-
###
|
|
374
|
-
|
|
375
|
-
Manage multiple Notion accounts (work, personal, client projects):
|
|
159
|
+
### Multi-workspace
|
|
376
160
|
|
|
377
161
|
```bash
|
|
378
|
-
|
|
379
|
-
notion workspace add
|
|
380
|
-
notion workspace add personal --key ntn_your_personal_key
|
|
381
|
-
|
|
382
|
-
# List workspaces
|
|
383
|
-
notion workspace list
|
|
384
|
-
# default ← active
|
|
385
|
-
# Key: ntn_3871... | Aliases: 5
|
|
386
|
-
# work
|
|
387
|
-
# Key: ntn_ab12... | Aliases: 0
|
|
388
|
-
|
|
389
|
-
# Switch active workspace
|
|
162
|
+
notion workspace add work --key ntn_work_key
|
|
163
|
+
notion workspace add personal --key ntn_personal_key
|
|
390
164
|
notion workspace use work
|
|
165
|
+
notion init # discovers databases for active workspace
|
|
391
166
|
|
|
392
|
-
#
|
|
393
|
-
notion init --workspace work
|
|
394
|
-
|
|
395
|
-
# Per-command override (no switching needed)
|
|
167
|
+
# Per-command override
|
|
396
168
|
notion query tasks --workspace personal
|
|
397
|
-
notion -w work add projects --
|
|
398
|
-
|
|
399
|
-
# Remove a workspace
|
|
400
|
-
notion workspace remove old-client
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
Aliases are scoped per workspace — same alias name in different workspaces won't collide. Old single-key configs are auto-migrated to a "default" workspace.
|
|
404
|
-
|
|
405
|
-
### `--json` — Raw JSON Output
|
|
406
|
-
|
|
407
|
-
Add `--json` to any command for the raw Notion API response:
|
|
408
|
-
|
|
409
|
-
```bash
|
|
410
|
-
notion --json query projects --limit 1
|
|
411
|
-
notion --json get tasks --filter "Name=Ship it"
|
|
169
|
+
notion -w work add projects --name "Q2 Plan"
|
|
412
170
|
```
|
|
413
171
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
### `--output` — Output Formats
|
|
172
|
+
### Output formats
|
|
417
173
|
|
|
418
174
|
```bash
|
|
419
|
-
notion query tasks --output
|
|
420
|
-
notion query tasks --output
|
|
421
|
-
notion query tasks --output json
|
|
422
|
-
notion query tasks --output
|
|
175
|
+
notion query tasks --output table # default
|
|
176
|
+
notion query tasks --output csv
|
|
177
|
+
notion query tasks --output json
|
|
178
|
+
notion query tasks --output yaml
|
|
179
|
+
notion --json query tasks # raw API response (pipe to jq)
|
|
423
180
|
```
|
|
424
181
|
|
|
425
182
|
---
|
|
426
183
|
|
|
427
|
-
##
|
|
184
|
+
## AI Agent Usage
|
|
428
185
|
|
|
429
|
-
notioncli
|
|
186
|
+
notioncli works well as a tool for LLMs and coding agents — no API key juggling, no JSON formatting, just shell commands:
|
|
430
187
|
|
|
431
188
|
```bash
|
|
432
|
-
#
|
|
433
|
-
notion
|
|
434
|
-
notion
|
|
435
|
-
|
|
436
|
-
#
|
|
437
|
-
notion query tasks --filter Status=Todo --sort Priority:desc
|
|
438
|
-
|
|
439
|
-
# Create and update pages — zero UUIDs workflow
|
|
440
|
-
notion add tasks --prop "Name=Fix bug #42" --prop "Status=In Progress"
|
|
441
|
-
notion update tasks --filter "Name=Fix bug #42" --prop "Status=Done"
|
|
442
|
-
|
|
443
|
-
# Explore relations between databases
|
|
444
|
-
notion relations tasks --filter "Name=Fix bug #42"
|
|
445
|
-
|
|
446
|
-
# View and edit page content
|
|
447
|
-
notion blocks tasks --filter "Name=Fix bug #42" --ids
|
|
448
|
-
notion block-edit <block-id> "Updated content"
|
|
449
|
-
notion append tasks "Deployed to production" --filter "Name=Fix bug #42"
|
|
450
|
-
|
|
451
|
-
# Comment and collaborate
|
|
452
|
-
notion comment tasks "Shipped! 🚀" --filter "Name=Fix bug #42"
|
|
453
|
-
|
|
454
|
-
# Delete by alias + filter
|
|
455
|
-
notion delete tasks --filter "Name=Fix bug #42"
|
|
456
|
-
|
|
457
|
-
# Get raw JSON for parsing
|
|
458
|
-
notion --json query projects --limit 10
|
|
189
|
+
notion dbs # discover databases
|
|
190
|
+
notion alias list # see available aliases
|
|
191
|
+
notion query tasks --filter Status=Todo # read data
|
|
192
|
+
notion add tasks --name "Fix bug" --status "In Progress" # write data
|
|
193
|
+
notion --json query tasks --limit 10 # structured output for parsing
|
|
459
194
|
```
|
|
460
195
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
### Zero-UUID Workflow
|
|
464
|
-
|
|
465
|
-
Every page-targeted command (`update`, `delete`, `get`, `blocks`, `relations`, `comments`, `comment`, `append`, `block-edit`, `block-delete`) accepts a **database alias + `--filter`** as an alternative to a raw page ID:
|
|
196
|
+
Every page-targeted command accepts `alias + --filter` instead of UUIDs:
|
|
466
197
|
|
|
467
198
|
```bash
|
|
468
|
-
#
|
|
469
|
-
|
|
199
|
+
# No UUIDs needed — ever
|
|
200
|
+
notion update projects --filter "Name=Ship it" --status "Done"
|
|
201
|
+
notion delete projects --filter "Name=Old task"
|
|
202
|
+
notion blocks projects --filter "Name=Ship it" --ids
|
|
470
203
|
```
|
|
471
204
|
|
|
472
|
-
The filter queries the database and expects **exactly one match**. If zero or multiple pages match, you get a clear error with guidance.
|
|
473
|
-
|
|
474
205
|
---
|
|
475
206
|
|
|
476
207
|
## Configuration
|
|
477
208
|
|
|
478
|
-
Config
|
|
479
|
-
|
|
480
|
-
```json
|
|
481
|
-
{
|
|
482
|
-
"apiKey": "ntn_...",
|
|
483
|
-
"aliases": {
|
|
484
|
-
"projects": {
|
|
485
|
-
"database_id": "a1b2c3d4-...",
|
|
486
|
-
"data_source_id": "a1b2c3d4-..."
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
```
|
|
209
|
+
Config lives at `~/.config/notioncli/config.json`. API key resolution: `NOTION_API_KEY` env var → config file.
|
|
491
210
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
211
|
+
```bash
|
|
212
|
+
notion alias list # see aliases
|
|
213
|
+
notion alias add tasks <database-id> # manual alias
|
|
214
|
+
notion workspace list # see workspaces
|
|
215
|
+
```
|
|
496
216
|
|
|
497
217
|
---
|
|
498
218
|
|
|
499
|
-
## Technical
|
|
500
|
-
|
|
501
|
-
### Notion API 2025-09-03 — Dual IDs
|
|
502
|
-
|
|
503
|
-
The latest Notion API introduced a dual-ID system for databases. Each database now has both a `database_id` and a `data_source_id`. **notioncli handles this automatically** — when you add an alias, both IDs are discovered and stored. When you pass a raw UUID, it resolves correctly.
|
|
219
|
+
## Technical Details
|
|
504
220
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
### Reliability
|
|
508
|
-
|
|
509
|
-
- 139 unit tests
|
|
510
|
-
- Tested against live Notion workspaces
|
|
511
|
-
- Designed to fail loudly and safely when filters match zero or multiple pages
|
|
512
|
-
|
|
513
|
-
### Built on the Official SDK
|
|
514
|
-
|
|
515
|
-
notioncli uses [`@notionhq/client`](https://github.com/makenotion/notion-sdk-js) v5.x, Notion's official JavaScript SDK.
|
|
221
|
+
For API internals, the 2025 dual-ID system, architecture decisions, and testing: see **[TECHNICAL.md](./TECHNICAL.md)**.
|
|
516
222
|
|
|
517
223
|
---
|
|
518
224
|
|
|
519
|
-
## Contributing
|
|
520
|
-
|
|
521
|
-
1. Fork the repo
|
|
522
|
-
2. Create a feature branch (`git checkout -b feature/my-feature`)
|
|
523
|
-
3. Commit your changes (`git commit -am 'Add my feature'`)
|
|
524
|
-
4. Push to the branch (`git push origin feature/my-feature`)
|
|
525
|
-
5. Open a Pull Request
|
|
526
|
-
|
|
527
|
-
### Development
|
|
528
|
-
|
|
529
|
-
```bash
|
|
530
|
-
git clone https://github.com/JordanCoin/notioncli.git
|
|
531
|
-
cd notioncli
|
|
532
|
-
npm install
|
|
533
|
-
export NOTION_API_KEY=ntn_your_test_key
|
|
534
|
-
node bin/notion.js --help
|
|
535
|
-
```
|
|
536
|
-
|
|
537
225
|
## License
|
|
538
226
|
|
|
539
227
|
MIT © [JordanCoin](https://github.com/JordanCoin)
|