OmniNode-ai

Decompose Epic

Analyze a Linear epic description and create sub-tickets as Linear children

OmniNode-ai 4 3 Actualitzat fa 3 mesos

Recursos

2
GitHub

Instal·la

npx skillscat add omninode-ai/omniclaude/plugins-onex-skills-decompose-epic

Instal·la des del registre de SkillsCat.

SKILL.md

Decompose Epic

Dispatch Surface

Target: Agent Teams

Overview

Analyze a Linear epic's description, goals, and context to generate a set of actionable
sub-tickets. Creates each sub-ticket as a Linear child of the epic, assigns repo hints
from the repo manifest, and returns ModelSkillResult with created ticket details.

Announce at start: "I'm using the decompose-epic skill to create sub-tickets for {epic_id}."

Implements: decompose-epic skill

  • Mode A (no --repos): reads epic description, infers repo breakdown from repo_manifest.yaml, creates sub-tickets with one per identified work area matched to its owning repo
  • Mode B (--repos omniclaude,omnibase_core,...): repos are pre-determined; creates one focused sub-ticket per repo, scoped to that repo's concerns

Usage Examples

/decompose-epic EPIC-ID
/decompose-epic EPIC-ID --dry-run

Decomposition Flow

  1. Fetch epic from Linear: tracker.get_issue({epic_id}, includeRelations=true)
  2. Read plugins/onex/skills/epic-team/repo_manifest.yaml for keyword-to-repo mapping
  3. Analyze epic description + goals:
    • Identify distinct workstreams (one ticket per independent deliverable)
    • Keep tickets atomic: each ticket = one thing, one repo, one PR
    • Assign repo hint based on keywords in the work description
    • Generate title, description, requirements, and DoD for each ticket
  4. If --dry-run: print plan, exit with status: dry_run
  5. Create each ticket via tracker.create_issue:
    • parentId: epic's Linear ID
    • team: same team as epic
    • labels: ["omniclaude"] (or appropriate repo label)
  6. Post-decomposition: generate contracts for ALL child tickets.
    For each created ticket:
    a. Fetch ticket details from Linear
    b. Extract DoD/acceptance criteria from description via dod_parser for ticket-specific checks.
    Exception — never emit test -f docs/plans/ checks: the no-planning-docs pre-commit
    hook in onex_change_control forbids planning docs from existing in that repo (they live
    in the canonical registry's docs/plans/). Any check_value containing test -f docs/plans/ or
    test -f docs/plans/ variants would be structurally unsatisfiable and must be omitted.
    Other ticket-specific acceptance criteria extracted by dod_parser are retained normally.
    c. Generate contract YAML (stub for non-seam, full for seam tickets)
    d. Validate each contract (YAML lint + schema check) before writing
    e. Write to $ONEX_CC_REPO_PATH/contracts/{ticket_id}.yaml
    f. Commit all contracts in a single batch via branch + PR:
    cd $ONEX_CC_REPO_PATH
    git checkout -b auto/contracts-{epic_id}
    git add contracts/OMN-*.yaml
    git commit -m "feat: auto-generate contracts for {epic_id} decomposition ({N} tickets)"
    git push origin auto/contracts-{epic_id}
    gh pr create --title "auto: contracts for {epic_id} ({N} tickets)" \
      --body "Auto-generated ticket contracts from decompose-epic" --auto
    This ensures tickets created by decompose-epic have the same contract coverage
    as tickets created by plan-to-tickets.
  7. Write result and exit

Ticket Creation Contract

tracker.create_issue(
    title="{ticket_title}",
    team="{epic_team}",
    parentId="{epic_linear_id}",
    description="""
## Summary
{what_this_ticket_implements}

## Requirements
{functional_requirements}

## Definition of Done
- [ ] Implementation complete
- [ ] Tests passing
- [ ] PR merged

## Repo Hint
{repo_name}: {rationale}
    """,
    labels=["{repo_label}"]
)

Repo Manifest

Loaded from plugins/onex/skills/epic-team/repo_manifest.yaml:

repos:
  - name: omniclaude
    path: ~/Code/omniclaude
    keywords: [hooks, skills, agents, claude, plugin]
  - name: omnibase_core
    path: ~/Code/omnibase_core
    keywords: [nodes, contracts, runtime, onex]

Skill Result Output

Output contract: ModelSkillResult from omnibase_core.models.skill

Note: This contract reference is behavioral guidance for the LLM executing this skill. Runtime validation not yet implemented.

Write to: $ONEX_STATE_DIR/skill-results/{context_id}/decompose_epic.json

Field Value
skill_name "decompose-epic"
status One of the canonical string values: "success", "dry_run", "error" (see mapping below)
extra_status Domain-specific status string (see mapping below)
run_id Correlation ID
extra {"epic_id": str, "created_tickets": list[{"id": str, "title": str, "repo_hint": str}], "count": int}

Note on context_id: Prior schema versions included context_id as a top-level field. This field is not part of ModelSkillResult — it belongs to the file path convention ($ONEX_STATE_DIR/skill-results/{context_id}/decompose_epic.json). Consumers should derive context from the file path, not from context_id in the result body.

Status mapping:

Current status Canonical status (string value) extra_status
created "success" (EnumSkillResultStatus.SUCCESS) "created"
dry_run "dry_run" (EnumSkillResultStatus.DRY_RUN) null
error "error" (EnumSkillResultStatus.ERROR) null

Behaviorally significant extra_status values:

  • "created" → ticket-pipeline (cross-repo split path) proceeds to invoke epic-team with parent epic ID; the extra["created_tickets"] list contains the sub-ticket IDs passed to epic-team
  • null (dry_run) → ticket-pipeline does not advance; decomposition plan is logged for human review only

Promotion rule for extra fields: If a field appears in 3+ producer skills, open a ticket to evaluate promotion to a first-class field. If any orchestrator consumer (epic-team, ticket-pipeline) branches on extra["x"], that field MUST be promoted. Note: ticket-pipeline already branches on extra["created_tickets"] — evaluate promotion.

Example result:

{
  "skill_name": "decompose_epic",
  "status": "success",
  "extra_status": "created",
  "run_id": "pipeline-1709856000-EPIC-ID",
  "extra": {
    "epic_id": "EPIC-ID",
    "created_tickets": [
      {"id": "TICKET-1", "title": "Implement X", "repo_hint": "omniclaude"},
      {"id": "TICKET-2", "title": "Add node Y", "repo_hint": "omnibase_core"}
    ],
    "count": 2
  }
}

Status values: success (extra_status: "created") | dry_run | error

See Also

  • epic-team skill (invokes decompose-epic when epic has 0 child tickets)
  • ticket-pipeline skill (planned: invokes decompose-epic on cross-repo auto-split)
  • plugins/onex/skills/epic-team/repo_manifest.yaml — repo keyword mapping