Skip to content

Implemented endpoints

Cirrus implements the XRPC methods required to run a single-user PDS. Methods outside that scope are proxied to the Bluesky AppView using a service JWT signed by the account.

A method appears here if Cirrus serves it directly from its own code. The proxied methods (most app.bsky.* reads) reach the same endpoints they would for an account on bsky.social; the Worker forwards the request and returns the response.

The status column uses:

  • ✅ — implemented and exercised in production.
  • 🟡 — implemented as a stub (returns a sensible default but does not do real work).
  • ❌ — not implemented locally. The Worker falls through to the auto-proxy and forwards to the AppView, which will usually reject the call. Cirrus does not return 501.

Repository read/write operations.

MethodStatusNotes
describeRepoLists collections and the DID document.
getRecordSingle record by URI.
listRecordsPaginated, cursor support, reverse order.
createRecordValidates against the loaded lexicon.
putRecordSame validation.
deleteRecord
applyWritesBatch create/put/delete in a single commit.
uploadBlob60 MB hard limit. Streams to R2.
importRepoAccepts a CAR file upload. Used during migration.
listMissingBlobsLists blobs referenced by records but not yet uploaded.

Federation and replication.

MethodStatusNotes
getRepoStreams a CAR export.
getRepoStatusActive state and current revision.
listReposSingle-user PDS returns only the local account.
getLatestCommitLatest commit CID and revision.
getBlocksCAR file with requested blocks.
listBlobsPaginated, with cursor.
getBlobStreams directly from R2.
getRecordSingle record by CID.
subscribeReposWebSocket firehose. CBOR frames.

Server-level metadata and session management.

MethodStatusNotes
describeServerCapabilities, supported auth methods.
createSessionAccount password or app password. Issues JWT pair.
refreshSessionStateless refresh.
getSession
deleteSessionStateless (clears refresh on client).
createAppPassword
listAppPasswords
revokeAppPassword
activateAccount
deactivateAccount
getAccountStatusActivation state, metrics.
checkAccountStatus
getServiceAuthIssues service JWTs for AppView callbacks.
requestEmailUpdate🟡Stub.
updateEmail🟡Stub.
requestEmailConfirmation🟡Stub.
createAccountSingle-user PDS — account is created by pds init. Falls through to the AppView proxy.
deleteAccountNot needed for single-user PDS. Falls through to the AppView proxy.

The unimplemented server methods are multi-user/operator features (creating accounts, password reset emails, admin invitations) that are not relevant to a single-user deployment. Cirrus does not return 501 for them — the request is forwarded to the AppView, which will typically reject it.

Identity resolution.

MethodStatusNotes
resolveHandleReturns the local DID for the local handle. Other handles fall through to the AppView proxy.
requestPlcOperationSignatureUsed by the outbound migration flow.
signPlcOperationSigns a PLC operation with the account’s signing key.

The CLI (pds identity, pds migrate) drives outbound migration on top of these endpoints. Other identity methods (submitPlcOperation, updateHandle, getRecommendedDidCredentials) are not registered locally and fall through to the AppView proxy.

Bluesky AppView surface. Most app.bsky.* methods are proxied to api.bsky.app. The exceptions are stored locally:

MethodStatusNotes
actor.getPreferencesStored in the Durable Object.
actor.putPreferences
ageassurance.getState🟡Returns assured. Stub.

Everything else under app.bsky.* (feeds, profiles, notifications, search) is proxied. The proxy attaches a service JWT signed by the account key.

For any XRPC method not in the lists above, Cirrus:

  1. Mints a service JWT with the account DID as the issuer, did:web:api.bsky.app as the audience, and the called method’s NSID as the lxm claim.
  2. Forwards the request to https://api.bsky.app with Authorization: Bearer <service-jwt>.
  3. Returns the AppView’s response unmodified.

This is what makes the Bluesky app work end-to-end against a Cirrus PDS without Cirrus needing to implement social-graph queries.

OAuth endpoints are not XRPC methods; they live under /oauth/* and /.well-known/oauth-authorization-server. See OAuth 2.1 surface.