Create a PRD as a Linear parent issue with child issues for implementation tasks, using team key from .ralph.toml.
/prd-linear <feature description>
/prd-linear
If no description is provided, ask clarifying questions to understand the feature.
LINEAR_TEAM from .ralph.toml in the project root to get the team key (e.g. SAB)Read the Linear team key from .ralph.toml at the project root:
linear-team = "SAB"
If .ralph.toml is missing or linear-team is not set, ask the user which team to use.
https://api.linear.app/graphqlAuthorization: $LINEAR_API_KEY (no "Bearer" prefix — the key is sent raw)First, read LINEAR_TEAM from .ralph.toml. Then resolve it:
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{"query":"query { teams(filter: { key: { eq: \"TEAM_KEY\" } }) { nodes { id name key } } }"}'
Replace TEAM_KEY with the value from .ralph.toml.
Extract data.teams.nodes[0].id — this is the teamId for all subsequent calls.
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d "{\"query\":\"query { team(id: \\\"TEAM_ID\\\") { states { nodes { id name } } } }\"}"
Use the state named "Backlog" for new issues.
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "mutation CreateIssue($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier title url } } }",
"variables": {
"input": {
"teamId": "TEAM_ID",
"title": "Feature: <feature name>",
"description": "<full PRD markdown>",
"priority": 2
}
}
}'
Extract data.issueCreate.issue.id as the parentId for child issues. Priority values: 1=Urgent, 2=High, 3=Medium, 4=Low.
For each task from the PRD's "Implementation Tasks" section, create a child issue:
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "mutation CreateIssue($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier title url } } }",
"variables": {
"input": {
"teamId": "TEAM_ID",
"parentId": "PARENT_ISSUE_ID",
"title": "<task title>",
"description": "<task details and acceptance criteria>",
"priority": 2,
"stateId": "STATE_ID"
}
}
}'
Map priority from the PRD:
234The parent issue description should follow this markdown structure:
## Overview
Brief 2-3 sentence description of what this feature does and why it's needed.
## Goals
- Primary goal
- Secondary goals
## User Stories
- As a [role], I want [feature] so that [benefit]
## Requirements
### Functional Requirements
1. Requirement with clear acceptance criteria
### Non-Functional Requirements
- Performance, security, accessibility considerations
## Technical Approach
### Affected Areas
- Models, Controllers, Frontend, Routes
### Database Changes
- New tables or columns, migrations needed
### API Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /api/... | Create... |
## Edge Cases
- Edge case and how to handle it
## Out of Scope
- Features explicitly NOT included
## Open Questions
- [ ] Questions that need answering before implementation
Each child issue should include:
After creating all issues, display a summary:
Parent: SAB-123 — Feature: <name>
URL: https://linear.app/...
Child issues:
SAB-124 — Task 1 (High)
SAB-125 — Task 2 (High)
SAB-126 — Task 3 (Medium)
SAB-127 — Task 4 (Low)
$LINEAR_API_KEY environment variable — never hardcode the keycurl output should be parsed with jq for readability