Kaloscope and the visual workflow engine behind a local media library
A local media library management tool powered by visual workflows
At a glance
- What is it?
- Kaloscope is a self-hosted media library manager whose searching, scraping, downloading and library maintenance are all expressed as editable node graphs you build in a browser, with a Python and Svelte backend packaged as a Docker container for a NAS. The interesting engineering is that the indexer is itself a workflow, and the interesting constraint is that the container needs an identity mapping to your media files or the library will not be able to write them.
- Who is it for?
- Kaloscope is a good fit for someone running a home NAS who wants media search and acquisition defined as an editable graph rather than as a set of scripts, because the indexer, the downloader and the library rules are all the same mechanism, and the whole thing deploys as one container plus a data volume.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Kaloscope is, and the idea that makes it different
Kaloscope is described as a local media library management tool powered by visual workflows, and the project's own summary makes the architecture explicit. It is a local media library management tool built on a visual workflow engine, where the resource search and metadata scraping capabilities are both driven by editable workflows, so it can connect to any resource site or metadata source.
That is the whole thesis. A conventional media manager has a hard-coded provider: it knows about a fixed set of sites and a fixed set of scrapers, and extending it means writing code and shipping a new version. In Kaloscope the indexer is a workflow graph you edit in the browser, so the boundary between the tool and the site you want to query moves from a code change to a configuration change.
The stack in the badges gives a good picture of the shape. The frontend is Svelte at version 5.57.1 with xyflow at 1.7.0, which is the node-graph library that draws a workflow editor, and the backend is Sanic at 25.12.1 on Python 3.13 or newer. The licence is GPLv3, the homepage is kaloscope.org, the last push was on 2026-10-20, and the recent releases are v0.12.1 from 2026-10-16, v0.12.0 from 2026-10-11 and v0.11.0 from 2026-10-01.
The topic list names the domains it covers: anime, bt, danmaku, docker, manga, media, movie, nas, novel, rss, torrent and workflow. The presence of nas in that list is the clearest signal of the intended deployment, and torrent and bt say plainly that acquisition of files is part of the design rather than an afterthought.
The audience is a self-hosting household or small group with a NAS, willing to build their own workflows. The documentation is linked in four places at the top of the readme, with an introduction, a deployment guide, a FAQ and a development page, all under kaloscope.org/docs, and there is a separate GitHub repository for workflow templates, plus a Telegram group.
The workflow engine, and the node types you get
The workflow section is the core of the product, and it lists four capabilities.
There is a node-based visual workflow editor where you build a business process by dragging. There are built-in node types for HTTP requests, Python scripts, conditional branches and loop control. You can import community workflow templates from a GitHub repository to reuse existing solutions quickly. And there is scheduled triggering, so a workflow can run automatically on a plan.
The node types are what make this more than a picture of a process. An HTTP request node and a Python script node means the workflow can do anything a script can do, and a conditional branch plus loop control means a workflow can express iteration over search results rather than a fixed sequence of steps.
The resource search section applies the same model to the indexer. The indexer is entirely driven by workflows and can connect to any resource site. It supports keyword search, detail preview and login authentication as complete interaction flows, so the workflow is not limited to a single request; it can log in, paginate, and preview a result page. There is global search that aggregates results from multiple indexers at once.
The download management section is where the workflow model meets a conventional downloader. It supports aria2, qBittorrent and Transmission, and it can pin OpenList's cloud drive offline download tool as the downloader and pull the remote result straight to local. Downloader configuration is defined in YAML, with adapters that can be extended as needed. There are download schedules that automatically fetch and dispatch download tasks by keyword and filter rules, and manual adding of magnet links or torrent files.
The library management section is more conventional. It supports several media library types including movies and television series, watches the filesystem in real time to pick up new media files automatically, and generates and parses NFO files to sync metadata.
Then there is playback. There is a built-in video player supporting FLV, HLS and MP4, real-time transcoding to an HLS stream with output quality limits, hardware-accelerated encoding through NVENC, VAAPI and VideoToolbox, danmaku display with a mobile-style fullscreen mode, and playback progress recording with resume.
The user model has multiple users with administrator and normal roles, access assignable per library and per indexer, and per-user preferences and avatar customisation. And there is PWA support, so the interface works on a phone.
Running the container, and the identity problem
The quick start is a single container run, and the command is long because every decision is explicit:
docker run -d \
--name kaloscope \
--add-host=host.docker.internal:host-gateway \
-e PUID=1026 \
-e PGID=100 \
-e UMASK=022 \
-e TZ=Asia/Shanghai \
-e AUTO_TLS=true \
-e TLS_HOSTNAME=192.168.31.2 \
-e ENABLE_ARIA2=true \
-v /volume1/kaloscope/workspace:/workspace \
-v /volume1/kaloscope/downloads:/downloads \
-v /volume1/kaloscope/anime:/anime \
-p 8000:8000 \
-p 6888:6888 \
-p 6888:6888/udp \
--restart unless-stopped \
kaloscope/kaloscope:latestThe environment variables are the ones to understand first. PUID and PGID default to 0 and are described as the UID and GID the process runs as, with the recommendation that on a NAS you set them to the owner of the media directory. UMASK defaults to 022 and controls the default permissions of newly created files inside the container. TZ sets the container timezone. AUTO_TLS defaults to false and uses mkcert to issue a local TLS certificate automatically, which the readme suggests for users who need HTTPS on the local network, and TLS_HOSTNAME names the host or IP the certificate binds to and only takes effect when AUTO_TLS is true. ENABLE_ARIA2 defaults to false and starts a built-in aria2 service inside the container for people who do not want to run a separate downloader.
The port mapping is minimal. 8000 over TCP is the web interface, and 6888 over both TCP and UDP is the aria2 DHT and BitTorrent listening port, needed only when ENABLE_ARIA2 is true.
The volume table has one row and one requirement. The /workspace path inside the container is the persistent storage directory and is marked as required, because it guarantees data survives a container restart. The /downloads and /anime mounts in the example are just the user's media directories.
That is where the PUID and PGID setting stops being optional. If the container runs as root and writes into a media directory owned by a NAS user, the files it creates end up owned by root, and the NAS share then behaves strangely for everyone else. Setting PUID and PGID to the media directory's owner is the fix, and it is the one configuration step worth getting right on the first run rather than after.
How the image is built, and what is inside it
The Dockerfile shows a two-stage build that mirrors the split between the Svelte frontend and the Python backend, and the comments in the file are unusually informative about why each package is there.
The first stage uses node:24-slim with the build platform passed in, installs pnpm globally, and copies the frontend package manifest, lockfile and workspace file first so the dependency layer caches separately from the source. It then installs with a frozen lockfile, copies the frontend source, and runs the production build.
The second stage is python:3.13-slim, and the runtime dependency list reads like a manual. git is needed by gitpython, libxml2 and libxslt1.1 are needed by lxml, gosu is used to drop privileges, aria2 is the optional download manager, curl and libnss3-tools are used by mkcert at runtime, media-types is used for MIME type detection, and ffmpeg is used for media transcoding. There are also three Intel-specific packages, the intel-media-va-driver-non-free runtime with encode shaders, libvpl2 and libmfx-gen1.2 for the newer oneVPL and QSV runtime, and libmfx1 for the older Intel Media SDK runtime, each marked as amd64 only. The apt sources are extended with the non-free and non-free-firmware Debian repositories so those Intel packages are installable at all.
That is a well-chosen dependency set for what the application does. ffmpeg at runtime rather than at build time is the decision that matters most, because the real-time transcoding feature needs it on every playback. The Intel packages with encode shaders are there for the hardware-accelerated encoding claim, and the fact that the driver is from non-free means the container will not work on every architecture without adjustment.
The repository layout reflects the same split, with a frontend/ directory, a backend/ directory, a Dockerfile, a scripts/ directory, a pre-commit configuration, an AGENTS.md file, a LICENSES.md, and a separate English readme alongside the Chinese original. The Docker Hub pulls badge and the GitHub release badge show both distribution channels are in use, and the release cadence, three releases in the first three weeks of October 2026, says the project is moving quickly.
Where Kaloscope is the wrong choice
Three limits follow from what the tool is.
The first is the effort curve. The value of a workflow-driven tool is proportional to the quality of the workflows you write, and a workflow that targets a site it does not know will not work until you adapt it. For a user who wants their library indexed tomorrow, that is a project. For a user who enjoys building a small automation graph per source site, it is exactly the right shape. The readme points to a workflow template repository, which tells you the community expects people to share these graphs, and that is the mitigation: you start from someone else's work rather than from a blank canvas.
The second is the platform and the browser support around acquisition. The download section lists aria2, qBittorrent and Transmission, and the built-in aria2 option is explicitly a convenience for people who do not want to run a separate downloader. None of that is a problem in itself, but it does mean the tool is designed for BitTorrent-based sources, and the topic list of bt, torrent, danmaku, anime and manga says the same thing. The media formats it handles best are the ones those ecosystems produce.
The third is that a workflow engine executing arbitrary Python and HTTP requests inside a container that also handles your media library and holds a torrent client is a meaningful security surface. The readme does not describe a sandboxing model for workflow scripts, and the project is a self-hosted tool for a home network rather than a multi-tenant service, so the risk is mostly about what you install from the template repository.
The alternative worth comparing against is a plain downloader and a plain media server: qBittorrent or Transmission for the acquisition, Jellyfin or Emby for the library, and a script for the metadata. That stack is less integrated and less flexible, and every part of it is a mature project with a large user base. Kaloscope earns its place when the workflows themselves are the point, that is, when the same search and fetch logic has to run across many sites with different shapes, and a fixed provider would need replacing every time one of them changes.
Editorial conclusion
Kaloscope is a good fit for someone running a home NAS who wants media search and acquisition defined as an editable graph rather than as a set of scripts, because the indexer, the downloader and the library rules are all the same mechanism, and the whole thing deploys as one container plus a data volume. It is a poor fit if you want a set-and-forget media server, because the value is in the workflows you build and in the per-site indexers you adapt, and a poor fit if you cannot give the container a UID and GID that match your media directory, since the README says that is what the PUID and PGID settings are for. Before deploying, read the deployment guide rather than the readme alone, and decide which downloader you want, because the built-in aria2 is optional and qBittorrent and Transmission are equally supported.
Frequently asked questions
What is Kaloscope?
It is a local media library management tool powered by visual workflows. Its resource search and metadata scraping are both driven by editable node graphs, so it can be pointed at arbitrary resource sites and metadata sources, with the backend in Python and Sanic and the frontend in Svelte with xyflow.
How do I run Kaloscope with Docker?
Run the container with `docker run -d --name kaloscope` and the documented flags, mounting /workspace as the persistent storage directory and the media directories you need, and publishing port 8000 for the web interface. Port 6888 over TCP and UDP is only needed when the built-in aria2 is enabled.
Why do I need to set PUID and PGID for Kaloscope?
They set the UID and GID the container process runs as, and on a NAS they should match the owner of the media directory. Leaving them at their default of 0 means files created in your media share end up owned by root, which breaks the share for every other user on the machine.
Which downloaders does Kaloscope support?
aria2, qBittorrent and Transmission, with the downloader configuration defined in YAML and adapters that can be extended. The container can also start a built-in aria2 service when ENABLE_ARIA2 is true, and it can use OpenList's cloud drive offline download tool and pull the remote result straight to local.
What node types does the Kaloscope workflow editor provide?
HTTP request, Python script, conditional branch and loop control nodes, with the option to import community workflow templates from GitHub and to trigger workflows on a schedule. The indexer is built from the same nodes, so search, detail preview and login flows are all expressed as a graph.
What licence is Kaloscope released under?
GPLv3, with the licence file at the repository root and a LICENSES.md alongside it. The most recent release is v0.12.1 from 2026-10-16, the last push was on 2026-10-20, and the homepage is kaloscope.org.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kaloscope-kaloscope)Was this useful?