Skip to main content

general-purpose cli for atproto record operations

Project description

pdsx

general-purpose cli for atproto record operations

📚 documentation

installation

uv add pdsx
# or run directly
uvx pdsx --help
# or from GitHub (latest)
uvx --from git+https://github.com/zzstoatzz/pdsx pdsx --help

quick start

important: flags like -r, --handle, --password go BEFORE the command (ls, get, etc.)

# read anyone's posts (no auth needed)
uvx pdsx -r zzstoatzz.io ls app.bsky.feed.post -o json | jq -r '.[].text'

# update your bio (requires auth)
export ATPROTO_HANDLE=your.handle ATPROTO_PASSWORD=your-app-password
uvx pdsx edit app.bsky.actor.profile/self description='new bio'

features

  • crud operations for atproto records (list, get, create, update, delete)
  • batch operations: delete multiple records concurrently with progress tracking
  • blob upload: upload images, videos, and other binary content
  • cursor pagination: paginate through large collections
  • MCP server: expose operations via model context protocol for AI agents
  • optional auth: reads with --repo flag don't require authentication
  • shorthand URIs: use app.bsky.feed.post/abc123 when authenticated
  • multiple output formats: compact (default), json, yaml, table
  • unix-style aliases: ls, cat, rm, edit, touch/add
  • jq-friendly json output
  • python 3.10+, type-safe

MCP server

pdsx includes an MCP server for AI agent integration (e.g., claude code, cursor).

hosted instance

the easiest way to use pdsx with claude code:

# read-only access (no auth needed for public data)
claude mcp add-json pdsx '{"type": "http", "url": "https://pdsx-by-zzstoatzz.fastmcp.app/mcp"}'

# with authentication for write operations
claude mcp add-json pdsx '{
  "type": "http",
  "url": "https://pdsx-by-zzstoatzz.fastmcp.app/mcp",
  "headers": {
    "x-atproto-handle": "your.handle",
    "x-atproto-password": "your-app-password"
  }
}'

get an app password at: https://bsky.app/settings/app-passwords

custom PDS configuration

if you're running your own PDS, add the x-atproto-pds-url header:

claude mcp add-json pdsx '{
  "type": "http",
  "url": "https://pdsx-by-zzstoatzz.fastmcp.app/mcp",
  "headers": {
    "x-atproto-handle": "your.handle",
    "x-atproto-password": "your-app-password",
    "x-atproto-pds-url": "https://your-pds.example.com"
  }
}'

for local/stdio usage with a custom PDS:

ATPROTO_HANDLE=your.handle \
ATPROTO_PASSWORD=your-app-password \
ATPROTO_PDS_URL=https://your-pds.example.com \
pdsx-mcp
local/self-hosted

run the MCP server locally (requires pdsx[mcp] extra):

# install with mcp extra
uv add pdsx[mcp]

# stdio mode (for local development)
ATPROTO_HANDLE=your.handle ATPROTO_PASSWORD=your-app-password pdsx-mcp

# or run with uvx (no install needed)
uvx --from 'pdsx[mcp]' pdsx-mcp
available tools
tool auth required description
list_records only without repo list records in a collection
get_record only without repo get a specific record
create_record yes create a new record
update_record yes update an existing record
delete_record yes delete a record

all tools support jmespath filtering via the _filter parameter to reduce response size.

usage examples

read operations (no auth with -r)

# list records from any repo (note: -r goes BEFORE ls)
pdsx -r zzstoatzz.io ls app.bsky.feed.post --limit 5 -o json

# read someone's bio
pdsx -r zzstoatzz.io ls app.bsky.actor.profile -o json | jq -r '.[0].description'

pagination

# get first page (note: -r before ls, --cursor after)
pdsx -r zzstoatzz.io ls app.bsky.feed.post --limit 2

# output includes cursor if more pages exist, copy it for next command
# next page cursor: 3m5335qycpc2z

# get next page (use actual cursor from previous output)
pdsx -r zzstoatzz.io ls app.bsky.feed.post --limit 2 --cursor 3m5335qycpc2z

post with image (end-to-end)

# download a test image
curl -sL https://picsum.photos/200/200 -o /tmp/test.jpg

# upload image and capture blob reference
pdsx upload-blob /tmp/test.jpg
# copy the blob reference from output, example:
# {"$type":"blob","ref":{"$link":"bafkreif..."},"mimeType":"image/jpeg","size":6344}

# create post with uploaded image (paste your actual blob reference)
pdsx create app.bsky.feed.post \
  text='Posted via pdsx!' \
  'embed={"$type":"app.bsky.embed.images","images":[{"alt":"test image","image":{"$type":"blob","ref":{"$link":"PASTE_YOUR_CID_HERE"},"mimeType":"image/jpeg","size":6344}}]}'

write operations (auth required)

# update your bio
pdsx edit app.bsky.actor.profile/self description='Building with pdsx!'

# create a simple post
pdsx create app.bsky.feed.post text='Hello from pdsx!'

# delete a post (use the rkey from create output)
pdsx rm app.bsky.feed.post/PASTE_RKEY_HERE

batch operations

# delete multiple records (runs concurrently)
pdsx rm app.bsky.feed.post/abc123 app.bsky.feed.post/def456 app.bsky.feed.post/ghi789

# delete from file via stdin (the Unix way)
cat uris.txt | pdsx rm

# control concurrency (default: 10)
pdsx rm uri1 uri2 uri3 --concurrency 20

# fail-fast mode (stop on first error)
pdsx rm uri1 uri2 uri3 --fail-fast

note: when authenticated, use shorthand URIs (collection/rkey) instead of full AT-URIs (at://did:plc:.../collection/rkey)

output formats

both ls and cat/get support four output formats:

compact (default for ls)

app.bsky.feed.post (3 records)
3m4ryxwq5dt2i: {"created_at":"2025-11-04T07:25:17.061883+00:00","text":"..."}

json

pdsx -r zzstoatzz.io ls app.bsky.feed.post -o json | jq '.[].text'
pdsx -r zzstoatzz.io cat app.bsky.feed.post/3m5335qycpc2z -o json

yaml

pdsx -r zzstoatzz.io ls app.bsky.feed.post --limit 3 -o yaml
pdsx -r zzstoatzz.io cat app.bsky.actor.profile/self -o yaml

table (default for cat/get)

pdsx -r zzstoatzz.io ls app.bsky.feed.post --limit 5 -o table
pdsx -r zzstoatzz.io cat app.bsky.actor.profile/self  # default
development
git clone https://github.com/zzstoatzz/pdsx
cd pdsx
uv sync
uv run pytest
uv run ty check

license

mit

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pdsx-0.0.1a12.tar.gz (140.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pdsx-0.0.1a12-py3-none-any.whl (28.4 kB view details)

Uploaded Python 3

File details

Details for the file pdsx-0.0.1a12.tar.gz.

File metadata

  • Download URL: pdsx-0.0.1a12.tar.gz
  • Upload date:
  • Size: 140.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pdsx-0.0.1a12.tar.gz
Algorithm Hash digest
SHA256 1475b4533b63386b82819f6fe7f1d9835fb0fdc199d4a11ae0bff53424dabbad
MD5 b85ce8ec186c4c688b73092e7fb2bf3f
BLAKE2b-256 4a09ad53b8d8a7f987ac835e600f86aec68a30b71a70ce1ae54ce1269231791f

See more details on using hashes here.

File details

Details for the file pdsx-0.0.1a12-py3-none-any.whl.

File metadata

  • Download URL: pdsx-0.0.1a12-py3-none-any.whl
  • Upload date:
  • Size: 28.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pdsx-0.0.1a12-py3-none-any.whl
Algorithm Hash digest
SHA256 8a9df926f88e0aa88c956335c4cd2925ee47dae064d65e7686727efb46af8dc8
MD5 a16e6fd77af598d4130645b69f101636
BLAKE2b-256 0b390b12ff07d04ebf0c495a7e92bd8b5d2d6611d04d5500bf7ec14b997cc125

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page