Pipe library / news-digest
news-digest
Classify new stories from tech feeds by topic and write a Markdown digest of the chosen topics.
News and research
hnrss.orglobste.rs
CLI
pipes run examples/news-digest.pipe.yaml
MCP call
{
"name": "pipe__news-digest",
"arguments": {}
}
Pipe file
examples/news-digest.pipe.yaml
# Example (c): news RSS -> llm_classify (cached, non-deterministic) -> filter -> digest file
pipes: 0
name: news-digest
version: 0.1.0
description: Classify new stories from tech feeds by topic and write a Markdown digest of the chosen topics.
permissions:
network: [hnrss.org, lobste.rs]
llm: [fast] # alias resolved via pipes.toml; exact model pinned in pipes.lock
inputs:
type: object
properties:
feeds:
type: array
items: { type: string, format: uri }
default: ["https://hnrss.org/frontpage", "https://lobste.rs/rss"]
topics:
type: array
items: { enum: [ai, security, rust, databases, other] }
default: [ai, security, rust]
max_items: { type: integer, minimum: 1, maximum: 200, default: 8 }
outputs:
type: object
properties:
markdown: { type: string }
count: { type: integer }
output:
markdown: "${steps.digest.text}"
count: "${steps.digest.count}"
steps:
- id: fetch
block: fetch_http
for_each: "${inputs.feeds}"
with: { url: "${item}" }
retry: { max: 2, backoff_ms: 500 }
on_error: skip # one dead feed shouldn't kill the digest
- id: stories
block: parse_rss
in: "${steps.fetch}"
- id: unique
block: dedupe
in: "${steps.stories}"
with: { key: [link] }
- id: new
block: diff_since_last # classify only unseen stories (fewer LLM calls)
in: "${steps.unique}"
with: { key: [link], emit: [added], first_run: all }
- id: capped
block: limit
in: "${steps.new}"
with: { n: "${inputs.max_items}" }
- id: classified
block: llm_classify # NON-DETERMINISTIC: cached by H(model, prompt, fields, params)
in: "${steps.capped}"
with:
model: fast
fields: [title, summary]
labels: [ai, security, rust, databases, other]
instructions: "Pick the single best topic for this tech news story."
into: topic
fallback: other # used if the model answers outside the label set
retry: { max: 2, backoff_ms: 2000 }
- id: wanted
block: filter
in: "${steps.classified}"
with:
where: { field: topic, op: in, value: "${inputs.topics}" }
- id: ordered
block: sort
in: "${steps.wanted}"
with: { by: [{ field: topic }, { field: published, desc: true }] }
- id: digest
block: format
in: "${steps.ordered}"
with:
header: "# Tech digest\n\n"
item_template: "- **[${item.topic}]** [${item.title}](${item.link})"
separator: "\n"
footer: "\n"
- id: write
block: emit_file
in: "${steps.digest.text}"
with: { path: news-digest.md, format: text, mode: write }