AT Protocol Ecosystem Repository Analysis#
Generated 2026-08-12 (rev. 2) · Reference document for future LLM sessions
1. Methodology#
Discovery. Seed sources: the psingletary.com Tangled profile, exosphere.site/airglow, rrcobb/atprotozoa, plus nekomimi.pet/wisp.place-monorepo (added rev. 2 — it is the source of the wisp.place hosting platform used by several repos in this set). Crawl rule: analysis stopped inside each repo once found; external sites referenced by repos were noted but not visited.
Access limitations (fields marked "unknown"). Tangled's web UI rendered READMEs and file trees but not raw package.json contents, so exact direct-dependency lists are unknown for zodiac, altifier, verifier, airglow, ATProtocol-Playground, and wisp.place-monorepo. atprotozoa was analyzed from its full file tree and README. Language attribution uses labels displayed on the Tangled repo listing plus observed file types.
2. Repository Inventory#
airglow — tangled.org/exosphere.site/airglow#
"Automations for the AT Protocol — listen to events, filter them, and trigger actions like webhook deliveries or PDS record creation"; connects to Jetstream, works like "IFTTT or Zapier, but the trigger side is always 'something happened on the AT Protocol.'"
- Language: TypeScript (primary)
- Framework/tooling: Bun runtime + Vite
- Hosting: self-hosted (env-var config:
DATABASE_PATHfor SQLite,JETSTREAM_URL, NSID allow/blocklists) - Deployment: manual self-host; CI unknown
- AT Proto specifics: Jetstream consumer; custom lexicons in
lexicons/managed with goat; exact npm deps unknown
wisp.place-monorepo — tangled.org/nekomimi.pet/wisp.place-monorepo#
The platform behind wisp.place: hosts static sites inside an AT Protocol repository — the PDS is the source of truth (signed manifests + file blobs), and a hosting microservice watches the firehose to cache and serve sites via *.wisp.place subdomains or custom domains with CDN distribution.
- Languages: TypeScript (primary — backend + frontend), Rust (secondary — CLI)
- Frameworks: Elysia (main backend), Hono (hosting microservice), React 19 (frontend)
- Structure (one inventory entry, monorepo):
apps/main-app(OAuth, site management, custom domains, React UI),apps/hosting-service(serves cached sites),cli/(Rust: PDS uploads, firehose updates),packages/(shared internals) - Hosting: self-hosted service (it is the delivery platform); end-user deploys via
wispctl/npm create wisp - Deployment: CLI-driven uploads to the PDS; no CI/CD configs observed — unknown
- AT Proto specifics: ATProto OAuth; custom lexicons; PDS blobs as site storage; firehose consumer; Jacquard (Rust ATProto library) in the CLI; supports
.wispignoreand_redirects
atprotozoa — github.com/rrcobb/atprotozoa#
"A monorepo of ~200 tiny atproto experiments" — many small sites, each its own Cloudflare Worker at <name>.bisks.net, deployed on commit; many built by the @buildthis.bisks.net Bluesky bot ("tag it with an idea and it builds the site").
- Language: TypeScript (per-site
src/index.tsWorkers) + vanilla JavaScript front-ends - Framework: none — hand-rolled static HTML + copied vanilla-JS libs; explicit "copy-don't-abstract" rule
- Hosting: Cloudflare Workers (
wrangler.tomlper site;apex/front-door Worker for gallery + handle verification) - Deployment: GitHub Actions deploy-on-commit (
.github/workflows/deploy.yml,buildthis.yml); pnpm workspaces - AT Proto specifics: hand-rolled per-site libs —
lib/oauth.js+lib/oauth-jwt.js+public/client-metadata.json(ATProto OAuth),lib/atproto.js,lib/car.js(CAR parsing),lib/identity.js,lib/handle-typeahead.js; OG image generation viaog-gen.mjs(+@resvg); repo-wideaudit/health-check scripts
altifier — tangled.org/psingletary.com/altifier#
"Scans the image posts (app.bsky.feed.post records with app.bsky.embed.images) in your PDS, identifies images missing alt text, generates descriptions via AI, and lets you apply them by recreating your posts."
- Language: JavaScript · Framework: React ("fully static React SPA")
- Hosting/deploy: wisp.place via
wispctl deploy, Tangled Sites (deploy dir/build), or any static host - Deps: ATProto OAuth (
src/contexts/AuthContext.js+public/client-metadata.json); Google Gemini 2.5 Flash; fullpackage.jsonunknown
verifier — tangled.org/psingletary.com/verifier#
"A lightweight tool for creating and managing Bluesky verification records (app.bsky.graph.verification) on an account's PDS."
- Language: JavaScript · Framework: React, fully static SPA
- Hosting/deploy: static host (same pattern as altifier); deps/CI unknown
zodiac — tangled.org/psingletary.com/zodiac#
"Private astrology compatibility website… no accounts, no tracking, no data storage" — ATProto-adjacent (hosted via ATProto-native infra).
- Language: TypeScript · Framework: Next.js 16 (App Router) + Tailwind CSS v4, "fully static — zero server routes… deployable to any static host (Tangled, wisp, Vercel, S3, etc.)"
- Deploy/CI: manual static deploy; no CI configs found; deps unknown
daily-bsky-hype-vid — tangled.org/psingletary.com/daily-bsky-hype-vid#
"A daily, AI-produced hype video of your Bluesky mutuals' last 24 hours" — Claude Code fetches mutuals' posts, composes a soundtrack, renders a <60s vertical video.
- Language: Python (numpy, scipy, Pillow, ffmpeg; Claude Code)
- AT Proto access: raw public Bluesky AppView API, no auth, no SDK (
fetch_bsky.py) - Hosting/deploy: none — local, manual run
ATProtocol-Playground — tangled.org/psingletary.com/ATProtocol-Playground#
"Scripts for fooling around with ATProto and BSky.app"; dirs: docs/, js/, sample/, tests/; no manifest or CI files visible.
- Language: Python (primary), some JS · Hosting/deploy/deps: unknown/none
ptharbor — tangled.org/psingletary.com/ptharbor#
Migration of a small-business site (Point Harbor Signs) from Weebly to the AT Protocol stack: wisp.place hosting, Protobase.at managed PDS, Tangled git, Marque.at registrar — "a repeatable blueprint for migrating small businesses off Facebook/Instagram/WordPress/Wix to AT Protocol."
- Language: HTML · Framework: none (static port)
- Hosting: wisp.place (PDS-based static hosting); did:web identity files (
did-web/, did.json at ptharbor.net) - Deployment: manual scripts (
scripts/for key generation, deploy)
3. Ranked: Programming Languages (primary, one per repo; n=9)#
| Rank | Language | Count | Repos |
|---|---|---|---|
| 1 | TypeScript | 4 | airglow, atprotozoa, zodiac, wisp.place-monorepo |
| 2 (tie) | JavaScript | 2 | altifier, verifier |
| 2 (tie) | Python | 2 | daily-bsky-hype-vid, ATProtocol-Playground |
| 4 | HTML | 1 | ptharbor |
Notable secondary: Rust (wisp.place CLI).
4. Ranked: Website Delivery Platforms#
| Rank | Platform | Count | Repos |
|---|---|---|---|
| 1 | PDS-based / ATProto-native static hosting (wisp.place, Tangled Sites) | 4 | altifier, verifier, zodiac, ptharbor |
| 2 | Self-hosted service | 2 | airglow, wisp.place-monorepo |
| 3 | Cloudflare Workers | 1 | atprotozoa (~200 sites, one repo) |
| — | N/A (local tools) | 2 | daily-bsky-hype-vid, ATProtocol-Playground |
5. Ranked: Deployment Processes#
| Rank | Process | Count | Repos |
|---|---|---|---|
| 1 | Manual static deploy (wispctl / Tangled Sites / copy build dir) |
4 | altifier, verifier, zodiac, ptharbor |
| 2 | Manual self-host (env vars / CLI) | 2 | airglow, wisp.place-monorepo |
| 3 | CI/CD deploy-on-commit (GitHub Actions + wrangler) | 1 | atprotozoa |
| — | None / run locally | 2 | daily-bsky-hype-vid, ATProtocol-Playground |
Note: Tangled offers native CI/CD via Spindle workflows (.tangled/workflows YAML, push/PR/manual triggers), but zero repos in this set were observed using it. See §8.2.
6. Ranked: Libraries (observed evidence only; most manifests unreadable — see Methodology)#
AT Protocol–specific:
| Rank | Library/approach | Count | Evidence |
|---|---|---|---|
| 1 (tie) | Hand-rolled vanilla JS against XRPC/AppView (no SDK) | 2 | atprotozoa file tree; daily-bsky-hype-vid README |
| 1 (tie) | Firehose/Jetstream consumers | 2 | airglow (Jetstream); wisp.place hosting-service (firehose) |
| 1 (tie) | Custom lexicons | 2 | airglow lexicons/; wisp.place-monorepo |
| 4 (tie) | goat (lexicon management, bluesky-social/indigo) | 1 | airglow |
| 4 (tie) | Jacquard (Rust ATProto library) | 1 | wisp.place CLI |
| — | @atproto/api / atcute |
0 confirmed | manifests unknown for TS/React apps — likely but unverified |
General:
| Rank | Library/tool | Count | Repos |
|---|---|---|---|
| 1 | React | 3 | altifier, verifier, wisp.place-monorepo (React 19) |
| 2 (tie) | Next.js + Tailwind v4 | 1 | zodiac |
| 2 (tie) | Bun + Vite + SQLite | 1 | airglow |
| 2 (tie) | Elysia + Hono | 1 | wisp.place-monorepo |
| 2 (tie) | pnpm workspaces + wrangler + @resvg | 1 | atprotozoa |
| 2 (tie) | numpy/scipy/Pillow/ffmpeg + Claude Code | 1 | daily-bsky-hype-vid |
| 2 (tie) | Google Gemini 2.5 Flash | 1 | altifier |
7. Aggregate Summary of AT Protocol Tools#
Categories observed: (a) PDS record tooling — altifier, verifier: static browser apps reading/writing records directly in the user's PDS; (b) event/automation infrastructure — airglow (Jetstream → actions); (c) hosting infrastructure — wisp.place: the PDS itself as a static-site origin, firehose-invalidated CDN cache in front; (d) micro-app factories — atprotozoa's bot pipeline (mention → LLM builds site → deploy-on-commit → Worker); (e) migration/identity tooling — ptharbor (did:web + managed PDS + wisp); (f) AppView-scraping content generators; (g) learning playgrounds.
Architectural patterns:
- Static-first, serverless-second. Dominant shape: fully static SPA doing ATProto OAuth in-browser, talking directly to the user's PDS — no backend. Backends, where present, are a tiny Worker or a single Bun/TypeScript process with SQLite.
- PDS as infrastructure primitive. wisp.place stores entire websites as PDS blobs with signed manifests; Tangled stores git and CI records (
sh.tangled.*lexicons) in PDSes. The PDS is becoming the deployment target, not just the social-data store. - ATProto-native supply chain. Code on Tangled, hosting on wisp.place, identity via did:web/did:plc, managed PDS (Protobase.at) — a full stack that never touches traditional PaaS.
- SDK avoidance in small projects. Copied single-file vanilla libs (OAuth, CAR parsing, identity resolution) or raw AppView calls instead of
@atproto/api; atprotozoa codifies this as "copy, not extract." Infrastructure projects, by contrast, adopt real libraries (Jacquard). - LLM-in-the-loop development. buildthis bot, Claude Code pipelines,
.hermes/plans/agent-planned implementations. - Repeated OAuth boilerplate: every app re-ships
client-metadata.jsonpinned to its domain,oauth.js/oauth-jwt.js, handle typeahead.
8. Recommendations: Tools That Need to Be Built#
Stack suggestions follow the rankings: TypeScript, static-first, wisp.place/Tangled or Cloudflare Workers hosting, vendorable vanilla-JS libs, Bun + SQLite for services.
-
create-atproto-appscaffolding CLI (the "project factory"). Problem: every app hand-assembles OAuth metadata, typeahead, deploy config. Stack: TypeScript CLI (Bun), templates for static SPA + optional Worker; emitsclient-metadata.json,wrangler.toml/wisp config, vendored single-file libs — and a.tangled/workflows/deploy.yml(see §8.2). (Directly serves the project-factory goal.) -
Spindle adoption kit + hosted runners. (Revised after evaluating Tangled Spindle docs.) The earlier claim "Tangled lacks native CI/CD" is no longer true: Spindle workflows live in
.tangled/workflows(YAML), trigger onpush/pull_request/manualwith branch/tag globs, run on Docker (nixery) or microVM engines, support repo secrets, and the docs include a working deploy-to-Cloudflare-Workers example and PDS artifact publishing. The real gap is adoption and infrastructure: (a) none of the four manually-deployed Tangled repos in this set use Spindle; (b) Spindle is a self-hosted Go runner service listening on Jetstream — most individual developers won't run one. What to build: ready-made workflow templates (especially deploy-to-wisp.place viawispctl, which doesn't exist as a documented example), and/or a community/hosted spindle offering so repos get CI without operating runner hosts. Stack: YAML templates + Go (spindle is Go) or a managed nixery-engine host. -
Vendorable ATProto micro-library set. Problem: the "copy-don't-abstract" culture exists because
@atproto/apiis heavy for static SPAs; copiedoauth.js/car.js/identity.jsfiles drift and duplicate bugs across ~200 sites. Build audited, zero-dependency single-file ES modules (OAuth+DPoP, CAR reader, DID/handle resolution) designed to be copied. Stack: TypeScript → standalone ESM. -
Non-destructive PDS record editor. (Expanded.) The problem in depth: altifier's only way to fix alt text is delete-and-recreate the post. Because the new record gets a new rkey, its at-uri changes, so every like, repost, reply, and quote — all of which point at the old at-uri (as a
strongRefof uri + CID) — is orphaned. The user must choose between accessibility and their engagement history. What's missing is a general-purpose tool built around the safer primitives the protocol already has:com.atproto.repo.putRecordoverwrites a record in place, preserving the rkey and at-uri (replies and likes keep resolving; only the CID changes);com.atproto.repo.applyWritesbatches creates/updates/deletes atomically;com.atproto.sync.getRepoexports a full CAR backup before any mutation. Feature set: browse any collection in your PDS (not justapp.bsky.*), edit records as validated JSON against their lexicon, show a dry-run diff of every proposed write, warn when an edit would change semantics AppViews index (e.g.createdAt), automatic pre-mutation CAR snapshot with one-click restore, and bulk find-and-replace across a collection. No tool in the analyzed set — or widely in the ecosystem — combines editing with backup/diff/undo safety rails; existing repo browsers are read-only, and writing tools (altifier, verifier) are single-purpose. Stack: static React/TypeScript SPA, ATProto OAuth, CAR parsing lib (§8.3), hosted on wisp.place. -
Managed multi-tenant Jetstream automation. Problem: airglow is self-host-only. A hosted or one-click-deploy version (Workers + Durable Objects, or Bun+SQLite image) would open ATProto automations to non-operators.
-
Small-business migration toolkit. Problem: ptharbor proves the demand but is a manual one-off. Automate: site scrape → static port → wisp.place deploy → did:web generation → managed-PDS provisioning checklist. Stack: TypeScript CLI + template repo on Tangled. (See companion doc
Migration_Toolkit_research.md.) -
Fleet health dashboard for micro-sites. Problem: atprotozoa needed bespoke
audit/scripts. A reusable uptime/OAuth-metadata/handle-verification monitor for many small ATProto sites doesn't exist in this set. Stack: scheduled Worker + static dashboard. -
OG-image service for ATProto apps. Problem: nearly every atprotozoa site bundles fonts + a per-site
og-gen.mjs. A shared Worker rendering OG cards from URL params would delete hundreds of copies. Stack: Cloudflare Worker + resvg-wasm.
Caveat: Tangled's web UI does not expose raw manifests, so the library ranking (§6) remains the weakest section — @atproto/api/atcute usage in the TS/React apps is plausible but unverified.