plan-qa
SkillAI & modelsGenerate QA test plan YAML from ticket
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the plan-qa skill
What this skill tells your AI
The instructions your AI receives, as published by rlajous/claude-code-commands in skills/plan-qa/SKILL.md and read by ahel’s review.
Cross-runtime: follow runtime compatibility for invocation, delegation, configuration precedence, state paths, and permissions.
You are helping generate a QA test plan from a ticket description, issue tracker ticket, or requirements. This command creates a structured YAML test plan that can be executed with /start-qa.
Step 1: Load Configuration
Check for configuration:
if [ -f ".git-workflow/config.yaml" ]; then CONFIG_PATH=".git-workflow/config.yaml"; elif [ -f ".claude/config.yaml" ]; then CONFIG_PATH=".claude/config.yaml"; else CONFIG_PATH=""; fi
Load from the resolved CONFIG_PATH (canonical first, legacy read-only fallback):
qa:
apiBaseUrl: ${API_BASE_URL}
testPlansDir: tests/qa
resultsDir: tests/qa/results
timeout: 10
sqsQueueUrl: ${SQS_QUEUE_URL}
issueTracker:
type: auto
Default Values:
qa:
apiBaseUrl: http://localhost:3000
testPlansDir: tests/qa
timeout: 10
Step 2: Parse Arguments
Extract from $ARGUMENTS:
$ARGUMENTS
Patterns to Extract:
| Pattern | Example | Meaning |
|---|---|---|
| Ticket ID | PROJ-123, ENG-456 | Issue tracker ticket |
--url <base_url> | --url https://api.example.com | Override API base URL |
--sqs <queue_url> | --sqs https://sqs.../queue | SQS queue for events |
--sqs-env <VAR_NAME> | --sqs-env SQS_EVENTS_QUEUE | SQS queue from env var |
| Remaining text | Test the /v2/risk endpoint | Task description |
Parsing Logic:
// Extract ticket ID
const ticketMatch = args.match(/([A-Z]+-\d+)/);
const ticketId = ticketMatch ? ticketMatch[1] : null;
// Extract URL override
const urlMatch = args.match(/--url\s+(\S+)/);
const baseUrl = urlMatch ? urlMatch[1] : config.qa.apiBaseUrl;
// Extract SQS queue
const sqsMatch = args.match(/--sqs\s+(\S+)/);
const sqsEnvMatch = args.match(/--sqs-env\s+(\S+)/);
const sqsQueue = sqsMatch ? sqsMatch[1] : sqsEnvMatch ? `\${${sqsEnvMatch[1]}}` : null;
// Remaining is description
const description = args.replace(ticketMatch, '').replace(urlMatch, '').trim();
Step 3: Fetch Ticket Details (If ID Provided)
Linear Integration (via MCP)
If ticket matches Linear format, use the Linear MCP server:
mcp__linear__get_issue(id: ticketId)
Extract:
- Title
- Description
- Acceptance criteria (from comments or description)
- Labels/tags
The MCP server handles authentication automatically via OAuth.
Jira Integration (via MCP)
If Jira configured, use the Jira MCP server:
mcp__jira__get_issue(issueKey: ticketId)
Extract:
- Summary (title)
- Description
- Acceptance criteria
- Labels
The MCP server handles authentication automatically.
GitHub Issues
If GitHub issue format (#123), use the gh CLI:
gh issue view ${ISSUE_NUMBER} --json title,body,labels
Step 4: Analyze Requirements
From the ticket or description, identify:
Endpoints to Test
Look for patterns in description:
GET /api/v1/usersPOST /endpoint- Path patterns:
/v1/,/v2/,/api/ - HTTP methods: GET, POST, PUT, PATCH, DELETE
Expected Behaviors
Extract from acceptance criteria:
- Success conditions
- Error scenarios
- Edge cases
- Authentication requirements
SQS Events (If Mentioned)
Look for:
- Event names (e.g., "USER_CREATED", "ORDER_PLACED")
- Queue mentions
- Async processing requirements
Step 5: Generate Test Plan
Create the test plan YAML:
# Auto-generated QA Test Plan
# Generated: {ISO_TIMESTAMP}
# Source: {TICKET_ID or "Manual description"}
name: "{DESCRIPTIVE_NAME}"
type: feature # feature | bug_fix | regression | smoke
description: |
{DESCRIPTION_FROM_TICKET_OR_INPUT}
# Base configuration
base_url: "${API_BASE_URL}" # or explicit URL
timeout: 10 # seconds
# Endpoints under test
endpoints:
- path: /api/v1/{endpoint}
method: GET
description: "{What this endpoint does}"
auth_required: true
# Test cases
test_cases:
# Happy path tests
- id: TC-001
name: "{Descriptive test name}"
type: happy_path
endpoint: /api/v1/{endpoint}
method: GET
headers:
Authorization: "Bearer ${API_TOKEN}"
Content-Type: application/json
params:
key: value
expected:
status: 200
body:
# Key assertions
success: true
priority: high
tags: [smoke, happy-path]
# Validation tests
- id: TC-002
name: "Invalid input returns 400"
type: validation
endpoint: /api/v1/{endpoint}
method: POST
body:
invalid_field: "bad_value"
expected:
status: 400
body:
error: true
priority: medium
tags: [validation]
# Authentication tests
- id: TC-003
name: "Missing auth returns 401"
type: auth
endpoint: /api/v1/{endpoint}
method: GET
# No Authorization header
expected:
status: 401
priority: high
tags: [auth, security]
# Edge cases
- id: TC-004
name: "Empty list returns empty array"
type: edge_case
endpoint: /api/v1/{endpoint}
method: GET
params:
filter: "nonexistent"
expected:
status: 200
body:
items: []
priority: low
tags: [edge-case]
# SQS assertions (if applicable)
sqs_assertions:
- name: "Event published after action"
queue_url: "${SQS_QUEUE_URL}"
trigger_test: TC-001 # Which test triggers this event
match_mode: json_field # json_field | contains | exact
expected_fields:
event_type: "EVENT_NAME"
# Additional field assertions
timeout_seconds: 30
required: true
# Acceptance criteria (from ticket)
acceptance_criteria:
- "{AC 1 from ticket}"
- "{AC 2 from ticket}"
- "{AC 3 from ticket}"
# Test environment
environment:
variables:
- API_BASE_URL
- API_TOKEN
setup_commands: []
cleanup_commands: []
Step 6: Save Test File
Determine file name:
// From ticket ID (lowercase)
const slug = ticketId ? ticketId.toLowerCase() : null;
// Or from description (kebab-case)
const descSlug = description
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.slice(0, 50);
const fileName = `${slug || descSlug}-test.yaml`;
Save to configured directory:
TEST_DIR=$(config.qa.testPlansDir || "tests/qa")
mkdir -p ${TEST_DIR}
# Write file
cat > "${TEST_DIR}/${FILE_NAME}" << 'EOF'
{GENERATED_YAML}
EOF
Step 7: Confirm
Test plan generated: {TEST_DIR}/{FILE_NAME}
Summary:
- Endpoints: {N} endpoints identified
- Test cases: {M} test cases generated
- Happy path: {X}
- Validation: {Y}
- Auth: {Z}
- Edge cases: {W}
- SQS assertions: {K}
To run tests:
/start-qa {FILE_NAME}
To edit:
Open {TEST_DIR}/{FILE_NAME} and customize as needed.
Configuration Reference
| Setting | Default | Description |
|---|---|---|
qa.apiBaseUrl | http://localhost:3000 | Default API base URL |
qa.testPlansDir | tests/qa | Directory for test plans |
qa.timeout | 10 | Default timeout (seconds) |
qa.sqsQueueUrl | - | Default SQS queue URL |
Examples
From Ticket ID
/plan-qa PROJ-123
Fetches ticket from issue tracker and generates test plan.
From Ticket with SQS
/plan-qa PROJ-456 --sqs-env SQS_EVENTS_QUEUE
Generates test plan with SQS event assertions.
From Description
/plan-qa Test the new /v2/risk endpoint returns risk scores 0-100
Generates test plan from description without ticket.
With Custom URL
/plan-qa PROJ-789 --url https://staging-api.example.com
Generates test plan targeting staging environment.
Test Case Templates
REST API Endpoint
- id: TC-001
name: "GET users returns paginated list"
endpoint: /api/v1/users
method: GET
params:
page: 1
limit: 10
expected:
status: 200
body:
items: [] # Array of users
pagination:
page: 1
limit: 10
Create Resource
- id: TC-002
name: "POST creates new user"
endpoint: /api/v1/users
method: POST
body:
email: "test@example.com"
name: "Test User"
expected:
status: 201
body:
id: "*" # Any non-null value
email: "test@example.com"
Error Handling
- id: TC-003
name: "Duplicate email returns 409"
endpoint: /api/v1/users
method: POST
body:
email: "existing@example.com"
expected:
status: 409
body:
error: "Email already exists"
Output Location
Test files are saved to: {qa.testPlansDir}/{slug}-test.yaml
Where {slug} is:
- Ticket ID lowercase (e.g.,
proj-123-test.yaml) - Or kebab-case from description (e.g.,
risk-endpoint-test.yaml)
Signals
- GitHub stars
- 30
- Forks
- 2
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
plan-qa-rlajous- Source
- github.com/rlajous/claude-code-commands