
Ticket Intake
- 1 installs
- Updated June 26, 2026
- comfydesigner/comfyui_frontend
Process for triaging and categorizing incoming ComfyUI frontend feature requests and bug reports.
About
Defines the ticket intake workflow for ComfyUI frontend issues. Team members use it to properly categorize and prioritize incoming work.
- Issue triage checklist and categorization system
- Priority and assignment guidelines
Ticket Intake by the numbers
- 1 all-time installs (skills.sh)
- Ranked #2,479 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/comfydesigner/comfyui_frontend --skill ticket-intakeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| Last updated | June 26, 2026 |
| Repository | comfydesigner/comfyui_frontend ↗ |
What it does
Process for triaging and categorizing incoming ComfyUI frontend feature requests and bug reports.
Files
Ticket Intake
Parses a ticket URL from supported sources (Notion or GitHub), extracts all relevant information, and creates a ticket in the pipeline API.
🚨 CRITICAL REQUIREMENT: This skill MUST register the ticket in the Pipeline API and update the source (Notion/GitHub). If these steps are skipped, the entire pipeline breaks. See Mandatory API Calls below.
Supported Sources
| Source | URL Pattern | Provider File |
|---|---|---|
| Notion | https://notion.so/... https://www.notion.so/... | providers/notion.md |
| GitHub | https://github.com/{owner}/{repo}/issues/{n} | providers/github.md |
Quick Start
When given a ticket URL:
1. Detect source type from URL pattern 2. Load provider-specific logic from providers/ directory 3. Fetch ticket content via appropriate API 4. Extract and normalize properties to common schema 5. Register ticket in pipeline API ← MANDATORY 6. Update source (Notion status / GitHub comment) ← MANDATORY 7. Run verification script to confirm API registration 8. Output summary and handoff to research-orchestrator
Configuration
Uses the production API by default. No configuration needed for read operations.
Defaults (no setup required):
- API URL:
https://api-gateway-856475788601.us-central1.run.app - Read-only endpoints at
/public/*require no authentication
For write operations (transitions, creating tickets), set:
export PIPELINE_API_KEY="..." # Get from GCP Secret Manager or ask adminOptional (for local working artifacts):
PIPELINE_DIR="${PIPELINE_DIR:-$HOME/repos/ticket-to-pr-pipeline}"Mandatory API Calls (Execute ALL Three)
⚠️ These three API calls are the ENTIRE POINT of this skill. Without them, the ticket is invisible to the pipeline, downstream skills will fail, and Notion status won't update.
You MUST make these HTTP requests. Use curl from bash — do not just read this as documentation.
Call 1: Create Ticket
API_URL="${PIPELINE_API_URL:-https://api-gateway-856475788601.us-central1.run.app}"
API_KEY="${PIPELINE_API_KEY}"
curl -s -X POST "${API_URL}/v1/tickets" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-H "X-Agent-ID: ${AGENT_ID:-amp-agent}" \
-d '{
"notion_page_id": "NOTION_PAGE_UUID_HERE",
"title": "TICKET_TITLE_HERE",
"source": "notion",
"metadata": {
"description": "DESCRIPTION_HERE",
"priority": "High",
"labels": [],
"acceptanceCriteria": []
}
}'Save the returned id — you need it for the next two calls.
Call 2: Transition to RESEARCH
TICKET_ID="id-from-step-1"
curl -s -X POST "${API_URL}/v1/tickets/${TICKET_ID}/transition" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-H "X-Agent-ID: ${AGENT_ID:-amp-agent}" \
-d '{
"to_state": "RESEARCH",
"reason": "Intake complete, starting research"
}'Call 3: Queue Source Update
curl -s -X POST "${API_URL}/v1/sync/queue" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-H "X-Agent-ID: ${AGENT_ID:-amp-agent}" \
-d '{
"ticket_id": "TICKET_ID_HERE",
"action": "update_status",
"payload": { "status": "In Progress" },
"priority": "normal"
}'Note: The action MUST be"update_status"(not"UPDATE_NOTION_STATUS"). Valid actions:update_status,update_pr_url,mark_done.
TypeScript Equivalent (if using pipeline client)
import { PipelineClient } from '@pipeline/client'
const client = new PipelineClient({
apiUrl:
process.env.PIPELINE_API_URL ||
'https://api-gateway-856475788601.us-central1.run.app',
agentId: process.env.AGENT_ID!
})
const ticket = await client.createTicket({
notion_page_id: pageId,
title: ticketTitle,
source: 'notion',
metadata: { description, priority, labels, acceptanceCriteria }
})
await client.transitionState(
ticket.id,
'RESEARCH',
'Intake complete, starting research'
)
await client.queueSync(ticket.id, 'update_status', { status: 'In Progress' })Workflow
Step 1: Detect Source Type
Parse the URL to determine source:
if (url.includes('notion.so')) {
source = 'notion'
// Load providers/notion.md
} else if (url.match(/github\.com\/[^\/]+\/[^\/]+\/issues\/\d+/)) {
source = 'github'
// Load providers/github.md
} else {
// Error: Unsupported URL format
}Step 2: Load Provider and Fetch Data
Read the appropriate provider file for source-specific instructions:
- Notion:
providers/notion.md- Uses Notion MCP, handles Slack links - GitHub:
providers/github.md- UsesghCLI, handles Dosu comments
Follow the provider's instructions for:
- Fetching content
- Extracting properties
- Updating the source (Notion status → "In Progress", Assignee → pipeline owner)
Step 3: Normalize to Common Schema
All providers must extract normalized ticket data following schema.md:
{
"id": "abc12345",
"url": "https://...",
"source": "notion | github",
"title": "Ticket title",
"description": "Full description",
"status": "Not Started",
"assignee": "username",
"priority": "High",
"area": "UI",
"labels": ["bug", "frontend"],
"acceptanceCriteria": ["Criterion 1", "Criterion 2"],
"fetchedAt": "2024-01-15T10:30:00Z"
}Step 4: Register Ticket in Pipeline API (MANDATORY — DO NOT SKIP)
Execute all three API calls from [Mandatory API Calls](#mandatory-api-calls-execute-all-three) above.
This is not optional. This is not documentation. You MUST make these HTTP requests right now.
1. createTicket() → save the returned ticket ID 2. transitionState(id, 'RESEARCH') → confirm state changed 3. queueSync(id, 'update_status', { status: 'In Progress' }) → confirm queued
If any call fails, retry once. If it still fails, report the error prominently — do NOT silently continue.
Step 5: Run Verification Script
After making the API calls, run the verification script to confirm everything worked:
bash scripts/verify-intake.sh TICKET_ID_OR_NOTION_PAGE_IDIf the script is not available locally, verify manually via the public API:
curl -s "${API_URL}/public/tickets/${TICKET_ID}" | jq '{id, state, title, notion_page_id}'Expected output:
{
"id": "...",
"state": "RESEARCH",
"title": "...",
"notion_page_id": "..."
}If `state` is not `RESEARCH`, go back to Step 4 and complete the missing calls.
Step 6: Output Summary and Handoff
Print a clear summary:
## Ticket Intake Complete
**Source:** Notion | GitHub
**Title:** [Ticket title]
**ID:** abc12345
**Status:** In Progress (queued)
**Priority:** High
**Area:** UI
### Description
[Brief description or first 200 chars]
### Acceptance Criteria
- [ ] Criterion 1
- [ ] Criterion 2
### Links
- **Ticket:** [Original URL]
- **Slack:** [Slack thread content fetched via slackdump] (Notion only)
### Pipeline
- **API Ticket ID:** abc12345
- **State:** RESEARCH
- **Verified:** ✅ (via verify-intake.sh or public API)After printing the summary, immediately handoff to continue the pipeline. Use the handoff tool with all necessary context (ticket ID, source, title, description, slack context if any):
Handoff goal: "Continue pipeline for ticket {ID} ({title}). Ticket is in RESEARCH state. Load skill: research-orchestrator to begin research phase. Ticket data: source={source}, notion_page_id={pageId}, priority={priority}. {slack context summary if available}"Do NOT wait for human approval to proceed. The intake phase is complete — handoff immediately.
Error Handling
Unsupported URL
❌ Unsupported ticket URL format.
Supported formats:
- Notion: https://notion.so/... or https://www.notion.so/...
- GitHub: https://github.com/{owner}/{repo}/issues/{number}
Received: [provided URL]Provider-Specific Errors
See individual provider files for source-specific error handling:
providers/notion.md- Authentication, page not foundproviders/github.md- Auth, rate limits, issue not found
Missing Properties
Continue with available data and note what's missing:
⚠️ Some properties unavailable:
- Priority: not found (using default: Medium)
- Area: not found
Proceeding with available data...API Call Failures
❌ Pipeline API call failed: {method} {endpoint}
Status: {status}
Error: {message}
Retrying once...
❌ Retry also failed. INTAKE IS INCOMPLETE.
The ticket was NOT registered in the pipeline.
Downstream skills will not work until this is fixed.Notes
- This skill focuses ONLY on intake — it does not do research
- Slack thread content is fetched automatically via the
slackdumpskill — no manual copy-paste needed - ALL API calls (createTicket, transitionState, queueSync) are MANDATORY — never skip them
- The
queueSyncaction must be"update_status", NOT"UPDATE_NOTION_STATUS" - Pipeline state is tracked via the API, not local files
- Working artifacts (research-report.md, plan.md) can be saved locally to
$PIPELINE_DIR/runs/{ticket-id}/ - The
sourcefield in the ticket determines which research strategies to use
API Client Reference
Available Methods
| Method | Description |
|---|---|
createTicket({ notion_page_id, title, source, metadata }) | Create a new ticket in the API |
getTicket(id) | Retrieve a ticket by ID |
findByNotionId(notionPageId) | Look up a ticket by its Notion page ID |
listTickets({ state, agent_id, limit, offset }) | List tickets with optional filters |
transitionState(id, state, reason) | Move ticket to a new state (e.g., 'RESEARCH') |
setPRCreated(id, prUrl) | Mark ticket as having a PR created |
queueSync(id, action, payload) | Queue a sync action (update_status, update_pr_url, mark_done) |
registerBranch(id, branch, repo) | Register working branch for automatic PR detection |
Error Handling
import { PipelineClient, PipelineAPIError } from '@pipeline/client';
try {
await client.createTicket({ ... });
} catch (error) {
if (error instanceof PipelineAPIError) {
console.error(`API Error ${error.status}: ${error.message}`);
}
throw error;
}GitHub Provider - Ticket Intake
Provider-specific logic for ingesting tickets from GitHub Issues.
URL Pattern
https://github.com/{owner}/{repo}/issues/{number}
https://www.github.com/{owner}/{repo}/issues/{number}Extract: owner, repo, issue_number from URL.
Prerequisites
ghCLI authenticated (gh auth status)- Access to the repository
Fetch Issue Content
Use gh CLI to fetch issue details:
# Get issue details in JSON
gh issue view {number} --repo {owner}/{repo} --json title,body,state,labels,assignees,milestone,author,createdAt,comments,linkedPRs
# Get comments separately if needed
gh issue view {number} --repo {owner}/{repo} --commentsExtract Ticket Data
Map GitHub issue fields to normalized ticket data (stored via API):
| GitHub Field | ticket.json Field | Notes |
|---|---|---|
| title | title | Direct mapping |
| body | description | Issue body/description |
| state | status | Map: open → "Not Started" |
| labels | labels | Array of label names |
| assignees | assignee | First assignee login |
| author | author | Issue author login |
| milestone | milestone | Milestone title if present |
| comments | comments | Array of comment objects |
| linkedPRs | linkedPRs | PRs linked to this issue |
Priority Mapping
Infer priority from labels:
priority:critical,P0→ "Critical"priority:high,P1→ "High"priority:medium,P2→ "Medium"priority:low,P3→ "Low"- No priority label → "Medium" (default)
Area Mapping
Infer area from labels:
area:ui,frontend,component:*→ "UI"area:api,backend→ "API"area:docs,documentation→ "Docs"bug,fix→ "Bug"enhancement,feature→ "Feature"
Update Source
For GitHub issues, update is optional but recommended.
Add a comment to indicate work has started:
gh issue comment {number} --repo {owner}/{repo} --body "🤖 Pipeline started processing this issue."Optionally assign to self:
gh issue edit {number} --repo {owner}/{repo} --add-assignee @meLog any updates via the Pipeline API:
await client.updateTicket(ticketId, {
metadata: {
...ticket.metadata,
githubWrites: [
...(ticket.metadata?.githubWrites || []),
{
action: 'comment',
issueNumber: 123,
at: new Date().toISOString(),
skill: 'ticket-intake',
success: true
}
]
}
})GitHub-Specific Ticket Fields
Store via API using client.createTicket():
{
"source": "github",
"githubOwner": "Comfy-Org",
"githubRepo": "ComfyUI_frontend",
"githubIssueNumber": 123,
"githubIssueUrl": "https://github.com/Comfy-Org/ComfyUI_frontend/issues/123",
"labels": ["bug", "area:ui", "priority:high"],
"linkedPRs": [456, 789],
"dosuComment": "..." // Extracted Dosu bot analysis if present
}Dosu Bot Detection
Many repositories use Dosu bot for automated issue analysis. Check comments for Dosu:
gh issue view {number} --repo {owner}/{repo} --comments | grep -A 100 "dosu"Look for comments from:
dosu[bot]dosu-bot
Extract Dosu analysis which typically includes:
- Root cause analysis
- Suggested files to modify
- Related issues/PRs
- Potential solutions
Store in ticket data via API:
{
"dosuComment": {
"found": true,
"analysis": "...",
"suggestedFiles": ["src/file1.ts", "src/file2.ts"],
"relatedIssues": [100, 101]
}
}Extract Linked Issues/PRs
Parse issue body and comments for references:
#123→ Issue or PR referencefixes #123,closes #123→ Linked issuehttps://github.com/.../issues/123→ Full URL reference
Store in ticket data via API for research phase:
{
"referencedIssues": [100, 101, 102],
"referencedPRs": [200, 201]
}Error Handling
Authentication Error
⚠️ GitHub CLI not authenticated.
Run: gh auth loginIssue Not Found
❌ GitHub issue not found or inaccessible.
- Check the URL is correct
- Ensure you have access to this repository
- Run: gh auth statusRate Limiting
⚠️ GitHub API rate limited.
Wait a few minutes and try again.
Check status: gh api rate_limitNotion Provider - Ticket Intake
Provider-specific logic for ingesting tickets from Notion.
URL Pattern
https://www.notion.so/workspace/Page-Title-abc123def456...
https://notion.so/Page-Title-abc123def456...
https://www.notion.so/abc123def456...Page ID is the 32-character hex string (with or without hyphens).
Prerequisites
- Notion MCP connected and authenticated
- If not setup:
claude mcp add --transport http notion https://mcp.notion.com/mcp - Authenticate via
/mcpcommand if prompted
Fetch Ticket Content
Use Notion:notion-fetch with the page URL or ID:
Fetch the full page content including all propertiesExtract Ticket Data
Extract these properties (names may vary):
| Property | Expected Name | Type |
|---|---|---|
| Title | Name / Title | Title |
| Status | Status | Select |
| Assignee | Assignee / Assigned To | Person |
| Description | - | Page content |
| Slack Link | Slack Link / Slack Thread | URL |
| GitHub PR | GitHub PR / PR Link | URL |
| Priority | Priority | Select |
| Area | Area / Category | Select |
| Related Tasks | Related Tasks | Relation |
If properties are missing: Note what's unavailable and continue with available data.
Update Source (REQUIRED)
⚠️ DO NOT SKIP THIS STEP. This is a required action, not optional.
⚠️ Notion Write Safety rules apply (see `$PIPELINE_DIR/docs/notion-write-safety.md` for full reference):
- Whitelist: Only
Status,GitHub PR, andAssigneefields may be written - Valid transitions: Not Started → In Progress, In Progress → In Review, In Review → Done
- Logging: Every write attempt MUST be logged with timestamp, field, value, previous value, skill name, and success status
Use Notion:notion-update-page to update the ticket:
1. Status: Set to "In Progress" (only valid from "Not Started") 2. Assignee: Assign to pipeline owner (Notion ID: 175d872b-594c-81d4-ba5a-0002911c5966)
{
"page_id": "{page_id_from_ticket}",
"command": "update_properties",
"properties": {
"Status": "In Progress",
"Assignee": "175d872b-594c-81d4-ba5a-0002911c5966"
}
}After the update succeeds, log the write via the Pipeline API:
await client.updateTicket(ticketId, {
metadata: {
...ticket.metadata,
notionWrites: [
...(ticket.metadata?.notionWrites || []),
{
field: 'Status',
value: 'In Progress',
previousValue: 'Not Started',
at: new Date().toISOString(),
skill: 'ticket-intake',
success: true
}
]
}
})If update fails, log with success: false and continue.
Notion-Specific Ticket Fields
Store via API using client.createTicket():
{
"source": "notion",
"notionPageId": "abc123def456...",
"slackLink": "https://slack.com/...",
"relatedTasks": ["page-id-1", "page-id-2"]
}Slack Thread Handling
If a Slack link exists, use the slackdump skill to fetch the thread content programmatically.
Slack URL Conversion
Notion stores Slack links in slackMessage:// format:
slackMessage://comfy-organization.slack.com/CHANNEL_ID/THREAD_TS/MESSAGE_TSConvert to browser-clickable format:
https://comfy-organization.slack.com/archives/CHANNEL_ID/pMESSAGE_TS_NO_DOTExample:
- Input:
slackMessage://comfy-organization.slack.com/C075ANWQ8KS/1766022478.450909/1764772881.854829 - Output:
https://comfy-organization.slack.com/archives/C075ANWQ8KS/p1764772881854829
(Remove the dot from the last timestamp and prefix with p)
Fetching Thread Content
Load the slackdump skill and use the export-thread workflow:
# Export thread by URL
slackdump dump "https://comfy-organization.slack.com/archives/CHANNEL_ID/pMESSAGE_TS"
# Or by colon notation (channel_id:thread_ts)
slackdump dump CHANNEL_ID:THREAD_TSSave the thread content to $RUN_DIR/slack-context.md and include it in the ticket metadata.
No manual action required. The slackdump CLI handles authentication via stored credentials at ~/.cache/slackdump/comfy-organization.bin.Database Reference: Comfy Tasks
The "Comfy Tasks" database has these properties (verify via notion-search):
- Status values: Not Started, In Progress, In Review, Done
- Team assignment: "Frontend Team" for unassigned tickets
- Filtering note: Team filtering in Notion may have quirks - handle gracefully
Pipeline Owner Details
When assigning tickets, use these identifiers:
| Platform | Identifier |
|---|---|
| Notion User ID | 175d872b-594c-81d4-ba5a-0002911c5966 |
| Notion Name | Christian Byrne |
| Notion Email | cbyrne@comfy.org |
| Slack User ID | U087MJCDHHC |
| GitHub Username | christian-byrne |
To update Assignee, use the Notion User ID (not name):
properties: {"Assignee": "175d872b-594c-81d4-ba5a-0002911c5966"}Finding Active Tickets
To list your active tickets:
Use Notion:notion-search for "Comfy Tasks"
Filter by Assignee = current user OR Team = "Frontend Team"Error Handling
Authentication Error
⚠️ Notion authentication required.
Run: claude mcp add --transport http notion https://mcp.notion.com/mcp
Then authenticate via /mcp command.Page Not Found
❌ Notion page not found or inaccessible.
- Check the URL is correct
- Ensure you have access to this page
- Try re-authenticating via /mcpTicket Schema
Common schema for normalized ticket data across all sources. This data is stored and retrieved via the Pipeline API, not local files.
Ticket Data Schema
{
// Required fields (all sources)
"id": "string", // Unique identifier (short form)
"url": "string", // Original URL
"source": "notion | github", // Source type
"title": "string", // Ticket title
"description": "string", // Full description/body
"fetchedAt": "ISO8601", // When ticket was fetched
// Common optional fields
"status": "string", // Current status
"assignee": "string", // Assigned user
"priority": "string", // Priority level
"area": "string", // Category/area
"labels": ["string"], // Tags/labels
"acceptanceCriteria": ["string"] // List of AC items
// Source-specific fields (see providers)
// Notion: notionPageId, slackLink, relatedTasks, notionWrites
// GitHub: githubOwner, githubRepo, githubIssueNumber, linkedPRs, dosuComment, referencedIssues
}Ticket State Schema (via API)
State is managed via the Pipeline API using client.transitionState():
{
"ticketId": "string",
"state": "intake | research | planning | implementation | pr_created | done | failed",
"stateChangedAt": "ISO8601",
// Timestamps tracked by API
"createdAt": "ISO8601",
"updatedAt": "ISO8601"
}Priority Normalization
All sources should normalize to these values:
| Normalized | Description |
|---|---|
| Critical | Production down, security |
| High | Blocking work, urgent |
| Medium | Normal priority (default) |
| Low | Nice to have, backlog |
Status Normalization
Pipeline tracks these statuses internally:
| Status | Description |
|---|---|
| research | Gathering context |
| planning | Creating implementation plan |
| implementation | Writing code |
| review | Code review in progress |
| qa | Quality assurance |
| done | PR merged or completed |
ID Generation
IDs are generated by the API when creating tickets. For reference:
- Notion: First 8 characters of page ID
- GitHub:
gh-{owner}-{repo}-{issue_number}(sanitized)
Examples:
- Notion:
abc12345 - GitHub:
gh-comfy-org-frontend-123