find unattached blobs for removal
JavaScript 83%
CSS 15%
Shell 1%
HTML <1%

README.md

Sifter #

Find and remove orphaned blobs on your AT Protocol account.

Features #

  • Scan — held vs referenced blob accounting, per collection, with a fail-closed trustworthy flag
  • Backup — per-blob download plus a zip with manifest.json
  • Cleanup — serial reference-and-delete with verified per-CID outcomes

What this does #

Sifter scans your AT Protocol account for blobs your PDS holds that no record references ("orphans"), lets you review and back them up, then removes them by briefly creating and deleting a throwaway record. On a healthy PDS the orphan set is empty — Sifter mostly exists to prove that.

There is no blob-delete API. Blob lifetime is tied to references: deleting the last record that references a blob deletes the blob. Sifter exploits that lever and verifies every deletion against listBlobs — it never reports success from a deleteRecord 200 alone.

Usage #

  1. Log in with your Bluesky/ATProto handle (OAuth, atproto transition:generic scope — repo write access is needed for the cleanup mechanism).
  2. Run the scan. Review the report: headline numbers, per-collection accounting, orphan grid.
  3. Export a backup before deleting anything.
  4. Run cleanup; each deletion is re-verified against listBlobs.

Development #

  • Stack: Create React App (JavaScript), Jest via react-scripts test
  • npm start — dev server
  • npm test — tests (scan.test.js, extract.test.js; fixtures F1–F5 in src/__tests__/__fixtures__/)
  • src/lib/ holds the pure logic: scan.js, extract.js, cleanup.js, backup.js, rateLimit.js

Build #

npm run build

Output in build/.

Deployment #

  • Wisp.place: wispctl deploy psingletary.com --path ./build --site sifter --spa --yes --db ~/.config/wispctl/state.sqlite
  • Tangled Sites: deploy directory /build
  • Any static host with SPA fallback works.

OAuth Configuration #

clientMetadata in src/contexts/AuthContext.js and public/client-metadata.json must match the deployed domain (currently https://sifter.psingletary.com). If you deploy elsewhere, update both and re-issue the client.

Scope: atproto transition:generic.

License #

MIT