Self-hosted print archive, management and automation system for Bambu Lab 3D printers
Hard fork of Bambuddy by maziggy, with Telegram bot, multi-chat auth, Ukrainian locale and more
BamDude grew out of a volunteer workshop. Its author volunteers with DrukArmy — Ukraine's largest volunteer 3D-printing effort for the front line — printing, and running the FPV direction as senior curator.
Batches, deadlines and a farm that has to keep moving around the clock do not fit any off-the-shelf tool, so every feature here earned its place on a real order first. That is also why Ukrainian is a first-class locale rather than an afterthought.
If you have a printer and want it to do something useful: join DrukArmy.
| DrukArmy | Ukraine's largest volunteer 3D-printing community, printing for the front line. BamDude was born in this workshop — and if you have a printer, there is useful work waiting for it: join. |
| Dragons of Defense | A volunteer 3D-printing initiative: a 24/7 print farm making plastic gear for Ukraine's defense forces, with fully transparent finances — everything public, counted automatically. |
| AdditHub | Ukraine's #1 3D-printing marketplace: post a job and verified makers place blind bids — FDM, SLA and SLS printing, 3D modelling and post-processing. |
BamDude is free and stays free — AGPL-3.0, no paid tiers, no pro edition. The most valuable support is a bug report, a translation PR or a star. If you would rather chip in:
| Monobank jar | https://send.monobank.ua/jar/2vREyf3SrF |
| PayPal | pushkar.valeriy@gmail.com |
| USDT (TRC20) | TWe1MaXz7mpDZZqDkY7Az7NdZ6s9H5fvMF |
0.7.1 keeps whether a file carries its own plate-swap sequence as a fact of the print file — older archives are unknown until you declare them — and lets you review and repair unresolved print-state conflicts from System. Smart-plug schedules repeat every day, energy accounting and Telegram cards are steadier, and printers can opt into automatic assignment of full inventory spools on loading. It also adds server-rendered pictures of printed parts, STEP thumbnails, whole-plate order quantities, forecasts that account for operator hours, loose stock components in order plans and a saved extra percentage on printed BOM parts. Swap farms: review the declaration of older archives before reprinting with BamDude's swap macros — see the 0.7.1 changelog.
0.7.0 adds configurable products (SKU, version, category and variants), five order views with stages and responsible operators, finished-goods stock and numbered dispatch notes. Orders, Products, Customers and Stock have separate permissions; review custom groups after upgrading. From a library file or its plate gallery, Add to order… opens a one-off product with that file already selected.
It also adds Home Assistant and shared Zigbee sensor bindings, optional sensor holds on queued starts, scheduled AMS drying, Bambu Studio model compatibility, H2C rack-nozzle selection, optional runout-spool archiving and printing labels from a partially used sheet. System reports the preview, camera, 3MF-analysis and library-file workers separately.
After 0.7.1, in the current development branch: shared editable order plans and machine-hour comparisons, improved plate selection, LAN HTTP submission, bulk retry of failed queue jobs, quieter AutoQueue obstacle notifications, filament-segment accounting, camera-light fixes, and responsive library controls with corrected folder trash handling. An unclean shutdown pauses new farm starts until an operator confirms recovery; reconnects do not revoke that confirmation or block the macros of an existing print. Info shows print-state inconsistencies and offers confirmed repair actions, including inspection of a completed queue item still held by a printing queue header.
Docker latest follows the latest stable release tag; dev follows the beta channel. Check the release changelog for what your image includes.
BamDude is a hard fork of Bambuddy, aimed at print farm operators. It still tracks upstream — each release is adapted through a tracked audit rather than a blind merge — so what the two projects share is deliberately not listed here. Each item below is either absent upstream or built on a different principle.
- Waiting is an explicit choice, not an unexplained green button. Print and Schedule check the complete filament assignment. If compatibility is unverified or refused, normal submission is disabled with an explanation; a separate confirmed action queues the job to wait, warning that it can hold up later jobs on that printer. Auto-Queue distinguishes an absent target model and offers deliberate storage for a future printer. A compatible but busy printer still accepts queue work. See the routing guide.
- One queue per printer, plus an Auto-Queue that distributes between them. Work you have already assigned waits in that printer's own queue. Work you have not goes to the Auto-Queue, which routes it to whichever printer can take it — matching filament type and colour, and preferring an idle printer without refusing a busy one.
- A queued file is independent of its original. Accepting work makes one verified, immutable copy in
data/queue-sources/. A laptop can sleep, an SMB share can disconnect, an external library file can be moved or deleted, and an archive can be cleaned without changing a job already in either queue. Copy Queue reuses that accepted copy for another compatible printer, then asks for that printer's current AMS mapping and options; it never needs the original again. Identical bytes are stored once and remain until their last printer-queue or Auto-Queue job is removed; portable backups include the queue copies that their database snapshot names. - The Schedule dialog asks once per group, not once per file. Files whose answers would coincide — same printer model and nozzle, same filament types, same build plate — are grouped, and one dialog stands for the group: the printer or auto-queue you chose, when it should start, how many copies, the print options and macros. Each file still keeps its own plates and gets its own filament mapping. A different filament colour does not split a group; a filament type nothing on the chosen printer can supply stops the run and shows you that file. Any group can be declined with a tick, and then its files are asked about one by one — already filled in with the answer you gave.
- A single dispatch layer. Queued prints, prints started from the printer's own screen, and files sent straight from a slicer all leave through one dispatcher. It claims the printer for the whole plate change, creates exactly one archive per physical print, and runs the swap macro before letting the next job in.
- A console for bulk firmware updates. Upstream updates a printer. BamDude takes a set of them, groups the set by model, downloads each model's firmware once into a shared store, and fans the transfer out under a concurrency cap — applying remotely where the model allows it.
- A printer that is printing is skipped, not interrupted, and one printer failing does not stop the rest of the batch.
- It is deliberately a separate orchestrator from print dispatch: firmware is not a print, and the single-dispatch rule stays intact.
Upstream can send a Telegram message — a notification channel, one way, over the Bot API. BamDude's is a complete aiogram 3.x bot you can hold a conversation with:
- Live status, printer control, camera snapshots and print-speed mode
- Controls under the camera snapshot — see the problem, act on it in the same message, rather than reaching for a VPN and the web
- Skip a failed object — the plate seen from above with a numbered pin on each part; press the number, confirm by name, and the other nineteen carry on printing
- Print from the library — pick a file, pick a model-compatible printer, print now or queue it
- Send the bot a file — it lands in the library with the same checks as a web upload, and offers to print it right there
- Queue management — paginated list, detail, reorder, cancel
- Maintenance — see what is overdue, mark it done, edit the hours
- Add a printer — type an IP and let SSDP fill in the serial, name and model
- Multi-chat with roles — every chat gets its own permission group, so a shop-floor chat and an admin chat are not the same thing
- Per-chat notification settings — event types, printer scope, milestone floor, quiet hours and the daily digest belong to the chat, not to a global switch
- Actionable notifications — "Clear plate" and "Mark maintenance done" are buttons in the message itself
- BamDude drives the radio itself. Upstream reaches Zigbee devices only through a Zigbee2MQTT bridge, as MQTT topics; BamDude talks to the dongle over USB or Ethernet, so smart plugs and temperature/humidity sensors pair into a network it owns — no Home Assistant, no Zigbee2MQTT, no broker to keep alive.
- Reporting intervals per device, defaulted from ZHA's own values and changed from the device's card.
- Measurement history — power draw and room conditions recorded as they arrive and kept for a month, charted per plug and per sensor. It is written above the plug drivers, so all five plug types get it rather than only the Zigbee ones.
- Sensor alarms — a lowest and/or highest value for anything a sensor measures, including its own battery.
- A file sent from the slicer lands in the file library, not in the print archive. Upstream's virtual printer archives whatever it receives, or holds it for review. BamDude's default mode saves the 3MF into the library as a file you can browse, tag, move into a folder and print later — which leaves the archive as what it is meant to be, a record of prints that actually happened.
- It can also feed either queue tier — a printer's own queue, or the Auto-Queue — as well as relay to a real printer.
- One record, not two. Upstream keeps a print log beside the archive. BamDude has no separate log because the archive is the log: every print is a row there — with its file, its plate, its filament, its energy and how it ended — so there is never a second list to reconcile against the first.
- A print nobody queued is still archived. Started from the printer's own screen, or sent straight from a slicer — BamDude notices it and builds the archive around it.
- If the file could not be fetched at the time, BamDude keeps trying. A printer that was busy, offline or mid-reconnect leaves an archive with no 3MF behind it; a retry service fills it in later from four separate triggers — a sweep at startup, the printer reconnecting, the print finishing, and a button.
- A reconciliation sweep compares what BamDude believes is printing against what the printers actually report, so a job that ended in a way nobody saw does not sit there forever claiming to be running.
- Two hashes per archive, because the file that prints is not always the file you handed over. BamDude patches the 3MF on its way to the printer, so an archive records both the original and the bytes actually sent. Deduplication on disk keys off the original — the same plate printed on five printers is stored once — and deleting an archive removes the file only when the last reference to it goes.
A project used to be a folder with a target number written on it. It is an order now: who it is for, what it is worth, when it is due — and lines that each say product × quantity. What a thing is made of is a property of the product, not of the order that happens to want twelve of them.
- Customers, orders, products and stock — four sections that mean different things. A line names a product and a quantity, with a material that filters and a colour that only hints; the order above it carries the customer, the price (and therefore the margin), the priority and the deadline. A product carries its parts — printed ones with how many go into one unit, purchased ones with a price and a link — and its plates, a plate being no more than "this plate of this file makes these parts". The same part sliced once per printer model is two plates of one product, not two products. Stock tracks finished configurations and free parts separately, with reservations, issues and dispatch notes.
- "What to print next", per line, recalculated on every read. BamDude picks plates greedily against the farm as it is loaded, until the line's shortfall is covered: plates that make the same still-needed parts are compared by when they would finish all of that work — one printer gets one 10-piece plate rather than two 5-piece prints, several printers still share it — and useful parts per hour only break ties. It subtracts what is already committed: prints in progress, everything sitting in both queues, and stock reserved for the line. Take from stock also reserves loose components even when no complete kit is available, so the plan asks only for the missing parts. Nothing is cached, so putting six plates in the queue and asking again offers six fewer.
- A line whose parts are sliced for two machines is offered both. Alternative plates of equal yield come with the row, and the count can be split across them — which is the only way one line's work reaches two printer models, because the auto-queue routes each file to the machines it was sliced for. Work sent from the plan carries the full print profile you saved for that model, macros and all, rather than the writer's own defaults.
- The split is a starting point, not a sentence. With Rebalance across printer models on (off by default), idle printers of another model take a line's still-pending prints when that finishes the line sooner — recalculating plates and counts for that bed, so a 6-part plate becomes three 2-part prints on a mini, or two parts one print on a bigger bed with at most a plate's worth of surplus. The same procedure runs on demand from the line's Rebalance button and from any pending row or
×Nblock on the auto-queue panel, which says why a row cannot move. Never moved: prints already handed to a printer, scheduled, staged, pinned to filament slots, aimed at a location, queued from an archive, or not filed under a line; a moved row wears a← P1Sbadge. - A print is filed under its order where it is started. The print and auto-queue dialogs ask "which order is this for?" and offer the orders that still need this plate first, with how many prints each still wants; the queue writers fill in the line themselves when exactly one line of the named order can accept the plate, and refuse to guess between two. An order is never guessed — one product stands in many orders, and only the person pressing Print knows which.
- A product's spare parts have a shelf of their own. The plate that makes four lids for an order that wanted three leaves a fourth: bank it to the product's free stock, and the next order can use it instead of printing it again. Reservations can take both complete kits and loose parts; mixed stock/print receipts count each part once. It is a ledger of movements rather than a stock column — every reservation, release, correction and credit is a row you can read — and a print that belongs to no order lands there by itself. Kits taken from stock count as done everywhere: the line's progress, the plan and the "everything is printed" banner all see them. The Stock tab shows every shelf on the farm at once — kits and balances per product, which active orders hold kits in reserve, and one journal of every movement — so the question is "what do we have", not "what does this product have".
- Defective parts still count against the target. An order for forty usable parts is not finished because forty came off the plates. Scrap is recorded per print and subtracted.
- Planned spare parts are an obligation of their own (since 0.7.1). A printed BOM part can carry an extra percentage, rounded up once for the order line. The line keeps its saved percentage when the catalog default changes. Extras do not change the base kit composition: they are planned, received and issued separately, and a customer order must deliver them before closing. See additional printed parts.
- Defects are recorded where you stand. Every completed print card on an order page shows printed and defective and offers Defects…; on the printer card the finished print's counters sit beside Clear plate and Repeat. In Telegram the complete assessment stays a short-lived, cancellable draft, bound to its bot, chat and operator, until the whole plate is confirmed; typed counts must reply to their own prompt, and the form refuses to overwrite an archive changed while it was open. Clear/Repeat buttons carry both the named run and its gate generation, so an old card cannot clear a newer plate. Statistics gain Defects by printer. A print already counted into free stock has its shelf credit corrected when defects are recorded later, in either direction.
- A file or folder belongs to the product — many-to-many, so one shared file can feed several products, and each product then feeds however many orders ask for it.
- A workshop holds shelves, a shelf holds printers. Printers, sensors and spool storage attach at whichever level fits, and the printers, queues and maintenance views group by them.
Both projects can set a temperature, a fan speed and jog the bed. BamDude speaks a considerably wider slice of the MQTT protocol beyond that, mirrored from BambuStudio's own sequences:
- The extruder and the steppers. Push and retract filament, and release the motors so the head can be pushed by hand. Both refuse a cold nozzle and a running print.
- The air duct as a whole, not just a fan speed — mode, filtration and every fan the machine has, with each fan's controllability resolved per mode, and the steps the printer actually accepts rather than a made-up 0/25/50/75/100.
- The print options Bambu Studio exposes and upstream never sends: air-print detection, auto-recovery, automatic filament switching, filament tangle, nozzle-blob detection, plate alignment, plate marking, plate type, air purification, sound, and saving remote prints to storage.
- The AMS as a device, not just slots — calibrate it, switch its firmware personality, reset its sequence, change its user settings. Backed by a Printer Settings and an AMS Settings dialog, each writing through MQTT and recording every applied change in an audit table.
- AMS Backup compatibility emulation — per printer, off by default: manually assigned spools can be advertised to the AMS under one canonical colour and/or the Generic profile of their base material, so the firmware treats several compatible spools as one auto-refill group. Only the advertisement changes — the spool, its colour, brand and accounting stay as they are, routing and dispatch keep matching the real spool, and RFID spools are never touched. The AMS Backup dialog applies the policy to the assigned slots with a preview and a per-slot reason, and the same button rolls them back; the printer's own reported backup groups stay the only proof a group actually formed.
- Filament calibration over MQTT — Pressure Advance and flow-rate runs started, tracked and read back, with K-profiles per nozzle and per extruder.
- Timelapse storage — which medium records it on a machine that has two, how much room is left there, and dropping the oldest recording to make room for the next one.
- The printer's answer is read back. Commands carry an acknowledgement listener, so a refusal is reported as a refusal instead of as success — and temperature requests are bounded by the machine's own limits rather than by a fixed table.
Also here:
- G-code macros — sequences you define, sent over MQTT, with plate-swap macros firing automatically between queued prints.
- 3MF patching on the way to the printer — mesh-mode flags and G-code injection are applied to a copy, so the archived file on disk stays the unpatched original.
X2D, P2S and the H2 family keep files in built-in storage as well as on a card. Both projects talk to those printers over FTP, which only ever sees the card — so with no card inserted the file browser is empty and every print fails, on a machine that needs no card at all.
BamDude speaks the printer's own file channel alongside FTP, and the difference shows up as ordinary behaviour rather than as a feature:
- The file browser has a SD card / Internal storage switch, and everything it does works on both — listing, downloading, plate previews, importing into the library, deleting. A printer with no card opens on its internal storage instead of on an empty list. Printers that have only a card show no switch and behave exactly as before.
- A print goes to internal storage when there is no card, over the same dispatch as always. Whether a printer gets this is decided by what the printer reports about itself, not by a list of model names — and a card that is present but unreadable still stops the print rather than being routed around.
- A print started from the printer's own screen gets its file into the archive, pulled back off the machine even when the card that would normally hold it isn't there.
- Timelapses are found on whichever medium recorded them, and the right one is attached. The printer reports the full path of the recording it has just finished, so that file is taken by name rather than "the first one that was not there before". On internal storage it also says which print each recording belongs to, matching it to the right archive outright.
The channel exists only on that newer generation, and BamDude decides by asking the printer rather than by model name — an open port proves nothing, since on A1 and P1 the same port belongs to the camera.
Bambu Studio thinks in filament families: one identity (filament_id) behind every "Generic PETG" or your own custom filament, with per-printer presets hanging under it. BamDude adopts that model outright:
- A built-in catalog of every official filament, distilled from Bambu Studio and OrcaSlicer themselves — names, vendors, types, temperatures, which printers each preset fits. No hardcoded tables, no cloud round-trips: slot names, tooltips and assignments resolve locally and offline.
- Your own cloud presets are mirrored in the background from both Bambu Cloud and Orca Cloud, so a custom filament created in either slicer is known here minutes later — family included.
- One family picker everywhere — the spool form, the AMS slot dialog, the K-profile editor. Spools link to a family, calibration auto-matching keys on it, and custom filaments finally match their own K-profiles instead of collapsing onto Generic.
- Create a filament in BamDude itself — vendor + type + serial, exactly like Bambu Studio's Create Filament dialog, with a Bambu-Studio-compatible identity and a root preset cloned per printer profile you tick. Optionally push it to Bambu Cloud, and desktop Bambu Studio sees it on its next sync; create it from the Bambu Cloud tab and it is born in the cloud outright.
-
Automatically assign full stock spools (since 0.7.1, built-in inventory). Opt in per printer and select an exact filament group. A witnessed insertion into an empty AMS slot takes the oldest eligible unused spool; manual assignments and RFID take priority. For an external holder, assignment requires an identified runout and the operator's resume, not ordinary loading. This assumes a new full reel: returning the old partial reel after runout needs manual assignment before insertion or resume. See setup and limits.
-
Ukrainian. Upstream ships twelve locales and Ukrainian is not among them. BamDude ships English and Ukrainian only, and both are strict: a key missing from either fails CI, and so does a placeholder that drifted between them.
-
Swap Mode — driving an A1 / A1 Mini / A2L plate swapper, with Kit, STL and JobOx profiles, swap files detected automatically, and the swap macro fired between queued prints.
-
Low-stock forecast alerts — the reorder forecast raises a notification rather than only colouring a panel nobody has open.
-
An audit row for every applied change to printer settings, AMS settings and calibration — what was sent, when, and by whom.
-
Notes on library files, and print-dialog options remembered per user and per printer model.
- Own your data — All print history stored locally, no cloud dependency
- Works offline — Uses Developer Mode for direct printer control via local network
- Full automation — Schedule prints, auto power-off, get notified when done
- Multi-printer support — Manage your entire print farm from one interface
|
The optional AI assistant connection provides read-only MCP diagnostics: farm and printer status, service health, archive timelines, opt-in sanitized logs, persisted energy, recovery explanations and period summaries. It discovers the tools allowed by the key owner's permissions and printer scope, labels unknown or incomplete evidence, and leaves repairs to the operator in the normal UI. BamDude AI includes a setup panel, client packages and a shared diagnostic skill for Claude Desktop, Claude Code and Codex. MCP is disabled by default; each key must opt in, with a separate log-access permission. Your chosen client may send returned data to its model provider. This is development work after v0.7.2, not a claim that the published v0.7.2 includes MCP; see the connection guide and support matrix for verified clients and remaining limits.
|
Plus: Customizable themes, mobile responsive, multi-language (EN/UK), auto updates, database backup/restore, PostgreSQL support — bundled or your own
- Python 3.12+ (only for a native install — the Docker image bundles its own)
- macOS 12+ for a native macOS install
- Bambu Lab printer with Developer Mode enabled
- Same local network as printer
docker run -d \
--name bamdude \
--network host \
-e TZ=Europe/Kyiv \
-v bamdude_data:/app/data \
-v bamdude_logs:/app/logs \
--restart unless-stopped \
kainpl/bamdude:latestOpen http://localhost:8000 in your browser.
macOS/Windows: Docker Desktop doesn't support
--network host. Use-p 8000:8000instead and add printers manually by IP.
git clone https://github.com/kainpl/bamdude.git
cd bamdude
docker compose up -d --buildgit clone https://github.com/kainpl/bamdude.git
cd bamdude
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn backend.app.main:app --host 0.0.0.0 --port 8000 --loop asyncio --timeout-graceful-shutdown 15Windows (native): download the latest bamdude-windows-setup.exe from the Releases page and run it. It's a self-contained installer (embedded Python — no Python or Node install required) that sets up a data directory and registers BamDude as an NSSM-supervised Windows Service that autostarts on boot.
See install/README.md for options, or installers/windows/ to build the installer yourself.
SmartScreen: the installer is not code-signed, so Windows shows "Windows protected your PC" on first run — click More info → Run anyway.
BamDude uses SQLite by default — nothing to set up. One variable, DATABASE_URL, switches it:
DATABASE_URL |
Backend |
|---|---|
| empty / unset | SQLite (default) |
embedded |
a PostgreSQL 18 that ships with BamDude and that BamDude starts and stops for you |
postgresql+asyncpg://… |
your own PostgreSQL server |
The bundled server comes from our open-source embedded-postgres package (PostgreSQL 18 + pgvector + pg_stat_statements; Linux x86_64/aarch64/armv7l, macOS, Windows) and arrives with the Python dependencies — nothing to install by hand. It lives under DATA_DIR/postgres/, listens on 127.0.0.1 only, and generates its own password. Pin EMBEDDED_PG_PORT=6432 if you want to reach it with psql or DBeaver.
Every installer asks which one you want: install.sh --db sqlite|embedded|external, a Database page in the Windows installer (where the bundled server can run as its own BamDudePostgres service), and the same question in docker-install.sh. Switching from SQLite imports your existing database automatically on the next start.
Full manual: https://docs.bamdude.top/features/postgresql/
For full diagnostics on an external server, enable pg_stat_statements in the database BamDude uses. The guide covers third-party images and host installations; changing only the BamDude image does not configure that server.
Full manual: https://docs.bamdude.top/getting-started/upgrading/ (source) — covers migration from Bambuddy-HE / BamDude 0.2.x, routine BamDude-to-BamDude updates, switching between self-install / Docker / GHCR, and rollback.
Short version:
- From Bambuddy — no longer supported since 0.6.0. BamDude forked at Bambuddy 2.2.2 and the two schemas have diverged too far for a one-time import; start BamDude with an empty data directory and re-add printers and spools.
- From Bambuddy-HE / BamDude 0.2.x / 0.3.x (tested & supported) — Docker users run
install/migrate-volumes.shonce to copybambuddy_he_*→bamdude_*; native users just point the installer at the existing data dir.
- Create a bot via @BotFather, get the token
- In BamDude Settings > Notifications, add a Telegram provider with the bot token
- Enable Registration Mode, send
/startto the bot from your Telegram - In Settings > Telegram Chats, assign a role to your chat and enable it
- Done! Use the reply keyboard or inline menus to control printers
- On printer: Settings > Network > LAN Only Mode > Enable
- Enable Developer Mode
- Note the Access Code and IP address
| Component | Technology |
|---|---|
| Backend | Python, FastAPI, SQLAlchemy, aiogram 3.x |
| Frontend | React 19, TypeScript, Tailwind CSS 4 |
| Database | SQLite (default), your own PostgreSQL, or a bundled PostgreSQL 18 on native installs |
| 3D Viewer | Three.js |
| Part thumbnails | Pinned Node.js (bundled in Docker and the Windows installer) |
| Communication | MQTT (TLS), FTPS |
| Telegram | aiogram 3.x, MarkdownV2, FSM |
| Series | Models |
|---|---|
| X1 | X1, X1 Carbon, X1E |
| H2 | H2D, H2D Pro, H2C, H2S |
| P1 | P1P, P1S |
| P2 | P2S |
| X2 | X2D |
| A2 | A2L |
| A1 | A1, A1 Mini |
# Backend
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
# --loop asyncio is not optional, in development either: uvicorn[standard]
# picks uvloop, whose TLS layer can silently truncate a file transfer.
DEBUG=true uvicorn backend.app.main:app --reload --loop asyncio --timeout-graceful-shutdown 15
# Frontend (separate terminal)
cd frontend && npm install && npm run devWant to contribute? CONTRIBUTING.md has the setup, the checks
CI runs and the house rules; SECURITY.md is for vulnerabilities.
Working with a coding agent? CLAUDE.md is the engineering guide it
should read first (AGENTS.md points there for other tools), and
each release attaches the repository's code graph (bamdude-code-graph-*.json.gz).
AGPL-3.0 License — see LICENSE for details.
https://docs.bamdude.top/privacy/. BamDude talks to your printers on your own network. The only data it sends out is anonymised usage telemetry (on by default; opt out in Settings or with TELEMETRY_DISABLED=true) and the bug reports you file explicitly. Optional integrations you enable yourself (Telegram, Spoolman, Obico, an OIDC provider, …) send data to the services you configure, under those services' own policies.
