Check your hole in the ground. Bagend is a portability and backup readiness checker for atproto accounts.

Files
README.md

Bagend #

Check your hole in the ground.

Bagend checks how ready you are to move your atproto account to another host. It gives you a score and points out potential problems with your identity and data.

atproto is the protocol behind Bluesky. It separates your identity from your host, which makes it possible to move servers while keeping your identity and followers. A rotation key, a handle on a domain you control, and a usable copy of your data can help you prepare for that move.

Bagend works with accounts on your own personal data server (PDS) or someone else's. It uses public endpoints, so you don't need to log in or provide a token.

What it checks #

  • Identity: Bagend lists your rotation keys, which can update your identity, and checks your handle and recent PLC log entries. The PLC log is the public history of changes to a did:plc identity.
  • Data: Bagend fetches and checks your repository, which contains your public records, and compares its media references with the PDS's blob list.
  • Exit: Bagend reports potential migration blockers, including an unavailable export or an inactive account.
  • Host: Bagend checks the account status your PDS reports and whether your handle and identity point back to each other. It doesn't monitor uptime or check TLS certificates.

Example #

$ bagend check you.bsky.social
               _.-~~~~~~~~-._
          _.-~~   ~~    ~~   ~~-._
       .-~   ~~    _______    ~~  ~-.
     .~   ~~     .'   |   '.    ~~   ~.
    /  .-.      /     |     \     .-.  \
   |  ( + )    |      |      |   ( + )  |
   |   '-'     |      O      |    '-'   |
   |           |      |      |          |
 __|___________|______|______|__________|__
   ,,  wWw  ,, [_____________] ,, wWw  ,,

Data checks passed. Identity checks need attention; rotation key ownership is unknown.

Subscores: identity 10/20, data 35/35, exit 25/25
Overall score: 70/80 (unknown checks excluded from maximum)

Failures and warnings:
  fail Handle domain: the handle lives on a known shared multi-tenant host domain (bsky.social), which the account owner does not control, so the handle can be reassigned without their consent (fix: Move to a handle on a domain you control, following the custom-domain handle documentation in the atproto project documentation (atproto.com).)
Unknown checks: 2 (excluded from score maximum)
Migration blockers: none
Coverage limits: This check covers the public repository and account state only. Data outside the repository, such as direct messages, is not covered by the portability check.

This example shows an account on a shared host. The repository export worked, and its media references appeared in the PDS's blob list. The handle uses the host's domain, and Bagend can't tell who controls the rotation keys from the public log alone. A supplied public rotation key is checked against the current PLC list, with its position reported when listed; a match does not establish private-key possession.

A handle matching a self-hosted PDS domain is reported as unknown: public checks cannot establish who controls that domain. Known shared-host domains such as bsky.social remain failures.

A refused export is reported as a failure. If Bagend can't fetch the export for another reason, it reports unknown rather than claiming the data is available.

Build #

Build the CLI from the repository root:

go build -o bagend ./cmd/bagend

Usage #

usage: bagend check <handle-or-did> [--full] [--json] [--rotation-key <did:key-or-file>]
  • <handle-or-did>: The account's handle, such as you.bsky.social, or its decentralized identifier (DID), such as did:plc:....
  • --full: Print every check, its explanation, available evidence, and fixes. The default report is compact.
  • --json: Print the result as JSON, including checks, evidence, scores, and blockers. JSON takes precedence over --full and does not include the illustration.
  • --rotation-key <did:key-or-file>: Supply a public did:key string or a path to a file containing one. Bagend reports whether the public key appears in the account's current PLC rotation-key list and its position when listed, or when it last appeared if available. Ownership remains unknown: a public key does not prove possession of its private key.

Exit codes #

Code Meaning
0 Completed with no failing checks. Warnings and unknowns do not change the code.
1 Completed with at least one failing check.
2 Usage or resolution error: missing or malformed argument, unresolvable handle or DID, or an unreadable or invalid --rotation-key value.
3 Could not complete: an endpoint outage prevented the checks. The message names the unreachable service.

The codes exist for unattended use: a cron job or systemd timer can tell an unhealthy account (1) from a broken run (2 or 3).

Other atproto tooling #

Bagend doesn't move your account or create a backup. PDS MOOver can help with both. For ongoing identity monitoring, see atshield.

The data check covers public repository records and the PDS's blob listing. It doesn't check data outside the repository, such as direct messages, or establish that you have a separate backup.

Bagend keeps no account history between runs. It uses a temporary file while checking the repository export and removes it after the check.

Status #

The CLI is available now. A self-hostable web view and further host health checks are planned.

Treat the score as a starting point, not a guarantee that you can move. Unknown checks are excluded from the score, so read the individual results too.