Sweep recent feedback (the Slack feedback channels, GitHub issues, CI on main, Sentry, Analytics errors, chat run health, deploys), fix as many real bugs as possible, ship them in one PR, then close the loop on every Slack report with 👀/✅/🎫 and one short plain-English reply. Use for scheduled or manual feedback sweeps, usually followed by /ship.
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
The job: find what's broken, fix as much of it as you can, ship it, and tell each reporter in one friendly sentence what happened. A sweep is judged by bugs fixed and merged, and by every claimed report getting a clear answer. It is not judged by ledgers, receipts, or checker output.
The detailed Slack reaction and reply rules are in slack-reaction-replies.md; read it before marking, replying to, or closing any Slack report.
Slack reactions on a report's root message mean exactly this:
| Mark | Meaning | When to add |
|---|---|---|
| 👀 | "I'm on this" | Before you investigate, and only on reports you will finish answering in this run |
| ✅ | "Fixed" | After the fix is merged to main (main deploys to beta automatically) |
| 🎫 | "Needs a person" | A product call, access or credentials, info from the reporter, or a fix you couldn't land |
A maintainer is a Builder.io team member in the workspace who is not the reporter and not a bot. Maintainers steer the sweep with reactions on a root:
| A maintainer adds | Meaning |
|---|---|
:mag: | Don't work on this; someone else will. Wins over everything below |
:yes-party: | Definitely do this, even if it looks ambiguous or like a UX change. Build the smallest version that does what was asked |
:upvote: | Same as :yes-party: for a feature request |
| 👀 by hand | They're working on it themselves; leave it (see "Open items first" for how to tell their 👀 from ours) |
Reactions can't be removed through the Slack connector, so never add one you might need to take back. Every 👀 you add ends the run with a reply, plus either ✅ or 🎫, or a fix PR that is still open and lists the report (its merge adds the ✅).
Every claimed report gets one reply in its thread per outcome. The one exception is
the merged ✅ close-out after an in-review reply, which gets no second reply. Each reply must be:
<url|fix>), never by number.**This was sent from a bot** on its own line,
once.Don't reply at all to jokes, venting, banter, a message meant for a specific teammate, or a thread a person is already handling. Once a person says they have it, or asks the bot to stop, post nothing more in that thread. Before posting, reread the reply as the reporter: would they get it in five seconds, know what happens next, and feel we did the legwork? Check the draft before sending, not after: the first version is the one that notifies them, so editing it afterwards doesn't undo it.
Good (each is the first line; the footer goes on the line below it):
thanks - the <https://github.com/BuilderIO/agent-native/pull/1234|fix> so the export keeps your column order is merged and will be on beta shortly.thanks - once this <https://github.com/BuilderIO/agent-native/pull/1234|fix> merges, the export will keep your column order; it's in review now.thanks - where that button should go is logged for a product decision.thanks - I couldn't find which deck this was; could you paste its link?So a full reply looks like:
thanks - the <https://github.com/BuilderIO/agent-native/pull/1234|fix> so the export keeps your column order is merged and will be on beta shortly.
**This was sent from a bot**Real replies that missed, and what to send instead:
| Sent | Instead |
|---|---|
| "Could you send the recording link, approximate time, and browser so we can trace whether the clip produced media before it tried to save?" | Find the recording from the reporter and message time first. If you still can't: "thanks - I couldn't find which recording this was; could you paste its link?" |
| "cleanup now waits for the transcript, and a fix is ready. It should be on beta shortly." (sent before the merge) | "thanks - recordings will keep their transcript once this <url|fix> is merged; it's in review now." |
| "I've left moving it somewhere easier to find for product to decide." | "thanks - where the editor should live is logged for a product decision." |
| "Partially fixed - PR #7512 merged the project-instructions/context carryover fix", after she'd asked whether FullStory could be added for the whole org | Answer that question first: "yes - I'll add it for everyone" or "not yet - that's logged for a decision". |
| "All fixed and verified. Please try again!" plus instructions to pull main and reinstall | "thanks - this <url|fix> is merged and will be on beta shortly." No homework. |
| More replies after Shawn wrote "bot please stop! I've got this all fixed and in flight" | Nothing. A person has it. |
| "Thanks for correcting me, Julia - I misread the replies. ... Open - no question: I don't have enough source evidence to claim a fix." | Nothing: the thread was a joke. |
| Asked for the app URL, what was clicked, and the time; then, in a second reply, for the time zone. | One reply, one question, only for what you can't look up. The message's own timestamp already says when. |
#product-agent-native-feedback (C0ATH3CCZT4)
and #qa-agent-native (C0C4U4XRT6X), a narrower set the invocation
names, or a caller's list (as in factory-run). Never
react or reply elsewhere. Reply only in a report thread this workflow
claimed with 👀 and investigated; a bot reply alone isn't a claim.
Never start a new channel message.:mag: or their own 👀 on it (table above);/ship closes the
report out when it merges.gh api user --jq .login), so
authorship proves nothing: a PR under that login may be another thread's
work in flight, and pushing to it lands unreviewed commits on it. Never touch any other PR unless the invocation names that exact PR and
action. That holds inside /ship too: its "Your PRs" means this run's PR.Reports section that this run didn't open belongs to
another run that may still be working on it. Don't push to, reply on, or
merge it; list it under "Still open from earlier runs".On "dry run", run every step but send nothing:
:mag: and 👀./ship, and comments.The factory VM runs this skill through factory-run, which differs on
purpose: replies post as the factory's own Slack app (no bot line, no profile
check), claims live in factory state, each fix group gets its own branch and
PR, and the watcher merges.
Work in a task-owned worktree on fresh origin/main. If you start in a shared
checkout, or the expected worktree is missing, create one
(git worktree add <path> origin/main) and carry on. That is never a reason
to stop.
Window: roots posted in the last 5 days (or since the timestamp or permalink
the invocation gives), for new reports and open items alike. An older thread
is in the window too when we have already replied in it and a person has
replied since the window began: a channel read only shows roots, so search for
recent thread replies (in:<#channel> is:thread after:<date>) to find them.
Roots in memory.md under "Claimed reports", "Claimed, not yet answered",
or "Must handle next run" are always in the window. Other older threads are left as they are, except reports listed under
Reports in a sweep PR opened or merged in that window: those always get
their close-out.
Give each source below its own helper on the cheapest model (Luna in Codex,
Haiku in Claude Code), and close it as soon as it reports. A helper gathers;
you triage. The Slack helper returns every root a person posted in the window with no ✅, 🎫, or :mag:,
and every root with a person's reply newer than ours, one line each (link,
author, first line). It never filters, ranks, or drops one: a new report has
no reaction and no thread yet.
slack_read_channel with
response_format: detailed (paginate) back 5 days. Its output shows
reaction counts but not who added them, so call slack_get_reactions on any
root showing eyes, white_check_mark, ticket, mag, yes-party, or
upvote. Avoid hasmy:; run the
backstop.Reports section of a sweep
PR that is still open and that this run didn't open belongs to the run
working on that PR: don't react
or reply there, and leave it out of your self-check; just list it under
"Still open from earlier runs". If that PR has had no push in 24 hours,
its run has stopped: its reports are yours again. Of the remaining
workflow roots, those without ✅ or 🎫 come first in this run. A newer
human reply is context, not by itself a reason to respond: investigate the
claimed report and leave conversations already handled by people alone. A
root with 🎫 and our reply after its latest human message is already answered: you may still fix it, but post nothing there
until the fix merges. A
reply like "still broken" after a ✅ means the earlier fix failed. Find what
that fix changed and why it didn't hold before trying again.ts. A channel-history row whose thread_ts differs from its
ts is a reply that was also sent to the channel: use its thread_ts
parent instead. Read the thread for every root
that looks like a report. Open screenshots and attachments, since the error
text in a screenshot is often the whole diagnosis.gh issue list --state open --search "updated:>=<date>"). Skip ones
someone else has offered to fix.list-error-issues, then
get-error-issue): unresolved, recent, and repo-owned. Rank by users
affected. An error with a stack trace is already a reproduction lead.pnpm ci:red-report (exit 2 means CI unavailable, not
clean).node scripts/chat-health.mjs --hours 72; see
chat-run-health.md for what each failure
reason usually means.gh run list --branch main --status failure --limit 30
for the deploy, release, desktop, and publish workflows.Put each report in one bucket:
:upvote: or :yes-party:.Issues from the error and health sources above go in the same buckets, ranked with the Slack reports by people affected. They have no thread to react on, so they appear only in the recap.
Claim Fix reports in order of people affected. Unfinished claims stay in "Claimed reports" for the next run. Any Fix, Build, or Needs-a-person root you leave unclaimed gets no reaction, only one line in the recap saying why, so nothing is dropped silently. That covers every candidate your source helpers return: each one ends the run either claimed or on a recap line with its reason.
In scheduled and manual runs, record each root (channel and ts) under "Claimed
reports" in the feedback automation's memory.md, then add and verify 👀
before investigating. A record alone does not establish a claim: the root
must also have the verified 👀 from this workflow. Retain the record until
the report is resolved or a person takes over. If shared memory is unavailable,
do not claim new roots.
git log --since=30.days --oneline -- <files>: if
this surface was fixed before for the same symptom, that fix treated a
symptom. Find the shared cause (fix-at-the-boundary) instead of adding
one more patch, and look for the same pattern elsewhere.main and pass with them. A check that passes without your fix
doesn't test the bug: write one that does. Tests that read source text
never count. For a purely visual fix, before and after screenshots are
evidence, not automated proof: before merging, a human must open both and
confirm they show the reported change. Put the evidence under the report in
the PR's Reports section. A test-only change (test files, optional
.changeset/) needs only fix-proof: test-only.Commit the fix and its check, then run
node scripts/fix-proof.ts --fix <that commit> -- <the check> from the
repo root and paste its fix-proof: proven ... line, unchanged, under
each report it fixes (visual: <before> <after> for a purely visual
fix). The required Lint & format check runs this gate for PRs with a
Reports section and re-runs machine proofs. It marks visual-only reports
as needing human validation before merge. The second
opinion below reads the red output to confirm the check failed on the
bug, not on setup.
Put every fix in one PR, and open it once every claimed Fix report has a
fix or a failed attempt, so CI waits come after the fixing. Don't open one
PR per item. End the PR body with a
## Reports heading listing the link of every report the PR fixes: the
Slack thread, or the Sentry, Analytics, or GitHub issue. That list is the
only set of threads a later /ship may close out as fixed.
Wait for CI with one command that blocks until every check finishes, and wait on it with the longest call your tool allows, not a short call you repeat: every call re-sends your whole context.
Here that command is pnpm ci:wait <number>: it prints nothing until CI is
done, then one summary. Exit 1 means a check failed. Exit 2 means it couldn't
tell, and its last line says why: rerun a cancelled check, run the command
again when time ran out with checks still going, and otherwise look at the PR
yourself. To need fewer calls, pass --max-minutes about a minute
under your tool's call limit.
Without a repo command for it, run
gh pr checks <number> --watch --interval 60 > /dev/null in one call bounded
by your tool's limit, then read gh pr checks <number> twice, a minute
apart: CI is done only when both reads list the same checks, at least one,
and none is pending. Otherwise wait again the same way and rerun any cancelled check; after
about two hours, stop and look at the PR yourself.
Fix each review round's findings in one batch. If a second round still finds
a problem in the same fix, take that fix out of the PR, remove its whole entry
from the PR's Reports section: the link and its fix-proof: and visual:
lines (close-out marks every listed report fixed, and a stray evidence line
counts toward the report above it). Then 🎫 its
report with what review found, and merge the rest. Close the PR only when nothing verified
is left in it.
Merge it the way this repo merges PRs. In a Factory workspace, that means the workflow's merge step after its merge gate, never a direct merge.
In the framework repo, run /ship through the merge.
A sweep's PR contains product fixes only. Don't edit this skill, add checker scripts, or add bookkeeping files in it. If the run taught something, propose a one-line lesson in the recap for a maintainer to accept or drop.
This step is the only place a claimed report gets its closing reply. Run it
after the merge for the threads in the PR's Reports section. If the merge
happened outside this run, the next sweep runs it: when you collect, list the
sweep PRs merged in the window (gh pr list --state merged --limit 100 --search "merged:>=<date>") and close out every report in their Reports sections
that still lacks its ✅, however old the report is.
Entries that aren't Slack threads get no Slack action: GitHub issues follow
the issue rule below, and Sentry and Analytics issues are only listed in the
recap.
In the framework repo, /ship step 6 runs this step after its merge, and
address-feedback-with-replies runs it for its own threads.
Run it once per thread: if a reply in the thread already links this PR, just make sure ✅ is there and move on.
Write only as the connected Slack profile, only in the feedback
channels, and in the reply format from the contract above. First re-read
the contract and this step from fresh origin/main (git fetch origin main && git show origin/main:.agents/skills/review-latest-feedback/SKILL.md): a
run that started hours ago may be holding older rules. Re-read each thread before
writing. If a maintainer has since added :mag: or a person has taken it over,
leave it. If a newer human reply says it's still broken, leave the 👀 for the
next sweep. Otherwise:
Reports entry carries a
proof (step 3). Without one, it's 🎫 and a reply that the fix is logged for a
person to check.GitHub issues fixed by the merged PR get a one-line thank-you comment linking the PR, and then get closed. Post it even when someone else opened the issue, or the PR already closed it: reporters should be told.
Report unresolved CI, deploy, and chat-health failures in the private run recap. Do not create Slack channel messages or GitHub issues for them.
Before ending, re-read each thread you touched and check:
Reports;Keep the recap short, for the maintainer reading it:
## Feedback sweep - <date, Pacific>
Fixed and merged (N): <one line each, with Slack thread link> · PR <link>
Closed out from earlier runs (N): <Slack thread link> · PR <link>
Needs a person (N): <what's needed, who, what you tried>
Still open from earlier runs (N): <why>
Seen, not picked (N): <Slack thread link> - <one-line reason>
Roots: <n> seen, <n> claimed, <n> left
Sources unavailable: <list or "none">
Lesson (optional): <one line>"Fixed and merged" is this run's PR only; reports you closed out for an earlier run's merged PR go under "Closed out from earlier runs".
In an automation, append the same recap to its memory.md.
BuilderIO/agent-native
46ed84c
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.