惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
A
About on SuperTechFans
NISL@THU
NISL@THU
V
Visual Studio Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
美团技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Google DeepMind News
Google DeepMind News
小众软件
小众软件
博客园 - Franky
罗磊的独立博客
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
MongoDB | Blog
MongoDB | Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
B
Blog
The GitHub Blog
The GitHub Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
有赞技术团队
有赞技术团队
Hacker News - Newest:
Hacker News - Newest: "LLM"
Cyberwarzone
Cyberwarzone
C
CXSECURITY Database RSS Feed - CXSecurity.com
Project Zero
Project Zero
Security Latest
Security Latest
L
Lohrmann on Cybersecurity
AWS News Blog
AWS News Blog
The Hacker News
The Hacker News
I
Intezer
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Privacy International News Feed
月光博客
月光博客
A
Arctic Wolf
Apple Machine Learning Research
Apple Machine Learning Research
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园_首页
WordPress大学
WordPress大学
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Tor Project blog
博客园 - 三生石上(FineUI控件)
The Last Watchdog
The Last Watchdog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org

Show HN

GitHub - steveking-gh/firmion: Firmion is DSL and engine for firmware image generation. GitHub - villagesql/villagesql-skills: Agent skills for VillageSQL - gemini-cli-extension; claude-code-plugin GitHub - flightdeckhq/flightdeck: Observability and control plane for AI agents. CSP Radar GitHub - Light-Heart-Labs/DreamServer: Turn your PC, Mac, or Linux box into an AI server. LLM inference, chat UI, voice, agents, workflows, RAG, and image generation. GitHub - Diplomat-ai/diplomat-agent-ts: What can your TypeScript AI agent do to the real world? Scan your code. See which tool calls have zero checks Code Block Selector - Visual Studio Marketplace Prometheus dependency graph — interactive showcase | Riftmap Show HN: I made a vi-like modal keyboard plugin for Figma GitHub - run-llama/liteparse: A fast, helpful, and open-source document parser GitHub - dalemyers/Roar: A macOS CLI tool for notifications GitHub - district-solutions/open-agent-tools-coder: Enables small-to-large self-hosted ai models to use local source code when running tool-calling agentic workloads. We actively data mine 20,900+ (2+ TB) popular github repos using large and small ai models to create reuseable: json, markdown and parquet files for local-first tool-calling models. GitHub - progapandist/stripeek: A local TUI proxy for real-time Stripe API debugging, built for navigating complex payloads fast. GitHub - sir1st/hermes-desktop: All-in-one cross-platform desktop app for Hermes Agent — bundles Python + hermes-agent + hermes-web-ui GitHub - astefanutti/shaderbang: Shebang for Shaders Show HN: Generate Claude Code Workflows using Spec Driven Development approach GitHub - nixys/nxs-universal-chart: The Helm chart you can use to install any of your applications into Kubernetes/OpenShift Show HN: AI agents for UK GDAD PCF roles and their skills The Two Pillars: Mixer Mode and Meta-Software in the Reorganization of Software Work After AI GitHub - JaiCode08/teleport-env What 1,000+ Harness Experiments Taught Me About Self-Improving Agents Show HN: Liiists, a Markdown-first, iOS and CLI list app SwiperTab – Get this Extension for 🦊 Firefox (en-US) GitHub - kouhxp/fftext: Summarize, explain, fact-check, or translate any text, URL, or file. No GPU. No cloud. One command GitHub - sweetpad-dev/sweetpad: Develop Swift/iOS projects using VSCode GitHub - dogmaticdev/IRON: IRON a.k.a. Intermediate Representation Object Notation is a Interpreter/Database that is used to create Programming Languages. GitHub - sjhalani7/vaen: Package your AI coding harness into a portable .agent file, and share it across repos, teams, & the community without ever having to copy-paste instructions, skills, MCP config, or secrets. Show HN: Gandalf the Grader Show HN: Citadeld – replay any CI failure locally from a single file GitHub - tdortman/cuSBF: High-Performance GPU Super Bloom Filter coral-ai/claude-code-token-xray at main · Coral-Bricks-AI/coral-ai GitHub - ulyssestenn/funes: Funes is a Git-based framework for LLM-managed knowledge work: an AI Librarian ingests raw sources, builds an interlinked Markdown knowledge base, and uses it to produce cited reports, analyses, and other outputs. GitHub - ThatXliner/gah: Git Add Hunk, built for agents to use GitHub - harmont-dev/harmont-cli: Command-line client for the Harmont CI platform GitHub - brooksmcmillin/mcp-authflow: OAuth 2.0 Authorization Server framework for MCP servers GitHub - javaid-codes/audit-supply-chain-agents GitHub - amorey/gochan: A small library of common channel architectures for Go, inspired by Rust GitHub - arifozgun/OpenGem: Free, Open-Source AI API Gateway with Gemini, OpenAI & Anthropic Compatibility in 1 file GitHub - Pranesh950/BioPetals: 🌸 Run BIOxAI models at home, BitTorrent-style. Fine-tuning and inference up to 10x faster than offloading GitHub - cnguyen14/bounty-doctor: Diagnose a GitHub bounty issue before you waste hours: detects honeypot scam repos, AI-bot attempt swarms, and stale contests. Show HN: CoreMCP – MCP Server for On-Prem DBs Show HN: KittyHTML – Render HTML/CSS as an inline image in your terminal GitHub - bingud/filemat: Web-based file manager Show HN: TruthLens – Free multi-signal deepfake image detector GitHub - apexlocal-jz/claude-usage-tray: Windows system-tray app showing your Claude Code rate-limit usage at a glance. Zero deps, ~300 lines of PowerShell. Cross-IDE (works regardless of VS Code, Cursor, plain terminal). Release v0.1.2.1 · kouhxp/yapsnap GitHub - noopolis/moltnet: Self-hostable chat network for AI agents. Pre-built bridges for Claude Code, Codex, and the Claws. Rooms, DMs, history. No Slack bots, no Matrix, no glue code. GitHub - tamerh/enju: Coordinating Humans, AI Agents, and Compute as Peers on a Shared Workflow Graph Show HN: Continuity-auth – Respect-weighted rate limits for the open web GitHub - luml-ai/luml: AI lifecycle platform where engineers and agents track experiments, train models, and ship to production. GitHub - mrdanielcasper/CoreTex: A UNIX-inspired, biomimetic, flat-file AI harness and knowledge engine. GitHub - clemg/pierre-github: Pierre's diffs.com and trees.software for Github GitHub - lyriks-io/unspaghettit: Behavior-driven AI development without prompt spaghetti. GitHub - sofumel/claude-handoff-revive: Resume Claude Code work after rate/usage/context limits without replaying the prior transcript. Auto-saves at 90%/95% usage. Plugin-installable, 10 languages. GitHub - dotexorg/saferpc: Typed, end-to-end encrypted RPC over any bidirectional channel. GitHub - BeeZeeAgent/beezee: Agent harness orchestration Legato Next.js Boilerplate for Internal Tools · CoreUI GitHub - clark-labs-inc/clark-hash: Clark Hash, 32x smaller searchable sketches for embeddings GitHub - ZeroPointRepo/youtube-mcp: The fastest YouTube transcript + YouTube search MCP for AI agents. Try for free. Typing Mastery — climb toward 100+ WPM, deliberately GitHub - Andebugulin/Awareen GitHub - fayzan123/claude-workflow-composer: Visual desktop app for composing multi-agent coding workflows. Drag agents, attach skills and MCPs, wire handoffs, export to .claude/ GitHub - harshaneel/humanize: Best static AI text humanizer. Two research-grounded skills that work in any LLM (Claude, ChatGPT, Gemini, Codex): humanize beats perplexity-based detectors, ai-check produces forensic scoring with evidence-quoted flags. Nine levers, 50+ peer-reviewed sources, 2024-2026 detection literature. GitHub - StackOneHQ/stack-nudge GitHub - nodes-app/swift-markdown-engine: A native AppKit Markdown editor for macOS, built on TextKit 2 and bridged to SwiftUI. We hardened an LLM agent. Each defense we added made it more exploitable. GitHub - alkait/WhatsKept: Agent-queryable WhatsApp history from an iOS backup — a single Go binary. GitHub - octelium/cordium: Open-source, general-purpose sandbox platform for devs and AI agents that provides identity-based secure access to infrastructure without credentials. WAR.GOV/UFO Microfilm5 GitHub - scosman/videowright: Build animated explainer videos with your coding agent GitHub - dipankar/dscode: The code editor you can take apart. GitHub - zoharbabin/web-researcher-mcp: MCP server (Go) for AI assistants: web search, content extraction, academic/patent/news research. Multi-provider routing, 4-tier scraping, search lenses. Works with Claude, Cursor, and any MCP client. GitHub - ruvnet/RuView: π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video. GitHub - scanaislop/aislop: Catch the slop AI coding agents leave in your code: narrative comments, swallowed exceptions, as-any casts, dead code, oversized functions. 50+ rules across 7 languages (TypeScript, JavaScript, Python, Go, Rust, Ruby, PHP). Sub-second, deterministic, no LLM at runtime. MIT-licensed. GitHub - kouhxp/cheap-im: CPU-only voice agent approximating Thinking Machines' Interaction Models demo GitHub - unprovable/OrchidMantis: Orchid Mantis — standalone framework for Zero-Knowledge Proofs of eXploit (ZKPoX). GitHub - MarcellM01/TinySearch: Shrink the web for your local LLMs! GitHub - TangibleResearch/Halgorithem: A Algo designed to detect AI Hallucitions GitHub - DO-SAY-GO/freelang: I love freelang GitHub - CarpseDeam/Aura-IDE: An AI coding harness that shaped itself - Planner/Worker agents, repo awareness, surgical edits, validation, recovery, and safe diff approvals. GitHub - chojs23/concord: A feature-rich TUI client for Discord GitHub - tommyjepsen/awesome-ux-skills: UX & AI Product designs skills you can use today in Claude Code GitHub - aerf-spec/aerf: Agent Evidence Receipt Format (AERF) — an open specification for tamper-evident, independently verifiable records of AI agent actions. GitHub - kklimuk/docx-cli: CLI for AI agents (Claude, Codex) to read, edit, and comment on .docx files with full format fidelity. GitHub - Jwrede/tokentoll: Catch LLM cost changes in code review. Infracost for LLM spend. GitHub - samchon/ttsc: A `typescript-go` toolchain for compiler-powered plugins and type-safe execution + 500x faster lint integrated into compiler GitHub - Higangssh/homebutler: 🏠 Manage your homelab from chat. Single binary, zero dependencies. GitHub - olalie/tapmap: See where your computer connects and what stands out on a live world map. GitHub - Diplomat-ai/diplomat-agent: What can your AI agent do to the real world? Scan your code. See which tool calls have zero checks GitHub - Bajusz15/beacon: Open-source agent for secure remote access, monitoring, and deploys across home-lab and self-hosted machines like Raspberry Pi, N100, or any Linux server. Open web based TTY or tunnel Home Assistant and other local services securely without opening ports. BigTech AI News - Chrome 应用商店 GitHub - vinhnx/VTCode: VT Code is an open-source coding agent with LLM-native code understanding and robust shell safety. Supports multiple LLM providers with automatic failover and efficient context management. GitHub - michaelaz774/decision-engine: A decision operating system for startup founders, powered by Claude Code. Synthesizes wisdom from 25+ legendary founders and investors into interactive AI-driven decision frameworks. GitHub - Chrilleweb/dotenv-diff: Validate environment variable usage in your codebase GitHub - Lumen-Labs/brainapi2: BrainAPI is a knowledge graph–powered AI memory layer that transforms unstructured data into structured knowledge, enabling intelligent search, recommendations, and contextual memory for AI agents and applications. GitHub - familiar-software/familiar: Let AI watch you work. Familiar lets your AI update its memory, skills, and knowledge by watching your screen. GitHub - skorotkiewicz/rudo: A small, elegant dock for Wayland GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. make sidebar/address bar rounded corner toggleable
GitHub - Sohex/musefs: Read-only passthrough FUSE filesystem presenting a virtually reorganized, re-tagged view of a music library backed by SQLite — without copying or modifying audio bytes.
sohex · 2026-06-13 · via Show HN

musefs — tag your library without duplicating a single byte

CI Coverage Release License: MIT

A read-only FUSE filesystem that presents a re-tagged, reorganized view of your music library — without modifying or duplicating a single byte of the original audio. Fix tags, art, and folder structure in a SQLite store; the mount shows a clean library while your files stay exactly as they are.

Quick start

cargo install musefs    # compiles from source — needs a Rust toolchain,
                        # libfuse3-dev and pkg-config; prebuilt binaries
                        # and container images: see Installing

musefs scan ~/Music --db library.db        # ingest your library
mkdir -p ~/mnt/music
musefs mount ~/mnt/music --db library.db \
    --template '$albumartist/$album/$title'
# mount blocks until unmounted: fusermount -u ~/mnt/music (or Ctrl-C)

~/mnt/music now serves your library as Album Artist/Album/Title.flac — with each file's metadata generated fresh from the database, spliced in front of your original, untouched audio.

What it's for

  • A clean view of a messy library. Your files keep their on-disk chaos; the mount presents one consistent, template-driven tree for players and media managers.
  • Tag editing without touching files. Edit the SQLite store (directly, or via the beets plugin, Picard plugin, or Lidarr integration) and the mounted view updates live — no remount, no rewrite, no re-rip anxiety.
  • Lossless-by-construction experimentation. Change your tags, try a different organization scheme, new cover art — the originals are physically read-only to the mount. Backing up a current library is as easy as copying the db file.
  • Hash-stable by construction. The mount never rewrites a byte, so each backing file's checksum is exactly what it was the day it arrived — anything verified by hash keeps verifying, and anything you're seeding keeps seeding, however aggressively you retag and reorganize the view on top.

Note

This project was built with AI. The general workflow was to use the superpowers skills to provide a framework. Claude Opus was used to write plans and specs which were then implemented by another model, primarily MiMo v2.5.

One of my goals in building this project was to "vibe code" something that was decisively not slop. I believe I've realized that objective and I hope that you take the project on its merits.

If you disagree, please let me know! I'd love to know where I came up short so I can improve things.

Installing

Three ways to get musefs: a prebuilt binary (no toolchain needed), building from source, or a container image. Whichever you pick, mounting needs a 64-bit FUSE-capable OS (Linux, FreeBSD, macOS) — see Platform support.

Important

Linux and FreeBSD are E2E tested. I don't have anything running macOS to test on, if you run this on one let me know if it works, or especially if it doesn't!

At present only AMD64 and AARCH64 are supported. If you'd like 32-bit support please open an issue.

Prebuilt binaries

Each tagged release attaches static/portable Linux binaries for four targets:

Target libc Notes
x86_64-unknown-linux-gnu glibc Pinned to glibc 2.17 — runs on essentially any current distro.
aarch64-unknown-linux-gnu glibc glibc 2.17 floor, ARM64.
x86_64-unknown-linux-musl musl Fully static — runs on Alpine / scratch containers.
aarch64-unknown-linux-musl musl Fully static, ARM64.

Download the tarball for your target from the latest release, verify it, and extract:

sha256sum -c musefs-<version>-<target>.tar.gz.sha256
tar -xzf musefs-<version>-<target>.tar.gz   # yields ./musefs

Runtime requirements: the binaries mount via FUSE's fusermount3 helper, so the target needs the FUSE userspace tools and /dev/fuse:

  • Debian/Ubuntu: apt-get install fuse3
  • Alpine: apk add fuse3

No glibc/libfuse install is needed for the musl binaries beyond fuse3.

Building from source

cargo install musefs compiles the latest release; building needs a stable Rust toolchain (2024 edition) plus the FUSE headers (libfuse3-dev) and pkg-config. To install the latest development version instead:

cargo install --git https://github.com/Sohex/musefs musefs

The same fuse3 runtime requirement as the prebuilt binaries applies.

Container images

Each tagged release also publishes multi-arch images to the GitHub Container Registry:

Image libc Platforms
ghcr.io/sohex/musefs:<version>, ghcr.io/sohex/musefs:latest glibc amd64, arm64
ghcr.io/sohex/musefs:<version>-musl, ghcr.io/sohex/musefs:musl musl amd64, arm64

docker pull selects the CPU architecture automatically. Use the -musl / :musl tags when slotting musefs into an Alpine-based stack; the default (glibc) tags suit everything else. Floating :latest / :musl track the most recent stable release only — prereleases publish only version-pinned tags.

Running musefs on the host is the simplest, best-supported option — it is an ordinary FUSE daemon and the image exists mainly to colocate musefs with containerized media managers (e.g. Lidarr). If you do containerize, mind the gotchas below.

Required flags

musefs mounts via FUSE, so the container needs /dev/fuse and the matching capability:

docker run --rm \
  --device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor=unconfined \
  -v /path/to/library:/library:ro \
  -v /path/to/store:/store \
  ghcr.io/sohex/musefs:latest scan /library --db /store/musefs.db

Without --device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor=unconfined the mount cannot be established.

Note

The apparmor flag may or may not be necessary depending on how your system is configured.

Note that CAP_SYS_ADMIN is a broadly privileged capability — it grants far more than FUSE mounting (mounting arbitrary filesystems, and more). It is unavoidable for an in-container FUSE mount — even rootless Podman cannot drop it; without --cap-add SYS_ADMIN the mount fails with fusermount3: mount failed: Permission denied. Under rootless Podman the capability is confined to the container's user namespace rather than the host, so its blast radius is smaller, but it is still required. Running musefs on the host needs no such capability at all.

Runs as a non-root user

The images run as a dedicated unprivileged user (default uid/gid 1000), not root — musefs mounts via the setuid fusermount3 helper and needs no root of its own. Consequences for the commands above:

  • The bind-mounted store volume must be writable by that uid. Either chown 1000:1000 /path/to/store on the host, or add --user $(id -u):$(id -g) to run as your own uid. The library volume is mounted :ro, so its ownership does not matter.
  • To bake an image whose user matches your host account (so no chown or --user is needed), build from source with --build-arg MUSEFS_UID=$(id -u) --build-arg MUSEFS_GID=$(id -g).
  • The images include user_allow_other in /etc/fuse.conf, so a non-root --allow-other / --owner / --group mount (needed to share the mount across containers or users, below) passes musefs's pre-flight check. See Ownership and permissions.

The mount-visibility gotcha (read this before sharing the mount)

A FUSE mount made inside a container lives in that container's mount namespace. By default neither the host nor other containers can see it, so pointing a second container (your media manager) at musefs's output does not work out of the box. To share the mount you propagate it between containers through a host directory: musefs binds that directory with rshared and mounts itself there, and the consumer binds the same directory with rslave so the mount propagates in. The host directory must itself be a shared mount.

# A host directory both containers bind to, marked shared so mounts propagate.
mkdir -p /srv/musefs-mnt
mount --bind /srv/musefs-mnt /srv/musefs-mnt
mount --make-rshared /srv/musefs-mnt

# A named volume for the store, writable by the image's unprivileged user.
podman volume create musefs-store

# musefs container: bind rshared, mount musefs there with --allow-other.
podman run -d --name musefs \
  --device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor=unconfined \
  -v /path/to/library:/library:ro -v musefs-store:/store \
  --mount type=bind,source=/srv/musefs-mnt,destination=/mnt/musefs,bind-propagation=rshared \
  ghcr.io/sohex/musefs:latest mount /mnt/musefs --db /store/musefs.db --allow-other

# consumer container: bind the same host path rslave; the mount propagates in.
podman run -d --name player \
  --mount type=bind,source=/srv/musefs-mnt,destination=/music,bind-propagation=rslave \
  ghcr.io/sohex/yourmediamanager:latest

Use a named volume (or an already-writable host path) for the store: a bind from a root-owned host directory is read-only to the image's unprivileged user and musefs aborts before mounting. --allow-other is required because the consumer container runs as a different uid than the musefs container; without it the consumer gets Permission denied on the mount. See Ownership and permissions.

Note

Some hardened kernels block cross-uid access to an unprivileged user's FUSE mount even with --allow-other — for example when the fuse module's allow_sys_admin_access parameter is N, or unprivileged user namespaces are restricted. If the consumer still gets Permission denied, set /sys/module/fuse/parameters/allow_sys_admin_access to Y, or run musefs and the consumer under the same uid.

Both the glibc and musl images carry the fuse3 userspace tools; pick :musl if your other containers are Alpine-based, otherwise the default tags are fine.

Sharing a host mount into a container

Running musefs on the host instead of in a container is simpler and needs no CAP_SYS_ADMIN. Mark the mount point as shared and mount musefs there with --allow-other, then bind it into the consumer container with rslave so the host's musefs mount propagates in:

# On the host: mark the mount point shared, then mount musefs with --allow-other.
mkdir -p /srv/musefs-mnt
mount --bind /srv/musefs-mnt /srv/musefs-mnt
mount --make-rshared /srv/musefs-mnt
musefs mount /srv/musefs-mnt --db /store/musefs.db --allow-other &

podman run -d \
  --mount type=bind,source=/srv/musefs-mnt,destination=/music,bind-propagation=rslave \
  ghcr.io/sohex/yourmediamanager:latest
# the container reads the re-tagged view at /music, byte-for-byte live

rslave is what keeps this working across restarts: a plain bind only captures whatever is mounted when the container starts, so it shows an empty directory if musefs mounts later and a stale view after a musefs restart.

Platform support

Platform FUSE Kernel passthrough (StructureOnly) Notes
Linux Yes (/dev/fuse + fusermount3, from the fuse3 package) Yes (6.9+, falls back to daemon serving otherwise) Full support.
FreeBSD Yes (pure-rust /dev/fuse backend; fusefs kernel module, no libfuse) No Full FUSE support.
macOS (FUSE-T) Best-effort No Compiles and runs unit tests with macos-no-mount; mounted e2e is not yet validated.

On platforms without kernel passthrough, --mode structure-only still serves the original bytes, just through the daemon instead of the kernel.

Usage

Scan

musefs scan /path/to/music --db library.db            # ingest (dirs recurse)
musefs scan /path/to/music --db library.db --revalidate

scan probes each audio file (FLAC, MP3, M4A/M4B, Ogg, WAV), recording its audio byte range, tags, and embedded art in the store. It takes one or more files or directories, and --jobs N controls probe parallelism. --follow-symlinks walks symlinked files and directories (off by default, so symlinks are logged and skipped). --quiet (-q) suppresses the per-target summary for scripting; scan failures still surface on stderr (raise detail with RUST_LOG=info).

The per-target summary reads scanned N: … skipped X, failed Y. skipped counts every file that isn't a supported audio format — cover art, .cue / .log / .nfo sidecars, and anything else non-audio — so a large skipped number (hundreds or thousands on a big library) is expected, not an error. failed is the one to watch: those are audio files musefs recognised by extension but could not parse.

--revalidate is the maintenance pass: it skips unchanged files — preserving any tag edits you made in the store — prunes tracks whose backing file is gone, and garbage-collects orphaned art.

Mount

musefs mount /path/to/mountpoint --db library.db \
    --template '$albumartist/$album/$title' \
    --default-fallback Unknown \
    --fallback albumartist='Unknown Artist' \
    --mode synthesis        # or: structure-only

mount blocks until the filesystem is unmounted (fusermount -u, or Ctrl-C).

Mounting at an arbitrary path may be denied by AppArmor. On distros that ship an AppArmor profile for fusermount3 (Ubuntu 24.04+ / libfuse ≥ 3.17), unprivileged FUSE mounts are only allowed when the mountpoint is under a whitelisted prefix — the shipped profile permits $HOME/**, /mnt, /media, /tmp, /cvmfs, $XDG_RUNTIME_DIR, plus flatpak dirs. Mounting elsewhere (e.g. a data volume at /data/...) fails with fusermount3: mount failed: Permission denied, and the kernel audit log shows apparmor="DENIED" operation="mount" … profile="fusermount3". The mountpoint's own ownership is irrelevant — AppArmor rejects the mount() syscall first. Fix it by mounting under a permitted prefix, or by whitelisting your prefix in /etc/apparmor.d/local/fusermount3 (the shipped profile ends with include if exists <local/fusermount3>).

Two modes:

  • synthesis (default) — files carry metadata freshly generated from the store, spliced ahead of the original audio bytes.
  • structure-only — files are served byte-for-byte as they are on disk; only the directory tree is virtual.

Edit tags or art in the database while mounted (another scan, a beets/Picard/Lidarr sync, raw SQL) and the view refreshes automatically.

Run musefs <command> --help for the full flag list.

Path templates

Paths come from a beets-style template (matched case-insensitively; any tag key in the store works):

  • $field / ${field} — substitute a tag field (e.g. $artist, $album, $title, $tracknumber, $date, $genre).
  • ${albumartist|artist}fallback chain: the first present field wins, before the --default-fallback value (default Unknown) is used.
  • A missing field resolves in order: the field's value, then a per-field fallback from --fallback FIELD=VALUE (repeatable, e.g. --fallback albumartist='Unknown Artist'), then --default-fallback. Per-field fallbacks let one field default differently from the rest.
  • [ … ]conditional section: the bracketed text is emitted only when at least one field inside it is present. So $album[ - CD $disc] yields Album - CD 2, or just Album on a single-disc release. Write $[ / $] for literal brackets.
  • $!{field}path field: the value's / are kept as directory separators (each segment sanitized; empty/./.. dropped). Lets an external tool precompute a whole relative path into one tag and mount it as --template '$!{beets_path}'.

Anything else is literal. Name collisions get a deterministic (2), (3), … suffix. Every rendered component is capped at 255 bytes (NAME_MAX, truncated on a UTF-8 boundary, extension preserved), and a plain field whose value is exactly . or .. is dropped rather than creating an unusable directory. The default template is $albumartist/$album/$title.

Tuning

The defaults are sensible for most setups. On slow backing storage (HDD, NFS) the one flag worth changing is --keep-cache; the read-ahead / background knobs have little measurable effect on musefs (see BENCHMARKS.md for the methodology and numbers).

Flag Default What it does
--poll-interval-ms 1000 Debounce window for detecting external DB edits.
--keep-cache disabled Keep the kernel page cache across opens. Worth enabling on HDD/NFS: repeat opens of a file are then served from cache instead of re-read over slow storage (~3× faster reopen in our benches). External re-tags auto-invalidate the affected files, so cached bytes never go stale.
--attr-ttl-ms 1000 How long the kernel may trust cached entry/attr lookups. Higher cuts lookup/getattr traffic — useful for metadata-heavy clients (library scanners) over high-latency backing — but bounds how fast external edits become visible.
--max-readahead-kib 512 Kernel read-ahead window (clamped to the kernel maximum). In practice this does not speed up musefs streaming: reads reach the daemon in fixed FUSE-sized chunks and a single stream is served serially, so a larger window doesn't reduce per-read latency. On HDD, values well above the default can even hurt. Leave at the default unless your own profiling shows otherwise.
--max-background 64 Max outstanding background (read-ahead/async) requests the kernel keeps in flight. Does not bound foreground reads (those scale with client concurrency), so it has little effect on read throughput; left for completeness.
--case-insensitive <true|false> OS default Compare filenames case-insensitively. Case-variant directories merge into one (first-seen casing wins) and case-variant files get a numeric suffix (e.g. Song (2)). Defaults to true on macOS and false on Linux/FreeBSD; case-insensitive mounts refresh via a full rebuild rather than the incremental fast path.

Ownership and permissions

By default the mount presents the launching process's uid/gid and read-only permission bits (555 dirs, 444 files), and is reachable only by the user who performed the mount (and root).

To present a different owner — e.g. a media-server service account — and let that account actually reach the mount, pass --owner/--group (or --allow-other). Either makes musefs mount with allow_other and default_permissions: other users can traverse the mount, and the kernel enforces the presented owner/mode bits instead of ignoring them.

Flag Default What it does
--owner <NAME|UID> process uid User presented as the owner of every entry. Accepts a username or a numeric uid. Implies --allow-other.
--group <NAME|GID> process gid Group presented for every entry. Accepts a group name or a numeric gid. Implies --allow-other.
--allow-other off Mount with allow_other + default_permissions so accounts other than the mounting user can reach the mount and the owner/mode bits are enforced. Implied by --owner/--group.
--file-mode <OCTAL> 444 Permission bits for regular files, in octal. The mount is read-only, so write bits are advertised but writes still fail with EROFS.
--dir-mode <OCTAL> 555 Permission bits for directories, in octal.

The default 444/555 bits are world-readable, so any account can read once allow_other is on. To restrict the mount to the presented owner/group, drop the world bits (e.g. --file-mode 440 --dir-mode 550) — only then does --owner/--group gate access rather than merely label it.

Non-root mounts need user_allow_other. When you are not root, libfuse refuses an allow_other mount unless /etc/fuse.conf contains a line user_allow_other. musefs checks this before mounting and fails with an explanatory error if it is missing; add the line to /etc/fuse.conf, or run musefs as root. (This is libfuse/system policy, not a musefs restriction.) The published container images already include this line, so non-root allow_other mounts work out of the box there.

Configuring with environment variables

Every scalar mount and scan flag can also be set with a MUSEFS_* environment variable — uppercase the long flag and turn dashes into underscores (e.g. --poll-interval-msMUSEFS_POLL_INTERVAL_MS, the mount mountpoint → MUSEFS_MOUNTPOINT). An explicit flag always overrides its env var, which overrides the default. The repeatable --fallback and the scan targets are command-line only. See contrib/systemd/musefs.conf.example for the full, canonical list.

These variables are read the same way no matter how musefs is launched: exported into the shell before running the binary directly (MUSEFS_DB=… musefs mount), set via a systemd EnvironmentFile= or Environment= directive, or passed into a container with -e/--env-file. The configuration surface is identical across all three; the sections below just show the per-deployment wiring.

Running as a systemd user service

To run musefs on the host at login, drop-in units live in contrib/systemd/: a musefs.service mount daemon, an optional musefs-scan.timer for periodic re-scans, and a commented musefs.conf.example holding every MUSEFS_* setting. Copy the units to ~/.config/systemd/user/, copy the config to ~/.config/musefs/musefs.conf, edit MUSEFS_MOUNTPOINT and MUSEFS_DB, then systemctl --user enable --now musefs.service. See contrib/systemd/README.md for the full walkthrough and the PATH / linger gotchas.

Supported formats

Format Extensions What synthesis does Details
FLAC .flac Regenerates the metadata blocks; preserves STREAMINFO/SEEKTABLE bit-exact docs/FLAC.md
MP3 .mp3 Regenerates the ID3v2.4 tag; the audio frames (incl. Xing/LAME) are untouched docs/MP3.md
M4A .m4a, .m4b Rebuilds the moov atom, patching chunk offsets; mdat served verbatim docs/M4A.md
Ogg .ogg, .oga, .opus Regenerates header pages (Opus/Vorbis/FLAC-in-Ogg); audio pages served verbatim, only page seq numbers/CRCs patched in place docs/OGG.md
WAV .wav Regenerates the RIFF front (LIST/INFO + embedded ID3v2); data payload verbatim docs/WAV.md

Text tags round-trip losslessly through a shared canonical vocabulary (so $albumartist, $date, etc. work the same regardless of source format), and binary metadata (ratings, embedded blocks, opaque frames) is preserved where the format allows. Each format has a handful of well-defined lossy edges — see its doc for the exact list.

FAQ

Does musefs ever write to my audio files? No. The mount is read-only and the scanner only reads. The served files are assembled on the fly: generated metadata plus positioned reads of your originals. Nothing is ever copied or rewritten.

Where do my edited tags live? In the SQLite store (--db). Edit it with the beets or Picard plugins, the Lidarr integration, or with plain SQL — the schema is a documented, stable contract (see ARCHITECTURE.md).

Do edits show up without remounting? Yes. The mount polls the database (debounced) and picks up external commits automatically, with stable inodes across refreshes — even files held open keep working.

Can I write through the mount? No — and it's not planned. Out-of-band editing against the store is the design: it's what guarantees your originals can never be corrupted.

Is it fast enough for a big library on a NAS? That's the design target: synthesized headers are cached, blocking reads run on a worker pool so a slow disk never stalls the filesystem, and read-ahead, cache TTLs, and poll intervals are all tunable. In structure-only mode on kernel 6.9+, reads can bypass the daemon entirely via FUSE passthrough (needs CAP_SYS_ADMIN).

A file in the mount won't open / reads error — why? The most common cause is a backing file that changed since its last scan (musefs refuses to serve a file whose size or mtime drifted, rather than splice at stale offsets). Run musefs scan --revalidate to re-probe it.

Status

All five formats ship with embedded cover art and binary-tag preservation. The serve path has been through a performance/concurrency hardening pass for real-world player and media-manager access against large libraries on HDD/SSD/NFS, and the parsers are continuously fuzzed. beets, Picard, and Lidarr plugins ship in contrib/. See the CHANGELOG for history.

Deeper reading: ARCHITECTURE.md for how it works, CONTRIBUTING.md for the development workflow.

License

Licensed under the MIT License.

Acknowledgements

The Lidarr real-instance end-to-end test plays a real album through a real Lidarr. With thanks to Komiku (Loyalty Freak Music), whose track "The calling" (from The Adventure Goes On, Vol. 1) is dedicated to the public domain under CC0 1.0 and vendored as that test's fixture — thank you for releasing music freely.