through the looking glass
0

Configure Feed

Select the types of activity you want to include in your feed.

3 1 0

Clone this repository

https://tangled.org/mokkenstorm.dev/at-mirror https://tangled.org/did:plc:srzreacwujfjvlqbclmjxqct
git@tangled.org:mokkenstorm.dev/at-mirror git@tangled.org:did:plc:srzreacwujfjvlqbclmjxqct

For self-hosted knots, clone URLs may differ based on your setup.



README.md

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_PASSWORD when none exists (useful headless).
  • Login verifies the callback state and iss, and that the issued sub matches what your identifier resolves to. Sessions auto-refresh; rotated refresh tokens are persisted before use.
  • Writes use swapRecord compare-and-swap, so a concurrent edit fails the write instead of being clobbered. Re-run to retry.
  • Only description is 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: false because 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.