Notion
Skill furkangonel/cowrangler/bundled_skills/productivity/notion
Autonomous terminal AI agent for workflows and feasible project procedures. Co-Worker Co-Wrangler π
npx -y skills add furkangonel/cowrangler --skill notionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Notion workspace management via API β pages, databases, blocks.
SKILL.md
10.2 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it
Notion Workspace Management SOP
Manage Notion content programmatically: create and update pages, query databases, write blocks, and automate workspace workflows via the Notion REST API.
When to Use
- User wants to create a new Notion page or sub-page
- User wants to add records to a Notion database
- User wants to query a database with filters or sorts
- User wants to update existing page content or properties
- User wants to read a page's blocks or a database's schema
Part 1 β Auth Setup
1. Create an Integration
- Go to https://www.notion.so/profile/integrations
- Click New integration β give it a name β select the workspace
- Copy the Internal Integration Secret β this is your
NOTION_API_KEY
2. Connect Pages to the Integration
Every page or database the integration should access must be explicitly shared:
- Open the page/database in Notion
- Click ... (top right) β Connections β find your integration β Confirm
3. Set the Environment Variable
export NOTION_API_KEY="secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Or store it in ~/.cowrangler/credentials.env:
NOTION_API_KEY=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Auth Helper (shell)
NOTION_API_KEY="${NOTION_API_KEY:-$(grep '^NOTION_API_KEY=' ~/.cowrangler/credentials.env 2>/dev/null | cut -d= -f2 | tr -d '\n\r')}"
NOTION_VERSION="2022-06-28"
notion_get() {
curl -s -X GET "https://api.notion.com/v1/$1" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: $NOTION_VERSION" \
-H "Content-Type: application/json"
}
notion_post() {
curl -s -X POST "https://api.notion.com/v1/$1" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: $NOTION_VERSION" \
-H "Content-Type: application/json" \
-d "$2"
}
notion_patch() {
curl -s -X PATCH "https://api.notion.com/v1/$1" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: $NOTION_VERSION" \
-H "Content-Type: application/json" \
-d "$2"
}
Part 2 β Key Concepts
| Object | What it is | API path |
|---|---|---|
| Page | A Notion page (can be inside a database or standalone) | /pages/{id} |
| Database | A structured collection of pages with typed properties | /databases/{id} |
| Block | A content unit inside a page (paragraph, heading, todo, etc.) | /blocks/{id}/children |
| Property | A column in a database (title, text, select, date, relation, etc.) | Part of page object |
Finding IDs: Copy a page/database URL from Notion β the 32-char hex string at the end (with or without hyphens) is the ID.
https://www.notion.so/My-Page-abc123def456...
^^^^^^^^^^^^^^^^^^^^ β page ID (add hyphens: 8-4-4-4-12)
Part 3 β Pages
Create a Standalone Page
notion_post "pages" '{
"parent": { "page_id": "PARENT_PAGE_ID" },
"properties": {
"title": {
"title": [{ "text": { "content": "My New Page" } }]
}
},
"children": [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [{ "type": "text", "text": { "content": "Welcome to my page." } }]
}
}
]
}'
Read a Page's Properties
notion_get "pages/PAGE_ID" | python3 -c "
import sys, json
page = json.load(sys.stdin)
title = page['properties']['title']['title'][0]['plain_text']
print('Title:', title)
print('URL:', page['url'])
"
Update a Page's Properties
notion_patch "pages/PAGE_ID" '{
"properties": {
"title": {
"title": [{ "text": { "content": "Updated Title" } }]
}
}
}'
Archive (soft-delete) a Page
notion_patch "pages/PAGE_ID" '{ "archived": true }'
Part 4 β Databases
Query a Database (with filter and sort)
notion_post "databases/DATABASE_ID/query" '{
"filter": {
"and": [
{
"property": "Status",
"select": { "equals": "In Progress" }
},
{
"property": "Due Date",
"date": { "before": "2026-06-01" }
}
]
},
"sorts": [
{ "property": "Due Date", "direction": "ascending" }
],
"page_size": 50
}' | python3 -c "
import sys, json
data = json.load(sys.stdin)
for page in data['results']:
props = page['properties']
title = props['Name']['title'][0]['plain_text'] if props['Name']['title'] else '(untitled)'
status = props.get('Status', {}).get('select', {}).get('name', '-')
print(f'{title:40s} {status}')
"
Create a Database Entry (row)
notion_post "pages" '{
"parent": { "database_id": "DATABASE_ID" },
"properties": {
"Name": {
"title": [{ "text": { "content": "New Task" } }]
},
"Status": {
"select": { "name": "To Do" }
},
"Due Date": {
"date": { "start": "2026-05-30" }
},
"Assignee": {
"people": [{ "id": "USER_ID" }]
},
"Tags": {
"multi_select": [
{ "name": "backend" },
{ "name": "urgent" }
]
}
}
}'
Retrieve Database Schema
notion_get "databases/DATABASE_ID" | python3 -c "
import sys, json
db = json.load(sys.stdin)
print('Database:', db['title'][0]['plain_text'])
print('\nProperties:')
for name, prop in db['properties'].items():
print(f' {name:30s} {prop[\"type\"]}')
"
Paginate Through All Results
python3 << 'EOF'
import os, json, urllib.request
API_KEY = os.environ['NOTION_API_KEY']
DATABASE_ID = "DATABASE_ID"
def query(cursor=None):
body = {"page_size": 100}
if cursor:
body["start_cursor"] = cursor
req = urllib.request.Request(
f"https://api.notion.com/v1/databases/{DATABASE_ID}/query",
data=json.dumps(body).encode(),
headers={
"Authorization": f"Bearer {API_KEY}",
"Notion-Version": "2022-06-28",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as r:
return json.load(r)
all_pages = []
cursor = None
while True:
data = query(cursor)
all_pages.extend(data["results"])
if not data["has_more"]:
break
cursor = data["next_cursor"]
print(f"Total records: {len(all_pages)}")
EOF
Part 5 β Blocks (Page Content)
Append Blocks to a Page
notion_patch "blocks/PAGE_ID/children" '{
"children": [
{
"object": "block",
"type": "heading_2",
"heading_2": {
"rich_text": [{ "type": "text", "text": { "content": "Meeting Notes" } }]
}
},
{
"object": "block",
"type": "bulleted_list_item",
"bulleted_list_item": {
"rich_text": [{ "type": "text", "text": { "content": "Discussed Q2 roadmap" } }]
}
},
{
"object": "block",
"type": "to_do",
"to_do": {
"rich_text": [{ "type": "text", "text": { "content": "Send follow-up email" } }],
"checked": false
}
},
{
"object": "block",
"type": "code",
"code": {
"rich_text": [{ "type": "text", "text": { "content": "npm install" } }],
"language": "shell"
}
}
]
}'
Read a Page's Blocks
notion_get "blocks/PAGE_ID/children?page_size=100" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for block in data['results']:
btype = block['type']
content = block.get(btype, {}).get('rich_text', [])
text = ''.join(t['plain_text'] for t in content) if content else ''
print(f'[{btype:25s}] {text[:80]}')
"
Part 6 β Common Patterns
Meeting Notes Template
import os, json, urllib.request, datetime
API_KEY = os.environ["NOTION_API_KEY"]
PARENT_PAGE_ID = "YOUR_NOTES_PAGE_ID"
today = datetime.date.today().isoformat()
body = {
"parent": {"page_id": PARENT_PAGE_ID},
"properties": {
"title": {"title": [{"text": {"content": f"Meeting Notes β {today}"}}]}
},
"children": [
{"object": "block", "type": "heading_2",
"heading_2": {"rich_text": [{"type": "text", "text": {"content": "Attendees"}}]}},
{"object": "block", "type": "bulleted_list_item",
"bulleted_list_item": {"rich_text": [{"type": "text", "text": {"content": ""}}]}},
{"object": "block", "type": "heading_2",
"heading_2": {"rich_text": [{"type": "text", "text": {"content": "Agenda"}}]}},
{"object": "block", "type": "numbered_list_item",
"numbered_list_item": {"rich_text": [{"type": "text", "text": {"content": ""}}]}},
{"object": "block", "type": "heading_2",
"heading_2": {"rich_text": [{"type": "text", "text": {"content": "Action Items"}}]}},
{"object": "block", "type": "to_do",
"to_do": {"rich_text": [{"type": "text", "text": {"content": ""}}], "checked": False}},
],
}
req = urllib.request.Request(
"https://api.notion.com/v1/pages",
data=json.dumps(body).encode(),
headers={"Authorization": f"Bearer {API_KEY}", "Notion-Version": "2022-06-28",
"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req) as r:
page = json.load(r)
print("Created:", page["url"])
Property Type Reference
| Type | Write format |
|---|---|
title | {"title": [{"text": {"content": "..."}}]} |
rich_text | {"rich_text": [{"text": {"content": "..."}}]} |
number | {"number": 42} |
select | {"select": {"name": "Option"}} |
multi_select | {"multi_select": [{"name": "A"}, {"name": "B"}]} |
date | {"date": {"start": "2026-05-18"}} |
checkbox | {"checkbox": true} |
url | {"url": "https://example.com"} |
email | {"email": "[email protected]"} |
people | {"people": [{"id": "USER_ID"}]} |
relation | {"relation": [{"id": "PAGE_ID"}]} |
Checklist
- Integration created at notion.so/profile/integrations
- Integration connected to the target page/database (via Connections menu)
-
NOTION_API_KEYset in environment - Page/database IDs extracted from URLs
- Pagination handled for database queries returning > 100 results