Sifter #
Find and remove orphaned blobs on your AT Protocol account.
Features #
- Scan — held vs referenced blob accounting, per collection, with a
fail-closed
trustworthyflag - 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 #
- Log in with your Bluesky/ATProto handle (OAuth,
atproto transition:genericscope — repo write access is needed for the cleanup mechanism). - Run the scan. Review the report: headline numbers, per-collection accounting, orphan grid.
- Export a backup before deleting anything.
- Run cleanup; each deletion is re-verified against
listBlobs.
Development #
- Stack: Create React App (JavaScript), Jest via
react-scripts test npm start— dev servernpm test— tests (scan.test.js,extract.test.js; fixtures F1–F5 insrc/__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