> ## Documentation Index
> Fetch the complete documentation index at: https://pdsx.zzstoatzz.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Addressing

> how pdsx locates and references records using AT-URIs and DIDs

## the addressing problem

to read or write a record, pdsx needs to know:

1. which repository contains it
2. which collection within that repository
3. which specific record (if applicable)

[ATProto](https://atproto.com/guides/overview) solves this with **[AT-URIs](https://atproto.com/specs/at-uri-scheme)** and **[DIDs](https://atproto.com/specs/did)**.

## AT-URI format

AT-URIs identify records using this structure:

```
at://AUTHORITY/COLLECTION/RKEY
```

example:

```
at://did:plc:44ybard66vv44zksje25o7dz/app.bsky.feed.post/3jwdwj2ctlk26
^--^ ^------------ authority --------^ ^--- collection ---^ ^-- rkey --^
scheme        (repository)
```

components:

* **scheme**: always `at://`
* **authority**: DID or [handle](https://atproto.com/specs/handle) identifying the repository
* **collection**: NSID of the collection (optional)
* **rkey**: record key within collection (optional)

## authority: DID vs handle

### using DIDs

```
at://did:plc:44ybard66vv44zksje25o7dz/app.bsky.feed.post/3jwdwj2ctlk26
```

DIDs are:

* **permanent**: never change
* **decentralized**: not controlled by any provider
* **portable**: work even if user changes PDS
* **cryptographic**: tied to signing keys

**best for**: durable references, long-term storage

### using handles

```
at://zzstoatzz.io/app.bsky.feed.post/3jwdwj2ctlk26
```

handles are:

* **human-readable**: easier to type/remember
* **changeable**: user can update their handle
* **reassignable**: if abandoned, someone else can claim it
* **DNS/HTTP-based**: resolved via DNS or .well-known

**best for**: user-facing displays, temporary references

**critical limitation**: if user changes handle, handle-based URIs break or point to wrong repository.

## how pdsx resolves addresses

### with -r flag (handle)

```bash theme={null}
pdsx -r zzstoatzz.io ls app.bsky.feed.post
```

resolution flow:

1. resolve handle → DID
   * try DNS: `_atproto.zzstoatzz.io` TXT record
   * fallback to HTTPS: `https://zzstoatzz.io/.well-known/atproto-did`
2. resolve DID → PDS URL
   * fetch DID document
   * extract PDS endpoint
3. query PDS for records
4. return results

### with -r flag (DID)

```bash theme={null}
pdsx -r did:plc:44ybard66vv44zksje25o7dz ls app.bsky.feed.post
```

resolution flow:

1. skip handle resolution (already have DID)
2. resolve DID → PDS URL
3. query PDS
4. return results

### without -r flag (authenticated)

```bash theme={null}
pdsx ls app.bsky.feed.post
```

uses authenticated session:

1. already authenticated with PDS
2. session knows your DID
3. query your own repository
4. return results

## shorthand URIs in pdsx

<Note>
  **IMPORTANT**: Shorthand URIs (`collection/rkey`) only work when you have an active authenticated session. Without authentication, you must use full AT-URIs (`at://authority/collection/rkey`). If you see an "invalid URI format" error, this is likely why.
</Note>

when authenticated, pdsx supports shorthand:

### full URI

```bash theme={null}
pdsx get at://did:plc:your-did/app.bsky.feed.post/3jwdwj2ctlk26
```

### shorthand (when authenticated)

```bash theme={null}
pdsx get app.bsky.feed.post/3jwdwj2ctlk26
```

pdsx automatically:

* uses your DID from session
* constructs full URI
* executes operation

this only works for **your own repository** - you're authenticated to it.

## did document structure

dids resolve to **did documents** that contain:

```json theme={null}
{
  "id": "did:plc:44ybard66vv44zksje25o7dz",
  "alsoKnownAs": ["at://zzstoatzz.io"],
  "verificationMethod": [
    {
      "id": "#atproto",
      "type": "Multikey",
      "controller": "did:plc:44ybard66vv44zksje25o7dz",
      "publicKeyMultibase": "..."
    }
  ],
  "service": [
    {
      "id": "#atproto_pds",
      "type": "AtprotoPersonalDataServer",
      "serviceEndpoint": "https://bsky.social"
    }
  ]
}
```

key fields pdsx uses:

* **service**: which pds hosts this repository
* **alsoKnownAs**: current handle (for verification)
* **verificationMethod**: public keys (for cryptographic verification)

## pds discovery

pdsx finds the pds hosting a repository:

1. resolve authority (handle or did) → did
2. fetch did document from plc directory
3. extract `service` entry with type `AtprotoPersonalDataServer`
4. use `serviceEndpoint` as pds url

example:

```
did:plc:44ybard66vv44zksje25o7dz
  → did document
  → service endpoint: https://bsky.social
  → pdsx connects to https://bsky.social
```

## --pds flag

pdsx lets you override pds discovery:

```bash theme={null}
pdsx --pds https://my-pds.example.com ls app.bsky.feed.post
```

useful for:

* testing local pds
* using non-standard pds
* debugging

**note**: authentication must still be with that specific pds.

## why this addressing model matters

### portability

if user migrates pds:

1. update did document → new service endpoint
2. did-based uris still work
3. handle-based uris still work (if handle unchanged)
4. pdsx follows did document to find new pds

### federation

different users on different pds instances:

* [alice@pds1.com](mailto:alice@pds1.com) has did:plc:alice
* [bob@pds2.com](mailto:bob@pds2.com) has did:plc:bob
* pdsx can read both repositories
* resolves each did → correct pds

### handles as aliases

handles are just friendly names:

* did is permanent identity
* handle can change
* handle can be reassigned
* did document links them

## authentication and addressing

### reading public records

```bash theme={null}
pdsx -r other-user.handle ls app.bsky.feed.post
```

no auth needed:

* pdsx resolves handle → did → pds
* queries pds as anonymous client
* pds returns public records

### writing to own repository

```bash theme={null}
export ATPROTO_HANDLE=your.handle
export ATPROTO_PASSWORD=your-password
pdsx create app.bsky.feed.post text='hello'
```

auth flow:

1. pdsx creates session with pds (using credentials)
2. pds validates credentials
3. pds returns session token + your did
4. pdsx uses session for subsequent requests
5. pds ensures you're writing to your own repository

### cross-repository references

when creating a record that references another repository's record:

```bash theme={null}
pdsx create app.bsky.feed.like \
  subject='at://other-user.handle/app.bsky.feed.post/abc123'
```

pdsx:

* doesn't need auth to other-user's repository
* just includes their uri in your record
* stores in your repository
* reference points across repositories

## uri validation

pdsx performs minimal uri validation:

valid formats:

```
at://authority/collection/rkey      # full
at://authority/collection            # collection-level
at://authority                       # repository-level
collection/rkey                      # shorthand (if authenticated)
```

invalid formats:

```
at://authority/invalid nsid/rkey    # spaces not allowed
authority/collection/rkey            # missing scheme
at://authority/rkey                  # missing collection
```

## why understanding addressing matters for pdsx

**-r flag specifies repository**: can be handle or did

```bash theme={null}
pdsx -r zzstoatzz.io ls collection     # handle
pdsx -r did:plc:abc123 ls collection  # did
```

**shorthand requires auth**: only works for your own repository

```bash theme={null}
pdsx get collection/rkey              # needs auth
```

**full uris are more durable**: use dids, not handles

```bash theme={null}
# durable
at://did:plc:abc123/collection/rkey

# fragile (if handle changes)
at://user.handle/collection/rkey
```

**pds is discovered automatically**: unless overridden with --pds

## from concept to command

these addressing concepts translate directly to pdsx usage:

**reading with handle**:

```bash theme={null}
pdsx -r zzstoatzz.io ls app.bsky.feed.post
```

pdsx resolves handle → DID → PDS → fetches records

**reading with DID** (more durable):

```bash theme={null}
pdsx -r did:plc:44ybard66vv44zksje25o7dz ls app.bsky.feed.post
```

pdsx finds PDS from DID document → fetches records

**shorthand (authenticated only)**:

```bash theme={null}
pdsx get app.bsky.feed.post/3jwdwj2ctlk26
pdsx edit app.bsky.actor.profile/self description='new bio'
```

pdsx uses `client.me.did` from session to construct full URI

## further reading

* [at-uri specification](https://atproto.com/specs/at-uri-scheme)
* [did specification](https://atproto.com/specs/did)
* [handle resolution](https://atproto.com/specs/handle)
* [pds service](https://atproto.com/specs/atp)
