Skip to main content

Mms

@keeb/mmsv2026.10.25.2· 6d agoBEHAVIORSREPORTSSKILLS
01README

Media management system — content discovery, deduplication, download protocol handling, LLM-powered file organization, and subtitle extraction

02Release Notes

Organizer scene route places new shows deterministically (shows//sN) unless an existing dir looks like the same show; filler words no longer count in similar-dir matching; Ollama only health-checked when the LLM is needed; organizer test accepts scene parse items.

03Behaviors9
@keeb/mms/sourcev2026.10.25.1mms_source.ts
fn search(query: string, provider: enum, resolution?: string, preferGroup?: string, preferCodec?: string, nyaaUser?: string, nyaaQuery?: string, eztvUrl?: string, eztvImdbId?: string, slug?: string, onlyEpisodes?: array, newznabUrl?: string, newznabApiKey?: string, newznabCat?: string)
Search a provider for content. Writes a single `episodes` resource
ArgumentTypeDescription
querystringShow name to search for
providerenumSource provider
resolution?stringResolution filter
preferGroup?stringPreferred release group (e.g. MeGusta)
preferCodec?stringPreferred codec (e.g. HEVC)
nyaaUser?stringNyaa uploader filter
nyaaQuery?stringOverride search query
eztvUrl?stringCustom EZTV RSS URL
eztvImdbId?stringIMDb ID (tt0239195): search EZTV's archival API instead of the rolling RSS feed
slug?stringCanonical catalog slug, stamped on every item (dedup checks disk at /<slug>/s<N>)
onlyEpisodes?arrayKeep only these episodes, e.g. dedup's missing items; anything else is dropped
newznabUrl?stringNewznab API base URL
newznabApiKey?stringNewznab API key
newznabCat?stringNewznab category ID
fn search_configured()
Search all configured shows. Writes a single `episodes` resource

Resources

episodes(infinite)— All items from the most recent invocation. Single instance named
@keeb/mms/downloaderv2026.10.25.1mms_downloader.ts

Global Arguments

ArgumentTypeDescription
transmissionUser?stringTransmission RPC username
fn blocklist_update()
Have Transmission re-download its peer blocklist. Optionally set the blocklist URL and enable it first.
fn add(uri: string)
Add a download to the appropriate backend (Transmission for torrents, SABnzbd for usenet)
ArgumentTypeDescription
uristringMagnet URI or NZB URL
fn add_nzb_url()
Construct an NZB URL from a vault-resolved template + a hash
fn add_from_source()
Read a source model's `episodes` resource and add every item in its episodes array as a torrent. Fan-out alternative to workflow-level forEach.
fn status()
Query all backends for current download status (factory: one resource per download)
fn remove()
Remove specific torrents from Transmission by name filter
fn clean()
Remove completed downloads from backends

Resources

download(infinite)— Tracked download state
add_batch(infinite)— Per-invocation summary of an add call — added/failed items and counts. Aggregate shape; does not track per-torrent lifecycle (see download spec for that).
blocklist(infinite)— Result of a blocklist_update call — URL, enabled flag, and rule counts before/after
@keeb/mms/dedupv2026.10.25.1mms_dedup.ts
fn filter()
Read episode data from a source model, check local directories, output only new episodes. Parses raw titles with Ollama when show/episode fields are missing.

Resources

episodes(infinite)— All actionable episodes from the most recent invocation. Single
@keeb/mms/organizerv2026.10.25.1mms_organizer.ts
fn process()
Pop pending jobs from MongoDB queue, classify with LLM, and move files to organized locations
fn pending(maxJobs?: number, retryHours?: number, name?: string)
List the video files plan would classify next (same job selection), so a scene-rules parse can run on them first. Writes pending-<name> with names[]. Moves nothing.
ArgumentTypeDescription
maxJobs?number
retryHours?number
name?string
fn plan(maxJobs?: number, retryHours?: number, scene?: array, name?: string)
Classify pending jobs without moving anything: destination, route and gate context per file, plus the Jev batch for LLM-placed files. Jobs a previous apply left in staging are re-planned as soon as the organizer's rules change, else every retryHours. Writes plan-<name>; apply executes it.
ArgumentTypeDescription
maxJobs?numberMaximum pending jobs to plan
retryHours?numberRe-plan a job left in staging after this long even if the rules haven't changed
scene?array@keeb/scenerules parse items for the pending files (see pending); enables the deterministic scene route
name?stringSuffix for the plan-<name> resource
fn apply(name?: string, judgeModel?: string, threshold?: number)
Execute plan-<name>: move each job's files into the catalog only when every file is a confident placement. A split risk, a Jev season_fits score below threshold, or no score leaves the job pending in staging (held_at/held_reason/held_rules), to be re-planned when the rules change. Writes job-<id> per job.
ArgumentTypeDescription
name?stringPlan to apply
judgeModel?stringModel whose evaluation-<key> resources hold the season_fits scores
threshold?numberHold LLM-placed files whose season_fits P(yes) is below this
fn evaluate(cases: array, models: array, llmOnly?: boolean, structured?: boolean, catalogHints?: boolean, scene?: array, name?: string)
Benchmark Ollama models on labeled filenames through the real classification pipeline; writes eval-<name> with accuracy, latency and misses per model. Moves nothing.
ArgumentTypeDescription
casesarrayFilenames with the directory each belongs in
modelsarrayOllama models to compare, e.g. ['qwen3:14b', 'gemma4:26b']
llmOnly?booleanSend every case to the LLM (skip special cases and the fast path), to compare models rather than the pipeline
structured?booleanConstrain stage 1 with Ollama structured outputs (JSON Schema), as production does
catalogHints?booleanTell stage 2 which existing catalog dirs look like the show, as production does
scene?array@keeb/scenerules parse items for the case filenames; enables the scene route (ignored with llmOnly)
name?stringSuffix for the eval-<name> resource
fn test(filename: string, scene?: array)
Dry-run classification: parse a filename and show where it would be organized without moving anything
ArgumentTypeDescription
filenamestringFilename to classify
scene?array@keeb/scenerules parse items (as plan takes them); enables the scene route
fn write_playlists()
Write an .m3u playlist of every video file, in episode order, into a catalog directory (and optionally its subdirectories)
fn write_playlists_recent()
Regenerate .m3u playlists for every directory touched by recent organizer jobs

Resources

job(infinite)— Processed media job result
playlist_run(infinite)— Playlist (.m3u) generation run summary
pending(infinite)— Video files the next plan will classify (input for a scene-rules parse)
plan(infinite)— Where each pending job would go, with review-gate context and the Jev batch to score it. Written by plan, read by apply.
eval(infinite)— Classification benchmark: accuracy and latency per Ollama model over labeled filenames
@keeb/mms/subtitlesv2026.10.25.1mms_subtitles.ts
fn extract(path: string)
Extract an embedded subtitle track from an MKV to a sibling .srt file
ArgumentTypeDescription
pathstringPath to the input MKV file
fn extract_recent()
Batch-extract subtitles from MKVs produced by recent organizer jobs
fn extract_dir(paths: array, recursive?: boolean)
Batch-extract subtitles from every MKV under catalog directories (backfill)
ArgumentTypeDescription
pathsarrayCatalog directories to walk
recursive?booleanWalk subdirectories too

Resources

extraction(infinite)— Subtitle extraction result (single-file extract)
run(infinite)— Batch subtitle-extraction run summary
@keeb/subsplease-schedulev2026.04.11.1subsplease_schedule.ts
fn fetch(tz?: string)
Fetch the SubsPlease weekly schedule, one resource per scheduled show
ArgumentTypeDescription
tz?stringTimezone for schedule times

Resources

show(infinite)— A show on the SubsPlease weekly schedule
@keeb/tmdb-lookupv2026.07.03.1tmdb_lookup.ts

Global Arguments

ArgumentTypeDescription
apiKeystringTMDB API key (v3)
fn search(query: string, limit?: number)
Search TMDB for a TV show by name, fetches full details including series status
ArgumentTypeDescription
querystringTV show name to search for
limit?numberMax results to return
fn seasons(tmdbId: number)
List a TV show's seasons with cumulative absolute episode ranges — for computing episode→season breaks
ArgumentTypeDescription
tmdbIdnumberTMDB TV id
fn searchMovie(query: string, year?: number, limit?: number)
Search TMDB for a movie by title, fetches full details (release date, runtime, vote, etc.)
ArgumentTypeDescription
querystringMovie title to search for
year?numberOptional release-year hint to disambiguate
limit?numberMax results to return

Resources

show(infinite)— TV show info from TMDB
movie(infinite)— Movie info from TMDB
@keeb/rottentomatoesv2026.10.25.3rottentomatoes.ts

Global Arguments

ArgumentTypeDescription
tmdbApiKeystringTMDB API key (v3)
headless?booleanRun Playwright headless.
nodeModulesDir?stringnode_modules directory that already has playwright installed. When unset, the model installs a pinned playwright into $XDG_CACHE_HOME/swamp-mms/scraper (default ~/.cache) on first use, so no consumer-repo node_modules is needed.
fn browse(sort: enum, loadMoreClicks?: number)
Scrape a Rotten Tomatoes TV browse list, enrich each show via TMDB, and write one resource per show keyed by TMDB ID.
ArgumentTypeDescription
sortenumWhich Rotten Tomatoes TV browse list to scrape
loadMoreClicks?numberHow many times to click Load More before extracting (0 = first page only)
fn browse_movies(list?: enum, sort?: enum, loadMoreClicks?: number)
Scrape a Rotten Tomatoes movie browse shelf, enrich each movie via TMDB, and write one resource per movie keyed by TMDB movie ID. Default shelf is at_home (streaming/VOD).
ArgumentTypeDescription
list?enumWhich Rotten Tomatoes movie shelf to scrape. at_home = streaming/VOD (watchable now), in_theaters = theatrical, coming_soon = unreleased
sort?enumSort order within the shelf. 'newest' is the only one RT honours reliably — the others often degrade to an alphabetical listing.
loadMoreClicks?numberHow many times to click Load More before extracting (0 = first page only)

Resources

show(infinite)— A single TV show: Rotten Tomatoes scores + TMDB metadata. Spec is the TMDB ID (or rt-<slug> when no match).
movie(infinite)— A single movie: Rotten Tomatoes scores + TMDB metadata. Spec is the TMDB movie ID (or rt-<slug> when no match). Kept separate from `show` because TMDB movie and TV IDs share numeric values but name different titles.
@keeb/mms/tv-recommenderv2026.09.25.1tv_recommender.ts

Global Arguments

ArgumentTypeDescription
personaPath?stringDefault persona markdown path. Relative paths resolve under the consumer's repo root. If unset, the bundled `personas/host.md` is used.
fn evaluate(browseSort: enum, limit?: number, minScore?: number, catalogModel?: string)
Score rottentomatoes shows against the host persona's lanes using structured TMDB fields only, and write the ranked `recommendations` resource. No LLM, no API key, one step.
ArgumentTypeDescription
browseSortenumWhich RT browse list to evaluate (matches rottentomatoes browseSort tag).
limit?numberMaximum number of shows to evaluate, taken by descending TMDB popularity.
minScore?numberBlended RT score a lane-matching show must clear to earn Watch. Below this it is in-lane but under the bar.
catalogModel?stringModel name to read the existing catalogue from, for the persona's 'new season of something I already watch' auto-include. Set empty to disable the lookup.
fn collect(browseSort: enum, limit?: number, personaPath?: string, bundledPersona?: string)
LEGACY LLM PATH — superseded by `evaluate`. Read rottentomatoes shows for a given browseSort and the persona markdown; write a single `pack` resource the workflow forEach can drive Claude with. Requires an @keeb/anthropic/claude instance named host-evaluator.
ArgumentTypeDescription
browseSortenumWhich RT browse list to evaluate (matches rottentomatoes browseSort tag).
limit?numberMaximum number of shows to package for evaluation.
personaPath?stringPersona markdown path for this run. Overrides the model's personaPath global arg. Relative paths resolve under the consumer's repo root.
bundledPersona?stringName of a persona bundled with @keeb/mms (file in `personas/`, without the .md suffix). Use 'host' for the default. Wins over personaPath only when no path is given.
fn aggregate(collectVersion?: number)
LEGACY LLM PATH — superseded by `evaluate`. Join the per-show Claude verdicts with the original RT metadata into a single ranked recommendation resource for the report.
ArgumentTypeDescription
collectVersion?numberVersion of tv_recommender's `pack` resource to aggregate against. Defaults to latest.
fn pack_typesafe(browseSort: enum, limit?: number, personaPath?: string, catalogModel?: string)
Package the current RT browse for @swamp/typesafe-ai.choice_batch: persona + watch question as instructions, one {name, state} item per show. Catalogue shows are auto-included and left out of items.
ArgumentTypeDescription
browseSortenumWhich RT browse list to evaluate (matches rottentomatoes browseSort tag).
limit?numberMaximum number of shows to package, taken by descending TMDB popularity.
personaPath?stringPersona markdown path for this run. Overrides the model's personaPath global arg. Relative paths resolve under the consumer's repo root.
catalogModel?stringModel name to read the existing catalogue from. Shows already in it are auto-included and not sent for evaluation. Set empty to disable.
fn aggregate_typesafe(evaluatorModel?: string, minScore?: number)
Join the evaluator's evaluation-<name> rubric answers onto the latest typesafe-pack, run them through the persona rules, and write the ranked `recommendations-typesafe` instance for the report.
ArgumentTypeDescription
evaluatorModel?stringName of the @swamp/typesafe-ai instance whose ask_batch answered the pack's items.
minScore?numberBlended RT score an in-lane show must clear to earn Watch — the same bar as evaluate.
fn pack_catalogue(library?: string, catalogModel?: string, personaPath?: string)
Package every series in a catalogue library as ask_batch items with the persona rubric, for calibrate to measure the rubric against shows the group already chose. Writes `catalogue-pack`.
ArgumentTypeDescription
library?stringCatalogue library display name whose series become the calibration set — the same value passed to the catalogue model's `series` method.
catalogModel?stringModel name holding the catalogue's `series` resources.
personaPath?stringPersona markdown path whose rubric is being calibrated. Overrides the model's personaPath global arg.
fn calibrate(evaluatorModel?: string)
Score the evaluator's rubric answers for the catalogue-pack with the persona rules (lane fit only, no RT bar) and write `rubric-calibration`: recall on shows the group already chose, per-statement stats, and the misses to tune against.
ArgumentTypeDescription
evaluatorModel?stringName of the @swamp/typesafe-ai instance whose ask_batch answered the catalogue-pack.

Resources

typesafe-pack(infinite)— Current RT browse as @swamp/typesafe-ai.choice_batch input: persona instructions, yes/no criteria, one item per show.
pack(infinite)— Per-show prompt material: persona text plus per-show JSON, ready for a forEach Claude call.
recommendations(infinite)— Aggregated verdicts: one row per show with parsed Watch/Skip + reasoning.
rubric-calibration(infinite)— How the persona rubric + lane rules judge the existing catalogue: recall, per-statement stats, and misses. Versions are the rubric optimizer's history.
04Reports5
@keeb/mms/add-summarymethod
add_summary.ts

Summarize an add / add_from_source invocation — lists torrents/NZBs accepted and items that failed to add

downloaderadd
@keeb/mms/dedup-summarymethod
dedup_summary.ts

Summarize dedup filter results: what's new vs what was skipped

discoverydedup
@keeb/mms/discovery-summarymethod
discovery_summary.ts

Summarize discovered content from source searches

discovery
@keeb/mms/download-statusmethod
download_status.ts

Show active downloads with name, progress, and state

status
@keeb/mms/tv-recommendationsmethod
tv_recommendations.ts

Render the host's Watch/Skip verdicts for a tv_recommender.evaluate, aggregate_typesafe (or legacy aggregate) run — sorted by score within Watch, then Skip.

recommendationshost
05Skills1
mms1 file
06Previous Versions16
2026.10.25.1

Modified 3 behaviors

2026.10.23.1

Modified 3 behaviors

2026.07.18.1
2026.07.03.1

subtitles: extract_recent now writes a single run rollup resource per batch (window/cutoff, jobs considered, extracted/skipped/failed counts, plus per-file results and captured failures) instead of one extraction per .srt. Per-file failures no longer abort the batch.

organizer: One Piece special-case — 'One Piece - NNNN' files route to anime/completed/one-piece/s23 (current Elbaph arc) so Jellyfin resolves the correct arc name and art.

tmdb-lookup: new seasons method lists a show's seasons with cumulative absolute episode ranges, for computing episode->season breaks.

Modified 2 behaviors

2026.05.22.2

Added 1 behaviors. Added 1 reports

2026.05.22.1

Added 1 behaviors

2026.05.18.1

Add extract_recent batch method to subtitles for organize-and-clean wiring

Modified 3 behaviors

2026.05.06.2

Added 2, modified 4 behaviors. Added 1 reports

2026.04.27.1

Added 1 behaviors

2026.04.22.3
2026.04.22.2

Added 1 skills

2026.04.06.1
2026.04.02.3
2026.04.02.2

Modified 1 behaviors

2026.04.02.1

Added 1 reports

2026.03.29.1
07Stats
B
87 / 100
Downloads
147
Archive size
621.1 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented0/1missing
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Docs keep secrets in a vault1/1earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License1/2partial

    no SPDX license declared

  • Verified public repository2/2earned
08Platforms
09Labels