{
  "id": "osc-stack-media-library-agent",
  "job": "Give a scheduled agent a standing job against your own media library: on a cron you set, it checks storage for new or unindexed assets, transcodes anything missing a delivery-ready rendition, updates the segment index, and reports what it did. No dashboard clicks, no manual runs.",
  "aliases": [
    "scheduled agent for media library",
    "nightly media library audit",
    "cron job against video storage",
    "agent task media pipeline",
    "bot that watches a media library"
  ],
  "buyerAudience": "the 'bots' audience named at the 2026-09-23 Nordic broadcaster conference keynote (agents, bots, consumers): a standing, unattended job, not a person clicking through a dashboard or an agent invoked once.",
  "distinctFrom": {
    "media-asset-indexing": "that stack is the index and query building block, invoked on demand. This stack puts a SCHEDULE in front of that same building block (plus an optional transcode step), so the library is checked and kept current without a human triggering each run.",
    "media-transcode-package": "that stack is a one-shot job submitted per source file. This stack is the standing job that decides WHEN to submit one, on a cron, against whatever is new in storage."
  },
  "inputs": [
    {
      "protocol": "cron",
      "source": "a cron schedule (UTC) provided at agent-task creation, e.g. \"0 3 * * *\" for nightly at 03:00 UTC"
    },
    {
      "protocol": "file",
      "source": "media assets already or newly present in S3-compatible storage, the same storage the media-asset-indexing and media-transcode-package stacks use"
    }
  ],
  "outputs": [
    {
      "protocol": "agent-task run log",
      "returns": "a per-run report of what the agent found, indexed, transcoded and skipped, retrievable via get-agent-task-logs",
      "reportIsTextNotStructuredData": true,
      "note": "the report is the agent's own run log, not a separate structured API response; an agent task can be prompted to also write a summary file or call a webhook, but that is a prompt choice, not a platform guarantee, and is not measured here"
    }
  ],
  "recommendedPath": {
    "orchestrationLayer": {
      "kind": "agent-task",
      "notAServiceId": true,
      "note": "Agent Tasks are an OSC platform capability reached through the MCP tool-filter category 'agent-tasks', not a catalog serviceId, so it does not appear in list-available-services. It is the scheduling and reasoning layer that drives the catalog services below.",
      "setup": [
        {
          "tool": "setup-agent",
          "role": "store the Claude or Codex credential the task runs as, once per workspace",
          "requiredArgs": ["credentialType", "credential"],
          "note": "credentialType is \"anthropicapikey\" or \"openaikey\"; credential is the raw API key. Both are required by the live schema, verified 2026-09-25."
        },
        {
          "tool": "create-agent-task",
          "role": "create the recurring task",
          "requiredArgs": ["name", "prompt", "sourceUrl"],
          "conditionallyRequiredArgs": [
            "cronExpression (required when scheduleType is \"cron\", which is the default when cronExpression is provided)"
          ],
          "optionalArgs": [
            "agentType (defaults to \"birme-claude-runner\")",
            "configService",
            "oscAccessToken"
          ],
          "credentialDelivery": "sourceUrl is a Git repository the agent clones before each run; it carries the prompt's working tree, NOT the storage/index/transcoder credentials. Those reach the running task through configService (an Application Config Service / parameter store instance, loaded as env vars at task startup - set it up once with setup-parameter-store and put the Minio, CouchDB and Encore endpoints/credentials in it) or, for calls back into the OSC platform itself, oscAccessToken. Neither is required by the tool schema in general, but this stack's prompt cannot authenticate against the chain below without one of them.",
          "example": {
            "name": "Nightly media library check",
            "sourceUrl": "https://github.com/<org>/<empty-or-scratch-repo>",
            "cronExpression": "0 3 * * *",
            "configService": "<name of a parameter store holding MinioRootUser/Password, CouchDB AdminPassword, TAMS Gateway and Encore endpoints>",
            "promptSketch": "Check the S3 bucket <bucket> for media files added since the last run. For each new file: submit it to Encore for transcoding if it lacks a delivery rendition, confirm it is indexed by TAMS Gateway, and log a one-line summary per file plus a run total."
          }
        }
      ],
      "diagnostics": [
        "list-agent-tasks",
        "get-agent-task-runs",
        "get-agent-task-logs"
      ],
      "planGating": {
        "requiresPaidPlan": true,
        "minimumPlan": "Personal",
        "source": "https://www.osaas.io/llms.txt, verified live 2026-09-25: \"Personal adds database backups and scheduled agent tasks\", corroborated by the create-myapp-sdlc-issue MCP tool description (\"Requires a paid plan (Personal or higher)\") and the live /pricing structured data, which lists \"agent tasks\" under the Personal offer.",
        "independenceNote": "three sources, not fully independent: all three describe the same platform gating rule rather than three separate enforcement points."
      }
    },
    "chain": [
      {
        "step": 1,
        "serviceId": "minio-minio",
        "role": "media library storage",
        "requiredConfig": ["name"],
        "recommendedConfig": ["RootUser", "RootPassword"],
        "requiresCredential": true,
        "note": "RootUser/RootPassword are optional on minio-minio's own schema (verified live 2026-09-25, get-service-schema), but are needed in practice: they become eyevinn-tams-gateway's AwsAccessKeyId/AwsSecretAccessKey in step 3. Same storage role as in media-asset-indexing.json; RootPassword must be at least 10 characters with upper case, lower case and a digit."
      },
      {
        "step": 2,
        "serviceId": "apache-couchdb",
        "role": "index store",
        "requiredConfig": ["name", "AdminPassword"],
        "requiresCredential": true,
        "note": "same role as in media-asset-indexing.json; becomes eyevinn-tams-gateway's DbPassword in step 3."
      },
      {
        "step": 3,
        "serviceId": "eyevinn-tams-gateway",
        "role": "index and query",
        "requiredConfig": [
          "name",
          "DbUrl",
          "DbUsername",
          "DbPassword",
          "AwsAccessKeyId",
          "AwsSecretAccessKey",
          "S3Bucket"
        ],
        "recommendedConfig": ["S3EndpointUrl"],
        "requiresCredential": true,
        "note": "identical wiring to media-asset-indexing.json step 3, including the S3EndpointUrl gotcha: without it set to the step-1 Minio endpoint, this service talks to AWS S3 instead of the deployed Minio."
      },
      {
        "step": 4,
        "serviceId": "encore",
        "role": "transcode, invoked BY THE AGENT when it finds an asset without a delivery-ready rendition",
        "requiredConfig": ["name"],
        "requiresCredential": false,
        "optional": true,
        "note": "not every library needs a transcode step; omit this if the library already stores delivery-ready renditions and the agent's job is index-and-report only."
      }
    ],
    "alternativePath": {
      "serviceId": "eyevinn-open-videocore",
      "role": "single-service alternative: a headless MAM that provisions its own transcoding, storage and database instances internally behind one API call, instead of the four-piece chain above wired by hand",
      "requiredConfig": [
        "name",
        "OscAccessToken",
        "ParameterStoreApiKey",
        "ParameterStore",
        "MinioRootPassword",
        "CouchdbAdminPassword"
      ],
      "requiresCredential": true,
      "note": "eyevinn-open-videocore's own catalog description opens with \"the headless MAM solution\", so the notMAM statement below does not apply to it; it is named here, not chosen as the recommended path, because this stack's job is the AGENT-TASK SCHEDULE around an index-and-transcode chain, and Open Videocore's provisioning behaviour and current operational state have not been evaluated for that role in this recipe. An agent choosing between the two should read Open Videocore's own schema and status before committing."
    },
    "tokensPerDay": null,
    "tokensPerDayMeasured": false,
    "measuredWallClockSeconds": null,
    "wallClockMeasured": false,
    "gapNote": "No author has run this chain end to end on a live cron and measured its per-run token cost or wall-clock time yet. No number is invented here; this is a named gap, the same discipline media-transcode-package.json and media-asset-indexing.json already apply to their own unmeasured fields. The agent-task layer adds a further unmeasured variable this stack does not have: prompt-dependent LLM token spend per run, on top of the catalog services' own token rate."
  },
  "configSurface": {
    "servicesInChain": 4,
    "orchestrationLayerAddsNoServiceId": true,
    "totalRequiredFieldsAcrossChain": 10,
    "sensitiveFields": [
      "RootPassword",
      "AdminPassword",
      "DbPassword",
      "AwsSecretAccessKey"
    ],
    "note": "10 required fields across the three mandatory catalog steps (1 minio-minio + 2 apache-couchdb + 7 eyevinn-tams-gateway), matching totalRequiredFieldsAcrossChain; RootUser/RootPassword on minio-minio are recommended, not required, on that service's own schema, but are wired into TAMS Gateway's credentials so they are needed in practice. The optional Encore step adds 1 more (name) when included. The agent-task layer itself requires name, prompt and sourceUrl (a Git repository, which may be empty), plus cronExpression for a recurring schedule, and needs a configService (or oscAccessToken) to reach the chain's own credentials at runtime; none of that is optional in practice even though the tool schema does not mark configService itself as required."
  },
  "setup": {
    "codeRequired": true,
    "knownDeployGotcha": "Deploy the storage, index-store and TAMS Gateway services first (same order and gotchas as media-asset-indexing.json). Then set up a parameter store (setup-parameter-store) holding their endpoints and credentials, THEN create the agent task with configService pointing at that store, so the prompt can authenticate against already-live resources instead of ones that do not exist yet. create-agent-task also requires a Git repository via sourceUrl even when the task needs no code of its own; an empty or scratch repo satisfies this."
  },
  "cost": {
    "unit": "tokens/day",
    "ceiling": null,
    "ceilingMeasured": false,
    "note": "Not costed as a named stack yet. Named gap, not an invented figure, per the same P5 CEO decision the other two stacks already follow. Cost here is two components, not one: the always-on catalog services (storage, index store, gateway) plus the per-run LLM token spend of the scheduled agent task, which scales with prompt length and how much new media the run finds."
  },
  "notMAM": {
    "statement": "Correction, 2026-09-25: the OSC catalog DOES carry a service that self-describes as a headless MAM, eyevinn-open-videocore (\"Unlock the potential of your media assets with Open Videocore, the headless MAM solution that seamlessly scales in the cloud\"), verified live in the media category (63 of 186 services) the same day this recipe was written. An earlier version of this statement, copied from media-asset-indexing.json's 2026-09-21 wording, said no MAM product existed at all; that was already false when copied and is corrected here. See recommendedPath.alternativePath for eyevinn-open-videocore's own required config. What THIS stack adds beyond Open Videocore is the schedule: a standing agent task deciding when to act, rather than a single API call a human or app triggers."
  },
  "servicesVerifiedLive": {
    "date": "2026-09-25",
    "method": "osc_call_tool wrap (list-available-services, category=media) for the four serviceIds; osc_search_tools for the agent-tasks tool-filter category (setup-agent, create-agent-task, list-agent-tasks, get-agent-task-logs, run-agent-task, get-agent-task-runs all present), per the same operator-mode form CLAUDE.md records for the catalog service count",
    "catalogTotal": 186,
    "mediaCategory": 63
  },
  "gateCheck": {
    "gatedServiceId": "eyevinn-just-go-live",
    "usesGatedService": false,
    "note": "This stack does not name or link eyevinn-just-go-live; the P3 gate does not bind it."
  },
  "duplicationCheck": {
    "date": "2026-09-25",
    "method": "compared against the live /use-cases index (37 pages, curl https://www.osaas.io/use-cases) and the three existing stack recipes before writing. The closest existing page is media-asset-indexing, which covers the index-and-query building block invoked on demand; no existing page or recipe uses the agent-tasks MCP category (setup-agent / create-agent-task) or a cron schedule at all.",
    "result": "no duplicate found; this is the scheduling/agent-task angle named as the likely uncovered gap in the CEO's 2026-09-23 brief, confirmed uncovered by a live check rather than assumed"
  },
  "verifiedOn": "2026-09-25",
  "publishedAt": "https://www.osaas.io/use-cases/media-library-agent",
  "descriptorUrl": "https://www.osaas.io/stacks/media-library-agent.json"
}
