关于 paragraph-cli
paragraph-cli 是用于管理 Paragraph Web3 发布与新闻简报平台的命令行技能,涵盖文章、草稿、订阅者和数据分析等,并提供 JSON 输出及发布、邮件发送等操作的安全控制。
主要功能
- 01管理文章与内容草稿
- 02配置出版物
- 03管理订阅者
- 04搜索文章与博客
- 05查询出版物数据分析
- 06管理代币与用户
适用场景
- 01创建和查看出版物文章
- 02准备社交平台及新闻简报草稿
- 03导入或管理订阅者名单
- 04查看出版物互动指标
MCP 相关
README 建议 MCP 兼容客户端使用 Paragraph MCP 服务。它提供托管远程服务和本地服务,向客户端开放文章、内容、出版物、订阅者、代币、搜索、数据分析等工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ paragraph-xyz/ skill --skill paragraph-cli安装后在 Claude Code 中输入/paragraph-cli确认已加载。
详细介绍
Paragraph CLI
Paragraph 的 CLI——一个 web3 发布和新闻简报平台。可用于管理帖子、草稿内容、出版物、订阅者和代币。
如需直接通过 HTTP 或 SDK 访问而无需安装任何内容,请改用 paragraph-api 技能。
MCP 服务(推荐用于兼容 MCP 的客户端)
如果你的客户端支持 MCP,建议使用 Paragraph MCP 服务,而不是 CLI,以获得更集成的体验。
远程服务(推荐)
使用托管服务 mcp.paragraph.com,无需安装或管理 API 密钥。通过浏览器中的 Paragraph 账户进行身份验证。
claude mcp add paragraph --transport http https://mcp.paragraph.com/mcp
对于其他客户端,请在 MCP 配置中添加 https://mcp.paragraph.com/mcp 作为服务 URL。
本地服务
如果你更倾向于在本地运行服务(需要 Node.js 18+):
claude mcp add paragraph -- npx @paragraph-com/mcp
本地模式需要通过 PARAGRAPH_API_KEY 环境变量提供 API 密钥,或使用 CLI 执行 paragraph login。
MCP 服务提供 29 个工具(帖子、内容、出版物、订阅者、代币、搜索、动态、用户、个人信息、分析、邮件),并与 CLI 共用身份验证。请参阅完整文档。
近期新增的工具包括:create-content / list-content / get-content / update-content / archive-content / restore-content(草稿形式的 X 帖子、LinkedIn 帖子、新闻简报和 X Articles——仅创建草稿,不会发送)、send-custom-email(向收件人列表发送 Markdown 邮件——需要出版物批准)、update-publication(设置、精选帖子、置顶帖子、邮件通知开关)、remove-subscriber(按电子邮件地址或钱包地址永久删除订阅者)、update-post 支持使用 publishedAt 回填发布日期,且 update-post 支持使用 imageUrl(设置或替换封面图片)和 clearImage(移除现有封面)。
CLI 设置
全局安装:
npm install -g @paragraph-com/cli
进行身份验证——登录后密钥会保存到 ~/.paragraph/config.json:
paragraph login --token <api-key>
echo "$PARAGRAPH_API_KEY" | paragraph login --with-token
或者跳过登录,通过环境变量为每条命令传入密钥:
PARAGRAPH_API_KEY=<api-key> paragraph post list --json
验证:paragraph whoami --json
使用约定
- 始终使用
--json获取可解析的输出。数据输出到 stdout,状态和错误输出到 stderr。 - 在
delete命令中始终使用--yes,跳过确认提示。 - 在执行
delete、publish和archive前使用--dry-run,预览操作内容。 - 使用标志,而不只是位置参数。 每个标识符都支持
--id,方便串联命令。 - 从文件创建或更新帖子时,通过 stdin 传递内容:
cat draft.md | paragraph post create --title "My Post" - 使用
--limit和--cursor分页。 JSON 响应包含pagination.cursor和pagination.hasMore。 - 不要使用交互式登录。 非交互式身份验证请使用
--token或--with-token。 - 运行命令前检查身份验证。 运行
paragraph whoami --json以验证凭据是否有效。 - 未经用户明确批准,不得发布。 发布会使内容上线,并可选择向订阅者发送邮件。
- 默认创建草稿。
post create会创建草稿。只有在用户提出要求时才调用post publish。 content命令不会发送内容。 它们只会将内容写入出版物的资料库;作者会在 Paragraph 应用中发送内容。不要告诉用户内容已经发送。- 未经用户明确批准,不得发送自定义邮件。
paragraph email send会发送真实邮件,且无法撤回。先拟好主题和正文;实际发送前使用--dry-run预览筛选结果。如果收到403,请告知用户“此出版物尚未获准发送自定义邮件”,然后停止——不要重试。 - 遵守速率限制。 如果收到
RATE_LIMITED,请等待后重试。分页请求之间避免紧密循环。
命令
帖子
# Create a draft
paragraph post create --title "My Post" --file ./post.md --tags "web3,defi" --json
paragraph post create --title "My Post" --text "# Hello World" --subtitle "A subtitle" --json
cat content.md | paragraph post create --title "My Post" --json
# List
paragraph post list --json
paragraph post list --status draft --limit 20 --json
paragraph post list --status scheduled --json
paragraph post list --publication <slug-or-id> --json
# Get (by ID, URL, or @pub/slug)
paragraph post get --id <post-id> --json
paragraph post get @my-blog/post-slug --json
# Extract a single field
paragraph post get --id <post-id> --field markdown > post.md
paragraph post get --id <post-id> --field title
# Update
paragraph post update --id <id-or-slug> --title "New Title" --json
paragraph post update --id <id-or-slug> --text "Updated content" --subtitle "New subtitle" --json
paragraph post update --id <id-or-slug> --file ./updated.md --tags "new,tags" --json
# Backdate (publishedAt sticks across re-publishes — useful for imported content)
paragraph post update --id <id-or-slug> --published-at "2024-01-01T00:00:00Z" --json
# Set/replace cover image (URL is fetched + re-hosted on Paragraph's CDN)
paragraph post update --id <id-or-slug> --image-url https://example.com/cover.jpg --json
# Remove the existing cover image
paragraph post update --id <id-or-slug> --clear-image --json
# Publish
paragraph post publish --id <id-or-slug> --json
paragraph post publish --id <id-or-slug> --newsletter --json
# Revert to draft
paragraph post draft --id <id-or-slug> --json
# Archive
paragraph post archive --id <id-or-slug> --json
# Schedule a post for future publication
paragraph post schedule --id <id-or-slug> --at "2026-05-01T09:00:00Z" --json
paragraph post schedule --id <id-or-slug> --at "2026-05-01T09:00:00Z" --newsletter --json
# Cancel a scheduled publication
paragraph post unschedule --id <id-or-slug> --json
# Create and schedule in one step
paragraph post create --title "Launch Day" --file ./post.md --schedule-at "2026-05-01T09:00:00Z" --newsletter --json
# Preview destructive actions
paragraph post delete --id <id-or-slug> --dry-run --json
paragraph post publish --id <id-or-slug> --dry-run --json
# Delete
paragraph post delete --id <id-or-slug> --yes --json
# Send test newsletter email
paragraph post test-email --id <post-id> --json
# Browse
paragraph post feed --limit 10 --json
paragraph post by-tag --tag web3 --limit 20 --json
内容
起草短篇内容:X 帖子和串文、LinkedIn 帖子、单封邮件以及 X Articles。这些命令只会起草内容,不会发布、发送邮件或安排发布时间。长篇帖子使用 paragraph post。
--kind 的值为 tweet、linkedin、newsletter 或 x_article,正文参数则根据类型而定:tweet 使用 --tweet(可重复,每条串文推文使用一次),newsletter 使用 --subject 和 --preheader,x_article 使用 --headline 和 --canonical-url。长篇文本通过 --text、--file 或标准输入提供。草稿仅包含文本;媒体必须在应用中添加。
# Create
paragraph content create --kind tweet --title "Launch note" --text "We shipped it." --json
paragraph content create --kind tweet --title "Thread" --tweet "First." --tweet "Second." --json
paragraph content create --kind linkedin --title "Launch note" --file ./post.md --json
paragraph content create --kind newsletter --title "October update" --subject "What we shipped" --file ./body.md --json
paragraph content create --kind x_article --title "Editor rewrite" --headline "Why we rebuilt the editor" --file ./article.md --json
cat post.md | paragraph content create --kind linkedin --title "Launch note" --json
# List (--status defaults to all, which excludes archived pieces)
paragraph content list --json
paragraph content list --kind tweet --status draft --limit 50 --json
paragraph content list --status archived --json
# Get, with its body
paragraph content get <id> --json
paragraph content get <id> --field body
# Update — the body is replaced, not merged. Read it first.
paragraph content update <id> --title "Launch note, second pass" --json
paragraph content update <id> --text "Rewritten, and shorter." --json
# Archive and restore
paragraph content archive <id> --dry-run --json
paragraph content archive <id> --json
paragraph content restore <id> --json
已有排队发送任务的内容无法编辑正文(必须在应用中取消排期),但始终可以重命名。JSON 中的 lockedReason 会说明原因;若内容可编辑,则该值为 null。
内容组
一个组将帖子及其衍生内容归为同一身份——帖子、由其改编的串文、LinkedIn 版本和新闻简报。作者在 Content 下看到的是一个单独的堆叠行。
改编帖子时,请将起草的内容与它归为一组,否则作者会得到彼此无关、互不关联的草稿。
# Get or create a post's group. Safe to repeat: the same ID comes back.
paragraph content bucket create <post-id> --json
# Draft into it
BUCKET=$(paragraph content bucket create <post-id> --json | jq -r .bucketId)
paragraph content create --kind tweet --title "Thread" --tweet "First." --bucket "$BUCKET" --json
# Group a draft made before the group existed
paragraph content update <id> --bucket "$BUCKET" --json
# Read a group and everything already made from its post
paragraph content bucket get <bucket-id> --json
# Find a post's group without creating one (bucketId is null when there is none)
paragraph content bucket for-post <post-id> --json
# List every group, most recently active first
paragraph content bucket list --limit 50 --json
起草前先读取内容组,避免重复创建已有的版本。每个成员的 kind 会说明在哪里读取:post 使用 paragraph post get,content 使用 paragraph content get。kind 为 other 的成员属于 Paragraph 内容组,但 CLI 无法获取。
如果某项内容已与另一个帖子分组,系统会拒绝操作,而不是将其移动——请告知用户在应用中取消分组。从组中移除内容也需要在应用中完成。
出版物
paragraph publication get --id <slug-or-id-or-domain> --json
# Update settings (only provided fields change). The publication ID must
# match the publication that owns your API key — run `paragraph whoami` to
# look it up.
paragraph publication update <publication-id> --name "My Blog" --theme-color purple-600 --json
# Featured post: a post ID, or one of "latest" | "popular" | "disabled"
paragraph publication update <publication-id> --featured-post latest --json
# Pinned posts (replaces the existing list, max 50, IDs must belong to this publication)
paragraph publication update <publication-id> --pinned-post-ids id1,id2,id3 --json
# Owner email-notification toggles (key=value pairs).
# Allowed keys: newComment, newSubscriber, newPaidSubscriber, newContentCollected.
paragraph publication update <publication-id> --email-notifications newSubscriber=true,newComment=false --json
# Apply a full settings body from a JSON file. Explicit flags override file values.
paragraph publication update <publication-id> --from-json ./settings.json --json
搜索
paragraph search post --query "ethereum" --json
paragraph search blog --query "web3" --json
订阅者
paragraph subscriber list --limit 100 --json
paragraph subscriber count --publication <id> --json
paragraph subscriber add --email [email protected] --json
paragraph subscriber add --wallet 0x1234...abcd --json
paragraph subscriber import --csv ./subscribers.csv --json
# Remove (hard delete, irreversible — prompts for confirmation; use --yes to skip)
paragraph subscriber remove --email [email protected] --yes --json
paragraph subscriber remove --wallet 0x1234...abcd --yes --json
Coins
paragraph coin get --id <id-or-address> --json
paragraph coin popular --limit 10 --json
paragraph coin search --query "ethereum" --json
paragraph coin holders --id <id-or-address> --limit 50 --json
paragraph coin quote --id <id-or-address> --amount <wei> --json
用户
paragraph user get --id <user-id-or-wallet> --json
分析
针对出版物的分析架构运行只读 SQL。系统会自动限定为拥有 API 密钥的出版物——请勿在 WHERE 子句中添加博客筛选条件。
# Discover tables and columns
paragraph analytics schema --json
paragraph analytics schema --table post_analytics_summary --json
# Run a query
paragraph analytics query --sql "SELECT title, total_views, open_rate FROM post_analytics_summary ORDER BY total_views DESC LIMIT 5" --json
# Read SQL from a file or stdin
paragraph analytics query --file ./query.sql --json
echo "SELECT active_subscriber_count FROM blog_subscriber_counts" | paragraph analytics query --json
优先使用预聚合视图(post_analytics_summary、subscriber_engagement_scores、blog_subscriber_counts),而非原始表——这些视图的响应时间不到一秒,且能满足大多数报告需求。仅允许使用 SELECT/WITH,不得使用分号,最多返回 10,000 行,语句超时时间为 30s。
自定义邮件
从你的出版物向你指定的收件人列表发送一封一次性 Markdown 邮件。邮件会分别发送给每位收件人,并且必须附带退订页脚。
适用于:
- 向定向细分受众发送邮件——“给所有打开了我上一篇文章的人发邮件”“给我最活跃的 50 位订阅者发送跟进邮件”“联系这份精心筛选的 20 位读者名单”。通过
paragraph analytics query或paragraph subscriber list创建细分受众。 - 向作者本人发送通知——“订阅者达到 1,000 人时给我发邮件”“每周发送分析摘要”。如有需要,使用
paragraph whoami查询作者的邮箱。 - 联系非订阅者邮箱地址——一份会议联系人 CSV、媒体名单,或介绍朋友的朋友。收件人可以来自任何地方,不必列在
paragraph subscriber list中。(此前已退订的用户仍会被标记为suppressed。) - 重新联系不活跃的订阅者——“给过去 90 天内没有打开邮件的所有人发邮件。”通过
paragraph analytics query查询subscriber_engagement_scores或newsletter_metrics,找出相应细分受众。 - 发送草稿供少数协作者审阅——“把这份提案草稿发给我的 3 位共同作者征求反馈。”需要给出版物所有者以外的人发邮件时,使用此功能;
paragraph post test-email只会发送给所有者。
请勿将此功能用于群发新闻邮件。 若要向所有订阅者发送一篇文章,请使用 paragraph post publish --newsletter(或 paragraph post create ... --newsletter)。这是新闻邮件发送流程;email send 用于向你指定的定向名单发送邮件。
Paragraph 必须先批准出版物,才能使用自定义邮件;不符合条件的出版物会收到 403。每次调用最多可发送给 10,000 位收件人。发送前务必先向用户确认——邮件会实际发出,且无法撤回。
# Send (prompts for confirmation; pass --yes to skip)
paragraph email send --subject "Hello" --body "# Hi" --to [email protected] --yes --json
# Read body from a file
paragraph email send --subject "Update" --body-file ./body.md --to [email protected] --to [email protected] --yes --json
# Comma-separated recipients (--to is repeatable)
paragraph email send --subject "Update" --body-file ./body.md --to "[email protected],[email protected]" --yes --json
# Pipe body via stdin
cat body.md | paragraph email send --subject "Update" --to [email protected] --yes --json
# Dry run — preview the accepted/skipped split without sending
paragraph email send --subject "Update" --body "# Hi" --to [email protected] --dry-run --json
JSON 响应包含 accepted(已加入发送队列)和 skipped;每位被跳过的收件人都带有一个 reason:invalid(地址格式错误)、suppressed(此前已退订)或 scheduling_failed(队列失败——这是唯一可以安全重试的原因)。
身份验证
paragraph login --token <api-key>
echo "<api-key>" | paragraph login --with-token
paragraph whoami --json
paragraph logout
JSON 响应格式
分页列表(注意:CLI 会将条目包装在 data 下;REST API 和 SDK 则使用 items):
{
"data": [{ "id": "...", "title": "..." }],
"pagination": { "cursor": "abc123", "hasMore": true }
}
单个条目:
{ "id": "...", "title": "...", "markdown": "..." }
变更操作:
{ "id": "...", "status": "published" }
错误(输出到 stderr):
{ "error": "Not found.", "code": "NOT_FOUND", "status": 404 }
错误代码:UNAUTHORIZED、FORBIDDEN、NOT_FOUND、RATE_LIMITED、SERVER_ERROR、REQUEST_FAILED、CLIENT_ERROR、UNKNOWN。
常见用法
在一个流程中创建并发布
ID=$(paragraph post create --title "My Post" --file ./post.md --json | jq -r '.id')
paragraph post publish --id "$ID" --newsletter --json
将所有文章导出为 Markdown
paragraph post list --limit 100 --json | jq -r '.data[].id' | while read id; do
SLUG=$(paragraph post get --id "$id" --json | jq -r '.slug')
paragraph post get --id "$id" --field markdown > "${SLUG}.md"
done
分页获取所有订阅者
CURSOR=""
while true; do
RESULT=$(paragraph subscriber list --limit 100 ${CURSOR:+--cursor "$CURSOR"} --json)
echo "$RESULT" | jq '.data[]'
CURSOR=$(echo "$RESULT" | jq -r '.pagination.cursor // empty')
HAS_MORE=$(echo "$RESULT" | jq '.pagination.hasMore')
[ "$HAS_MORE" = "true" ] || break
done
环境变量
| 变量 | 用途 |
|---|---|
| PARAGRAPH_API_KEY | API 密钥(跳过登录) |
| PARAGRAPH_API_URL | 自定义 API 基础 URL |
| PARAGRAPH_NON_INTERACTIVE | 设为 1 以强制使用 CLI 模式 |
| CI | 设为 true 以强制使用 CLI 模式 |
故障排除
身份验证错误
如果命令失败并返回 UNAUTHORIZED:
# Check if logged in
paragraph whoami --json
# Re-authenticate
paragraph login --token <api-key>
CLI 会在收到 401 时自动清除已存储的凭据。如果凭据已被撤销,请重新登录。
速率限制
如果收到 RATE_LIMITED,请等待后重试。错误中会包含 429 状态码。避免紧密循环请求——分页请求之间应加入延迟。
命令挂起
如果命令似乎一直在等待,可能是在等待标准输入。请确保通过 --text、--file 或管道向标准输入传递内容。如果标准输入已通过管道连接但没有数据到达,CLI 会在 30 秒后超时。
安装后找不到 CLI
npm install -g @paragraph-com/cli
# Verify
npx paragraph --version