Sweep recent Slack, GitHub issue, Sentry, first-party Agent-Native Analytics error issues, and explicitly linked tracker feedback: first answer reporters, then fix verified bugs and actionable objective UI defects at the owning boundary, require human signoff for subjective UI changes, build features the invoking user endorsed with an :upvote:, and recap every disposition. Use for scheduled or manual sweeps.
Four phases, in order. Phase 0 comes before any investigation, not after.
👀, before investigating
any of it.Output is fixes; reply only when informative. Two fixes and three messages beats thirty replies.
By default, apply this Slack workflow equally to #product-agent-native-feedback
(C0ATH3CCZT4) and #qa-agent-native (C0C4U4XRT6X), including evidence,
eligibility, claims, reactions, dispositions, and replies. Repeat each
<#CHANNEL> search/read in both; track pagination and reply cursors and message
counts per channel. Honor narrower invocation scope.
👀 is permanent claim history; add it before investigation and never remove
it. An eye without a terminal disposition is unresolved, not available to
another workflow. Check its thread and linked work; continue or coordinate
active work, and defer if ownership is unclear. Post In progress only when
work continues beyond this run.
Defects are in scope: fix them or ask for the one detail needed to fix them. Investigate first; ask what they saw or did in plain language. Gather request details and logs yourself; don't send reporters to developer tools.
The proposed remedy may be wrong while the bug is real. Trace the failure to its owning boundary; do not reject it because the suggestion is unsuitable.
For a parent with multiple symptoms, record a disposition for each symptom
before claiming it. A subjective or out-of-scope suggestion does not close a
separate defect. Keep 👀 on the parent once claimed, and add ✅ only after
every actionable defect in that parent has a verified fix.
✅ is for verified Fixed only, after Phase 2's four bars. For a shared
fix, add it to every claimed report it resolves. Shipped and Live
verified alone do not qualify. Never remove reactions; newer evidence
controls status.
If no safe repo-owned fix is evident, record the evidence limit. Ask only a question that could unblock a fix; after four days without an answer, record Abandoned - no answer in 4 days.
Use Skipped only for non-defects, never breakage. Open - no question means you found neither a fix nor a useful question; state why in the thread.
Use one disposition per ledger row; keep its wording in the recap and thread or linked work:
Record terminal disposition in the thread or linked work; if neither states it, reply once. Current status comes from text or work, never the eye. For clusters, use one owner status listing each source permalink and Clustered state; reply in a non-owner only for a distinct question or update.
✅ only for verified
fixes.After source merge, Fixed is terminal; track publication, beta, and live work separately. Link follow-ups with the original issue, target package/ release/runtime, owner, and verification command or URL. Do not rediscover or reopen closed fixes through open-issue scans. Clustered closes one row but retains it.
Enumerate slack_read_channel newest backward through next_cursor until a
parent is older than 5 days. Record the oldest in-range parent as the scan
boundary. Classify parent text, attachments, and reactions before opening
threads.
slack_search can rank and truncate. Use channel reads to enumerate parents
and put their count in the recap. Sort targeted searches oldest-first and follow
next_cursor until exhausted.
A channel read returns parents, so use its timestamps directly; search hits
are usually replies, so resolve those through the permalink thread_ts first.
Read back each 👀 once before investigation. Follow status for resumed work.
Claiming does not investigate. Search-discovered work gets the same eye-first
read-back. Do not claim items that are already
classified as out of scope. If an item is later found out of scope after being
claimed, keep 👀, record Skipped, and post one concise status reply, no
question. New
evidence or a current :upvote: can restore scope after any non-fixed terminal
disposition; continue on the existing eye. Preserve foreign eyes. Confirm an
active owner from current thread status or linked work, not the eye alone.
Give each claim a disposition and recap row; reply only with informative outcomes. Cluster fresh repeats for Phase 2.
For a supplied spreadsheet, export, test matrix, or tracker, read metadata then the bounded range with its named connector. Enumerate every row and its completion status; retain its id, reporter, symptom, status, retest, and source link.
Status, reactions, a merged PR, a source diff, or a unit test is not behavior proof. Each row needs a post-change ledger result. If it cannot be read, say tracker unavailable, never "no matches."
Every question you ask creates an obligation to come back for the answer. Discharge it before reading anything new.
Slack is the ledger; a per-run state file cannot carry state across runs. First, exhaust this search to enumerate prior questions and context:
slack_search: "this was sent from a bot." in:<#CHANNEL>
sort=timestamp sort_dir=asc include_context=true max_context_length=300Keep include_context=true on every page and follow next_cursor until
exhausted. Its Context after block identifies human replies; do not filter to
replies ending in ?. Open only threads with a human reply.
The parent is the permalink's thread_ts. Message_ts is your own
reply's timestamp; acting on it targets the wrong message.
Find replies even when their parent is older than the five-day scan. Read this channel's prior reply-scan cursor; without one, scan all available history. A new reply can belong to an old disclosure, so search all channel messages over an overlapping date window instead of cursor-filtering the disclosure search:
slack_search: in:<#CHANNEL> after:<YYYY-MM-DD>
sort=timestamp sort_dir=ascFilter hits by their own timestamp after the cursor, resolve each to its
parent's thread_ts, and read the full thread. Never filter by the older
parent/disclosure timestamp. Slack's after: is date-only, so begin one day
before the cursor date. Exhaust next_cursor; advance each cursor only to its
greatest fully processed timestamp.
Count a question answered only when a person posts after it without this workflow's disclosure marker; read the thread to reject partial, unrelated, or deferred replies. Count each answer once; only a newer message reopens it. Enumerate answered threads before new work and recap the count. Keep unanswered Clarification needed pending until answered, resolved, or four days old; other dispositions do not substitute. Reapply Phase 0 eye/checkmark rules.
Apply the age branches only to unanswered Clarification needed threads; restore any such thread mistakenly marked Open - no question.
👀 and record who resolved it and where. The
participant's reply is the status; do not add ✅.👀, record Abandoned - no answer in 4 days once in the
thread without a new question, and carry any still-relevant bug forward as an
internal investigation.Search without after, then apply the four-day expiry; disclosure is the
cross-identity cursor. For legacy replies without disclosure or eyes, run once
per valid workflow identity:
slack_search: from:<EACH_WORKFLOW_IDENTITY> in:<#CHANNEL>
sort=timestamp sort_dir=ascClassify these hits by clarification wording (for example, if you can share),
not as the discovery cursor. Inspect author and full thread; never re-ask a
result from either search. Search the disclosure string, not a display name,
and include it in every reply.
Phase 0 applies these from parent-level evidence to decide what to claim. Phase 2 reapplies these rules after full-thread review.
Use ## Slack channels unless the invocation narrows scope.
Defects and design feedback. A clear bug has observable broken behavior: a click or submit does nothing, an action errors, data is lost or reverted, the result is wrong, or a working flow regressed. A credible "nothing happens" is valid evidence — inspect the owning path before doubting the reporter.
Do not change code for an unrelated product idea, praise, status update, merge or review request, bot forward, duplicate, or work outside the invocation's ownership.
Keep subjective UI changes human-in-the-loop. Automatically fix only
objective UI defects: broken interactions, misalignment, overlap or clipping,
unusable controls, or removing clear excess clutter. A reporter request is not
product signoff. Discoverability complaints and preferences do not authorize
adding, promoting, moving, or duplicating buttons or other persistent chrome.
Check overflow, keyboard, Cmd+K, and contextual surfaces first. Adding or
promoting chrome requires the invoking user's explicit current-task request or
:upvote:below. Otherwise mark **Skipped**. If already claimed, keep our👀 and post **Skipped** once if the thread does not state it; do not ask the reporter to decide. Measure failures withtext-heavy-ui`.
Requests for a new capability still follow the invoking identity's :upvote:
gate. Content remains Alice's area unless the invocation claims it.
:upvote: authorizes feature requestsAn :upvote: from the invoking identity - not from anyone else - promotes
an otherwise out-of-scope item into scope and authorizes the work. It is the
endorsement that settles the product question: the person who would otherwise
route this away has read it and decided it should happen. Build it.
Find them alongside the newest-message scan:
slack_search: hasmy::upvote: in:<#CHANNEL>hasmy: is already scoped to the connected identity you verified, so every
hit is an endorsement by definition. Hits are not self-evidently in scope —
the query also returns ordinary replies and old polls that happen to carry the
reaction. Take the ones that name a concrete improvement; skip the rest
without comment.
An upvoted item is a feature or UX change: it skips only the clear-bug bar,
not 👀, fix-altitude, verification, or question-budget requirements. The
upvote overrides the bug gate, not ownership; build the smallest endorsed
version and name Sid or Alice in the recap. Add 👀 before investigation or
delegation and read it back. Keep an evidence-limited disposition until Phase
2's four bars hold; then use Shipped, adding ✅ only if it also meets
Fixed.
Every run, exhaust oldest-first has::eyes: pages. Revisit active/waiting
claims at any age, even without replies; terminal claims reopen on new evidence:
slack_search: has::eyes: in:<#CHANNEL>
sort=timestamp sort_dir=ascRead each full thread and linked work before classifying its current status; use reaction metadata only as history. Mark Owned elsewhere only when thread status or linked work confirms an active owner. New evidence after terminal status reopens the report; keep reactions.
For GitHub, Sentry, and first-party Agent-Native Analytics, use native state as the cursor: recent open or unresolved items with no maintainer disposition, deduplicated against Slack. If a source cannot be read, record it as unavailable. Never report "nothing matched" for a source you could not query.
Read each issue's body, comments, author, labels, linked PRs. Treat
prior fixed, shipped, or merged comments as leads; recheck the surface.
When a fix merges, thank the reporter, link it, and close. Track release/runtime
gaps separately; keep open only while scope is unfixed, unmerged, or needs input.
Before claiming an issue, check comments for handoffs. If someone offers a PR, or Steve asks them to, mark Owned elsewhere; do not investigate, edit, test, ship, reply, or close it. A direct request overrides this.
Fix every defect at its root or ask an unblock question; do not
skip old, bot-filed, or maintainer-commented issues. Feature requests and
subjective feedback need user/:upvote: authorization. Ask three questions max;
re-read before posting/closing.
Query both production Sentry projects - frontend/browser and backend/CLI - paginate unresolved issues, and record representative events, releases, and fingerprints. Classify each as repo-owned, external/provider, deployment/configuration, or unclear; fix repo-owned failures at the boundary and verify the source/build. Check the published runtime when available, but record any release or live gap separately rather than holding a merged fix open. Record external actions for the rest; silence or an old release is not proof the current error is gone.
Query authenticated Agent-Native Analytics error issues in parallel. Use
list-error-issues for unresolved groups, then get-error-issue for stacks,
occurrences, breadcrumbs, tags, and replay links. It captures client exceptions
and server captureError() failures when the server Analytics key/provider is
configured. Use it as the Sentry fallback when rate-limited. Do not query
error_issues or error_events through
query-agent-native-analytics; use that action only for bounded event/LLM
correlation. Apply the same ownership gate: fix worthwhile repo-owned issues
at their boundary, verify runtime, and record external, deployment, or unclear
issues without inventing a fix.
Before changing code, read fix-at-the-boundary, verifying-changes, and
concurrent-agents. Read ship when a verified fix is ready to publish.
Read the evidence the reporter already attached before forming a hypothesis. Open every screenshot, clip, and linked artifact. The error text in a screenshot is usually the whole diagnosis. Track an artifact that is permission-gated or expired separately from one that was never provided — inaccessible is not absent.
Sweep siblings before you claim anything is fixed. Derive the fingerprint
from the symptom, not the file — the exact crashing token, call shape, or
literal — then search the repo for it and enumerate every hit in your recap
before editing. fix-at-the-boundary owns the method. A fix that repairs the
reported route and leaves the identical crash in its sibling is not a fix, and
the reporter was told otherwise.
Before fixing anything, search the channel for prior reports of the same symptom:
slack_search: <2-4 distinctive symptom words> in:<#CHANNEL>
sort=timestamp sort_dir=descSearch in the reporter's words — zoom invalid_client, logout twice — not
your diagnosis. People describe one bug differently, so read the hits rather
than trusting the count.
A repeat report after a Fixed claim is evidence that fix failed. It is the only falsification signal this workflow gets, and it outranks your belief that the code is correct. Treat it as a stop, not a fresh report:
verifying-changes owns the proof.Record Repeat of: <link> and the prior failed fix in each row; never call a
repeat fixed on the evidence that supported the earlier claim.
Measure this gate with friction keys false-done and
repeat-report-refix. Run node scripts/agent-friction-report.mjs --weeks 2 --pattern <key> for each before changing it and again later. A climbing count
requires a mechanical proof or release gate, not more prose.
For Design, Slides, Core/framework, and template bashes, the reachable reported surface is the contract:
✅ or call Fixed without merged source proof. A post-checkmark repeat
reopens the item and needs a fresh failing pre-change reproduction.For each row, record symptom/surface, reproduction steps and account, expected
and pre/post behavior, tested commit/build, sibling results, untested layers,
and runtime layer (local, source-only, built, deployed, observed-live).
Without merged source proof, use an active or waiting disposition above. After merge, Fixed may coexist with release follow-up; Live verified requires all four bars. Status labels, reactions, and tests alone do not prove closure. Repeats require a new pre-change failure and link the earlier false claim.
Regression claims require Red/Green proof: reverse-apply hunk with
git apply -R, record failure, reapply, record pass. Repeat timing checks 10x.
If output missing, build it and rerun on origin/main before calling them
pre-existing.
Npx scaffolds are versioned. Record pinned/filed versions, fresh npm cache/no
local override, candidate result, release, and existing-app path (pnpm add @agent-native/core@<version> or hand edit).
Local proof, beta promises, and scaffolds are not Shipped/Live verified until published. A verified merged fix is Fixed and closes the issue. Record merge commit, release, verification, and bump/re-scaffold follow-up. Unknown package/endpoint context is a release follow-up. Ask only if source scope or reporter input is unclear; missing evidence does not keep a merged fix open. Merge/beta is not npx delivery.
For each docs row, copy commands into a clean temporary scaffold; verify every
referenced file, directory, script, env var, deploy target, link, and fence
order. A docs diff/build is not enough. Update configured locales and run
guard:i18n-catalogs plus guard:i18n-changed-copy.
Choose the narrowest seam the evidence supports:
Never hard-code a rule for the wording of one report. One data point justifies a local regression test or a contained fix; it never justifies a global agent instruction or prompt exception.
Say Fixed only when all four hold: named symptom; exact pre/post reproduction; clean or triaged sibling sweep; and verified change in the merged shipping snapshot with source or built layer named. Shipped adds build/deploy provenance; Live verified adds target-runtime proof. Otherwise use a narrower disposition without implying beta or production health. Upvoted improvements state requested versus actual behavior and use Shipped.
Start GitHub issue comments by thanking the reporter for opening the issue;
start Slack feedback replies by thanking them for sharing the issue. Then give
the status or ask a question. Follow address-feedback-with-replies for the
remaining Slack reply voice and wording. Every reply ends with
this was sent from a bot. after the plain-language status.
Reply with a new status or useful information; do not repeat a status already in the thread.
Unclaimed scope and noise get only an internal recap row. An unverified defect
earns a targeted question when one answer would unblock it; otherwise record
Open - no question once in the thread. Keep our eye and do not add ✅ for
this terminal disposition. Cluster duplicate causes.
Re-read the full thread before replying and stay out of active human work.
At most three questions per run, across all sources. Most runs ask zero or one.
So rank before you ask. For each candidate, state: if I get this answer, I can ship the fix. Ask the three with the strongest answer. If fewer than three clear that bar, ask fewer. Everything below the cut is an internal open item, not a message.
Never ask for supplied/inspectable evidence, irrelevant IDs/build numbers, subjective choices, or internal blockers. If a user-visible link or ID is the sole blocker, ask plainly and say where to find it.
At most one clarification question may be pending per thread at a time. Once it is answered or resolved, attempt the fix; if that exposes a different required detail, ask at most one new, non-repeating question. Never stack questions or repeat a pending one. If a needed artifact is inaccessible to you, ask for a fresh link - not for its contents again.
Follow the ## Slack identity contract in address-feedback-with-replies:
confirm the connected profile is the invoking user before the first write, and
keep that identity for every read, reaction, reply, and read-back.
Resolve the Slack, GitHub, Sentry, and first-party Analytics error action schemas once and reuse them.
For every Slack write: use the exact parent thread_ts from a full-thread
read, never a search-result or adjacent timestamp, and re-read after posting.
Do not close, label, assign, or comment on GitHub or Sentry unless the
invocation authorizes it; link them in the recap instead.
Use this worktree's branch. Batch fixes with one
corepack pnpm ship:push -m "<specific fix>"; each head reruns CI. Sync
origin/main only for GitHub conflicts; prefer normal merges on shared
branches. Behind/pending never justify syncing.
With shipping authority — an explicit request, or a caller that already
granted it — continue straight into ship in the same worktree without asking
again. Without it, prepare the ready-to-ship handoff and say shipping is
pending authorization. Carry each channel's start cursor, grouped reports,
evidence, owning seam, sibling results, and dispositions into the PR body.
Keep source-tested, built, deployed, and observed-live claims separate.
If a tracker was supplied, carry its exact row ids and the reproduction ledger into the PR or release recap. Never turn a tracker status into a shipping claim. Give every row its own disposition marker. A single reaction, checkmark, or "reviewed" marker must not stand in for several rows, including expected, docs-owned, cross-team, or duplicate items. Any source/docs change is linked to its exact PR or commit; non-coding dispositions link the evidence or named owner instead of borrowing a nearby PR link.
If the sweep found no verified fix, finish with the recap and say why no ship
started. Unavailable connectors and external failures are not shipping blockers.
While waiting, Clarification needed stays open with 👀 and no ✅. It
must not block merging independently verified fixes unless the report could
affect a PR change. Keep the eye when new evidence arrives.
Every item inspected gets a row, including ones you deliberately stayed silent on - that is how silence stays auditable.
## Feedback sweep
Start cursors: product [Slack message](...) · QA [Slack message](...)
Reply cursors (from prior recap; reuse next run): product <last processed timestamp> · QA <last processed timestamp>
Messages enumerated: product N · QA N (total N) · Claimed: N · Answered since last run: N
Questions asked: N/3 · Dropped at 4 days: N
Repeats of a prior Fixed claim: N (each with its earlier thread and failed fix)
Upvoted items in scope: N (built: N)
| Tracker row / source item | Reporter | Disposition | Repro and expected vs actual | Pre / post result | Runtime / build / live evidence | Docs locales | Replied? | Slack reactions |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 18 / [Slack thread](...) | ... | <one disposition from the authoritative list above> | command or click sequence; expected / actual | before: ...; after: ... | source / tests / build / deploy / URL | updated / not applicable / pending | yes / no | 👀 ours / 👀 other / unclaimed; ✅ only for verified fixes |
Sibling sweep: <fingerprint> - N hits, M fixed, K triaged
Tracker: <sheet/export and bounded range> - N rows enumerated, N ledgers complete
Unavailable or unverified: ...Open - no question is a last resort, not a success state. It requires that
you worked the defect, could not fix it, and could not form a question that would
unblock it; a run whose ledger is mostly Open - no question has under-asked, not
finished. It keeps our eye and has no checkmark. "Nothing
matched" is valid only after each source was queried successfully, with the
cursor stated.
address-feedback, address-feedback-with-replies, fix-at-the-boundary,
concurrent-agents, verifying-changes, ship
f07726b
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.