Ticket Intake
Parses a ticket URL from supported sources (Notion or GitHub), extracts all relevant information, and creates a ticket in the pipeline API.
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:
- Detect source type from URL pattern
- Load provider-specific logic from
providers/directory - Fetch ticket content via appropriate API
- Extract and normalize properties to common schema
- Create ticket in pipeline API
- Queue source update (Notion status / GitHub comment) via sync queue
- Output summary and next steps
Configuration
Required environment variables:
export PIPELINE_API_URL="http://localhost:3000" # Pipeline API server
export AGENT_ID="agent-001" # Identifies this agent instance
Optional (for local working artifacts):
PIPELINE_DIR="${PIPELINE_DIR:-$HOME/repos/ticket-to-pr-pipeline}"
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
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
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: Create Ticket via API
import { PipelineClient } from '@pipeline/client'
const client = new PipelineClient({
apiUrl: process.env.PIPELINE_API_URL!,
agentId: process.env.AGENT_ID!,
})
// Create a new ticket
const ticket = await client.createTicket({
notion_page_id: 'abc12345-...', // Full Notion page UUID (for Notion tickets)
title: 'Ticket title',
source: 'notion', // or 'github'
metadata: {
description: 'Full description',
priority: 'High',
labels: ['bug', 'frontend'],
acceptanceCriteria: ['Criterion 1', 'Criterion 2'],
},
})
// Transition to research phase
await client.transitionState(ticket.id, 'RESEARCH', 'Intake complete, starting research')
// Queue a source update via the sync queue
await client.queueSync(ticket.id, 'UPDATE_NOTION_STATUS', { status: 'In Progress' })
Local working artifacts can still be saved to $PIPELINE_DIR/runs/{ticket-id}/ for files like research-report.md, plan.md, etc.
Step 5: Verify Completion
Before outputting summary, confirm:
- Source type detected correctly
- Ticket created in pipeline API
- State transitioned to RESEARCH
- Source update queued (Notion status / GitHub comment)
Step 6: Output Summary
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 link] ← (Notion only) Copy thread content manually if needed
### Pipeline
- **API Ticket ID:** abc12345
- **State:** RESEARCH
---
**Next Step:** Load the `research-orchestrator` skill to begin research phase.
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...
Notes
- This skill focuses ONLY on intake - it does not do research
- 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 (e.g., Notion status update) |
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;
}
