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 #
OAuth client metadata lives in public/client-metadata.json — the single
source of truth (served at /client-metadata.json). AuthContext fetches
it at startup, so there is no second copy to drift. If you change the
client_id / redirect_uris / scope in that file, the OAuth flow breaks with
opaque failures.
Scope: atproto transition:generic.
License #
MIT
- TypeScript 52%
- JavaScript 40%
- CSS 5%
- Shell 3%
- HTML <1%