Ruby CLI tool for accessing Bluesky API / ATProto
1# RatProto – Ruby ATProto Tool 🐀
2
3RatProto (`rat`) is a small command-line tool in Ruby for accessing the Bluesky API / AT Protocol.
4
5It builds on top of the existing ATProto Ruby gems:
6
7- [`minisky`](https://tangled.org/mackuba.eu/minisky/) — XRPC client
8- [`skyfall`](https://tangled.org/mackuba.eu/skyfall/) — firehose & Jetstream streaming
9- [`didkit`](https://tangled.org/mackuba.eu/didkit/) — DID & handle resolution
10
11> [!NOTE]
12> Part of ATProto Ruby SDK: [ruby.sdk.blue](https://ruby.sdk.blue)
13
14
15## Installation
16
17To run this tool, you need some reasonably recent version of Ruby installed – it should run on Ruby 2.6 and above, although it's recommended to use a version that still gets maintainance updates, i.e. currently 3.2+.
18
19An older version of Ruby (2.6.x) that should work is shipped with macOS versions 11.0 or later, a recent version of Ruby is also likely to be already installed on most Linux systems, or at least available through the OS's package manager. More installation options can be found on [ruby-lang.org](https://www.ruby-lang.org/en/downloads/).
20
21To install `rat`, run:
22
23```
24[sudo] gem install ratproto
25```
26
27## Features
28
29Currently implemented features/commands:
30
31- resolving DIDs & handles (`rat resolve`)
32- fetching & printing ATProto records (`rat fetch`)
33- streaming firehose / Jetstream events with optional filters (`rat stream`)
34
35
36## Resolving a DID or handle
37
38```
39rat resolve <did>|<handle>
40```
41
42Pass a DID or a handle (@ optional) to look up the given account's identity & print the DID document:
43
44```
45$ rat resolve atproto.com
46
47{
48 "@context": [
49 "https://www.w3.org/ns/did/v1",
50 "https://w3id.org/security/multikey/v1",
51 "https://w3id.org/security/suites/secp256k1-2019/v1"
52 ],
53 "id": "did:plc:ewvi7nxzyoun6zhxrhs64oiz",
54 "alsoKnownAs": [
55 "at://atproto.com"
56 ],
57 "verificationMethod": [
58 {
59 "id": "did:plc:ewvi7nxzyoun6zhxrhs64oiz#atproto",
60 "type": "Multikey",
61 "controller": "did:plc:ewvi7nxzyoun6zhxrhs64oiz",
62 "publicKeyMultibase": "zQ3shunBKsXixLxKtC5qeSG9E4J5RkGN57im31pcTzbNQnm5w"
63 }
64 ],
65 "service": [
66 {
67 "id": "#atproto_pds",
68 "type": "AtprotoPersonalDataServer",
69 "serviceEndpoint": "https://enoki.us-east.host.bsky.network"
70 }
71 ]
72}
73```
74
75
76## Fetching a record
77
78```
79rat fetch at://<did>/<collection>/<rkey>
80```
81
82Pass an at:// URI as the argument to fetch a single record from the user’s PDS:
83
84```
85% rat fetch at://did:plc:ragtjsm2j2vknwkz3zp4oxrd/app.bsky.feed.post/3lxxmboqmf22j
86
87{
88 "text": "a gatinha gorda",
89 "$type": "app.bsky.feed.post",
90 "embed": {
91 "$type": "app.bsky.embed.images",
92 "images": [
93 {
94 "alt": "Kit lying on the ground under the chair ",
95 "image": {
96 "$type": "blob",
97 "ref": {
98 "$link": "bafkreiebzsetrrvymvq6dvwma77zqprnv73ovgeqilanzi453dm6xart4q"
99 },
100 "mimeType": "image/jpeg",
101 "size": 963750
102 },
103 "aspectRatio": {
104 "width": 2000,
105 "height": 1500
106 }
107 }
108 ]
109 },
110 "langs": [
111 "en"
112 ],
113 "createdAt": "2025-09-03T21:48:05.910Z"
114}
115```
116
117## Streaming commit events
118
119```
120rat stream <firehose-host> [-j] [-r cursor] [-c collections] [-d dids]
121```
122
123Rat can connect to either a relay/PDS firehose:
124
125```
126rat stream bsky.network
127```
128
129or a Jetstream service (use `-j`):
130
131```
132rat stream -j jetstream2.us-east.bsky.network
133```
134
135You can also pass a cursor to connect with using `-r` / `--cursor` (tip: pass `-r0` to rewind as far back as the buffer allows).
136
137Once connected, you’ll see output like:
138
139```
140[2025-01-02T12:34:56+01:00] did:plc:xwnehmdpjluz2kv3oh2mfi47 :create app.bsky.feed.post 3mbjs5rgtin2z {"text":"hi", ...}
141[2025-01-02T12:34:57+01:00] did:plc:3mfkuhmjxd2wvz2e7nhl4poi :delete app.bsky.graph.follow 3mbjs5rghri23
142```
143
144Press Ctrl-C to disconnect.
145
146You can also apply the filtering options below (for Jetstream, these are passed to the server to apply filtering server-side via `wantedCollections` / `wantedDids` parameters):
147
148
149### Filtering by DID
150
151To print only events from given DID(s):
152
153```
154rat stream bsky.network -d did:plc:abcd1234,did:plc:xyz9999,...
155```
156
157You can either pass a comma-separated list as one parameter, or repeat `-d val` more than once.
158
159
160### Filtering by collection
161
162To print only records from given collection(s):
163
164```
165rat stream bsky.network -c app.bsky.feed.post -c app.bsky.actor.profile
166```
167
168
169## Credits
170
171Copyright © 2026 Kuba Suder ([@mackuba.eu](https://bsky.app/profile/did:plc:oio4hkxaop4ao4wz2pp3f4cr)).
172
173The code is available under the terms of the [zlib license](https://choosealicense.com/licenses/zlib/) (permissive, similar to MIT).
174
175Bug reports and pull requests are welcome 😎