بنقرة واحدة
create-ticket
Create a single Linear ticket from args, contract file, or plan milestone with conflict resolution
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Create a single Linear ticket from args, contract file, or plan milestone with conflict resolution
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Dispatch a background worker with role-templated prompt and auto-populated collision fences
Comprehensive system health monitoring — checks agent performance, database, Kafka topics, pattern discovery, and service status across the ONEX platform
Orchestrate a Claude Code agent team to autonomously work a Linear epic across multiple repos
Run DoD evidence checks against a ticket contract and generate a verification receipt
Autonomous per-ticket pipeline that chains ticket-work, local-review, PR creation, CI watching, PR review loop, integration verification gate, and auto-merge into a single unattended workflow with Slack notifications and policy guardrails
Full autonomous audit-debug-fix loop for all dashboard pages — Playwright recon, parallel systematic-debug, fix, PR, Linear ticket, re-audit, iterate until clean. Supports local and cloud targets with optional post-fix redeployment.
| name | create-ticket |
| description | Create a single Linear ticket from args, contract file, or plan milestone with conflict resolution |
Usage:
/create-ticket <title>
/create-ticket --from-contract <path>
/create-ticket --from-plan <path> --milestone <M1-M5>
Arguments:
title - Ticket title (mutually exclusive with --from-contract, --from-plan)--from-contract <path> - Path to YAML contract file--from-plan <path> - Path to plan markdown file--milestone <id> - Milestone ID when using --from-plan (e.g., M4)--repo <label> - Repository label (e.g., omniclaude, omnibase_core)--parent <id> - Parent issue ID for epic relationship (e.g., OMN-1800)--blocked-by <ids> - Comma-separated issue IDs that block this ticket--project <name> - Linear project name--team <name> - Linear team name (default: Omninode)--allow-arch-violation - Bypass architecture dependency validationYou are creating a Linear ticket with standardized format and conflict resolution.
Announce at start: "Creating Linear ticket from {source_type}."
These argument groups are mutually exclusive:
--title (direct title specification)--from-contract (load from YAML contract file)--from-plan + --milestone (extract from plan markdown)If more than one group is provided, report error:
Error: Arguments are mutually exclusive. Provide ONE of:
- --title "Ticket title"
- --from-contract path/to/contract.yaml
- --from-plan path/to/plan.md --milestone M4
--from-plan requires --milestone (e.g., --milestone M4)Error: Must provide ticket source. Use ONE of:
- --title "Ticket title"
- --from-contract path/to/contract.yaml
- --from-plan path/to/plan.md --milestone M4
--title)When --title is provided:
ticket_data = {
"title": args.title,
"repo": args.repo or get_current_repo(),
"requirements": [],
"verification": [],
"context": {}
}
User will need to provide description interactively or via additional args.
--from-contract)Parse YAML contract file matching the ticket-work schema:
def parse_contract_file(path: str) -> dict:
"""Parse YAML contract file for ticket data.
Expected schema (from ticket-work skill):
- ticket_id: optional (will be assigned by Linear)
- title: required
- repo: optional
- requirements[]: list of {id, statement, rationale, acceptance[]}
- verification[]: list of {id, title, kind, command, expected, blocking}
- context: {relevant_files[], patterns_found[], notes}
"""
import yaml
from pathlib import Path
content = Path(path).read_text()
contract = yaml.safe_load(content)
# Validate required fields
if not contract.get("title"):
raise ValueError(f"Contract missing required 'title' field: {path}")
return {
"title": contract["title"],
"repo": contract.get("repo"),
"requirements": contract.get("requirements", []),
"verification": contract.get("verification", []),
"context": contract.get("context", {})
}
Error handling:
--from-plan + --milestone)Extract milestone from plan markdown:
def parse_plan_milestone(path: str, milestone_id: str) -> dict:
"""Extract milestone from plan markdown.
Milestones follow pattern: ## M\d+: Title
Content until next ## heading is the description.
"""
import re
from pathlib import Path
content = Path(path).read_text()
# Pattern: ## M{N}: Title
pattern = rf'^## ({milestone_id}):\s*(.+?)$'
match = re.search(pattern, content, re.MULTILINE | re.IGNORECASE)
if not match:
available = re.findall(r'^## (M\d+):', content, re.MULTILINE)
raise ValueError(
f"Milestone {milestone_id} not found in {path}.\n"
f"Available milestones: {', '.join(available) or 'none'}"
)
milestone_title = match.group(2).strip()
start_pos = match.end()
# Find next ## heading or end of file
next_heading = re.search(r'^## ', content[start_pos:], re.MULTILINE)
if next_heading:
description = content[start_pos:start_pos + next_heading.start()].strip()
else:
description = content[start_pos:].strip()
return {
"title": f"{milestone_id}: {milestone_title}",
"description": description,
"repo": None, # Will use --repo arg or current repo
"requirements": [],
"verification": [],
"context": {}
}
Before creating, search for existing tickets with same title:
mcp__linear-server__list_issues(
query="{ticket_title}",
team="{team}",
limit=10
)
Check if any returned issue has a title that matches (case-insensitive):
def find_existing_ticket(issues: list, title: str) -> dict | None:
"""Find ticket with matching title."""
normalized_title = title.lower().strip()
for issue in issues:
if issue.get("title", "").lower().strip() == normalized_title:
return issue
return None
If existing ticket found, use AskUserQuestion with options:
Found existing ticket "{existing_title}" ({existing_id}).
How would you like to proceed?
1. Update existing ticket (merge descriptions)
2. Cancel old ticket and create new
3. Skip this ticket
Option 1: Update existing
mcp__linear-server__update_issue(id="{existing_id}", description="{merged}")Option 2: Cancel and create new
Option 3: Skip
Generate standardized ticket description:
## Summary
{summary_from_title_or_context}
**Repository**: {repo}
**Dependencies**: {blocked_by_list or "None"}
## Design Decisions
| Decision | Rationale |
|----------|-----------|
| {decision_1} | {rationale_1} |
| ... | ... |
## Files to Create/Modify
- `path/to/file1.py` - Description of changes
- `path/to/file2.py` - Description of changes
## Requirements
{foreach requirement in requirements}
### R{n}: {requirement.statement}
**Rationale**: {requirement.rationale}
**Acceptance Criteria**:
{foreach criterion in requirement.acceptance}
- [ ] {criterion}
{/foreach}
{/foreach}
## Verification
| ID | Title | Kind | Command | Blocking |
|----|-------|------|---------|----------|
{foreach v in verification}
| {v.id} | {v.title} | {v.kind} | `{v.command}` | {v.blocking} |
{/foreach}
## Definition of Done
- [ ] All acceptance criteria verified
- [ ] Verification commands pass
- [ ] Code reviewed and approved
- [ ] Documentation updated (if applicable)
- [ ] No regressions introduced
def build_ticket_description(ticket_data: dict, args) -> str:
"""Build standardized ticket description."""
lines = []
# Summary
lines.append("## Summary\n")
if ticket_data.get("description"):
lines.append(ticket_data["description"])
else:
lines.append(f"Implementation for: {ticket_data['title']}")
lines.append("")
# Metadata
repo = args.repo or ticket_data.get("repo") or get_current_repo()
lines.append(f"**Repository**: {repo}")
blocked_by = [id.strip() for id in args.blocked_by.split(",") if id.strip()] if args.blocked_by else []
deps = ", ".join(blocked_by) if blocked_by else "None"
lines.append(f"**Dependencies**: {deps}")
lines.append("")
# Design Decisions (from context if available)
lines.append("## Design Decisions\n")
lines.append("| Decision | Rationale |")
lines.append("|----------|-----------|")
if ticket_data.get("context", {}).get("patterns_found"):
for pattern in ticket_data["context"]["patterns_found"]:
lines.append(f"| Follow {pattern} pattern | Consistency with codebase |")
else:
lines.append("| *To be determined during implementation* | |")
lines.append("")
# Files to Create/Modify
lines.append("## Files to Create/Modify\n")
if ticket_data.get("context", {}).get("relevant_files"):
for f in ticket_data["context"]["relevant_files"]:
lines.append(f"- `{f}`")
else:
lines.append("- *To be determined during implementation*")
lines.append("")
# Requirements
lines.append("## Requirements\n")
requirements = ticket_data.get("requirements", [])
if requirements:
for i, req in enumerate(requirements, 1):
req_id = req.get("id", f"R{i}")
lines.append(f"### {req_id}: {req.get('statement', 'TBD')}\n")
if req.get("rationale"):
lines.append(f"**Rationale**: {req['rationale']}\n")
lines.append("**Acceptance Criteria**:")
for criterion in req.get("acceptance", []):
lines.append(f"- [ ] {criterion}")
lines.append("")
else:
lines.append("*Requirements to be defined*\n")
# Verification
lines.append("## Verification\n")
verification = ticket_data.get("verification", [])
if verification:
lines.append("| ID | Title | Kind | Command | Blocking |")
lines.append("|----|-------|------|---------|----------|")
for v in verification:
cmd = f"`{v.get('command', 'N/A')}`"
blocking = "Yes" if v.get("blocking", True) else "No"
lines.append(f"| {v.get('id', '-')} | {v.get('title', '-')} | {v.get('kind', '-')} | {cmd} | {blocking} |")
else:
lines.append("*Default verification steps will be used*")
lines.append("")
# Definition of Done
lines.append("## Definition of Done\n")
lines.append("- [ ] All acceptance criteria verified")
lines.append("- [ ] Verification commands pass")
lines.append("- [ ] Code reviewed and approved")
lines.append("- [ ] Documentation updated (if applicable)")
lines.append("- [ ] No regressions introduced")
return "\n".join(lines)
mcp__linear-server__create_issue(
title="{ticket_title}",
team="{team}", # Default: Omninode
description="{generated_description}",
project="{project}", # If --project provided
parentId="{parent}", # If --parent provided
blockedBy=["{id1}", "{id2}"] # If --blocked-by provided
)
mcp__linear-server__update_issue(
id="{existing_ticket_id}",
description="{merged_description}"
)
mcp__linear-server__update_issue(
id="{existing_ticket_id}",
state="Canceled"
)
# Validate mutual exclusivity
sources = [args.title, args.from_contract, args.from_plan]
source_count = sum(1 for s in sources if s)
if source_count == 0:
error("Must provide ticket source")
if source_count > 1:
error("Arguments are mutually exclusive")
if args.from_plan and not args.milestone:
error("--from-plan requires --milestone")
if args.title:
ticket_data = {"title": args.title, ...}
elif args.from_contract:
ticket_data = parse_contract_file(args.from_contract)
elif args.from_plan:
ticket_data = parse_plan_milestone(args.from_plan, args.milestone)
existing = search_existing_tickets(ticket_data["title"], args.team)
if existing:
resolution = ask_user_conflict_resolution(existing)
if resolution == "update":
update_existing_ticket(existing, ticket_data)
return
elif resolution == "cancel_create":
cancel_ticket(existing["id"])
# Continue to create new
elif resolution == "skip":
print(f"Skipped: {ticket_data['title']}")
return
description = build_ticket_description(ticket_data, args)
When --blocked-by is provided, validate that dependencies respect the OmniNode architecture.
Reference: See plugins/onex/lib/dependency_validator.md for validation logic.
# Import validation logic (conceptually - this is documentation)
from lib.dependency_validator import validate_dependencies, filter_errors, filter_warnings, FOUNDATION_REPOS
if args.blocked_by:
blocked_by_ids = [id.strip() for id in args.blocked_by.split(",") if id.strip()]
ticket_repo = args.repo or get_current_repo()
if not ticket_repo:
print("Warning: No --repo specified and unable to detect repository. Skipping architecture validation.")
else:
violations = validate_dependencies(
ticket_repo=ticket_repo,
blocked_by_ids=blocked_by_ids,
fetch_ticket_fn=lambda id: mcp__linear-server__get_issue(id=id)
)
# Filter using ValidationResult severity field
errors = filter_errors(violations)
warnings = filter_warnings(violations)
for w in warnings:
print(f"[WARNING] {w.message}")
if errors:
if not args.allow_arch_violation:
print("\nDependency architecture violations detected:\n")
for err in errors:
print(f" - {err.message}\n")
print("\nValid dependencies flow: app->foundation or foundation->foundation.")
print("To proceed anyway, use --allow-arch-violation flag.")
raise SystemExit(1)
else:
print("\n[WARNING] Proceeding with architecture violations (--allow-arch-violation):\n")
for err in errors:
print(f" - {err.message}\n")
# Append warning to description
description += "\n\n---\n\n**Warning**: This ticket has dependencies that violate architecture guidelines."
Architecture Rules:
| Ticket Repo | Blocked By Repo | Verdict |
|---|---|---|
| application | application | INVALID (app->app) |
| foundation | application | INVALID (foundation->app) |
| application | foundation | VALID |
| foundation | foundation | VALID |
Foundation repos: omnibase_compat, omnibase_core, omnibase_spi, omnibase_infra
# Build create params
params = {
"title": ticket_data["title"],
"team": args.team or "Omninode",
"description": description
}
if args.project:
params["project"] = args.project
if args.parent:
params["parentId"] = args.parent
if args.blocked_by:
params["blockedBy"] = [id.strip() for id in args.blocked_by.split(",") if id.strip()]
result = mcp__linear-server__create_issue(**params)
print(f"""
Ticket created successfully!
ID: {result["identifier"]}
Title: {result["title"]}
URL: {result["url"]}
Team: {args.team or "Omninode"}
Parent: {args.parent or "None"}
Blocked by: {args.blocked_by or "None"}
""")
| Error | Behavior |
|---|---|
| File not found | Report path, suggest checking location |
| YAML parse error | Show line number and syntax issue |
| Missing required field | Report which field is missing |
| Milestone not found | List available milestones in file |
| Architecture violation | List violations, suggest --allow-arch-violation to override |
| Linear API error | Report error, suggest checking permissions |
| Network timeout | Report timeout, suggest retry |
Never:
/create-ticket --title "Add rate limiting to API endpoints" --repo omnibase_core --team Omninode
/create-ticket --from-contract ./specs/rate-limiting.yaml --project "API Improvements"
/create-ticket --from-plan ./EVENT_ALIGNMENT_PLAN.md --milestone M4 --parent OMN-1800
/create-ticket --title "Implement retry logic" --blocked-by OMN-1801,OMN-1802 --team Omninode
/create-ticket --title "Cross-app coordination" --repo omniclaude --blocked-by OMN-1805 --allow-arch-violation