- Ruby 60.9%
- TypeScript 20.4%
- JavaScript 9.9%
- SCSS 4.5%
- Haml 3.9%
- Other 0.3%
Add the fields that were only in the web initial_state so third-party/native
clients (Busky) can detect every feature: auto_thread.warning, gancio.description,
radio.link, peertube.description, and the new neighborhood { enabled, instances }.
Also fix peertube being missing from the serializer attributes list on bida, so
it was never actually exposed in /api/v2/instance.
|
||
|---|---|---|
| .devcontainer | ||
| .forgejo/workflows | ||
| .github | ||
| .husky | ||
| .rubocop | ||
| .storybook | ||
| .yarn | ||
| app | ||
| bin | ||
| chart | ||
| config | ||
| db | ||
| dist | ||
| docs | ||
| lib | ||
| log | ||
| public | ||
| spec | ||
| streaming | ||
| vendor | ||
| .annotaterb.yml | ||
| .browserslistrc | ||
| .buildpacks | ||
| .dockerignore | ||
| .editorconfig | ||
| .env.development | ||
| .env.production.sample | ||
| .env.test | ||
| .env.vagrant | ||
| .foreman | ||
| .gitattributes | ||
| .gitignore | ||
| .haml-lint.yml | ||
| .nvmrc | ||
| .oxfmtrc.json | ||
| .rspec | ||
| .rubocop.yml | ||
| .rubocop_todo.yml | ||
| .ruby-gemset | ||
| .ruby-version | ||
| .simplecov | ||
| .slugignore | ||
| .watchmanconfig | ||
| .yarnrc.yml | ||
| app.json | ||
| Aptfile | ||
| AUTHORS.md | ||
| CHANGELOG.md | ||
| CODE_OF_CONDUCT.md | ||
| config.ru | ||
| CONTRIBUTING.md | ||
| crowdin.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.mjs | ||
| FEDERATION.md | ||
| Gemfile | ||
| Gemfile.lock | ||
| jsconfig.json | ||
| LICENSE | ||
| lint-staged.config.js | ||
| package.json | ||
| priv-config | ||
| Procfile | ||
| Procfile.dev | ||
| publiccode.yml | ||
| Rakefile | ||
| README.md | ||
| scalingo.json | ||
| SECURITY.md | ||
| stylelint.config.js | ||
| tsconfig.json | ||
| Vagrantfile | ||
| vite.config.mts | ||
| vitest.config.mts | ||
| vitest.shims.d.ts | ||
| yarn.lock | ||
Bastodon
Bastodon is a fork of Mastodon that is fully compatible with upstream. It does not change the default behavior: it adds optional features that can be enabled through environment variables. If no variables are set, Bastodon behaves exactly like vanilla Mastodon.
- Repository: git.lattuga.net/bida/bastodon
Why Bastodon
Bastodon was born out of a critique of how Mastodon is developed: a roadmap driven from the top down, where the priorities and choices of the upstream project do not always reflect the needs of the communities that actually inhabit the network.
Against that model, every feature in this fork was discussed and decided collectively by the instance assemblies of mastodon.bida.im. The software follows the choices of the community that uses it, not the other way around. The features below are the concrete result of those assemblies — which is also why they are all optional and disabled by default: each instance stays free to enable only what it has collectively chosen.
Bastodon Features
Neighborhood Timeline
A dedicated timeline that aggregates public posts from configured friendly instances. Allows following the activity of nearby communities without having to search through the federated timeline.
NEIGHBORHOOD_TIMELINE_ENABLED=true- enables the "Neighborhood" tab in live feedsNEIGHBORHOOD_INSTANCES=instance1.org,instance2.net- comma-separated list of friendly instance domainsNEIGHBORHOOD_DEBUG=true- debug logging
Configurable Max Characters
Allows setting a character limit different from the default 500.
MAX_CHARS=840- maximum number of characters per post
Auto-thread for Long Posts
When enabled, posts exceeding the character limit are automatically split into a thread. The first post keeps the visibility chosen by the user, subsequent ones are unlisted to avoid flooding the public timeline. Also works for third-party apps via API.
AUTO_THREAD_ENABLED=true- enables automatic splittingAUTO_THREAD_WARNING=message- warning message shown below the Post button when composing a post that will be split. Useful to discourage excessive use of the feature
Events Agenda (Gancio Integration)
Integration with Gancio, the federated platform for event management. Allows browsing events from configured Gancio instances and saving them to a personal agenda.
GANCIO_ENABLED=true- enables the integrationGANCIO_INSTANCES=balotta.org,agenda.reteappenninica.it- Gancio instances to fetch events fromGANCIO_DESCRIPTION=text- description shown at the top of the events page
Features:
/eventspage to browse all events from Gancio instances with interactive calendar- Personal agenda: save events you're interested in with "Add to agenda" button
/events-personalpage with your personal calendar and saved events- Mini-calendar in the sidebar (desktop) with dots on days that have events
- Click on a day in the mini-calendar opens your personal agenda for that day
- Remove events from your agenda
- Background fetch via Sidekiq worker (every 15 minutes) + manual refresh button
- Events and Radio links visible to non-logged-in users; My Agenda only for logged-in users
- Data exposed via API for third-party apps
- Event thumbnails are cached locally and served from our own domain through a
proxy (
/gancio_media) instead of being hotlinked from the Gancio instances. This fixes images that often failed to load (slow/down remote instance, hotlink protection, mixed content) and keeps them working even if the Gancio instance goes down. The Sidekiq worker pre-downloads images into the cache (Redis, 1 day TTL) so they are ready before anyone opens the page; the proxy downloads on demand as a fallback. Only the hosts listed inGANCIO_INSTANCEScan be proxied, so it cannot be turned into an open proxy.
After deploying changes to the events feature, the Gancio events already cached in Redis (30 min TTL) may still hold the old image URLs. Force a refresh so they are regenerated with the proxied URLs and their images get pre-downloaded:
# Docker (sidekiq or web service)
docker compose exec sidekiq bin/rails runner "Rails.cache.delete('gancio:events'); GancioFetchWorker.new.perform"
# Non-Docker
bin/rails runner "Rails.cache.delete('gancio:events'); GancioFetchWorker.new.perform"
Radio Player
Audio player integrated in the sidebar (desktop) and as a dedicated page (mobile) for listening to a community web radio.
RADIO_ENABLED=true- enables the playerRADIO_URL=https://stream.example.org/stream.ogg- audio stream URLRADIO_NAME=Radio Spore- radio name shown in the playerRADIO_DESCRIPTION=Community radio- description (visible on mouseover on desktop, shown on radio page)RADIO_LINK=https://radiospore.oziosi.org- URL opened when clicking the radio name
Features:
- Persistent playback: audio continues playing when navigating between pages
- On mobile, a mini bar appears at the bottom while radio is playing
- Supports OGG, MP3, and other formats handled by the HTML5
<audio>tag - Dedicated
/radiopage with large player, description, and link
PeerTube Videos
Integration with PeerTube, the federated video platform. Reads the latest videos from configured PeerTube instances and shows them in a single chronological list, with a live-stream alert.
PEERTUBE_ENABLED=true- enables the integrationPEERTUBE_INSTANCES=tube1.org,tube2.net- PeerTube instances to fetch videos fromPEERTUBE_DESCRIPTION=text- description shown at the top of the videos page
Features:
/peertubepage listing the most recent videos from all configured instances, merged and sorted chronologically server-side (via each instance's public API/api/v1/videos?sort=-publishedAt)- Clicking a video opens it on its origin instance in a new tab
- "Live now" section for currently active live streams, plus a fixed in-app red bar "● N live" (60s polling) that links to the videos page
PeertubeFetchWorker(Sidekiq, every 5 minutes) + Redis cache + manual refresh button- "Video" nav link below Radio, visible to non-logged-in users too
- Thumbnails are cached locally and served from our own domain through a proxy
(
/peertube_media), like the Gancio events — avoids hotlink/CSP/mixed-content issues and keeps them working even if the remote instance is slow or down. Only the hosts listed inPEERTUBE_INSTANCEScan be proxied, so it cannot be turned into an open proxy. - Data exposed via API (
/api/v2/instance) for third-party apps
After deploying changes to the PeerTube feature, force a cache refresh so the videos are regenerated with the proxied image URLs:
# Docker (sidekiq or web service)
docker compose exec sidekiq bin/rails runner "Rails.cache.delete('peertube:data'); PeertubeFetchWorker.new.perform"
# Non-Docker
bin/rails runner "Rails.cache.delete('peertube:data'); PeertubeFetchWorker.new.perform"
All Environment Variables
| Variable | Default | Description |
|---|---|---|
NEIGHBORHOOD_TIMELINE_ENABLED |
false |
Enable the friendly instances timeline |
NEIGHBORHOOD_INSTANCES |
'' |
Friendly instance domains, comma-separated |
NEIGHBORHOOD_DEBUG |
false |
Debug logging for neighborhood |
MAX_CHARS |
500 |
Maximum characters per post |
AUTO_THREAD_ENABLED |
false |
Automatic splitting of long posts into threads |
AUTO_THREAD_WARNING |
'' |
Warning message shown below Post button during auto-thread |
GANCIO_ENABLED |
false |
Gancio integration |
GANCIO_INSTANCES |
'' |
Gancio instances, comma-separated |
GANCIO_DESCRIPTION |
'' |
Description shown on events page |
RADIO_ENABLED |
false |
Radio player |
RADIO_URL |
'' |
Audio stream URL |
RADIO_NAME |
'' |
Radio name |
RADIO_DESCRIPTION |
'' |
Description (mouseover / radio page) |
RADIO_LINK |
'' |
URL opened when clicking radio name |
PEERTUBE_ENABLED |
false |
PeerTube videos integration |
PEERTUBE_INSTANCES |
'' |
PeerTube instances, comma-separated |
PEERTUBE_DESCRIPTION |
'' |
Description shown on the videos page |
Compatibility
Bastodon is 100% compatible with Mastodon. All additional features are optional and controlled by environment variables. Without any variables set, the behavior is identical to vanilla Mastodon. Information about active features is exposed in the REST API (/api/v2/instance) to allow third-party apps to adapt.
For the technical guide on porting to new Mastodon branches, see PORTING_GUIDE.md.
What follows is the original Mastodon README.
Features
No vendor lock-in: Fully interoperable with any conforming platform - It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! Learn more
Real-time, chronological timeline updates - updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well!
Media attachments like images and short videos - upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously!
Safety and moderation tools - Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. Learn more
OAuth2 and a straightforward REST API - Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices!
Deployment
Tech stack
- Ruby on Rails powers the REST API and other web pages
- React.js and Redux are used for the dynamic parts of the interface
- Node.js powers the streaming API
Requirements
- Ruby 3.3+
- PostgreSQL 14+
- Redis 7.0+
- Node.js 22+
- FFmpeg 5.1+
The repository includes deployment configurations for Docker and docker-compose as well as specific platforms like Heroku, and Scalingo. For Helm charts, reference the mastodon/chart repository. The standalone installation guide is available in the documentation.
Contributing
Mastodon is free, open-source software licensed under AGPLv3.
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository or translations via Crowdin. To get started, look at the CONTRIBUTING and DEVELOPMENT guides. For changes accepted into Mastodon, you can request to be paid through our OpenCollective.
IRC channel: #mastodon on irc.libera.chat
License
Copyright (c) 2016-2025 Eugen Rochko (+ mastodon authors)
Licensed under GNU Affero General Public License as stated in the LICENSE:
Copyright (c) 2016-2025 Eugen Rochko & other Mastodon contributors
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
details.
You should have received a copy of the GNU Affero General Public License along
with this program. If not, see https://www.gnu.org/licenses/