A nano implementation of the AT Protocol for Python.
A nano implementation of the AT Protocol for Python.
pip install nanoatp
BskyAgent.login()
.export ATP_IDENTIFIER="foo.bsky.social"
export ATP_PASSWORD="password"
from nanoatp import BskyAgent, RichText
agent = BskyAgent("https://bsky.social")
agent.login()
# post a simple text
record = {"text": "Hello World!"}
response = agent.post(record)
print(response)
# create a RichText
rt = RichText("Hello @nanoatp.bsky.social, check out this link: https://huggingface.co/")
rt.detectFacets(agent)
print(rt.facets)
# upload an image
image = agent.uploadImage("example.png")
# post a RichText with an image
embed = {"$type": "app.bsky.embed.images", "images": [image]}
record = {"text": rt.text, "facets": rt.facets, "embed": embed}
response = agent.post(record)
print(response)
# upload an external link (create a link card with title, description and thumbnail)
uri = rt.facets[1]["features"][0]["uri"] # https://huggingface.co/
external = agent.uploadExternal(uri)
# post a RichText with an external link
embed = {"$type": "app.bsky.embed.external", "external": external}
record = {"text": rt.text, "facets": rt.facets, "embed": embed}
response = agent.post(record)
print(response)
See examples for more.
Log into a server using these APIs. You'll need an active session for most methods.
from nanoatp import BskyAgent
agent = BskyAgent("https://bsky.social")
# if you don't specify credentials,
# ATP_IDENTIFIER and ATP_PASSWORD environment variables will be used
agent.login("alice@mail.com", "hunter2")
The agent includes methods for many common operations, including:
# Feeds and content
agent.getPost(repo, rkey, cid)
agent.post(record)
agent.deletePost(postUri)
agent.uploadBlob(data, encoding)
agent.uploadImage(path, alt, encoding) # wrapper for uploadBlob
agent.uploadExternal(url) # wrapper for uploadBlob
# Identity
agent.resolveHandle(handle)
# Session management
agent.login(identifier, password)
Some records (ie posts) use the app.bsky.richtext
lexicon. At the moment richtext is only used for links and mentions, but it will be extended over time to include bold, italic, and so on.
ℹ️ Currently the implementation is very naive. I have not tested it with UTF-16 text.
from nanoatp import BskyAgent, RichText
agent = BskyAgent()
agent.login()
rt = RichText("Hello @nanoatp.bsky.social, check out this link: https://example.com")
rt.detectFacets(agent)
record = {"text": rt.text, "facets": rt.facets}
agent.post(record)
The methods above are convenience wrappers. It covers most but not all available methods.
The AT Protocol identifies methods and records with reverse-DNS names. You can use them on the agent as well:
res1 = agent._repo_createRecord(
agent.session["did"], # repo
"app.bsky.feed.post", # collection
{
"$type": "app.bsky.feed.post",
"text": "Hello, world!",
"createdAt": datetime.datetime.now(datetime.timezone.utc).isoformat().replace("+00:00", "Z")
}
)
export ATP_IDENTIFIER="foo.bsky.social"
export ATP_PASSWORD="password"
git clone https://github.com/susumuota/nanoatp.git
cd nanoatp
uv sync
source .venv/bin/activate
ptw . -s
MIT License. See LICENSE for details.
Susumu Ota
Just having fun with python and Bluesky's AT Protocol. Trying to build a simple CLI and enough of SDK to easily explore and collect my own Bluesky data
A small python library to post basic text and media to bsky.app via atproto's xrpc API.
A script for auto-deleting Bluesky posts
A site that measures the current percentage of Bluesky posts missing alt text
🌉 A bridge between decentralized social networks
💬 The social web translator
Your Brand Here!
50K+ engaged viewers every month
Limited spots available!
📧 Contact us via email🦋 Contact us on Bluesky