← 返回
安全合规 Key 中文

solid-notion

Manage Notion pages locally as Markdown: pull, edit with JSON patches, write changes, submit edits with rollback, and handle API authentication via solid-not...
在本地将 Notion 页面转为 Markdown 管理:支持拉取、使用 JSON 补丁编辑、写入更改、提交编辑并回滚,以及通过 solid‑not 进行 API 认证。
vincentdchan
安全合规 clawhub v0.1.1 1 版本 100000 Key: 需要
★ 0
Stars
📥 500
下载
💾 16
安装
1
版本
#latest

概述

solid-notion CLI Guide

solid-notion is a CLI for reading, editing, and writing Notion pages as Markdown with local reversible changesets.


0. Installation

For normal usage (published package):

npm install -g solid-notion
solid-notion --version

For local development from source:

pnpm install
pnpm build

1. Authentication Setup

Before using any command that talks to Notion, a token must be configured.

Getting a Notion Token

Create a Notion integration to get an API token:

  1. Visit https://www.notion.so/profile/integrations/internal
  2. Click "New integration" and give it a name
  3. Copy the "Internal Integration Token"
  4. Share your pages with this integration (via page "Share" settings)

Check current auth status

solid-notion auth status --json

Returns:

{
  "ok": true,
  "profile": "default",
  "config_path": "...",
  "token_present": true,
  "token_fingerprint": "a1b2c3d4",
  "token_valid": null
}

If token_present is false, run init first.

Save a token (agent-recommended method)

printf "%s" "$NOTION_TOKEN" | solid-notion init --token-stdin --json

Returns on success:

{
  "ok": true,
  "action": "init",
  "profile": "default",
  "config_path": "...",
  "token_saved": true,
  "overwritten": false,
  "ignored_inputs": [],
  "dry_run": false
}

Other token input methods (in precedence order):

MethodFlagNotes
---------------------
Direct--token Visible in ps / shell history
Stdin--token-stdinRecommended for agents
JSON--input-json '{"token":"..."}'Useful for structured protocols

Additional flags:

FlagEffect
--------------
--jsonMachine-readable JSON output only
--dry-runPreview without writing
--forceOverwrite existing token
--profile Use a named profile (default: "default")

Remove a token

solid-notion auth logout --json

2. Command Reference

2.1 Browse

List locally pulled pages

solid-notion ls
solid-notion ls --json

Lists all pages that have been pulled to $SOLID_NOTION_HOME/. Does not call the Notion API.

Default output: tab-separated \t\t</code>, sorted newest first.</p><p>JSON output (<code>--json</code>): array of objects with <code>page_id</code>, <code>title</code>, <code>pulled_at</code>, <code>path</code>.</p><h4>List all pages (remote)</h4><pre><code>solid-notion pages </code></pre><p>Output: tab-separated lines of <code><last_edited>\t<page_id>\t<title></code>.</p><h4>Search pages</h4><pre><code>solid-notion search <query> </code></pre><p>Output: same tab-separated format as <code>pages</code>.</p><h3>2.2 Read</h3><h4>Show a page (non-recursive, stdout)</h4><pre><code>solid-notion show page <page_id_or_name> --format markdown solid-notion show page <page_id_or_name> --format json </code></pre><p><code><page_id_or_name></code> can be a UUID or a page title. Default format: <code>markdown</code>.</p><h4>Show a block (JSON only)</h4><pre><code>solid-notion show block <block_id> --format json </code></pre><h4>Pull a page to local files</h4><pre><code>solid-notion pull page <page_id_or_name> --format markdown --outdir ./output </code></pre><p>Options:</p><table><thead><tr><th>Flag</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td>------</td><td>---------</td><td>-------------</td></tr><tr><td><code>--format <format></code></td><td><code>json</code></td><td><code>json</code> or <code>markdown</code></td></tr><tr><td><code>--outdir <dir></code></td><td><code>$SOLID_NOTION_HOME/<page_id></code></td><td>Output directory</td></tr><tr><td><code>--no-local-images</code></td><td>(images downloaded)</td><td>Skip downloading images</td></tr><tr><td><code>--no-local-videos</code></td><td>(videos downloaded)</td><td>Skip downloading videos</td></tr><tr><td><code>--no-recursive</code></td><td>(recursive)</td><td>Only first-level blocks</td></tr></tbody></table><p>Outputs the path of the written file.</p><p>If the page was already pulled locally, running <code>pull page</code> again fetches the latest content from Notion and overwrites local output files in that directory.</p><h4>Pull a block to local file</h4><pre><code>solid-notion pull block <block_id> --outdir ./output </code></pre><p>Options: <code>--outdir <dir></code>, <code>--no-recursive</code></p><h3>2.3 Edit and Write</h3><p>All edit/write/submit commands require a <strong>strict Notion page ID</strong> (UUID format like <code>aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</code>). Page names are NOT accepted.</p><h4>Apply a JSON patch</h4><p>Pipe a JSON patch object to stdin:</p><pre><code>echo '{"ops": [...]}' | solid-notion edit <page_id> </code></pre><p>Also accepts a markdown file path (<code>notion-page-<uuid>.md</code>) to resolve the page ID.</p><p><strong>CRITICAL: Valid Patch Schema</strong></p><p>The patch object must have exactly these keys: <code>ops</code> (array) and <code>notes</code> (string). No other keys allowed.</p><pre><code>{ "ops": [ { "op": "replace_block_text", "block_id": "...", "new_markdown": "...", "reason": "..." }, { "op": "append_blocks", "parent_block_id": "...", "blocks": [...], "reason": "..." }, { "op": "set_props", "page_id": "...", "set": {...}, "reason": "..." } ], "notes": "optional notes" } </code></pre><p><strong>Three allowed operation types:</strong></p><h5><code>replace_block_text</code></h5><p>Replaces rich_text content of a block. Supported block types:</p><p><code>paragraph</code>, <code>heading_1</code>, <code>heading_2</code>, <code>heading_3</code>, <code>bulleted_list_item</code>, <code>numbered_list_item</code>, <code>to_do</code>, <code>quote</code>, <code>callout</code></p><pre><code>{ "op": "replace_block_text", "block_id": "block-uuid", "new_markdown": "## New heading", "reason": "Clarified section title" } </code></pre><h5><code>append_blocks</code></h5><p>Appends new blocks under a parent block.</p><ul><li>Most block types need <code>type</code> + <code>rich_text_md</code></li><li><code>divider</code> needs only <code>type</code></li><li><code>code</code> supports optional <code>language</code> (defaults to <code>plain text</code>)</li></ul><pre><code>{ "op": "append_blocks", "parent_block_id": "parent-uuid", "blocks": [ { "type": "paragraph", "rich_text_md": "New paragraph content" }, { "type": "heading_2", "rich_text_md": "New section" } ], "reason": "Added conclusion section" } </code></pre><p>Allowed block types:</p><ul><li><code>paragraph</code>, <code>heading_1</code>, <code>heading_2</code>, <code>heading_3</code></li><li><code>bulleted_list_item</code>, <code>numbered_list_item</code>, <code>to_do</code>, <code>quote</code>, <code>callout</code></li><li><code>code</code>, <code>divider</code></li></ul><h5><code>set_props</code></h5><p>Updates page properties (title, rich_text, number, checkbox, select, multi_select, date).</p><pre><code>{ "op": "set_props", "page_id": "page-uuid", "set": { "Status": { "type": "select", "name": "Done" }, "Priority": { "type": "number", "value": 3 }, "Done": { "type": "checkbox", "value": true }, "Tags": { "type": "multi_select", "names": ["urgent", "important"] }, "Due Date": { "type": "date", "start": "2026-03-02", "end": null }, "Title": { "type": "title", "md": "New page title" }, "Notes": { "type": "rich_text", "md": "Some notes" } }, "reason": "Updated status to Done" } </code></pre><p><strong>Property value types:</strong></p><table><thead><tr><th>Type</th><th>Shape</th><th>Example</th></tr></thead><tbody><tr><td>------</td><td>-------</td><td>---------</td></tr><tr><td><code>number</code></td><td><code>{ "type": "number", "value": 42 }</code></td><td>-</td></tr><tr><td><code>checkbox</code></td><td><code>{ "type": "checkbox", "value": true }</code></td><td>-</td></tr><tr><td><code>select</code></td><td><code>{ "type": "select", "name": "Option" }</code></td><td>-</td></tr><tr><td><code>multi_select</code></td><td><code>{ "type": "multi_select", "names": ["A", "B"] }</code></td><td>-</td></tr><tr><td><code>date</code></td><td><code>{ "type": "date", "start": "2026-03-02", "end": null }</code></td><td>end optional</td></tr><tr><td><code>title</code></td><td><code>{ "type": "title", "md": "markdown" }</code></td><td>-</td></tr><tr><td><code>rich_text</code></td><td><code>{ "type": "rich_text", "md": "markdown" }</code></td><td>-</td></tr></tbody></table><h4>Write workspace changes back to Notion</h4><pre><code>solid-notion write <page_id> </code></pre><p>Reads the workspace files (<code>page.md</code>, <code>.original.md</code>), replaces the page content in Notion, creates a changeset, and cleans up the workspace.</p><h4>Submit pending edits with rollback</h4><pre><code>solid-notion submit <page_id> -m "description of changes" </code></pre><p><strong>CRITICAL: How submit works</strong></p><p><code>submit</code> consumes <strong>pending edit logs</strong> (created by previous <code>edit</code> commands) and applies them to Notion with transaction-like semantics:</p><ol><li><strong>Phase 0: Load</strong> — Reads all edit log files from <code>edit-logs/<page_id>/</code> that don't have <code>.submitted</code> markers</li><li><strong>Phase 1: Prepare</strong> — Fetches before-snapshots (current block content, property values) so rollback is possible</li><li><strong>Phase 2: Apply</strong> — Applies ops sequentially to Notion</li><li><strong>Phase 3: Finalize</strong> — On success, saves commit to <code>versions/</code>. On failure, rolls back already-applied ops using before-snapshots.</li></ol><p><strong>Exit statuses:</strong></p><table><thead><tr><th><code>status</code></th><th>Meaning</th><th><code>ok</code></th></tr></thead><tbody><tr><td>----------</td><td>---------</td><td>------</td></tr><tr><td><code>pushed</code></td><td>All ops applied successfully</td><td><code>true</code></td></tr><tr><td><code>nothing_to_submit</code></td><td>No pending edits found</td><td><code>false</code></td></tr><tr><td><code>rolled_back</code></td><td>Apply failed but rollback succeeded</td><td><code>false</code></td></tr><tr><td><code>failed_needs_reconcile</code></td><td>Apply failed AND rollback partially failed</td><td><code>false</code></td></tr></tbody></table><p><strong>Submit result format:</strong></p><pre><code>{ "ok": true, "commit_id": "cmt_20260302_143022", "notion_id": "3d1b-...", "status": "pushed", "applied_ops": 3, "included_edits": 2 } </code></pre><p><strong>Best practices:</strong></p><ul><li>Always run <code>submit</code> after <code>edit</code> operations to publish changes</li><li>If submit returns <code>rolled_back</code>, the page is back to original state — no manual cleanup needed</li><li>If submit returns <code>failed_needs_reconcile</code>, manual intervention may be required</li><li>The <code>-m</code> (message) flag is <strong>required</strong></li></ul><h3>2.4 Create New Pages</h3><p><strong>CRITICAL: Use the <code>new</code> command to create Notion pages programmatically</strong></p><p>The <code>new</code> command creates a new page under a parent (page or database) with <strong>metadata only</strong> (title, icon, cover, props) via stdin as JSON. After creation, the page is <strong>automatically pulled</strong> locally as markdown. To add content (blocks), use the existing <code>edit</code> + <code>submit</code> workflow.</p><h4>Create a new page</h4><pre><code>echo '{"title":"My New Page","notes":""}' | solid-notion new --parent <parent_id> -m "Create page" --json </code></pre><p><strong>Required flags:</strong></p><ul><li><code>--parent <parent_id></code> — Parent page or database ID</li><li><code>-m, --message <message></code> — Commit message</li></ul><p><strong>Optional flags:</strong></p><ul><li><code>--database</code> — Parent is a database (creates as database entry)</li><li><code>--json</code> — Output JSON only</li><li><code>--dry-run</code> — Validate without creating</li></ul><p><strong>CRITICAL: Valid Payload Schema</strong></p><p>The JSON payload via stdin must have exactly these keys:</p><pre><code>{ "title": "Page Title", "icon": { "type": "emoji", "emoji": "📝" }, "cover": { "type": "external", "url": "https://..." }, "props": { "Status": { "type": "select", "name": "In Progress" } }, "notes": "optional notes about this creation" } </code></pre><p><strong>Required fields:</strong></p><ul><li><code>title</code> (string, non-empty)</li><li><code>notes</code> (string, can be empty)</li></ul><p><strong>Optional fields:</strong></p><ul><li><code>icon</code> — <code>{ "type": "emoji", "emoji": "🎉" }</code> or <code>{ "type": "external", "url": "..." }</code></li><li><code>cover</code> — <code>{ "type": "external", "url": "..." }</code></li><li><code>props</code> — Page properties (database entries), same types as <code>set_props</code> plus <code>url</code>, <code>email</code>, <code>phone_number</code></li></ul><p><strong>No <code>blocks</code> field.</strong> Content is added via <code>edit</code> + <code>submit</code> after creation.</p><p><strong>Property types for <code>props</code> (database entries):</strong></p><p>All types from <code>set_props</code> plus:</p><ul><li><code>url</code>: <code>{ "type": "url", "value": "https://..." }</code></li><li><code>email</code>: <code>{ "type": "email", "value": "user@example.com" }</code></li><li><code>phone_number</code>: <code>{ "type": "phone_number", "value": "+1234567890" }</code></li></ul><p><strong>CRITICAL rules:</strong></p><ul><li>Payload must have exactly <code>title</code>, <code>notes</code>, and optional fields — no extra keys</li><li>For database pages, <code>props</code> must match the database schema</li><li>After creation, the page is auto-pulled locally as markdown</li></ul><p><strong>Transaction semantics:</strong></p><p><code>new</code> follows the same 4-phase pipeline as <code>submit</code>:</p><ol><li><strong>Phase 0: Parse</strong> — Read and validate JSON from stdin</li><li><strong>Phase 1: Prepare</strong> — Verify parent exists, derive internal ops, create commit draft</li><li><strong>Phase 2: Apply</strong> — Create page on Notion (metadata only)</li><li><strong>Phase 3: Finalize</strong> — Persist version record, auto-pull page. On failure, rollback (archive page).</li></ol><p>Rollback for <code>new</code>:</p><ul><li>Archives the created page (soft-delete)</li></ul><p><strong>Success output (JSON mode):</strong></p><pre><code>{ "ok": true, "commit_id": "parent-id-20260304T120000Z", "action": "new", "status": "pushed", "created_page_id": "abc123-def456", "page_url": "https://notion.so/abc123def456", "title": "My New Page", "parent_id": "parent-id", "parent_type": "page", "pulled_to": "/path/to/notion-page-abc123-def456.md" } </code></pre><p><strong>Dry run output:</strong></p><pre><code>{ "ok": true, "action": "new", "status": "dry_run", "dry_run": true, "validation": "passed", "title": "My New Page", "parent_id": "parent-id" } </code></pre><h3>2.5 History and Restore</h3><h4>View history</h4><pre><code>solid-notion history <page_id> </code></pre><p>Output: tab-separated <code><id>\t<created_at>\t<type></code>.</p><p>Types:</p><ul><li><code>changeset</code> — Created by <code>write</code> or <code>restore</code></li><li><code>new</code> — Created by <code>new</code> command</li><li><code>submit</code> — Created by <code>submit</code> command</li></ul><h4>Restore to a previous changeset or version</h4><pre><code>solid-notion restore <page_id> <changeset_or_commit_id> solid-notion restore <changeset_or_commit_id> </code></pre><p><strong>Behavior depends on type:</strong></p><ul><li><strong>Changeset</strong> (from <code>write</code>/<code>restore</code>): Restores page to that changeset's state</li><li><strong>Version (<code>submit</code> or <code>new</code>)</strong>: Restore to the target hash by undoing only the later <code>submit</code> versions, then writes a new changeset</li></ul><p>Hash-only lookup is supported. If the hash exists in multiple pages, CLI asks you to disambiguate with page ID.</p><p>After restore-to-version, local version files after the target hash are deleted.</p><p>Outputs the new changeset ID created by restore.</p><hr><h2>3. Agent Workflows</h2><h3>Workflow: Read a page as Markdown</h3><pre><code>solid-notion pull page <page_id_or_name> --format markdown --outdir /tmp/notion-work </code></pre><p>Then read the output file path printed to stdout.</p><h3>Workflow: Full edit cycle (Markdown mode)</h3><ol><li><strong>Pull</strong> the page to a workspace:</li></ol><p> ```bash</p><p> solid-notion pull page <page_id> --format markdown --outdir ~/.local/share/solid-notion-cli/<page_id></p><p> ```</p><ol><li><strong>Edit</strong> the local <code>page.md</code> file as needed.</li></ol><ol><li><strong>Write</strong> changes back:</li></ol><p> ```bash</p><p> solid-notion write <page_id></p><p> ```</p><ol><li><strong>Submit</strong> with a message:</li></ol><p> ```bash</p><p> solid-notion submit <page_id> -m "Updated section headings"</p><p> ```</p><h3>Workflow: Edit via JSON patch (Programmatic mode)</h3><p>Use this workflow when making precise, targeted edits without pulling full markdown.</p><ol><li><strong>Get the target block IDs</strong> (you may need to pull JSON first):</li></ol><p> ```bash</p><p> solid-notion pull page <page_id> --format json --outdir /tmp</p><p> # or inspect specific block:</p><p> solid-notion show block <block_id> --format json</p><p> ```</p><ol><li><strong>Construct a valid patch</strong> with <code>ops</code> array and <code>notes</code>:</li></ol><p> ```json</p><p> {</p><p> "ops": [</p><p> {</p><p> "op": "replace_block_text",</p><p> "block_id": "block-uuid-here",</p><p> "new_markdown": "Updated content here",</p><p> "reason": "Clarified the explanation"</p><p> },</p><p> {</p><p> "op": "set_props",</p><p> "page_id": "page-uuid-here",</p><p> "set": {</p><p> "Status": { "type": "select", "name": "In Progress" }</p><p> },</p><p> "reason": "Moving to next phase"</p><p> }</p><p> ],</p><p> "notes": "Batch update from review session"</p><p> }</p><p> ```</p><ol><li><strong>Apply the patch</strong> via stdin:</li></ol><p> ```bash</p><p> cat patch.json | solid-notion edit <page_id></p><p> ```</p><ol><li><strong>Submit</strong> the pending edits:</li></ol><p> ```bash</p><p> solid-notion submit <page_id> -m "Applied review feedback"</p><p> ```</p><p><strong>CRITICAL rules for JSON patch editing:</strong></p><ul><li>The patch must have exactly <code>ops</code> and <code>notes</code> — no extra keys</li><li>Each op must have <code>op</code>, <code>reason</code>, and type-specific fields</li><li><code>block_id</code> in <code>replace_block_text</code> must be a valid Notion block ID</li><li><code>page_id</code> in <code>set_props</code> must be the target page UUID</li><li><code>append_blocks</code> creates new blocks — the <code>created_block_ids</code> are recorded in edit logs for rollback</li></ul><h3>Workflow: Batch multiple edits before submit</h3><p>You can run multiple <code>edit</code> commands before a single <code>submit</code>. All pending edits are aggregated:</p><pre><code># First edit echo '{"ops":[...],"notes":"First change"}' | solid-notion edit <page_id> # Second edit echo '{"ops":[...],"notes":"Second change"}' | solid-notion edit <page_id> # Third edit echo '{"ops":[...],"notes":"Third change"}' | solid-notion edit <page_id> # Submit all at once solid-notion submit <page_id> -m "Batch: three related updates" </code></pre><p>Submit reads all edit logs from <code>edit-logs/<page_id>/</code>, marks them <code>.submitted</code> on success, and creates a single commit record.</p><h3>Workflow: Restore a change</h3><ol><li><strong>List</strong> changesets:</li></ol><p> ```bash</p><p> solid-notion history <page_id></p><p> ```</p><ol><li><strong>Restore</strong> to a specific hash:</li></ol><p> ```bash</p><p> solid-notion restore <page_id> <changeset_or_commit_id></p><p> # or hash-only when unique:</p><p> solid-notion restore <changeset_or_commit_id></p><p> ```</p><hr><h2>4. Storage Concepts & Layout</h2><p>All data is stored under <code>$SOLID_NOTION_HOME</code> (default: <code>~/.local/share/solid-notion-cli</code>).</p><h3>Storage Concepts Explained</h3><p><strong>Workspace files</strong> (<code><page_id>/</code>) — Created by <code>pull</code>, used by <code>write</code>:</p><ul><li><code>page.md</code> — The markdown you edit</li><li><code>.original.md</code> — Snapshot before editing (for diff/comparison)</li><li><code>page.meta.md</code> — Page metadata (properties, etc.)</li><li><strong>Lifecycle</strong>: Created on <code>pull</code>, deleted on successful <code>write</code></li></ul><p><strong>Edit logs</strong> (<code>edit-logs/<page_id>/</code>) — Created by <code>edit</code>, consumed by <code>submit</code>:</p><ul><li>JSONL files recording each patch operation with before/after snapshots</li><li><strong>Purpose</strong>: Enable rollback if submit fails</li><li><strong>Format</strong>: Each line is a JSON object with <code>op</code>, <code>block_id</code>/<code>page_id</code>, <code>reason</code>, and before/after values</li><li><strong>Lifecycle</strong>: Created on <code>edit</code>, marked <code>.submitted</code> on successful <code>submit</code></li></ul><p><strong>Versions</strong> (<code><page_id>/versions/</code>) — Created by <code>submit</code>:</p><ul><li>Commit records with full operation history and snapshots</li><li><strong>Purpose</strong>: Immutable history of what was published to Notion</li><li><strong>Format</strong>: JSON with <code>commitId</code>, <code>status</code>, <code>ops</code>, <code>beforeSnapshots</code>, <code>applyState</code></li><li><strong>Lifecycle</strong>: Created on every <code>submit</code> attempt (even failures)</li></ul><p><strong>Changesets</strong> (<code>changesets/<page_id>/</code>) — Created by <code>write</code> and <code>restore</code>:</p><ul><li>Reversible markdown diffs for the "write -> restore" workflow</li><li><strong>Purpose</strong>: Track full page content changes for <code>history</code> and <code>restore</code></li><li><strong>Format</strong>: Markdown files with YAML frontmatter containing before/after content</li><li><strong>Lifecycle</strong>: Created on <code>write</code>, referenced by <code>history</code> and <code>restore</code></li></ul><h3>Directory Layout</h3><pre><code>$SOLID_NOTION_HOME/ config.json # Auth tokens (mode 0600) # Workspace (markdown editing workflow) <page_id>/ page.md # Edited markdown page.meta.md # Page metadata .original.md # Original for diff versions/ # Submit commits (JSON) # Edit logs (JSON patch workflow) edit-logs/<page_id>/ <page_id>-<timestamp>.jsonl # Pending edits (before submit) <page_id>-<timestamp>.jsonl.submitted # Marker file (after submit) # Changesets (restorable full-page versions) changesets/<page_id>/ <page_id>-<timestamp>.md # Changeset with YAML frontmatter </code></pre><p>Override the base directory with <code>SOLID_NOTION_HOME</code> environment variable.</p><hr><h2>5. Global Flags</h2><table><thead><tr><th>Flag</th><th>Effect</th></tr></thead><tbody><tr><td>------</td><td>--------</td></tr><tr><td><code>-v, --verbose</code></td><td>Print debug logs to stderr</td></tr><tr><td><code>-V, --version</code></td><td>Print version</td></tr></tbody></table><hr><h2>6. Error Handling</h2><h3>init command error codes</h3><table><thead><tr><th>Exit code</th><th>Error</th><th>Meaning</th></tr></thead><tbody><tr><td>-----------</td><td>-------</td><td>---------</td></tr><tr><td>2</td><td><code>missing_arguments</code></td><td>No token provided</td></tr><tr><td>3</td><td><code>invalid_token</code></td><td>Token is empty or invalid</td></tr><tr><td>4</td><td><code>token_already_exists</code></td><td>Token exists, use <code>--force</code></td></tr><tr><td>5</td><td><code>write_failed</code></td><td>Could not write config file</td></tr></tbody></table><h3>General errors</h3><p>All other commands exit <code>1</code> on failure and print diagnostics to stderr including error name, message, metadata (status, code, errno, syscall, hostname), cause chain, and stack trace.</p><hr><h2>7. Anti-Patterns</h2><h3>Authentication</h3><ul><li><strong>Do NOT</strong> use <code>--token <value></code> in automated flows. Use <code>--token-stdin</code> to avoid leaking tokens in process lists.</li><li><strong>Do NOT</strong> skip <code>solid-notion auth status --json</code> before running commands. If there is no token, all Notion API calls will fail.</li></ul><h3>Page IDs</h3><ul><li><strong>Do NOT</strong> pass page names to <code>edit</code>, <code>write</code>, <code>submit</code>, <code>history</code>, or <code>restore</code>. These commands require strict page UUIDs.</li></ul><h3>Output parsing</h3><ul><li><strong>Do NOT</strong> forget <code>--json</code> when you need to parse command output programmatically.</li></ul><h3>Submit command</h3><ul><li><strong>Do NOT</strong> call <code>submit</code> without <code>-m</code>. The message flag is <strong>required</strong>.</li><li><strong>Do NOT</strong> assume <code>submit</code> takes stdin — it reads from local <code>edit-logs/</code>, not from stdin.</li><li><strong>Do NOT</strong> ignore <code>status: "rolled_back"</code> — this means Notion writes failed but were undone.</li><li><strong>Do NOT</strong> ignore <code>status: "failed_needs_reconcile"</code> — this means both apply AND rollback failed.</li></ul><h3>Edit patch schema</h3><ul><li><strong>Do NOT</strong> include extra keys in the patch object (only <code>ops</code> and <code>notes</code> allowed).</li><li><strong>Do NOT</strong> forget the <code>reason</code> field in each op — it is required.</li><li><strong>Do NOT</strong> use unsupported block types in <code>replace_block_text</code> or <code>append_blocks</code>.</li><li><strong>Do NOT</strong> use <code>set_props</code> on properties with unsupported types (only: number, checkbox, select, multi_select, date, title, rich_text).</li><li><strong>Do NOT</strong> pass Notion block objects as <code>new_markdown</code> — pass simple Markdown text (e.g., "## Heading" or "Paragraph with <strong>bold</strong>").</li></ul></div> </div> </div> <div id="tab-versions" class="detail-content"> <div class="detail-section"> <h2>版本历史</h2> <p style="margin-bottom:12px;font-size:14px;color:#94a3b8;">共 1 个版本</p> <ul class="version-list"> <li> <div> <span class="version-tag">v0.1.1</span> <span style="font-size:11px;color:#5b6abf;margin-left:8px;background:#eef0ff;padding:1px 8px;border-radius:10px;">当前</span> </div> <div style="font-size:12px;color:#94a3b8;"> 2026-03-30 13:11 安全 安全 </div> </li> </ul> </div> </div> <div id="tab-security" class="detail-content"> <div class="detail-section"> <h2>安全检测</h2> <div class="sec-grid"> <div class="sec-card"> <h4>腾讯云安全 (Keen)</h4> <div class="sec-status sec-safe"> 安全,无风险 </div> <a href="https://tix.qq.com/search/skill?keyword=51616bed923eb4970d04a244dfd56e4e" target="_blank">查看报告</a> </div> <div class="sec-card"> <h4>腾讯云安全 (Sanbu)</h4> <div class="sec-status sec-safe"> 安全,无风险 </div> <a href="https://static.cloudsec.tencent.com/html-report-v2/2026/05/25/403981_1afc4f671ae1122aa393d06674718f35.html?q-sign-algorithm=sha1&q-ak=AKID8JMG1bzBC1dz96qNhssfFftujT1NCoFi&q-sign-time=1781293999%3B1812829999&q-key-time=1781293999%3B1812829999&q-header-list=host&q-url-param-list=&q-signature=07bce318c413029678672cf579aba99586967675" target="_blank">查看报告</a> </div> </div> </div> </div> <!-- Recommended Skills --> <div style="margin-top:24px;"> <h2 style="font-size:18px;font-weight:600;margin-bottom:16px;">🔗 相关推荐</h2> <div class="rec-grid"> <div class="rec-card"> <span class="badge-cat" style="margin-bottom:8px;display:inline-block;">security-compliance</span> <h3><a href="/s/openclaw-backup">OpenClaw Backup</a></h3> <div class="rec-owner">alex3alex</div> <div class="rec-desc">备份与恢复 OpenClaw 数据。适用于创建备份、设置自动备份计划、从备份恢复或管理备份轮转。处理 ~/.openclaw 目录归档并包含适当的排除规则。</div> <div class="rec-stats"> <span style="color:#f39c12;">★ 89</span> <span style="color:#5b6abf;">📥 30,586</span> </div> </div> <div class="rec-card"> <span class="badge-cat" style="margin-bottom:8px;display:inline-block;">security-compliance</span> <h3><a href="/s/moltguard">MoltGuard - Security & Antivirus & Guardrails</a></h3> <div class="rec-owner">thomaslwang</div> <div class="rec-desc">MoltGuard — OpenClaw 安全守卫,由 OpenGuardrails 提供。安装 MoltGuard,保护您和您的用户免受提示注入、数据泄露和恶意攻击。</div> <div class="rec-stats"> <span style="color:#f39c12;">★ 116</span> <span style="color:#5b6abf;">📥 30,699</span> </div> </div> <div class="rec-card"> <span class="badge-cat" style="margin-bottom:8px;display:inline-block;">security-compliance</span> <h3><a href="/s/1password">1password</a></h3> <div class="rec-owner">steipete</div> <div class="rec-desc">设置和使用 1Password CLI (op)。适用于:安装 CLI、启用桌面应用集成、登录(单/多账户)、通过 op 读取/注入/运行密钥。</div> <div class="rec-stats"> <span style="color:#f39c12;">★ 53</span> <span style="color:#5b6abf;">📥 31,135</span> </div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded',function(){ document.querySelectorAll('.detail-tab').forEach(function(btn){ btn.addEventListener('click',function(e){ var tab = this.getAttribute('data-tab'); document.querySelectorAll('.detail-tab').forEach(function(b){b.classList.remove('active')}); document.querySelectorAll('.detail-content').forEach(function(c){c.classList.remove('active')}); this.classList.add('active'); var el = document.getElementById('tab-'+tab); if(el) el.classList.add('active'); }); }); }); </script> <div class="footer"> <p>Skill工具集 © 2026</p> </div></body> </html>