Customer feedback product loop

A Zendesk ticket arrives. A webhook sensor shapes it into a CustomerTicket, and one agent decides whether the ticket points at real work in the codebase. When it does, the agent opens a pull request that links back to the ticket; when it is a question or nothing actionable, it does nothing. Most tickets are not code changes, so the workflow's first job is to tell the two apart.

The sensor

One webhook sensor in sensors/sensors.py. Zendesk POSTs every new ticket to /hooks/zendesk, and the function shapes the payload into a typed CustomerTicket. Run loopy webhooks list to get the full URL to paste into Zendesk.

sensors/sensors.py
from loopy import sensor
from loopy.events import CustomerTicket


# webhook: Zendesk POSTs a new ticket; you shape it into a CustomerTicket
@sensor(webhook="/hooks/zendesk", emits="CustomerTicket")
def zendesk_tickets(req) -> CustomerTicket:
    ticket = req.json["ticket"]
    return CustomerTicket(ticket_id=ticket["id"], subject=ticket["subject"],
                          body=ticket["description"], link=ticket["url"])

The workflow

1 step in workflows/customer-feedback/, triggered by the CustomerTicket the sensor emits. The agent judges the ticket first and only writes code when it warrants it, so a how-to question costs a read and nothing else.

entry.md
---
on: CustomerTicket
agent: SupportEngineer
output: { pr_url: url, verdict: str }
---
A customer opened Zendesk ticket {{ event.ticket_id }}:
"{{ event.subject }}".

{{ event.body }}

Decide whether this ticket points at real work in this codebase.

1. Search the code for the behavior the ticket describes.
2. If it is a bug or a small feature you can address, implement
   the change on a branch and open a pull request that links back
   to {{ event.link }}. If it is a question, a duplicate, or not
   actionable in code, do nothing.
3. Return the PR URL (empty if you skipped) and a one-line verdict.

The token

This workflow writes, so it needs git write access: a GitHub App via loopy auth github, or a GITHUB_TOKEN with contents:write + pull_requests:write in the sandbox's env file.

From the registry

CustomerTicket is emitted by the sensor and consumed by the workflow, so it is declared here because it crosses the bus. The workflow is terminal: it opens a pull request and returns its result, so it emits nothing.

registry.yml
agents:
  SupportEngineer: {}  # judges the ticket, opens a PR when it warrants work

events:
  CustomerTicket:      # inbound, from the Zendesk sensor
    ticket_id: str
    subject:   str
    body:      str
    link:      url
open on github → back to overview