manifest: qloops.loop/v1

# Produce a structured summary that a downstream service can consume without manual reformatting.
# OpenRouter example: configure the model explicitly. CLI acceptance uses the caller interface.

id: json-digest
name: "JSON digest: structured output or nothing"
version: 1.1.0
description: >
  Asks the model for strict JSON and refuses the step when it gets prose.
  Covers the format:json path, where a wrong answer fails instead of leaking on.
owner: oleg
enabled: true

triggers:
  - kind: manual

settings:
  budgetUsd: 0.10

steps:
  - id: jd-fetch
    kind: fetch
    config:
      name: "Read feed"
      url: "{{env.QLOOP_SOURCE_URL}}"
      format: rss
      limit: "5"
      timeoutSec: "20"

  - id: jd-shape
    kind: llm-call
    config:
      name: "Shape it"
      format: json
      maxTokens: "600"
      instructions: |
        Return STRICTLY this JSON and nothing else — no fences, no prose:
        { "count": <integer>, "titles": ["<title>", …] }
        `count` is the number of entries you were given.

  - id: jd-send
    kind: api-request
    config:
      name: "Send the shape"
      method: POST
      url: "{{env.QLOOP_WEBHOOK_URL}}"
      expect: "2xx"
      timeoutSec: "20"
      body: '{"count":"{{steps.Shape it.output.count}}","run":"{{run.id}}","cost":"{{run.costUsd}}"}'
