atmirror#
Mirror your atproto bio across app-specific profile records.
Half the apps in the atmosphere forked a copy of your Bluesky bio into their
own profile lexicon (Grain, Spark, Popfeed, Smokesignal, atwork, ...), and none
of them ever look at it again. atmirror treats app.bsky.actor.profile as the
source of truth and fans the description out to the copies.
Phase 1 is hub-and-spoke: one source, many targets, description only. The omnidirectional reconciler (any record as edit origin, field-level last-writer-wins) is sketched but not built.
Usage#
export ATMIRROR_IDENTIFIER=you.example.com
# read-only: show the source bio and what each target would do
gleam run -- plan # or: reveal
# OAuth login (loopback flow: opens your browser, catches the callback
# on 127.0.0.1, stores a DPoP-bound session at ~/.config/atmirror/)
gleam run -- login
# apply
gleam run -- sync --yes
# poll the source profile and fan out whenever it changes
gleam run -- watch --interval 60
# revoke and forget the stored session
gleam run -- logout
Behaviour#
- Reads are unauthenticated. Writes prefer the stored OAuth session and fall
back to
ATMIRROR_APP_PASSWORDwhen none exists (useful headless). - Login verifies the callback
stateandiss, and that the issuedsubmatches what your identifier resolves to. Sessions auto-refresh; rotated refresh tokens are persisted before use. - Writes use
swapRecordcompare-and-swap, so a concurrent edit fails the write instead of being clobbered. Re-run to retry. - Only
descriptionis touched; every other field in a target record (avatars, display names, app settings, blob refs) rides along byte-for-byte. - Targets whose record does not exist are skipped: atmirror updates profiles, it never creates them.
- Writes send
validate: falsebecause most PDSes cannot resolve third-party app lexicons for schema validation. - Bios over a target's grapheme limit (default 256) are skipped with a warning, not truncated.
Identity resolution goes through a Slingshot-compatible resolver
(ATMIRROR_RESOLVER, defaults to slingshot.microcosm.blue).
Targets#
The target list lives in src/atmirror/config.gleam. Edit it to match the
profile records in your own repo (goat repo describe you.example.com shows
what you have).
Development#
gleam test
The XRPC client modules are extracted from at-record's atproto package and will switch to the Hex release once that lands.