Our busiest internal Slack channel carries scheduling, PR links, bug reports, feature debates, and general discussion in one stream. Turning a week of it into Asana tickets a manager could act on was a Monday morning job for whoever had the time, and it took about an hour. The Task that replaced it took about an hour to build. It runs at 5 AM every Monday, reads the week's messages and threads, checks Asana and GitHub for what already shipped, and files one Asana ticket with a subtask per theme. Triage now takes minutes.
What's covered
- The digest ticket in Asana: a summary line, one line per theme, and subtasks tagged bug, feature, or mixed
- The Task overview: Asana, GitHub, and Slack as tools, three inline prompts, a memory folder, and a Monday morning schedule
- The eight steps in the script, from loading the ledger to writing it back
- The classify prompt and what it is told to leave out
- A manual run, and one subtask traced back to the two Slack messages it came from
One ticket a week
The Task creates a single parent task in the Inbox section of the team's Asana board, named for the week it covers. The description opens with a count, "6 open, 1 resolved this week" in the ticket the video opens on, then gives one line per theme with its current state. Under the parent sits one subtask per theme, each prefixed with its category: [FEATURE], [BUG], or [MIXED].
Each subtask holds a summary written for someone who was not in the channel, one triage line naming an owner or a blocker, the individual items under that theme, and the Slack messages it came from, quoted with permalinks. A manager reads the parent, opens the subtasks that need a decision, and skips the rest.
The ledger
Themes carry over between weeks. A record in the Platform Channel Digest memory folder lists every open theme with its age. The run loads that record first and writes it back last. A feature the team discussed three weeks ago and finished last week comes through as resolved. A bug nobody touched carries forward, one week older. Anything past four weeks is evicted, so the digest stays the size of the live backlog instead of growing every Monday.
What counts as resolved
Status comes from four sources.
- The Staging / Test section in Asana. A ticket that moved there during the week is completed work.
- The In Progress / Work Underway section. A ticket that moved there means a developer picked it up, and the digest notes that against the theme.
- Merged pull requests in the repo. A merge during the week closes the matching theme.
- The Slack channel itself. A thread where someone confirms a fix resolves the theme too.
For each Asana section the script pages through the tasks, fetches each task's stories in parallel to find the date it entered the section, and keeps the ones that moved inside the week. The staging scan looks like this:
staging_with_dates = qbash.parallel(
fn=lambda t: fetch_task_with_move_date(t, SECTION_NAME_STAGING),
items=staging_tasks_raw,
concurrency=5,
continue_on_error=True,
).results
for s in staging_with_dates:
if s is None:
continue
moved_dt = s.pop("_moved_at_dt", None)
if moved_dt is not None and window_start <= moved_dt <= window_end:
s["completed"] = True
staging_tickets.append(s)
An inline prompt, match-staging-tickets, then matches these tickets and PRs against the open ledger items by meaning, because a Slack thread and an Asana ticket title rarely use the same words.
The script
The top of the script is config: the Slack channel ID, the Asana project and section GIDs, the GitHub owner and repo, the memory folder name, and a rolling window of four weeks. The date window is the previous Monday through Sunday, so a run early Monday morning covers the week that just ended. Then eight steps run in order.
- Load the ledger from memory.
- Scan the two Asana sections and the GitHub repo for moved tickets and merged PRs.
- Match those tickets and PRs against the open ledger items.
- Classify the week's Slack messages, threads included.
- Reconcile. A staging move or a merged PR marks a theme resolved, an in-progress move annotates it, a Slack confirmation resolves it, duplicates merge, and everything else ages a week.
- Evict anything past the rolling window.
- Create the Asana parent task and its subtasks.
- Write the updated ledger back for next week.
The Slack step fetches the channel history for the window, then the replies for every thread, again in parallel. Threads are where the detail sits, so a digest built from top-level messages alone would miss most of it. User profiles are loaded once so the messages carry names rather than IDs.
The classify prompt
The classify-messages inline prompt runs on Claude Sonnet 4.6 and returns JSON. Its system message asks for a triage-ready digest for an engineering manager, limited to items that need attention. It includes bugs, features, and iterations, where an iteration is refining or scoping an existing feature or an unresolved design question. It excludes settled decisions, shipped announcements with no follow-up, general chatter, and status updates. Related items group into one theme per area, so a bug and an iteration on the same feature become one theme.
Per theme the output has a title, a category, a two or three sentence summary for a reader with no context, a one-line outcome in the form "Owner, next step" or "Blocked on X", the PRs referenced, the timestamps of the one or two messages that best capture the issue, and the individual items. Those timestamps become the Slack permalinks in the subtask.
The other two prompts, reconcile-open-items and match-staging-tickets, use the same pattern: structured output whose fields map straight onto the ledger record.
The run
The schedule fires every Monday at 5 AM Toronto time, and the video runs it by hand to watch it go. The ledger loads with six open themes from prior weeks. The staging scan finds 20 tasks and pulls stories for each to find its move date, then the in-progress scan does the same. GitHub returns four PRs merged in the previous week. The match prompt streams its output and finishes in a few seconds. Slack loads 117 user profiles and prepares 22 messages, threads included, for the classifier, which identifies six new themes. Reconciling six new against six prior leaves seven open and none resolved. This is a repeat run over the same week as the ticket the video opens on, so the counts differ. The parent task is created, moved into the Inbox section, and the subtasks appear on the board one at a time.
One of them is [FEATURE] GPT-6 Astra Model Support. On the Thursday, Mitch had asked in the channel whether the team could add Astra yet and linked the announcement. Alex Blom replied the next morning that there was no API access yet. The subtask summarises the situation for someone who missed both messages, gives the triage line "Blocked on OpenAI API access, Alex Blom monitoring", and quotes each message with a permalink back to the channel. GPT-6 Astra has since been added to qbash.
Video transcript
Today, I'll show you how we turn one of our busiest internal channels, which contains things like scheduling, general discussions PRs iterations bug flagging, etc. into this a clean Asana weekly digest for managers to come in and triage each Monday morning looking at only the things they care about, which would be feature discussions, bug discussions, iterations, and allow them quickly see which PRs are closed, open, or pending for the week. So, let's take a look at the task responsible for this. As we take a look at the overview page, we can see we have a brief description, which explains we're going to pull the week's worth of Slack messages, including threads, so we don't lose any valuable information from them, classify the discussions into themes, and then create the structure of the Asana task with subtasks that we just saw previously that are grouped by theme. If we take a look down here at the supporting pieces, we can see we have Asana, GitHub, and Slack as integrations or tools for the task.
And you can see we have three inline prompts. We'll take a look at one of those later. We've also set the task to run on an automated schedule every Monday morning at 5:00 a.m., which lets our managers come in on Monday morning and already have this digest ready to go, so they can just get straight to work. So, let's look at some of the details. First, we're going to load a ledger from the memory.
That's this platform channel digest memory right here in the integrations tab. And what this is is a living document which lets us track all of the items from the previous weeks on a rolling window, so that we're not continuously starting from scratch, and we get some context into what things have changed from week to week each time we generate this digest. Then, we're going to scan two Asana sections, which is staging or testing, telling us that the work has been completed, gives us a result signal. We're also going to look at the in progress bucket, telling us that a dev is actively working on this, which gives us an in progress signal. So, this might let us help understand that a ticket was discussed, and then a dev picked it up later that week or the next week.
And then we're going to look at merged or closed PRs from the from the repo. This also tells us that the work has been resolved, so we can keep that up-to-date. Next, we'll match all of the artifacts that we just pulled against the open ledger items. So, for example, like we talked about, this in-progress signal, let's say it was discussed 2 weeks ago and a dev picked it up last week, we would reconcile that. We're going to classify all of the week's Slack messages into bugs, discussions, feature iterations, etc.
And then we're going to reconcile all of the data. Once we've done all that, we're going to evict anything that's beyond the rolling window. This lets us help avoid the digest getting larger and larger each week and becoming unwieldy. And then we're going to create the Asana parent tasks from all of the reconciled output. And last but not least, we'll persist the updated ledger so that the next week's run is fresh with all of the updated information we've pulled from these previous steps.
So, let's take a look at some of the key pieces here. We're pulling from four different data sources, so we're loading the ledger as we talked about. We're going to scan all of the tickets in the corresponding buckets for Asana. So, this is the staging test. You can see here we're using parallel with concurrency set to speed things up a little bit.
Again, we're going to scan the second bucket in Asana. Then we're going to go and fetch all of the merged PRs from our repo. These are some of our helper functions here. If we come down to branch C, you can see we're fetching all of the threads from Slack, so we don't lose any of that valuable information, again using concurrency. We're preparing message data here.
And you can see here this is where our classification works. So, if we take a look at this classified messages prompt right here, you can see that we're only including bugs, features, iterations, and we're excluding things like settled decisions settled decisions, shipped announcements. So, we do the classification reconciliation again using an inline prompt. We're going to apply the rolling window eviction here to get rid of anything that we don't need anymore and keep the digest up-to-date and focus just on what's important. And you can see here, last but not least, we're creating the Asana tickets with Slack links, snippet lines, etc.
And we're creating subtasks for the digest. Once all that's done, we're going to persist the ledger as a final step so that next week's run has all the updated information as we talked about. So, let's see the task in action and we can see some of the tickets that it generates for us. So, like we mentioned, this is running on a timer each week, but we're going to run it manually just to see things flow through. Here we load the ledger which has open themes from the previous weeks.
Here you can see we found 20 total tasks in the staging test bucket in Asana. We're pulling all of the tasks and the stories to see when it got moved to that bucket to see if it makes sense to include in this week. The same thing is happening for the in progress section. And then we're fetching all closed PRs from GitHub. We found four merged PRs from the previous week.
We're going to run our semantic match prompt here and you can see this is streaming its output. Finished quite quickly. We're going to grab all of the Slack conversations and replies. And then we're running our classifier prompt, that's the one we took a look at. You can see we're already pulling in good data here from the Slack channel.
We'll give this a second to run and then we'll come back once it's done. Great, so our prompts are finished and you can see that we're into the create task step here. So, if we move to the board, we can actually see this task come in and if we're quick enough, we might just catch Here you can see some of the subtasks is streaming in. So, we have that nice clean description. We have bug, feature, mixed, etc.
classifications here. If we take a look here, we were talking about GPT-6 Astra, is it available in the API? Side note, we have released this on qbash as of this recording, so please get in there and use it. And you can see here that Mitch is asking, "Are we able to add Ashfur yet?" If we move back to the channel, we can probably find find this. And here we are at the bottom.
So, are we able to add Ashfur yet? We've linked here. There's been a reply from Alex who said he checked earlier this morning and there was no access yet. And you can see here that's captured here along with a helpful link. Hopefully this gives you some ideas of how you can use qbash to automate some of the recurring jobs that you or your team have to do each week and let you focus on the things that are important.