This project aims to create a way to sync mastodon timeline between different devices and apps
- HTML 51.5%
- Ruby 45.5%
- Dockerfile 1.4%
- Shell 0.9%
- JavaScript 0.4%
- Other 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| .github | ||
| .kamal | ||
| app | ||
| bin | ||
| config | ||
| db | ||
| docs | ||
| lib/tasks | ||
| log | ||
| public | ||
| script | ||
| storage | ||
| test | ||
| tmp | ||
| vendor/ruby/3.4.0 | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| .rubocop.yml | ||
| .ruby-version | ||
| CODE_OF_CONDUCT.md | ||
| config.ru | ||
| CONTRIBUTING.md | ||
| Dockerfile | ||
| Gemfile | ||
| Gemfile.lock | ||
| LICENSE | ||
| Procfile | ||
| Rakefile | ||
| README.md | ||
ReadSync
Centralise your Mastodon "last toot read" position across all your clients.
ReadSync is a small, self-hostable Rails API + web app that lets Mastodon clients stay in sync on where you left off in your timeline. Any client that supports ReadSync can pick up exactly where another left off — on any device.
How it works
- You create a ReadSync account and link your Mastodon account(s) (server + access token — your password is never stored).
- You generate an API key in the dashboard.
- Any Mastodon client that supports ReadSync authenticates with your API key and:
- Reads your last-read position on startup.
- Writes your last-read position whenever you scroll.
Features
- 🔑 API key authentication — no OAuth dance required for clients
- 🔒 Mastodon access tokens encrypted at rest (AES-256-GCM via lockbox)
- ⚡ Live dashboard updates via Turbo Streams (Solid Cable)
- 🛡️ Rate limiting (rack-attack), security headers (secure_headers), CSRF protection
- 🐘 PostgreSQL + Solid Cache / Cable / Queue — no Redis needed
- 🌙 Dark mode
- 🌍 Self-hostable — deploy your own instance in minutes
API
All endpoints require Authorization: Bearer <api_key>.
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/read_position |
Get the last-read toot ID |
PUT |
/api/v1/read_position |
Update the last-read toot ID |
GET |
/api/v1/mastodon_accounts |
List linked Mastodon accounts |
Response envelope
{ "data": { ... }, "meta": { "version": "v1" } }
{ "error": { "code": "unauthorized", "detail": "..." } }
GET /api/v1/read_position
Optional query param: ?handle=@user@mastodon.social
{
"data": {
"last_read_id": "114262948242478592",
"mastodon_account": "@you@mastodon.social",
"updated_at": "2026-04-27T14:00:00Z"
},
"meta": { "version": "v1" }
}
PUT /api/v1/read_position
Body (JSON): { "last_read_id": "114262948242478592" }
Optional param: ?handle=@user@mastodon.social
Self-hosting
Prerequisites
- Docker + Docker Compose, or a Dokku server
- PostgreSQL 14+
Quick start with Docker Compose
git clone https://git.wstech.dev/YOUR_ORG/readsync.git
cd readsync
cp .env.example .env
# Edit .env — set SECRET_KEY_BASE, LOCKBOX_MASTER_KEY, DATABASE_URL
docker compose up
Deploy to Dokku
See docs/deploy-dokku.md for the full step-by-step guide.
Required environment variables
| Variable | Description |
|---|---|
SECRET_KEY_BASE |
Rails session signing key (openssl rand -hex 64) |
LOCKBOX_MASTER_KEY |
Token encryption key (openssl rand -hex 32) |
DATABASE_URL |
PostgreSQL connection URL |
RAILS_ENV |
Must be production |
See .env.example and docs/credentials.md for all options.
Development setup
# Clone and install
git clone https://git.wstech.dev/YOUR_ORG/readsync.git
cd readsync
bundle install
# Database
bin/rails db:create db:migrate
# Start the server
bin/rails server
Run tests
bin/rails test
Security checks
bundle exec brakeman --no-pager -q
bundle exec bundler-audit check --update
Contributing
Contributions are welcome! Please read CONTRIBUTING.md before opening a PR.
License
MIT — © 2026 ReadSync Contributors