← Back to Cookbook

Bug Report Triage

Classifies bug severity, assigns priority, notifies the right Slack channel, and emails the reporter.

aiswitchhttpresend

Source

/**
 * Triages incoming bug reports. Classifies severity, assigns priority,
 * and sends to the right team channel.
 */

form bug_report {
  label: "Bug Report"
  schema: @json {
    {
      "type": "object",
      "required": ["title", "description", "reporter_email"],
      "properties": {
        "title": { "type": "string", "title": "Bug Title" },
        "description": { "type": "string", "title": "Description" },
        "steps_to_reproduce": { "type": "string", "title": "Steps to Reproduce" },
        "reporter_email": { "type": "string", "format": "email", "title": "Reporter Email" },
        "component": {
          "type": "string",
          "title": "Component",
          "enum": ["frontend", "backend", "api", "database", "infrastructure"]
        }
      }
    }
  }
}

graph triage_bug {
  label: "Triage Bug Report"

  root {
    type: code
    label: "Extract bug report"
    code: @ts { return context.nodes.root.input }
    outputSchema: @json {
      {
        "type": "object",
        "properties": {
          "title": { "type": "string" },
          "description": { "type": "string" },
          "steps_to_reproduce": { "type": "string" },
          "reporter_email": { "type": "string" },
          "component": { "type": "string" }
        }
      }
    }
  }

  node classify {
    type: ai
    label: "Classify bug"
    kind: object
    model: "google/gemini-2.5-flash"
    prompt: @ts {
      const bug = context.nodes.root.output
      return "Classify this bug report.\n\nTitle: " + bug.title + "\nComponent: " + (bug.component || "unknown") + "\nDescription: " + bug.description + "\nSteps: " + (bug.steps_to_reproduce || "not provided")
    }
    schema: @json {
      {
        "type": "object",
        "required": ["severity", "priority", "category"],
        "properties": {
          "severity": { "type": "string", "enum": ["critical", "major", "minor", "trivial"] },
          "priority": { "type": "string", "enum": ["p0", "p1", "p2", "p3"] },
          "category": { "type": "string", "enum": ["crash", "data_loss", "performance", "ui", "functionality", "security"] },
          "suggested_assignee_team": { "type": "string" }
        }
      }
    }
  }

  node route_severity {
    type: switch
    label: "Route by severity"
    cases: ["critical", "standard"]
    router: @ts {
      if (context.nodes.classify.output.severity === "critical") return "critical"
      return "standard"
    }
  }

  node page_oncall {
    type: http
    label: "Page on-call"
    method: "POST"
    url: @ts { return "https://hooks.slack.com/services/EXAMPLE/ONCALL" }
    body: @ts {
      const bug = context.nodes.root.output
      const cls = context.nodes.classify.output
      return JSON.stringify({
        text: "CRITICAL BUG: " + bug.title + "\nCategory: " + cls.category + "\nPriority: " + cls.priority + "\n" + bug.description
      })
    }
  }

  node log_bug {
    type: code
    label: "Log triaged bug"
    code: @ts {
      const bug = context.nodes.root.output
      const cls = context.nodes.classify.output
      return {
        title: bug.title,
        severity: cls.severity,
        priority: cls.priority,
        category: cls.category,
        component: bug.component || "unknown",
        team: cls.suggested_assignee_team || "unassigned"
      }
    }
  }

  node ack_reporter {
    type: resend
    label: "Acknowledge reporter"
    from: @ts { return "[email protected]" }
    to: @ts { return "[email protected]" }
    subject: @ts { return "Bug received: " + context.nodes.root.output.title }
    text: @ts {
      return "Thanks for reporting this bug. It has been triaged as " + context.nodes.classify.output.priority + " (" + context.nodes.classify.output.severity + "). Our team is on it."
    }
  }

  flow {
    root -> classify
    classify -> route_severity
    route_severity -["critical"]-> page_oncall
    route_severity -["standard"]-> log_bug
    classify -> ack_reporter
  }
}

trigger on_bug {
  form:bug_report -> triage_bug
  enabled: true
}

Flow

Trigger → graph

Graph nodes