A cross-browser extension that lets you edit your own Bluesky posts directly on bsky.app — no copy-paste to a third-party site required.
Click the ✏ Edit badge on any of your posts, change the text, and save. skeeditor authenticates via OAuth 2.0 + PKCE, fetches the current record from the Bluesky PDS, and writes the updated record back — preserving rich-text facets, embeds, and timestamps automatically.
- In-place editing — edit button appears directly on bsky.app next to your posts
- Secure by design — OAuth 2.0 + PKCE; tokens stored only in extension storage, never sent to any third party
- Rich text preserved — links, @mentions, and #hashtags are re-detected and byte-offset facets recalculated on every save
- Conflict-safe — CID-based optimistic locking detects concurrent edits and prompts before overwriting
- Cross-browser — Chrome 120+, Firefox 121+, Safari (macOS 14+)
| Browser | Minimum version |
|---|---|
| Chrome | 120+ |
| Firefox | 121+ |
| Safari | macOS 14+ (Sonoma) |
- Node.js 20+
- pnpm 9+
- Chrome or Firefox for manual testing
git clone https://github.com/selfagency/skeeditor.git
cd skeeditor
pnpm installpnpm build:chrome # → dist/chrome/
pnpm build:firefox # → dist/firefox/
pnpm build:safari # → dist/safari/ (macOS, requires Xcode)
pnpm build # alias for build:chromeWatch mode:
pnpm build:watch:chrome
pnpm build:watch:firefoxChrome: chrome://extensions → Developer mode → Load unpacked → dist/chrome/
Firefox: about:debugging#/runtime/this-firefox → Load Temporary Add-on → dist/firefox/manifest.json
Safari: Build, then open the generated Xcode project under dist/safari/ and run it. See Cross-Browser Platform docs for full instructions.
pnpm test # unit + integration
pnpm test:unit # Vitest (jsdom + browser API mocks)
pnpm test:integration # Vitest + MSW (HTTP mocking)
pnpm test:e2e # Playwright (Chrome + Firefox, requires built dist/)
pnpm test:watch # watch modepnpm lint # oxlint
pnpm format # oxfmt (write)
pnpm format:check # oxfmt (check only)
pnpm typecheck # tsc --noEmitpnpm lex:install # download AT Protocol lexicon JSON files
pnpm lex:build # compile lexicons → TypeScript types in src/lexicons/
pnpm lex:sync # both steps in orderThe extension has three contexts that communicate via typed runtime messages:
- Content script (
src/content/) — runs on bsky.app; detects your posts, injects the Edit badge, shows the edit modal - Background worker (
src/background/) — manages OAuth tokens, makes all XRPC calls to the Bluesky PDS - Popup (
src/popup/) — toolbar button UI for sign-in, sign-out, and auth status
Tokens never touch the content script. All authenticated network requests go through the background worker.
See the Architecture and Message Protocol docs for details.
| Section | Description |
|---|---|
| User Guide | Installation, usage, privacy & security, FAQ |
| Architecture | Extension context model, data flow |
| Getting Started | Dev environment setup |
| Build System | Vite config, per-browser builds, manifest merging |
| Testing | Unit, integration, E2E test layers |
| Contributing | Beans workflow, branch naming, TDD, PR requirements |
| Authentication | OAuth PKCE flow, token storage, session management |
| XRPC Client | getRecord, putRecordWithSwap, conflict handling |
| Facets & Rich Text | Link/mention/hashtag detection, byte offsets |
| Cross-Browser Platform | API differences, manifest structure, Safari setup |
All work is tracked with Beans. Before writing code, find or create a bean and create the issue branch. All changes require tests (TDD: red → green → refactor). See Contributing for the full workflow.
Commits follow Conventional Commits. PRs require passing CI (lint, typecheck, unit + integration tests) and must reference a bean ID.
MIT © selfagency