bluesky-social/goat
{ "createdAt": "2025-08-13T01:38:12Z", "defaultBranch": "main", "description": "Go AT protocol CLI tool", "fullName": "bluesky-social/goat", "homepage": null, "language": "Go", "name": "goat", "pushedAt": "2025-10-22T04:36:12Z", "stargazersCount": 85, "topics": [], "updatedAt": "2025-11-27T06:27:34Z", "url": "https://github.com/bluesky-social/goat"}goat: Go AT protocol CLI tool
Section titled “goat: Go AT protocol CLI tool”This is a re-implementation of adenosine-cli in golang.
Install
Section titled “Install”If you have the Go toolchain installed and configured correctly, you can directly build and install the tool for your local account:
go install github.com/bluesky-social/goat@latestA more manual way to install is:
git clone https://github.com/bluesky-social/goatgo build .sudo cp goat /usr/local/binThe intention is to also provide a Homebrew “cask” and Debian/Ubuntu packages.
goat is relatively self-documenting via help pages:
goat --helpgoat bsky -hgoat help bsky# etcMost commands use public APIs are don’t require authentication. Some commands, like creating records, require an atproto account. You can log in using an “app password” with goat account login -u <handle> -p <app-password>.
WARNING: goat will store both the app password and authentication tokens in the current users home directory, in cleartext. goat logout will wipe the file. Intention is to eventually support configuration via environment variables to keep sensitive state in a password manager or otherwise not-cleartext-on-disk.
Some commands output JSON, and you can use tools like jq to process them.
Examples
Section titled “Examples”Resolve an account’s identity in the network:
$ goat resolve wyden.senate.gov{ "id": "did:plc:ydtsvzzsl6nlfkmnuooeqcmc", "alsoKnownAs": [ "at://wyden.senate.gov" ], "verificationMethod": [ { "id": "did:plc:ydtsvzzsl6nlfkmnuooeqcmc#atproto", "type": "Multikey", "controller": "did:plc:ydtsvzzsl6nlfkmnuooeqcmc", "publicKeyMultibase": "zQ3shuMW7q4KBdsFcdvebGi2EVv8KcqS24tF9Pg7Wh5NLB2NM" } ], "service": [ { "id": "#atproto_pds", "type": "AtprotoPersonalDataServer", "serviceEndpoint": "https://shimeji.us-east.host.bsky.network" } ]}List record collection types for an account:
$ goat ls -c dril.bsky.socialapp.bsky.actor.profileapp.bsky.feed.postapp.bsky.feed.repostapp.bsky.graph.followchat.bsky.actor.declarationFetch a record from the network as JSON:
$ goat get at://dril.bsky.social/app.bsky.feed.post/3kkreaz3amd27{ "$type": "app.bsky.feed.post", "createdAt": "2024-02-06T18:15:19.802Z", "langs": [ "en" ], "text": "I do not Fucking recall them asking the blue sky elders permission to open registration to commoners ."}Make a public snapshot of your account:
$ goat repo export jay.bsky.teamdownloading from https://morel.us-east.host.bsky.network to: jay.bsky.team.20240811183155.car
$ downloading blobs to: jay.bsky.team_blobsjay.bsky.team_blobs/bafkreia2x4faux5y7v7v54yl5ebkbaek7z7nhmsd4cooubz3yj4zox34cq downloadedjay.bsky.team_blobs/bafkreia3qgbww7odprmysd6jcyxoh5sczkwoxinnmzpsp73gs623fqfm3a downloadedjay.bsky.team_blobs/bafkreia3rgnywdrysy65vid42ulyno2cybxhxrn3ragm7cw3smmsxzvbs4 downloaded[...]Show PLC history for a single account, or make a snapshot of all PLC records (this takes a while), or monitor new ops:
$ goat plc history atproto.com[...]
$ goat plc dump | pv -l | gzip > plc_snapshot.json.gz[...]
$ goat plc dump --cursor now --tail[...]Verify syntax and generate TIDs:
$ goat syntax handle check xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8svalid
$ goat syntax rkey check dHJ1ZQ==error: recordkey syntax didn't validate via regex
$ goat syntax tid inspect 3kzifvcppte22Timestamp (UTC): 2024-08-12T02:08:03.29ZTimestamp (Local): 2024-08-11T19:08:03-07:00ClockID: 0uint64: 0x187dcbda2b5ca800The firehose commands subscribes to the repo commit stream from a Relay. The default stream outputs event metadata, but doesn’t include record blocks (bytes). The --ops variant will unpack records and output one line per record operation (instead of one line per commit event), and includes the record values themselves. Some example invocations:
# possible handle updates$ goat firehose --account-events | jq .payload.handle[...]
# text of posts (empty lines for post-deletions)$ goat firehose - app.bsky.feed.post --ops | jq .record.text[...]
# sample ratio of languages in current posts$ goat firehose --ops -c app.bsky.feed.post | head -n100 | jq .record.langs[0] -c | sort | uniq -c | sort -nr 51 "en" 33 "ja" 7 null 3 "pt" 2 "ko" 1 "th" 1 "id" 1 "es" 1 "am"A minimal bsky posting interface, requires account login:
$ goat bsky post "hello from goat"License
Section titled “License”This project is dual-licensed under MIT and Apache 2.0 terms:
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.