@kody/bluesky
README.md
150 lines · 5.9 KB · Markdown@kody/bluesky
Official Bluesky butterfly from Bluesky brand assets (bluesky_media_kit_logo_transparent_1.svg). Paths are unmodified. Bluesky® and the butterfly mark are trademarks of Bluesky Social PBC.
Intent
Give agents fork-ready Bluesky and AT Protocol helpers for profiles, posts, search, notifications, and guarded social writes. Posts should behave like posts created in the Bluesky UI, including clickable links and external cards with uploaded thumbnails.
This listing is meant to be forked. The live @kody/bluesky package does not share a handle. After you fork, store your handle in packageStorage and save your app password.
When To Use
- Verify Bluesky auth and read a profile, feed, thread, or notifications
- Resolve handles and search posts
- Call uncommon AT Protocol XRPC methods through one helper
- Draft or publish posts, likes, reposts, follows only after
confirm: true - Publish links with UTF-8 byte-indexed facets and optional external cards
Required setup
Auth is a Bluesky handle plus an app password. There is no Kody Bluesky OAuth integration.
1. App password secret
- Create an app password at https://bsky.app/settings/app-passwords. Do not use your account password. Do not paste the value into chat.
- Save it as
blueskyAppPasswordand approve the hosts below:
| Host | When to approve |
|---|---|
bsky.social | Session create and authenticated XRPC (default auth service) |
*.bsky.network | Account PDS hosts after session (for example *.host.bsky.network) |
Unauthenticated AppView reads (get-profile, get-author-feed, get-post-thread, and other GET request calls) default to https://public.api.bsky.app and do not need the secret. Session creation and authenticated calls use https://bsky.social. Pass service to override either.
2. Handle in package storage
After you fork (or when invoking your own copy), persist the default actor:
import { packageStorage } from 'kody:runtime'
await packageStorage().set('blueskyHandle', 'yourhandle.bsky.social')Or pass identifier / actor / handle on each call. Do not treat the live @kody/bluesky storage bucket as yours.
Smoke test
./smoke-test is safe before anyone saves credentials: it returns { ok: true, live: false } and the prefilled secret URL. After blueskyAppPassword and a handle are present, invoke the package so the secret placeholder resolves:
import { packages } from 'kody:runtime'
export default async function main() {
return await packages.invoke({
kodyId: 'bluesky',
exportName: './smoke-test',
})
}A live result reads the session profile and does not post.
dryRun
Mutating helpers never create a session when dryRun: true (or when confirm is omitted). Live writes require confirm: true after the user approves the exact text or target.
import createPost from 'kody:@kody/bluesky/create-post'
export default async function main() {
return await createPost({
text: 'Watch this: https://example.com',
externalCard: {
uri: 'https://example.com',
title: 'Example video',
description: 'A useful video.',
},
dryRun: true,
})
}create-post automatically adds clickable facets for HTTP(S) URLs unless callers provide facets or set autoLinkFacets: false. Pass externalCard with uri, title, description, and an optional thumbnailUrl to render a link preview. The helper fetches thumbnails and, when a Cloudinary image is over Bluesky's 1 MB blob limit, requests a fitted JPEG derivative before upload. Dry-runs report originalBytes, uploadBytes, mimeType, and fitted for the thumbnail instead of uploading a blob.
Exports
| Export | Description |
|---|---|
. | Package overview, auth hosts, and export map |
./smoke-test | Local setup check plus optional live profile read |
./request | Generic XRPC helper; mutating calls need dryRun / confirm |
./resolve-handle | Resolve a handle to a DID |
./get-profile | Read an actor profile (public AppView by default) |
./search-posts | Search posts (authenticated) |
./get-author-feed | Read an author feed |
./get-post-thread | Read a post thread |
./list-notifications | List authenticated notifications |
./create-post | Preview or create a post |
./delete-post | Preview or delete a post |
./like-post | Preview or like a post |
./repost | Preview or repost |
./follow | Preview or follow an actor |
./unfollow | Preview or unfollow |
./default-handle | Read the stored handle |
./migrate-from-values | Copy a leftover user value into package storage |
Examples
Public profile read (no secret):
import getProfile from 'kody:@kody/bluesky/get-profile'
export default async function main() {
return await getProfile({ actor: 'bsky.app' })
}Preview a post, then publish only after confirmation:
import createPost from 'kody:@kody/bluesky/create-post'
export default async function main() {
const preview = await createPost({
text: 'Hello from Kody',
dryRun: true,
})
// After the user confirms the exact text:
return await createPost({
text: 'Hello from Kody',
confirm: true,
})
}Notes
- This package is not affiliated with or endorsed by Bluesky Social PBC.
- Fork first. Platform
@kody/blueskystorage is shared by the official listing, not a personal account. migrate-from-valuesexists only for leftovervalue_get('blueskyHandle')rows. New setups should writepackageStoragedirectly.