- Python 86.1%
- HTML 13.2%
- Dockerfile 0.7%
| .forgejo/workflows | ||
| .github/workflows | ||
| src/spacebee | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| icon.png | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| sshot_moonreader.webp | ||
| sshot_spacebee.png | ||
| uv.lock | ||
spacebee
Sync Moon+ Reader reading position to your Atmosphere account and share your progress on bookhive.buzz.
It also serves a simple web page showing your reading status:

🚨 This is vibecoded, I don't know much Python but it works 👍️
How to use
Spacebee pretends to be WebDAV but reads and writes from your Atmosphere account. In the Moon Reader app, go to Options->Sync with WebDAV and point it to spacebee:
Running locally
cp .env.example .env
uv sync --extra dev
uv run uvicorn spacebee.main:app --reload --port 8080
Point a test device at http://<wherever>:8080/ as the WebDAV target.
Docker
Copy compose file, fill in a .env, run:
curl -O https://raw.githubusercontent.com/oakbrad/spacebee/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/oakbrad/spacebee/main/.env.example
mv .env.example .env # then edit with your creds
docker compose up -d
By default it listens on 127.0.0.1:8080.
Configuration
Copy .env.example to .env and fill in:
| Var | Purpose |
|---|---|
BSKY_HANDLE |
The handle spacebee writes records as |
BSKY_APP_PASSWORD |
An app password for that handle |
DAV_USER / DAV_PASSWORD |
Basic-auth credentials Moon+ Reader will send |
PASSTHROUGH_ROOT |
Local-disk scratch dir for non-.po paths |
PDS |
Optional. If unset, resolved from the handle. |
How it works
graph LR
MR[Moon+ Reader] -->|"WebDAV: PROPFIND / GET / PUT"| SB[spacebee]
SB -->|"buzz.bookhive.book"| PDS[ATProto PDS]
PROPFIND /Books/.Moon+/Cache/synthesizes a directory listing from yourbuzz.bookhive.bookrecords that have abookProgress.moonReader.filefield.GET /Books/.Moon+/Cache/{file}.poreturns the stored position string verbatim (preserves Moon+ Reader's internal chapter/offset encoding).PUT /Books/.Moon+/Cache/{file}.poparses the.pobody, finds the matching bookhive record (or catalog-searches and creates one), and updatesbookProgress.{percent,currentChapter,moonReader}on your PDS.
Non-position WebDAV paths (Books/.Moon+/Settings/, backups, etc.) fall through to a local-disk scratch area rooted at $PASSTHROUGH_ROOT.
spacebee also serves a small read-only HTML dashboard at / that renders
your bookhive records (currently-reading, finished, etc.). The dashboard and
cover-image blob proxy at /blob/{cid} are public; all WebDAV endpoints are
gated by HTTP Basic.
Record
{
"$type": "buzz.bookhive.book",
"bookProgress": {
"percent": 11,
"updatedAt": "2026-04-17T10:01:24.000Z",
"moonReader": {
"file": "The Necromancers House - Buehlman Christopher.epub.po",
"position": "1703297605115*21@0#4826:11.1%",
"syncedAt": "2026-04-17T10:01:24.000Z"
},
"currentChapter": 22
}
}
Related
- bookhive.buzz — the AT Protocol book tracker whose records spacebee reads and writes.
- Moon+ Reader - Android eReader app