bluesky

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
Everything runs through the shipped CLI
scripts/bluesky.py
— self-contained (
requests
+
Pillow
, both preinstalled in the sandbox). One call creates the session, auto-computes clickable facets (links, #hashtags, @mentions with correct UTF-8 byte offsets), and for image posts downloads the file, resizes/recompresses it to Bluesky's ~1 MB blob limit,
uploadBlob
s it and builds the
app.bsky.embed.images
embed — so there's no fragile
curl + jq + heredoc
to hand-assemble (the old inline recipe kept breaking on shell quoting, especially once an image + facets were involved).
Three connector credentials are injected:
$BLUESKY_HANDLE
(e.g.
name.bsky.social
),
$BLUESKY_APP_PASSWORD
(an App Password from Bluesky Settings → Privacy and Security → App Passwords, NOT the login password) and
$BLUESKY_SERVICE
(PDS base URL, default
https://bsky.social
). The CLI reads them from the env — never echo them.
sh
BSKY="$SKILL_DIR/scripts/bluesky.py"
python3 "$BSKY" whoami          # verify the session → {did, handle, service}
If
whoami
fails with
session_failed
/
AuthenticationRequired
, the identifier or App Password is wrong. The #1 cause is a bare handle — the CLI auto-appends
.bsky.social
to a bare username on the default PDS, but if it still fails the user must reconnect the connector with their full handle (
name.bsky.social
, a custom domain, a DID, or the account email) and a valid App Password.
所有操作都通过内置的CLI脚本
scripts/bluesky.py
完成 —— 该脚本独立运行(依赖
requests
Pillow
,二者已预安装在沙箱环境中)。单次调用即可创建会话,自动生成可点击的facets(链接、#话题标签、@提及,并计算正确的UTF-8字节偏移量);对于带图帖子,会自动下载图片、调整大小/压缩至Bluesky约1MB的blob限制、调用
uploadBlob
上传,并构建
app.bsky.embed.images
嵌入内容——无需手动编写脆弱的
curl + jq + heredoc
组合(旧版内联方案经常因shell引号问题失效,尤其是涉及图片和facets时)。
注入了三个连接器凭据:
$BLUESKY_HANDLE
(例如
name.bsky.social
)、
$BLUESKY_APP_PASSWORD
(来自Bluesky的设置→隐私与安全→应用密码,并非登录密码)以及
$BLUESKY_SERVICE
(PDS基础URL,默认值为
https://bsky.social
)。CLI会从环境变量中读取这些凭据——切勿回显它们。
sh
BSKY="$SKILL_DIR/scripts/bluesky.py"
python3 "$BSKY" whoami          # 验证会话 → {did, handle, service}
如果
whoami
返回
session_failed
/
AuthenticationRequired
错误,说明标识符或应用密码有误。最常见的原因是使用了不完整的handle——在默认PDS环境下,CLI会自动为纯用户名追加
.bsky.social
,但如果仍失败,用户必须重新配置连接器,提供完整的handle
name.bsky.social
、自定义域名、DID或账户邮箱)以及有效的应用密码。

Post — text, images and links in one call

发布帖子——文本、图片和链接一键完成

Confirm the text with the user before posting (it publishes as their real account). Text ≤ 300 graphemes. Clickable links / #hashtags / @mentions are turned into facets automatically — just write them in the text, no byte-offset math needed.
sh
undefined
发布前请与用户确认文本内容(帖子将以用户真实账号发布)。文本长度≤300个字符(按用户感知的字符数计算,表情符号算1个)。可点击的链接/#话题标签/@提及会自动转换为facets——只需在文本中正常书写,无需计算字节偏移量。
sh
undefined

plain text post

纯文本帖子

python3 "$BSKY" post --text "Hello Bluesky 👋 shipping with the AT Protocol"
python3 "$BSKY" post --text "Hello Bluesky 👋 shipping with the AT Protocol"

带图发送 / post WITH an image (URL or local path) — the image is downloaded,

带图发布(支持URL或本地路径)——图片会自动下载、调整大小以符合blob限制、上传并嵌入:

resized to fit the blob limit, uploaded and embedded automatically:

python3 "$BSKY" post
--text "Stop wiring 3 image APIs. One endpoint → posters, cards, mockups. https://platform.acedata.cloud/documents/openai-images-generations-integration #AI #API"
--image "https://cdn.acedata.cloud/xxxx.png" --alt "AI image API hero"
python3 "$BSKY" post
--text "Stop wiring 3 image APIs. One endpoint → posters, cards, mockups. https://platform.acedata.cloud/documents/openai-images-generations-integration #AI #API"
--image "https://cdn.acedata.cloud/xxxx.png" --alt "AI image API hero"

up to 4 images, each with its own --alt (paired by order)

最多支持4张图片,每张图片需对应一个--alt参数(按顺序配对)

python3 "$BSKY" post --text "gallery" --image a.png --alt "one" --image b.png --alt "two"

Multi-line text or lots of emoji? Skip shell-quoting headaches by writing the
text to a file and using `--text-file` (or pipe via `--text -`):

```sh
cat > /tmp/post.txt <<'EOF'
Line one 🎨

Line two with a link https://platform.acedata.cloud #AI
EOF
python3 "$BSKY" post --text-file /tmp/post.txt --image "https://cdn.acedata.cloud/xxxx.png"
Success prints
{"posted":true,"uri":"at://…","url":"https://bsky.app/profile/<handle>/post/<rkey>", ...}
. The
url
is the public, shareable link — hand it to the user verbatim.
python3 "$BSKY" post --text "gallery" --image a.png --alt "one" --image b.png --alt "two"

如果需要发布多行文本或大量表情符号?为避免shell引号问题,可将文本写入文件并使用`--text-file`参数(或通过管道符`--text -`传入):

```sh
cat > /tmp/post.txt <<'EOF'
Line one 🎨

Line two with a link https://platform.acedata.cloud #AI
EOF
python3 "$BSKY" post --text-file /tmp/post.txt --image "https://cdn.acedata.cloud/xxxx.png"
发布成功后会输出
{"posted":true,"uri":"at://…","url":"https://bsky.app/profile/<handle>/post/<rkey>", ...}
。其中
url
是公开可分享的链接——直接将其提供给用户即可。

List my recent posts + engagement

查看我的近期帖子及互动数据

sh
python3 "$BSKY" list --limit 20                    # default filter: posts_no_replies
python3 "$BSKY" list --limit 50 --filter posts_with_media
--filter
:
posts_no_replies
|
posts_with_replies
|
posts_with_media
|
posts_and_author_threads
.
--limit
max 100.
sh
python3 "$BSKY" list --limit 20                    # 默认筛选条件:posts_no_replies
python3 "$BSKY" list --limit 50 --filter posts_with_media
--filter
可选值:
posts_no_replies
|
posts_with_replies
|
posts_with_media
|
posts_and_author_threads
--limit
最大值为100。

Delete a post

删除帖子

sh
python3 "$BSKY" delete --uri "at://did:plc:xxxx/app.bsky.feed.post/3kabc123xyz"
Pass the full
at://…
post
uri
(from
list
or a prior
post
); the CLI extracts the
rkey
. An empty result /
deleted:true
is success.
sh
python3 "$BSKY" delete --uri "at://did:plc:xxxx/app.bsky.feed.post/3kabc123xyz"
传入完整的
at://…
格式帖子
uri
(来自
list
命令或之前发布帖子的返回结果);CLI会自动提取
rkey
。返回空结果或
deleted:true
即为删除成功。

Gotchas

注意事项

  • App Password, not account password: creating a session with the real login password may be rejected or trip 2FA. Always the App Password from Settings → App Passwords.
  • Facets & image resizing are automatic — the CLI computes link/#tag/@mention byte offsets and shrinks oversized images to the ~1 MB blob limit for you.
  • 300 graphemes, counted as user-perceived characters (emoji = 1).
  • Rate limits: the PDS rate-limits writes per account; space out bulk posts or you'll get
    429 {"error":"RateLimitExceeded"}
    .
  • Self-hosted PDS: if the user runs their own PDS,
    $BLUESKY_SERVICE
    points there; all XRPC calls target that host, not
    bsky.social
    .
  • The CLI creates a fresh short-lived session on every invocation, so an expiring
    accessJwt
    is never a concern — just run the command again.
  • 使用应用密码而非账户密码: 使用真实登录密码创建会话可能会被拒绝或触发二次验证。务必使用来自「设置→应用密码」的应用密码。
  • Facets与图片调整自动完成——CLI会自动计算链接/#话题标签/@提及的字节偏移量,并将过大的图片压缩至约1MB的blob限制。
  • 文本限制300个字符,按用户感知的字符数计算(表情符号算1个)。
  • 速率限制: PDS对每个账号的写入操作有速率限制;批量发布时需间隔一段时间,否则会返回
    429 {"error":"RateLimitExceeded"}
    错误。
  • 自托管PDS: 如果用户运行自己的PDS,
    $BLUESKY_SERVICE
    需指向该PDS地址;所有XRPC调用都会针对该主机,而非
    bsky.social
  • CLI每次调用都会创建一个新的短期会话,因此无需担心
    accessJwt
    过期——只需重新运行命令即可。

Record the output

记录输出结果

After you successfully publish and obtain the live result URL, call the built-in
publish_artifact
tool ONCE so the user can track this deliverable in My Outputs:
publish_artifact(kind="message", channel="bluesky", title="<title>", url="<the REAL returned URL>", status="delivered")
Use the real returned URL — never fabricate one. Call it once per published item, only after delivery is confirmed; skip it (or use
status="failed"
) if publishing failed. See
_shared/artifacts.md
.
成功发布并获取到实时结果URL后,调用内置的
publish_artifact
工具一次,以便用户在「我的输出」中跟踪该交付物:
publish_artifact(kind="message", channel="bluesky", title="<title>", url="<the REAL returned URL>", status="delivered")
请使用真实返回的URL——切勿伪造。每个发布的内容仅调用一次该工具,且仅在确认交付成功后调用;如果发布失败,请跳过调用(或使用
status="failed"
)。详情请查看
_shared/artifacts.md