Files
command-center/agent/managed-skills/arr-stack-api-config/SKILL.md
T
Frank 9bfa0be85d chore(skills): promote runbook skills to managed-skills; drop superseded SKILL.md
- 31 new managed skills (anubis/arr/authentik/hermes/freetoken/podman/llm-swap
  runbooks etc.) now tracked.
- Removed superseded skills: omp_harness_config, peon_ping_integration
  (replaced by user-authored peon-ping-* managed skills),
  rocmfp4-strix-benchmark-orchestration.
- New memory-root skills: niri_compositor_ops, omp_git_workflow,
  omp_model_config, quadlet-media-migration, homelab-service-triage,
  hermes-dankclaw-ops, frank-default-large-ops, caddy-auth-dns-playbook.
2026-09-09 16:20:28 -07:00

2.6 KiB

name, description
name description
arr-stack-api-config Configure/download-client and indexer wiring for the *arr stack on Dankserver via live API calls — schema-first, test-before-enable; covers Sonarr/Radarr v3 vs Lidarr/Readarr v1 API split and Prowlarr v2 Applications/sync model.

Arr-stack API config (Dankserver)

API version split

  • Sonarr/Radarr: /api/v3/...; Lidarr/Readarr/Prowlarr: /api/v1/....
  • PUT /downloadclient and PUT /indexer/{id} take a SINGLE resource object (GET it, patch settings, PUT whole object back). An array body fails with Path: $ | BytePositionInLine: 1.
  • API keys live in each container's config: podman exec <svc> grep -o "<ApiKey>[^<]*" /config/config.xml | cut -d">" -f2.

Schema-first probing (validators are free documentation)

Send the FULL schema template object with fields filled; v1 validators reject partials:

  • 'Fields' must not be empty -> send full schema copy, not fields:[].
  • 'Base Url' must not be empty when keys were camelCase -> PascalCase required (BaseUrl, ApiKey).
  • targetType null -> configContract not registered in that build (this Prowlarr build has no Prowlarr-plugin indexer; integration is Torznab-family only).
  • testingPackageId in a PUT body downgrades validation failures to warnings.

Prowlarr v2 model (inverted from v1)

Indexers live ON THE ARR SIDE; Prowlarr syncs indexer configs via ApplicationSync commands (POST /api/v1/command {"name":"ApplicationSync","body":{"applicationId":N}}). Applications settings keys must be PascalCase or sync throws NullConfig. Torznab feed paths can answer with the SPA HTML shell when absent — verify by byte count (HTML shell ~1946 bytes, 1 ms) vs XML, not just status code.

DB as arbiter

When endpoint shapes are opaque, stop the container and edit /opt/prowlarr/config/prowlarr.db with sudo python3 sqlite directly, then start. Indexers table columns are Id/Name/Implementation/Settings/ConfigContract/Enable/Priority/Added — the enable flag column is Enable (not EnableRss).

Verification rules

  • POST /downloadclient returns the COLLECTION, not the created object — verify via GET.
  • Test endpoints return verdicts in the BODY at HTTP 200 ({} = pass, list = fail) — judge from bodies, not status codes.
  • syncLevel is enum ApplicationSyncLevel — omit or use int 2; string rejected.
  • Command POSTs (MoviesSearch etc.) run server-side and respond only when the work finishes: curl -m timeouts (HTTP 000) during search/grab are NOT failures; poll queue/history afterward instead of re-firing. Warm small commands (RefreshMonitoredDownloads) answer in ~20 ms — a hang means live work in progress, not a dead API.