Skip to content

F.4: Funkwhale bundle — federated music pod#13

Open
kh0pper wants to merge 1 commit intof3-matrix-dendrite-bundlefrom
f4-funkwhale-bundle
Open

F.4: Funkwhale bundle — federated music pod#13
kh0pper wants to merge 1 commit intof3-matrix-dendrite-bundlefrom
f4-funkwhale-bundle

Conversation

@kh0pper
Copy link
Copy Markdown
Owner

@kh0pper kh0pper commented Apr 12, 2026

Summary

First federated-media bundle (category already wired by F.1) and the first exerciser of F.0's storage-translators.funkwhale() S3 wiring. Stacked on F.3 (Matrix-Dendrite).

  • Funkwhale 1.4 pod: api + celeryworker + celerybeat + internal nginx + postgres + redis (6 containers on crow-federation). No host port publish; exposed via caddy_add_federation_site → funkwhale-nginx:80 with the activitypub profile.
  • 13 MCP tools matching the plan's federated-media verb taxonomy: fw_status, fw_list_library, fw_search, fw_upload_track, fw_follow, fw_unfollow, fw_playlists, fw_now_playing, fw_block_user, fw_mute_user (inline/rate-limited), fw_block_domain, fw_defederate (QUEUED via moderation_actions + Crow notification), fw_media_prune.
  • Audio storage: on-disk by default; set FUNKWHALE_S3_* in .env and scripts/configure-storage.mjs translates through F.0's storage-translators.funkwhale() into the AWS_* schema Funkwhale expects, then writes a managed block to the bundle's .env for compose to pick up.
  • Hardware gate: min_ram_mb=1500, recommended=3000 — realistic numbers with any federated follow graph. Celery workers + Django API are the hot paths.
  • Consent text (EN/ES) covers federation reach, library cache growth (5-20 GB / 1000 tracks), federated-metadata caching, copyright liability, and hardware gate threshold.

Test plan

  • node --check on all JS files (server, panel, configure-storage.mjs)
  • bash -n on both shell scripts
  • MCP server boots via createFunkwhaleServer() with no env set
  • docker compose config parses (with required env vars set)
  • JSON parse on manifest, package, registry
  • npm run check passes
  • End-to-end install on a test host (deferred to the roll-out QA pass; first-boot needs DNS + Caddy + ≥1.5 GB free RAM)
  • S3 translation exercise — set FUNKWHALE_S3_*, confirm configure-storage.mjs writes the managed block, confirm uploads land in MinIO
  • Queued moderation end-to-end (needs F.11 panel UI)

Integration notes

  • First bundle to exercise servers/gateway/storage-translators.js funkwhale() translator. If the mapping needs adjustment per the upstream Funkwhale S3 docs, we fix it here before F.5 (Pixelfed, which uses the same AWS_* pattern but with a FILESYSTEM_CLOUD=s3 activation flag).
  • loadSharedDeps() pattern copied from bundles/gotosocial/server/server.js — works both monorepo-mode and installed-to-~/.crow.
  • Registry entry inserted before developer-kit to keep bundles grouped. No new category/icon wiring needed (both present from F.1).

Rollout position

  • F.0 → F.3 shipped
  • F.4 (this PR)
  • Next: F.5 Pixelfed → F.6 Lemmy → F.7 Mastodon → F.8 PeerTube → F.11 identity attestation → F.12 cross-app bridging

🤖 Generated with Claude Code

First federated-media bundle and the first exerciser of F.0's
storage-translators.funkwhale() S3 wiring. Stacked on F.3 (Matrix-Dendrite).

Funkwhale is a self-hosted music + podcast server that federates over
ActivityPub — remote Mastodon/GoToSocial/Pixelfed users can follow your
channels; your pod can subscribe to remote libraries and keep local audio
caches. Six containers on crow-federation: api (Django/Gunicorn),
celeryworker, celerybeat, internal nginx (Funkwhale's static/media server,
fronted by Caddy on :443), postgres, redis.

Bundle (bundles/funkwhale/):

- manifest.json  consent_required with explicit EN/ES text on federation
                 reach, library cache growth (5-20 GB / 1000 tracks;
                 hundreds of MB for federated caches), copyright-liability
                 note, and hardware gate. min_ram_mb=1500 (below the
                 recommended 3 GB; hard-refused on <8 GB total hosts only
                 when co-installed with a heavier bundle since the gate is
                 "effective RAM after committed bundles"). Declares
                 FUNKWHALE_S3_* env vars as optional — presence activates
                 the storage-translator wiring below.
- docker-compose.yml  funkwhale/funkwhale:1.4 + funkwhale/nginx:1.4 +
                 postgres:15-alpine + redis:7-alpine. Postgres/redis
                 isolated to default network; api + nginx on both default
                 and crow-federation so Caddy reaches nginx:80. AWS_* env
                 vars passthrough with blank defaults — configure-storage.mjs
                 populates them in-place when FUNKWHALE_S3_* is set.
                 Healthchecks on api (2 min start period for Django
                 migrations) and nginx. mem_limits: api=1500m,
                 celeryworker=768m, celerybeat=256m, nginx=128m,
                 postgres=512m, redis=256m. On-disk audio: stored in
                 /srv/funkwhale/data/media with ~/.crow/funkwhale/data
                 volume-mount; optional read-only /music for in-place import.
- server/server.js  13 MCP tools matching the plan's federated-media verb
                 taxonomy: fw_status, fw_list_library, fw_search,
                 fw_upload_track, fw_follow, fw_unfollow, fw_playlists,
                 fw_now_playing, fw_block_user, fw_mute_user (inline;
                 rate-limited), fw_block_domain, fw_defederate (QUEUED via
                 moderation_actions + Crow notification), fw_media_prune.
                 Upload accepts file_path OR file_base64+filename and posts
                 multipart FormData. Bearer-auth via FUNKWHALE_ACCESS_TOKEN
                 (PAT from Settings → Applications). All z.string() fields
                 have .max() bounds. loadSharedDeps() pattern borrowed from
                 GoToSocial so the bundle works both monorepo-mode and
                 installed-to-~/.crow (shared helpers resolve via try/catch
                 import; fall back to pass-through wrappers).
- server/index.js  stdio transport.
- panel/funkwhale.js + panel/routes.js  Crow's Nest panel (status, libraries,
                 recent listens). XSS-safe (textContent/createElement).
                 Panel API routes serve /api/funkwhale/{status,libraries,listens}.
- skills/funkwhale.md  first-run workflow (superuser, Caddy site, PAT),
                 upload/search/follow/moderation examples, troubleshooting
                 (413 payload, celery queue, federated cache disk pressure).
- scripts/post-install.sh  waits for api health (up to 180s for first-boot
                 migrations), detects FUNKWHALE_S3_ENDPOINT, invokes
                 configure-storage.mjs for the translation, and prints
                 Caddy + superuser + PAT next steps.
- scripts/configure-storage.mjs  imports servers/gateway/storage-translators.js
                 translate('funkwhale', {...}) and appends a managed block to
                 the bundle's .env so compose picks up AWS_* on next up. Falls
                 back to inline mapping if the helper isn't resolvable
                 (installed-mode).
- scripts/backup.sh  pg_dump (custom format) + data dir tar (excludes
                 __cache__ + static — regenerable). S3-backed audio
                 explicitly NOT in scope — operator's provider is the
                 durability layer. Prefers zstd; falls back to gzip.
- package.json  MCP + zod deps only.

Integrations with shipped F-series:

- F.0 storage-translators.funkwhale()  wires MinIO/S3 at install time when
  operator opts in via FUNKWHALE_S3_* in .env. First bundle to exercise
  this code path end-to-end.
- F.0 rate limiter  content + moderation verbs (upload, follow, search,
  block_user, mute_user, block_domain, defederate, media_prune). Read-only
  verbs uncapped.
- F.0 hardware gate  min_ram_mb + min_disk_mb per manifest schema.
- F.1 federated-media category wiring  already present in extensions.js,
  nav-registry.js, and i18n keys — no additions needed here.

Human-in-the-loop moderation:

- fw_block_user / fw_mute_user: inline, rate-limited (5/hour).
- fw_block_domain / fw_defederate: QUEUED. Writes pending row into
  moderation_actions with 72h expiry + idempotency key; surfaces a Crow
  notification with action URL; returns {status: 'queued', action_id,
  expires_at} to the AI. Confirmation UI lands with F.11. Same rationale
  and implementation as F.1 GoToSocial.

Registry / discovery surface:

- registry/add-ons.json  entry inserted before developer-kit to keep
  bundles grouped. category: federated-media (existing from F.1 wiring).
- skills/superpowers.md  trigger row added between matrix-dendrite and
  tutoring (EN + ES intents: funkwhale, federated music, upload track,
  follow channel, music library, fediverse audio, podcast, playlist).
- CLAUDE.md  Skills Reference entry added after matrix-dendrite.

Verified:

- node --check on all JS files (server, panel, configure-storage)
- bash -n on both shell scripts
- MCP server boots via createFunkwhaleServer() with no env set
- docker compose config parses (with required env vars)
- JSON parse on manifest.json, package.json, registry/add-ons.json
- npm run check passes

Next in the roll-out:

- F.5 Pixelfed (photos, 1.5 GB min)
- F.6 Lemmy (link aggregator, 1 GB min)
- F.7 Mastodon (flagship AP, 3 GB min)
- F.8 PeerTube (heaviest; needs S3 + aggressive transcoding policy)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant