design-reviewer: dispatch on area:design-review label, not just designer-authored PRs #82

Closed
opened 2026-04-19 08:42:50 +00:00 by claude-desktop · 0 comments
Collaborator

User story

As the operator, I want the design-reviewer agent to pick up
area:design-review tickets (or labelled issues) automatically, so
that a Penpot handoff from designer gets reviewed without me
manually invoking the agent.

What happens today

design-reviewer only fires on one trigger: a PR authored by
designer with review_requested (routed via
src/webhook-routing.ts:44). For the common case — designer
produces a Penpot handoff as a comment on an area:design issue,
not a code PR — there is no trigger at all. The designer skill
itself says so:

No design-reviewer request — operator dispatches manually per
skill rules; not opening a PR.

So the operator has to reset / manually kick the agent, or the
handoff sits unreviewed. Observed today on #62 in a full end-to-end
smoke — designer landed a clean handoff comment, design-reviewer
never fired.

Why this matters

area:design routing to designer is already in place (#56); the
symmetric path for design-reviewer is missing. Without it, the
design flow is half-automated.

Proposed design — label-based

Add area:design-review to the label scheme (pink #be185d or
similar — pair it with area:design). Route it in
webhook-routing.ts:

const LABEL_AGENT_MAP: Record<string, string> = {
    "area:design": "designer",
    "area:design-review": "design-reviewer",
};

The designer skill's handoff step adds the label to the issue
on completion (right after posting the handoff comment). The
existing issues.labeled handler
(src/webhook-handlers.ts:handleIssueLabeled) picks it up and
dispatches to design-reviewer.

Pros:

  • No new event type; reuses issues.labeled routing.
  • Explicit marker on the issue — an operator can see at a glance
    whether a handoff has been reviewed (label still present ⇒ no).
  • Easy manual override: operator can add the label on any design
    issue to force a review pass.

Cons:

  • design-reviewer must clear the label on completion, else
    re-adding any other label re-fires. That's the same
    "route on the newly-added label only" rule we already have in
    handleIssueLabeled, so it's safe by construction.

Acceptance criteria

Label & routing

  • Add area:design-review label to labels/ scheme (hex
    distinct from area:design but in the same pink family for
    grouping — e.g. #be185d).
  • webhook-routing.ts:LABEL_AGENT_MAP maps it to
    design-reviewer.
  • design-reviewer agent's review skill knows how to start
    from a Penpot deep-link (pulled from the latest designer
    handoff comment on the issue) instead of from a PR.

Designer skill — handoff marker

  • skills/design-implement.md workflow: after posting the
    handoff comment, call
    mcp__forgejo__add_issue_labels(..., labels=[ID for area:design-review]).
    The skill already knows how to resolve label IDs via
    list_repo_labels.

Design-reviewer skill — cleanup

  • skills/design-review.md workflow: on completion, call
    mcp__forgejo__remove_issue_labels(..., labels=[ID for area:design-review]).
    Prevents re-firing when the operator edits other labels
    later.

Tests

  • webhook-routing.test.ts — assert area:design-review
    routes to design-reviewer.
  • webhook-handlers.test.ts — assert dispatch fires only on
    the newly-added label, same rule as area:design.

Smoke

  • Re-dispatch #62 via the label flow: add area:design-review
    to #62 manually → design-reviewer picks it up → posts a
    visual-defect review comment → removes the label.

Out of scope

  • A fully automated "designer finishes → design-reviewer picks it
    up" chain. The intermediate label step keeps the operator in
    the loop (they can see the handoff, decide whether review is
    warranted). Auto-chaining is a follow-up if manual label flip
    feels friction-y in practice.
  • Routing the inverse direction (design-reviewer feedback →
    designer re-iterates). Today's scope is first-pass review only.

References

  • #62 — the e2e that surfaced this gap; designer comment
    #issuecomment-5604.
  • src/webhook-routing.ts:24 — existing label map (area:design
    only).
  • src/webhook-handlers.ts:handleIssueLabeled — handler to extend.

Dependencies

  • Blocked by: nothing.
  • Blocks: closing out the design-review half of #56 / #62.
  • Branch off: main.
## User story As the **operator**, I want the `design-reviewer` agent to pick up `area:design-review` tickets (or labelled issues) automatically, so that a Penpot handoff from `designer` gets reviewed without me manually invoking the agent. ## What happens today `design-reviewer` only fires on one trigger: a PR authored by `designer` with `review_requested` (routed via `src/webhook-routing.ts:44`). For the common case — designer produces a Penpot handoff as a **comment on an `area:design` issue**, not a code PR — there is no trigger at all. The designer skill itself says so: > No `design-reviewer` request — operator dispatches manually per > skill rules; not opening a PR. So the operator has to reset / manually kick the agent, or the handoff sits unreviewed. Observed today on #62 in a full end-to-end smoke — designer landed a clean handoff comment, design-reviewer never fired. ## Why this matters `area:design` routing to `designer` is already in place (#56); the symmetric path for `design-reviewer` is missing. Without it, the design flow is half-automated. ## Proposed design — label-based Add `area:design-review` to the label scheme (pink `#be185d` or similar — pair it with `area:design`). Route it in `webhook-routing.ts`: ```ts const LABEL_AGENT_MAP: Record<string, string> = { "area:design": "designer", "area:design-review": "design-reviewer", }; ``` The `designer` skill's handoff step adds the label to the issue on completion (right after posting the handoff comment). The existing `issues.labeled` handler (`src/webhook-handlers.ts:handleIssueLabeled`) picks it up and dispatches to `design-reviewer`. Pros: - No new event type; reuses `issues.labeled` routing. - Explicit marker on the issue — an operator can see at a glance whether a handoff has been reviewed (label still present ⇒ no). - Easy manual override: operator can add the label on any design issue to force a review pass. Cons: - `design-reviewer` must clear the label on completion, else re-adding any other label re-fires. That's the same "route on the newly-added label only" rule we already have in `handleIssueLabeled`, so it's safe by construction. ## Acceptance criteria ### Label & routing - [ ] Add `area:design-review` label to `labels/` scheme (hex distinct from `area:design` but in the same pink family for grouping — e.g. `#be185d`). - [ ] `webhook-routing.ts:LABEL_AGENT_MAP` maps it to `design-reviewer`. - [ ] `design-reviewer` agent's `review` skill knows how to start from a Penpot deep-link (pulled from the latest `designer` handoff comment on the issue) instead of from a PR. ### Designer skill — handoff marker - [ ] `skills/design-implement.md` workflow: after posting the handoff comment, call `mcp__forgejo__add_issue_labels(..., labels=[ID for area:design-review])`. The skill already knows how to resolve label IDs via `list_repo_labels`. ### Design-reviewer skill — cleanup - [ ] `skills/design-review.md` workflow: on completion, call `mcp__forgejo__remove_issue_labels(..., labels=[ID for area:design-review])`. Prevents re-firing when the operator edits other labels later. ### Tests - [ ] `webhook-routing.test.ts` — assert `area:design-review` routes to `design-reviewer`. - [ ] `webhook-handlers.test.ts` — assert dispatch fires only on the newly-added label, same rule as `area:design`. ### Smoke - [ ] Re-dispatch #62 via the label flow: add `area:design-review` to #62 manually → `design-reviewer` picks it up → posts a visual-defect review comment → removes the label. ## Out of scope - A fully automated "designer finishes → design-reviewer picks it up" chain. The intermediate label step keeps the operator in the loop (they can see the handoff, decide whether review is warranted). Auto-chaining is a follow-up if manual label flip feels friction-y in practice. - Routing the inverse direction (`design-reviewer` feedback → designer re-iterates). Today's scope is first-pass review only. ## References - #62 — the e2e that surfaced this gap; designer comment [#issuecomment-5604](https://forge.jacquin.app/charles/claude-hooks/issues/62#issuecomment-5604). - `src/webhook-routing.ts:24` — existing label map (`area:design` only). - `src/webhook-handlers.ts:handleIssueLabeled` — handler to extend. ## Dependencies - **Blocked by:** nothing. - **Blocks:** closing out the design-review half of #56 / #62. - **Branch off:** `main`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks#82
No description provided.