AT Protocol Tools Guide#
This guide demonstrates how to use the example tools together to explore the AT Protocol ecosystem. We'll walk through a complete workflow: finding interesting posts in the firehose, investigating user identities, and inspecting their repositories.
Prerequisites#
Build all examples:
dune build examples/
Set up your credentials for bsky_bot (required for authenticated operations):
export BSKY_USER="yourhandle.bsky.social"
export BSKY_PASS="xxxx-xxxx-xxxx-xxxx" # App password from Settings > App Passwords
Overview of Tools#
| Tool | Purpose |
|---|---|
feed_generator |
Subscribe to the firehose and filter events |
identity_tool |
Resolve handles/DIDs and verify identities |
repo_inspector |
Download and explore user repositories |
bsky_bot |
Interact with Bluesky (post, timeline, profiles) |
Step 1: Find Interesting Posts with feed_generator#
Start by subscribing to the firehose and filtering for posts containing a keyword of interest. Let's look for posts about "ocaml":
`dune exec examples/feed_generator/feed_generator.exe -- \
--filter posts \
--keyword "ocaml" \
--limit 5 \
--content`
Example output:
Feed Generator
==============
Type filter: posts
Keyword: "ocaml"
Connecting to wss://bsky.network/xrpc/com.atproto.sync.subscribeRepos...
Connected!
#commit seq=12345678 repo=did:plc:abc123xyz456
+app.bsky.feed.post/3abc123 "Just discovered OCaml! The type system is amazing..."
#commit seq=12345680 repo=did:plc:def789uvw012
+app.bsky.feed.post/3def456 "Working on my first OCaml project today..."
--- Stats: 1523 events (5 matched) | seq=12345700 | 8.2s | 185.7 evt/s ---
Key information extracted:
did:plc:abc123xyz456- The DID of a user who posted about OCamlapp.bsky.feed.post/3abc123- The record key of their post
Generating a Feed Skeleton#
If you want to build a custom feed, use the --skeleton flag to output a feed skeleton:
dune exec examples/feed_generator/feed_generator.exe -- \
--filter posts \
--keyword "rust" \
--limit 20 \
--skeleton
This outputs a JSON structure you can serve via app.bsky.feed.getFeedSkeleton:
{
"feed": [
{"post": "at://did:plc:xxx/app.bsky.feed.post/abc123"},
{"post": "at://did:plc:yyy/app.bsky.feed.post/def456"}
]
}
Monitoring Multiple Event Types#
Watch for posts, likes, and follows simultaneously:
dune exec examples/feed_generator/feed_generator.exe -- \
--filter posts,likes,follows \
--limit 50
Step 2: Verify User Identity with identity_tool#
Now that we have a DID from the firehose, let's verify the identity and get more details about the user.
Verify Identity (Bidirectional)#
The default mode verifies that the DID and handle point to each other:
dune exec examples/identity_tool/identity_tool.exe -- did:plc:abc123xyz456
Example output:
PASSED
DID: did:plc:abc123xyz456
Handle: alice.bsky.social
Key: zQ3shXjHeiBuRCKmM...
PDS: https://morel.us-east.host.bsky.network
This tells us:
- The identity verification passed (handle and DID are correctly linked)
- The user's handle is
alice.bsky.social - Their signing key (for verifying commits)
- Their PDS (Personal Data Server) URL
Resolve Handle to DID#
If you have a handle and need the DID:
dune exec examples/identity_tool/identity_tool.exe -- -H alice.bsky.social
Output:
Handle: alice.bsky.social
DID: did:plc:abc123xyz456
Resolve DID to Full Document#
Get the complete DID document with all services and keys:
dune exec examples/identity_tool/identity_tool.exe -- -d did:plc:abc123xyz456
Output:
DID: did:plc:abc123xyz456
Handle: at://alice.bsky.social
Key: zQ3shXjHeiBuRCKmM... (Multikey)
Service: AtprotoPersonalDataServer -> https://morel.us-east.host.bsky.network
Step 3: Inspect User Repository with repo_inspector#
With the verified DID, we can download and inspect the user's entire repository. The tool automatically resolves the user's PDS from their DID document.
Repository Summary#
Get an overview of the repository:
dune exec examples/repo_inspector/repo_inspector.exe -- did:plc:abc123xyz456
Example output:
Repository Inspector
====================
Resolving PDS for did:plc:abc123xyz456...
PDS: https://morel.us-east.host.bsky.network
Fetching https://morel.us-east.host.bsky.network/xrpc/com.atproto.sync.getRepo?did=did:plc:abc123xyz456...
CAR Header
----------
Version: 1
Roots: 1
- bafyreib...
Blocks: 1234
Commit
------
DID: did:plc:abc123xyz456
Version: 3
Rev: 3la7j2xyz...
Data: bafyreic...
Collections
-----------
app.bsky.feed.post: 456
app.bsky.feed.like: 789
app.bsky.graph.follow: 123
app.bsky.actor.profile: 1
Total records: 1369
List Collections#
See all collections with record counts:
dune exec examples/repo_inspector/repo_inspector.exe -- \
did:plc:abc123xyz456 --collections
Browse Records#
View individual records:
dune exec examples/repo_inspector/repo_inspector.exe -- \
did:plc:abc123xyz456 --records --limit 10
Output:
Records
-------
app.bsky.feed.post/3abc123
CID: bafyreig...
Text: Just discovered OCaml! The type system is amazing...
app.bsky.feed.post/3def456
CID: bafyreih...
Text: Working on my second OCaml project...
... and 454 more
Filter by Collection#
View only posts:
dune exec examples/repo_inspector/repo_inspector.exe -- \
did:plc:abc123xyz456 --records --collection app.bsky.feed.post --limit 20
View only follows:
dune exec examples/repo_inspector/repo_inspector.exe -- \
did:plc:abc123xyz456 --records --collection app.bsky.graph.follow --limit 20
Verify Commit Signature#
Check the repository commit signature:
dune exec examples/repo_inspector/repo_inspector.exe -- \
did:plc:abc123xyz456 --verify
Skip PDS Resolution#
If you already know the PDS URL (from identity_tool or a previous run), you can skip the resolution step:
dune exec examples/repo_inspector/repo_inspector.exe -- \
did:plc:abc123xyz456 --pds https://morel.us-east.host.bsky.network
Step 4: Get User Profile with bsky_bot#
For a more user-friendly view, use bsky_bot to get the profile (requires authentication):
dune exec examples/bsky_bot/bsky_bot.exe -- \
--user "$BSKY_USER" \
--password "$BSKY_PASS" \
--profile alice.bsky.social
Output:
Logged in as yourhandle.bsky.social
Handle: @alice.bsky.social
DID: did:plc:abc123xyz456
Name: Alice
Bio: OCaml enthusiast and functional programming advocate
Followers: 1234
Following: 567
Posts: 456
View Your Timeline#
See recent posts from people you follow:
dune exec examples/bsky_bot/bsky_bot.exe -- \
--user "$BSKY_USER" \
--password "$BSKY_PASS" \
--timeline --limit 10
Follow a User#
Follow someone using their DID (obtained from identity_tool or feed_generator):
dune exec examples/bsky_bot/bsky_bot.exe -- \
--user "$BSKY_USER" \
--password "$BSKY_PASS" \
--follow did:plc:abc123xyz456
Complete Workflow Example#
Here's a complete example workflow to find OCaml enthusiasts and explore their content:
#!/bin/bash
# 1. Find users posting about OCaml
echo "=== Finding OCaml posts ==="
dune exec examples/feed_generator/feed_generator.exe -- \
--filter posts --keyword "ocaml" --limit 3 --json 2>/dev/null | \
head -3
# Let's say we found: did:plc:z72i7hdynmk6r22z27h6tvur
DID="did:plc:z72i7hdynmk6r22z27h6tvur"
# 2. Verify the identity
echo -e "\n=== Verifying identity ==="
dune exec examples/identity_tool/identity_tool.exe -- "$DID"
# 3. Get their handle from the verification and look up their profile
HANDLE="jay.bsky.social" # Extracted from step 2
echo -e "\n=== Getting profile ==="
dune exec examples/bsky_bot/bsky_bot.exe -- \
--user "$BSKY_USER" --password "$BSKY_PASS" \
--profile "$HANDLE"
# 4. Inspect their repository
echo -e "\n=== Repository overview ==="
dune exec examples/repo_inspector/repo_inspector.exe -- "$DID"
# 5. See their recent posts
echo -e "\n=== Recent posts ==="
dune exec examples/repo_inspector/repo_inspector.exe -- \
"$DID" --records --collection app.bsky.feed.post --limit 5
Advanced Usage#
JSON Output for Scripting#
The feed_generator supports JSON output for integration with other tools:
dune exec examples/feed_generator/feed_generator.exe -- \
--filter posts --keyword "atproto" --limit 5 --json --content
You can pipe this to jq for further processing:
dune exec examples/feed_generator/feed_generator.exe -- \
--filter posts --limit 10 --json 2>/dev/null | \
jq -r '.repo' | sort | uniq
Resume from Cursor#
If you need to resume from a specific point in the firehose:
dune exec examples/feed_generator/feed_generator.exe -- \
--cursor 1234567890 --limit 100
Monitoring Identity Changes#
Watch for handle changes and identity updates:
dune exec examples/feed_generator/feed_generator.exe -- \
--filter identities,handles --limit 20
Watching Account Events#
Monitor account activations and deactivations:
dune exec examples/feed_generator/feed_generator.exe -- \
--filter accounts --limit 10
Architecture Overview#
+-------------------+
| Bluesky Relay |
| bsky.network |
+-------------------+
|
| WebSocket (firehose)
v
+-------------------+
| feed_generator |
| (filter events) |
+-------------------+
|
| DID extracted
v
+-------------------+ +-------------------+ +-------------------+
| identity_tool |<---->| PLC Directory | | User's PDS |
| (resolve/verify) | | DID Documents | | |
+-------------------+ +-------------------+ +-------------------+
| ^
| DID verified |
v |
+-------------------+ |
| repo_inspector |------------------------------------------+
| (download & parse)| com.atproto.sync.getRepo
+-------------------+
+-------------------+
| bsky_bot |-------> Authenticated XRPC calls
| (social actions) | (post, timeline, profile, follow)
+-------------------+
Troubleshooting#
Connection Errors#
If the firehose connection fails:
- Check your internet connection
- The relay at
bsky.networkmay be temporarily unavailable - Try again after a few seconds
Identity Resolution Failures#
If identity verification fails:
- The handle may have changed recently (DNS propagation delay)
- The DID document may be temporarily unavailable
- Try resolving the handle and DID separately to diagnose
Large Repositories#
For users with many records:
- Use
--limitto restrict the number of records shown - Use
--collectionto filter to specific record types - Repository download may take several seconds for active users
Next Steps#
- Build a custom feed generator using
feed_generatoras a template - Create a bot that responds to mentions using
bsky_bot - Build analytics tools using
repo_inspectorto analyze user behavior - Implement identity verification in your applications using
identity_tool
See the individual README files in each example directory for more details: