2026-06-27 Manga Stack (Suwayomi + Komga + KOMF)

What I set out to do

Add manga management to the media-stack. Started open-ended (“what should I add for books/comics/manga?”), narrowed to manga first because it reuses the existing Flaresolverr, then built it end-to-end: research → draft → test → orchestrate → PR → merge → deploy. Tracked in Add Manga Stack to Media Stack.

What I actually did

  • Research. Compared the books/comics/manga landscape. Key realization: the three are separate pipelines. Books = Readarr-fork + rreading-glasses (Readarr is dead) or Calibre-Web-Automated; comics = Mylar3/Kapowarr; manga = Suwayomi (Mihon extensions), which does not use Prowlarr/qBittorrent at all. Picked manga first.
  • Built three services: Suwayomi (downloader → CBZ+ComicInfo.xml into ${MEDIA_DIR}/manga, direct port 4567), Komga (reader under nginx /komga), KOMF (AniList/MangaUpdates metadata). Wrote setup-komga.sh for the orchestrator.
  • Live-tested at every step rather than trusting the draft. This caught a string of real bugs before they shipped (below).
  • Shipped PR #36, addressed five rounds of AI review, squash-merged (5126644).

What was striking

The bugs only surfaced because I ran the containers, not because I read the code:

  • Suwayomi EXTENSION_REPOS must be a HOCON array literal — a bare URL crashes the config parser on the :.
  • KOMF crash-loops without a committed application.yml.
  • Komga claim API (POST /api/v1/claim) bootstraps the admin headlessly — turned a “manual first-boot UI step” into a zero-manual flow.
  • Two setup-komga.sh bugs: jq '.isClaimed // empty' swallows boolean false (and a missing key prints the string "null"); and a global $http_code set inside a $(...) subshell never escaped it, silently masking non-2xx responses.

And the meta-lesson on AI review: it regenerates on every push and ships occasional false “deploy-breaking” claims — review #5’s “gotson/komga has no curl” was wrong (verified /usr/bin/curl + {"status":"UP"} in-container), and review #1’s “every other service is pinned” was false (the stack is :latest + Watchtower). The user caught the second one before I did. Verify empirically; don’t accept a reviewer’s premise.

What’s left

  • Live deploy on the box (set KOMGA_EMAIL/KOMGA_PASSWORD, mstack, docker compose up -d).
  • The one path not yet exercised: a real chapter flowing Suwayomi → disk → Komga index.

Add Manga Stack to Media Stack · Homelab Services Architecture · Media Stack IaC Declarative Config Evaluation

Follow-up session — declarative sources + covers (PR #39)

After the smoke test, two refinements to make sources and covers declarative, then merged + redeployed.

  • Series cover was blank. KOMF was applying metadata (summary/genres/status) but never a poster. Root cause: I’d put the metadataUpdate block at the top level of application.yml; KOMF only honors it nested under komga: (komga.metadataUpdate.default.seriesCovers). Top-level is silently ignored — metadata updates, no cover. After nesting + overrideExistingCovers: true, re-matching One Piece (POST /komga/match/library/{id}/series/{id} on KOMF port 8085, internal-only) uploaded the real MangaUpdates poster (255×400 USER_UPLOADED, selected).
  • Declarative source installs. Extended setup-suwayomi.sh to install a SUWAYOMI_EXTENSIONS list (comma-separated pkgNames) via the GraphQL updateExtension(input:{id,patch:{install:true}}) mutation, idempotently (GET install state first, skip installed). Defaults: Comick (Unoriginal) all.comicklive, MangaDex all.mangadex, Weeb Central en.weebcentral.
  • KOMF API path quirk: the REST endpoints are under /komga (e.g. /komga/match/...), not /api/metadata/.... The web UI is a Compose/WASM canvas, so routes can’t be scraped from it — got the paths from the README.

What was striking

  • Chapter-1 cover is black, and it’s a source artifact, not config. The ArcaneScans/Comick release ships page 001.webp as a 556-byte blank placeholder (white with two black bars). Komga auto-thumbnails page 1 → black cover. Real content starts at page 2 (full-color Gold Roger spread). No clean declarative fix; bookCovers won’t help (MangaUpdates has no per-chapter covers). Left as-is — cosmetic, series poster is what matters.
  • Redeploy was a clean no-op confirmation: mstackdocker compose up -d → orchestrator reapplied everything idempotently (library present, all three extensions already installed).

First real backfill — Egghead arc onward

Used the stack for real: bulk-downloaded One Piece ch. 1058–1186 (Egghead arc → latest, 130 chapters) via the Suwayomi GraphQL API. Comick lists ~2500 chapter entries (many scanlators per number), so the trick was deduping to one scanlator per chapter number before enqueuing — otherwise it’s 2-3× duplicates. Downloader sits STOPPED after enqueue and needs an explicit startDownloader; Komga didn’t auto-index on FS events, so a manual library scan was needed. All 131 CBZ indexed cleanly. Recipe captured in Add Manga Stack to Media Stack.

Also confirmed the Suwayomi browse-card blur is inherent: it serves the Comick source cover at 225×322, upscaled on the card. Komga (the actual reader) has the sharp poster, so left it. Suwayomi = downloader/browser, Komga = reader.