Examples / Community forum digest
Community forum digest
Every weekday morning, take the newest threads off a community forum's listing page, drop the ones earlier runs already covered, read each new thread once, and post one summary to Slack. A short pipeline does the reading; the model only writes the digest.
Web pagesJavaScriptYour AI modelsSlack
What you tell the assistant
Why it works
- One web.extract call takes the thread links off the listing page, and a for_each step reads each thread once. No model reads a page it doesn't need to.
- The workflow remembers the threads it has covered, so each run reads only what is new and a quiet morning costs no model tokens at all.
- A thread that fails to load is recorded and the rest carry on, and a run interrupted halfway picks up at the next thread rather than starting over.
What it builds
Trigger
Schedule
0 8 * * 1-5 · America/Toronto
tool
Recall covered threads
builtin.recall
tool
Read the listing
web.extract
javascript
Keep new threads
→ threads, covered
for_each
Read each thread
each of fresh.output.threads · web.extract
llm
Write the digest
fast
if threads.output.succeeded > 0
tool
Post to
slack.post_message
tool
Remember covered threads
builtin.remember
View the definition
trigger:
kind: schedule
cron: "0 8 * * 1-5"
timezone: America/Toronto
steps:
- key: seen
name: Recall covered threads
kind: tool
tool: builtin.recall
args: { key: covered_threads }
- key: listing
name: Read the listing
kind: tool
tool: web.extract
args:
url: https://community.northwind.example/latest
markdown: false
links: false
selectors: { threads: "a.topic-title" }
- key: fresh
name: Keep new threads
kind: javascript
inputs: { threads: "{{ steps.listing.output.matches.threads }}", seen: "{{ steps.seen.output.value }}" }
outputs: { threads: array, covered: array }
code: |
function main({ threads, seen }) {
const known = new Set(seen || []);
const fresh = (threads || []).filter(t => t.href && !known.has(t.href)).slice(0, 10);
console.log(`${fresh.length} new of ${(threads || []).length} threads`);
return { threads: fresh, covered: [...fresh.map(t => t.href), ...(seen || [])].slice(0, 300) };
}
- key: threads
name: Read each thread
kind: for_each
over: "{{ steps.fresh.output.threads }}"
continue_on_error: true
step:
kind: tool
tool: web.extract
args:
url: "{{ item.href }}"
markdown: false
links: false
selectors: { posts: ".topic-post .cooked" }
limit: 8
- key: digest
name: Write the digest
kind: llm
model: fast
if: steps.threads.output.succeeded > 0
system: You write short, plain digests for a community team. No preamble.
prompt: |
Here are new threads from our community forum, each with its opening post and first replies.
For each, write one line: what the person needs, and whether anyone has answered yet, with its link.
Then one line on any theme that comes up more than once.
{{ steps.threads.output.items }}
- key: post
name: Post to #community
kind: tool
tool: slack.post_message
args:
channel: "#community"
text: "*New on the forum*\n{{ steps.digest.output.text }}"
- key: remember
name: Remember covered threads
kind: tool
tool: builtin.remember
depends_on: [post]
args: { key: covered_threads, value: "{{ steps.fresh.output.covered }}" }
A sample run
What each step produces
Recall covered threads tool
succeeded
Recall covered threads tool
Calling builtin.recall
{
"key": "covered_threads",
"found": true,
"value": [
"https://community.northwind.example/t/csv-export-times-out/4120"
],
"updated_at": "2026-10-07T12:00:41Z"
}
Read the listing tool
succeeded
Read the listing tool
Calling web.extract
Extracted https://community.northwind.example/latest · 3 threads
{
"url": "https://community.northwind.example/latest",
"title": "Latest topics - Northwind Community",
"status": 200,
"truncated": false,
"matches": {
"threads": [
{
"text": "Webhook retries after a 410?",
"href": "https://community.northwind.example/t/webhook-retries-after-a-410/4131"
},
{
"text": "SSO with Okta groups",
"href": "https://community.northwind.example/t/sso-with-okta-groups/4128"
},
{
"text": "CSV export times out",
"href": "https://community.northwind.example/t/csv-export-times-out/4120"
}
]
},
"notes": []
}
Keep new threads javascript
succeeded
Keep new threads javascript
2 new of 3 threads
{
"threads": [
{
"text": "Webhook retries after a 410?",
"href": "https://community.northwind.example/t/webhook-retries-after-a-410/4131"
},
{
"text": "SSO with Okta groups",
"href": "https://community.northwind.example/t/sso-with-okta-groups/4128"
}
],
"covered": [
"https://community.northwind.example/t/webhook-retries-after-a-410/4131",
"https://community.northwind.example/t/sso-with-okta-groups/4128",
"https://community.northwind.example/t/csv-export-times-out/4120"
]
}
Read each thread for_each
succeeded
Read each thread for_each
Running tool for each of 2 items
Item 1 of 2 · https://community.northwind.example/t/webhook-retries-after-a-410/4131
Extracted https://community.northwind.example/t/webhook-retries-after-a-410/4131 · 1 posts
Item 2 of 2 · https://community.northwind.example/t/sso-with-okta-groups/4128
Extracted https://community.northwind.example/t/sso-with-okta-groups/4128 · 2 posts
Finished 2 items: 2 succeeded, 0 failed
{
"items": [
{
"url": "https://community.northwind.example/t/webhook-retries-after-a-410/4131",
"title": "Webhook retries after a 410? - Northwind Community",
"status": 200,
"matches": {
"posts": [
{
"text": "Our endpoint returns 410 for deleted orders but Northwind keeps retrying for a day. Is there a way to stop retries for a specific status?"
}
]
}
},
{
"url": "https://community.northwind.example/t/sso-with-okta-groups/4128",
"title": "SSO with Okta groups - Northwind Community",
"status": 200,
"matches": {
"posts": [
{
"text": "Can Okta groups map to Northwind roles, or only to teams?"
},
{
"text": "Groups map to teams today. Roles are on the roadmap for Q1."
}
]
}
}
],
"errors": [],
"count": 2,
"succeeded": 2,
"failed": 0,
"skipped": 0
}
Write the digest llm
succeeded
Write the digest llm
{
"text": "• Webhook retries after a 410: wants retries to stop on 410 for deleted orders. Unanswered. https://community.northwind.example/t/webhook-retries-after-a-410/4131\n• SSO with Okta groups: asks whether groups can map to roles. Answered: teams only for now. https://community.northwind.example/t/sso-with-okta-groups/4128\nTheme: nothing repeats today.\n"
}
Post to tool
succeeded
Post to tool
Calling slack.post_message
{
"ok": true,
"channel": "C05COMMUNITY",
"ts": "1791460861.000300"
}
Remember covered threads tool
succeeded
Remember covered threads tool
Calling builtin.remember
{
"key": "covered_threads",
"bytes": 214,
"updated_at": "2026-10-08T12:01:02Z"
}
Trigger payload
{
"scheduled_at": "2026-10-08T12:00:00Z"
}
More examples
Turn one person's AI process into the company's.
Murmurator is invite-only. Already invited? Sign in and build something real.