# Batch Linear Tickets

> Batch-analyze and resolve multiple Linear tickets — bug fixes and feature work. For each ticket: classifies as bug or feature (auto from Linear labels, or via the --type flag), dispatches the appropriate per-ticket analysis (linear-ticket-investigator + rca-investigator for bugs, just linear-ticket-investigator for features), gates on confidence, correlates findings across tickets, asks for user approval, then fans out aw-planner + aw-executor to ship PRs. Posts PR links back to each Linear ticket on completion. Triggers on "batch-linear-tickets", "batch analyze", "solve these tickets", "implement these tickets", "analyze tickets", "/batch-linear-tickets".

- Skill: `mthines/batch-linear-tickets` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add mthines/batch-linear-tickets`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mthines/batch-linear-tickets/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: mthines (https://skillmd.com/u/mthines)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mthines/batch-linear-tickets

---


# Batch Linear Ticket Resolver

Orchestrate parallel analysis and resolution of multiple Linear tickets — bug fixes **and**
feature work. This skill owns batch-level concerns: per-ticket type classification, parallel
fan-out of the right analysis tools, cross-ticket correlation, the user-facing approval gate,
and Linear writeback.

Per-ticket investigation lives in `linear-ticket-investigator`. Per-ticket bug root-cause
analysis is dispatched to the `rca-investigator` agent — it runs `holistic-analysis` (`fix`) +
`confidence` (`analysis`) in an **isolated context per ticket**, so N bug analyses run in
**parallel** and none of their verbose walkthroughs land in this orchestrator's window. Per-ticket
planning lives in `aw-planner`. Per-ticket implementation lives in `aw-executor`. This skill wires
them together for batch operation.

## Architecture

```text
Phase 1: Per-Ticket Analysis    → per ticket: classify type → investigator → (video-analyser if video flagged) → (rca-investigator if bug, carries confidence) | confidence(plan) if feature
Phase 2: Cross-Ticket Correlation → detect shared root causes, file conflicts, duplicates
Phase 3: Approval Gate          → user picks tickets to ship
Phase 4: Parallel Execution     → fan out aw-planner + aw-executor for approved tickets
Phase 5: Results & Linear Updates → status table + per-ticket PR comments
```

Phase 1's analysis runs **once per ticket**. Phase 4 dispatches `aw-planner` directly using the
analysis from Phase 1.

---

## Prerequisites

| Dependency | Purpose | Required? |
|-----------|---------|-----------|
| Linear MCP (`mcp__claude_ai_Linear__*` or `mcp__linear-server__*`) | Read tickets + labels, post PR comments | **Yes** |
| `linear-ticket-investigator` agent | Per-ticket evidence extraction | **Yes** |
| `rca-investigator` agent ([`agents/rca-investigator.md`](../../../agents/rca-investigator.md)) | Per-ticket bug root-cause analysis — isolated + parallel; carries `confidence(analysis)` in its Root-Cause Record | **Yes** (for bug tickets) |
| `holistic-analysis` skill | Run transitively inside `rca-investigator`; in-context fallback if the agent is unavailable | **Yes** (for bug tickets) |
| `confidence` skill | Feature-ticket gate scoring (bug score comes from `rca-investigator`) | **Yes** |
| `video-analyser` skill | Analyse a video / screen-recording attachment flagged on a ticket (Step 1b.5) | Optional — skips silently if absent or no video flagged |
| `aw-planner` + `aw-executor` agents (from [`autonomous-workflow`](../autonomous-workflow/SKILL.md)) | Phase 4 dispatch | **Yes** |
| `gh` CLI | PR creation by `aw-executor` | **Yes** |
| `gw` CLI | Worktree management (planner) | Recommended |
| `lorekit-memory` skill (LoreKit `memory.*` tools) | `batch-lessons` self-improvement loop (read Phase 1, write Phase 5) | Optional — loop is a silent no-op if `memory.*` is not connected |
| Project domain-navigator skill | Investigation accuracy in monorepos | Optional — see [Customization](#customization) |

---

## Rules

| Rule | When it loads |
|------|---------------|
| [ticket-type-classification](./rules/ticket-type-classification.md) | Phase 1 — classify each ticket as bug or feature |
| [cross-ticket-correlation](./rules/cross-ticket-correlation.md) | Phase 2 — detect shared root causes, duplicates, conflicts |
| [batch-approval-ux](./rules/batch-approval-ux.md) | Phase 3 — summary table format, status values, approval commands |
| [self-improvement-loop](./rules/self-improvement-loop.md) | Cross-cutting — `batch-lessons` fast tier (read Phase 1 / write Phase 5) + promotion to `diagnose` |
| [diagnostic-surface](./rules/diagnostic-surface.md) | Consumed by `/create-skill diagnose batch-linear-tickets` — phase model, guards, hard invariants |

> Investigation rules live in `linear-ticket-investigator`.
> Bug root-cause rules live in `holistic-analysis`, dispatched via the `rca-investigator` agent.
> Planning and execution rules live in `aw-planner` and `aw-executor`.
> This skill only owns batch-level fan-out, classification, and the user-facing approval gate.

---

## Arguments

Parse `$ARGUMENTS` for ticket identifiers and the optional `--type` flag.

- If `$ARGUMENTS` contains ticket IDs (e.g., `SUP-123 ENG-456`), use them directly.
- If `$ARGUMENTS` contains a Linear filter / project URL, extract the relevant ticket IDs first.
- If `$ARGUMENTS` is empty, ask the user to provide ticket IDs.

Accept ticket formats: `SUP-123`, `ENG-456`, `123` (bare number), Linear URLs.
Comma-, space-, or newline-separated.

### Type flag (optional)

| Flag | Effect |
|------|--------|
| `--type=auto` (default) | Classify each ticket via Linear labels (see [ticket-type-classification](./rules/ticket-type-classification.md)) |
| `--type=bug` | Force every ticket in the batch to bug pipeline (investigator + holistic-analysis) |
| `--type=feature` | Force every ticket in the batch to feature pipeline (investigator only) |

The flag applies to the whole batch.
For mixed batches with no labels, surface the unclassified tickets as `Needs Info` and ask the
user to either tag them in Linear or re-run with explicit `--type`.

---

## Phase 1: Per-Ticket Analysis (Fan-Out)

For each ticket, run the analysis pipeline appropriate to its type. **Launch homogeneous calls
in a single message** so they run in parallel.

### Step 1.read — Read prior batch lessons

Before classifying, load `batch-lessons` from LoreKit (narrow-to-broad — this
repo's scope, then `global`) so prior classification and correlation misfires
bias this batch:

```text
memory.list { scope: "repo::{owner}/{repo}", tags: ["loop::batch-lessons"], limit: 50 }   # no-op if memory.* not connected
memory.list { scope: "global", tags: ["loop::batch-lessons"], limit: 50 }
```

Match lessons by label set / ticket-type / affected-area; apply as **advisory
inputs** to classification (Step 1a) and correlation (Phase 2). Skip lessons
whose `expires` has passed. Lessons never override an explicit `--type` flag or
auto-approve a `Needs Info` ticket. Full contract:
[`rules/self-improvement-loop.md`](./rules/self-improvement-loop.md#read-lessons-phase-1).
(The planning / implementation phases inherit the `aw-lessons` loop automatically
via the `aw-planner` / `aw-executor` fan-out in Phase 4 — no action needed here.)

### Step 1a — Classify

If `--type=bug` or `--type=feature`: every ticket inherits that type. Skip to Step 1b.

Otherwise (`--type=auto`):

1. Fetch each ticket's labels via `mcp__claude_ai_Linear__get_issue` (or the equivalent
   `mcp__linear-server__*` tool). **Launch all fetches in one message** for parallelism.
2. Apply the classification rules in
   [ticket-type-classification](./rules/ticket-type-classification.md):
   - Has any label in `{bug, defect, incident, regression, hotfix, fix, kind/bug}` → **bug**
   - Otherwise → **feature**
   - No labels at all → **unknown** (status becomes `Needs Info`)

Record the type per ticket. Surface any `unknown` tickets to the user before continuing.

### Step 1b — Dispatch the investigator (every ticket)

Dispatch the `linear-ticket-investigator` agent for every ticket — bug or feature.
**Launch all investigator calls in one message** for parallelism.

The investigator returns an Evidence Record (problem description, affected code, certainty
markers, information gaps). It does not implement; it investigates. It also flags any video /
screen-recording attachment in the record's `Video evidence` field — but it cannot analyse the
video (no `Bash`). That is Step 1b.5's job.

### Step 1b.5 — Analyse flagged video attachments

For every ticket whose Evidence Record has `Video evidence: Present`, run the `video-analyser`
skill before analysis (Step 1c). A screen recording usually carries the clearest reproduction
steps and exact error state available — treating it as first-class evidence materially improves
the downstream root-cause analysis and confidence score.

For each such ticket, pass the Linear ticket URL so `video-analyser`'s own Linear resolution
obtains an authenticated (pre-signed) download URL via MCP:

```text
Skill("video-analyser", "<Linear ticket URL>")
```

Because `video-analyser` shells out to `ffmpeg`, these calls are **not** parallelisable via a
single message the way the agent dispatches are — run them sequentially (one ticket's video at a
time). For a ticket with multiple distinct videos, re-invoke with each direct video URL from the
`Video evidence` list.

Fold the structured video findings (errors, UI state, inferred reproduction steps) into that
ticket's Evidence Record before Step 1c, so `rca-investigator` sees them. If the `video-analyser`
skill is not installed, note the un-analysed video URL in the Evidence Record and continue — do
not block the batch on it.

### Step 1c — Dispatch rca-investigator (bug tickets only)

For tickets classified as **bug**, dispatch the `rca-investigator` agent with the Evidence Record
from Step 1b:

```text
Task(subagent_type="rca-investigator", prompt="<Evidence Record from Step 1b>")
```

**Launch all bug-ticket rca-investigator calls in one message** so the analyses run in parallel —
this is exactly the case where parallelism makes sense (N independent tickets, no shared state).
Each agent runs `holistic-analysis` (`fix`) + `confidence` (`analysis`) in its **own** context and
returns a compact **Root-Cause Record** (root cause, causal chain, evidence, ruled-out
alternatives, **confidence score**, fix direction). The verbose 8-phase walkthrough never reaches
this orchestrator.

If the `rca-investigator` agent is not available in the host project, fall back to running
`Skill("holistic-analysis", "fix")` + `Skill("confidence", "analysis")` in-context per bug ticket
(serial, non-isolated) — the same analysis, without the isolation/parallelism benefit.

Feature tickets skip this step — the investigator's Evidence Record (intent + acceptance
criteria + affected code) is the analysis output. Root-cause analysis is bug-shaped and would
mis-frame feature work.

### Step 1d — Gate per ticket

- **Bug tickets** — the `confidence(analysis)` score is already in the Root-Cause Record from
  Step 1c (it scored evidence strength, root-cause certainty, fix confidence). Do **not** re-run
  it; read it from the record.
- **Feature tickets** — run `Skill("confidence", "plan")` in-context. It scores completeness,
  feasibility, and ambiguity of the proposed approach captured in the investigator's Evidence
  Record.

Status mapping (same shape for both types, different source skill):

| Status | Bug source | Feature source | Approvable? |
|--------|-----------|---------------|-------------|
| **Ready** | `confidence(analysis)` ≥ 90% | `confidence(plan)` ≥ 90% | Yes |
| **Needs Review** | `confidence(analysis)` 70–89% | `confidence(plan)` 70–89% | Yes (with warning) |
| **Needs Info** | Information gap from investigator | Acceptance criteria missing or unclassified | **No** |
| **Stopped** | `confidence(analysis)` < 70% | `confidence(plan)` < 70% | **No** |

### Capture per ticket

- **Type** (`bug` | `feature`).
- The **Evidence Record** from the investigator.
- For bugs: the **root cause** and **proposed fix direction** from the `rca-investigator`
  Root-Cause Record.
- For features: the **proposed approach** + **acceptance criteria** from the Evidence Record.
- The **confidence score** and **status**.

If some sub-calls fail, proceed with what returned and offer to re-run the failed ones.

---

## Phase 2: Cross-Ticket Correlation

Analyze findings **in the main context** (no agent needed).
See [cross-ticket-correlation](./rules/cross-ticket-correlation.md) for the methodology.

Detect: shared root causes (bug clusters), shared affected files (any type), duplicates,
dependencies. Group correlated tickets so a single PR can resolve multiple.

Correlation works across types — a feature and a bug touching the same file is still a conflict
worth surfacing.

---

## Phase 3: Approval Gate

Present findings using the format in [batch-approval-ux](./rules/batch-approval-ux.md): summary
table (with Type column), per-ticket details, correlation notes, information gaps, and an
approval prompt.

Tickets with status `Needs Info` cannot be approved until gaps are resolved.
If the user provides missing info, re-run only the relevant Phase 1 steps for those tickets and
re-present.

Approval commands: `all`, `1, 3, 5`, `all including risky`, `none`.

---

## Phase 4: Parallel Execution (Fan-Out)

For each approved ticket (or correlated group), dispatch `aw-planner` directly using the analysis
from Phase 1.

Use the Agent tool with `subagent_type: "aw-planner"` and `isolation: "worktree"`. Pass the
appropriate pack:

| Ticket type | Pack template | Source |
|-------------|---------------|--------|
| **Bug** | [`bug-fix-pack.md`](../fix-bug/templates/bug-fix-pack.md) | `fix-bug` skill |
| **Feature** | [`feature-pack.md`](./templates/feature-pack.md) | This skill |

Fill in the pack from the Phase 1 analysis. **Launch ALL approved planners in a single message.**

For correlated tickets that resolve to a single PR, list all ticket IDs in the pack's
"Correlated Tickets" addendum so the executor's PR description references each one with
"Fixes {TICKET_ID}" (bug) or "Implements {TICKET_ID}" (feature).

Each planner returns one of:

- **Plan ready** (confidence ≥ 90%) — worktree + `plan.md` ready for execution.
- **Below gate** (confidence < 90% after retries) — concerns surfaced for user decision.

For below-gate plans, present the planner's concerns and offer:

- **refine** — re-spawn the planner for another iteration.
- **proceed** — accept and dispatch the executor anyway (NOT recommended).
- **stop** — abandon this ticket.

For each plan that cleared the gate (or was force-proceeded), dispatch `aw-executor` with
`subagent_type: "aw-executor"` and `isolation: "worktree"` pointing at the same worktree the
planner used. **Launch ALL executors in a single message:**

```text
Execute the plan at .agent/<branch>/plan.md in the current worktree.

Lesson-write serialization: do NOT write to shared lesson scopes (aw-lessons)
during this run — return your lesson candidates in your result payload; the
orchestrator writes them serially after the fan-out completes.
```

The executor runs autonomous-workflow Phases 3–7: implement, test, document, open the draft PR,
watch CI.

**Lesson-write serialization (batch fan-out contract).**
Parallel executors return lesson candidates in their result payload; the orchestrator writes all lessons serially after fan-out completes.
Executors MUST NOT write to shared lesson scopes directly during fan-out.
Concurrent `memory.write` calls to the same `loop::aw-lessons` scope + key can race and clobber each other's `seen_count`; the serial post-fan-out write (one `memory.write` with tag `loop::aw-lessons` per candidate, in Phase 5) is the only safe path.

---

## Phase 5: Results & Linear Updates

As executors complete, present a final status table:

```markdown
## Execution Results

| Ticket | Type | Status | PR | Branch | Notes |
|--------|------|--------|----|--------|-------|
| SUP-123 | bug | Done | #456 | fix/SUP-123 | Confidence 95%, all tests pass |
| AI-1165 | feature | Done | #457 | feat/AI-1165 | Confidence 92%, 3 components updated |
| SUP-789 | bug | Failed | — | fix/SUP-789 | Stuck-loop in Phase 4 |
```

For each successful PR, comment on the Linear ticket with the PR link via
`mcp__claude_ai_Linear__save_comment`:

```text
PR created: {PR_URL}
Branch: {BRANCH}
Type: {bug | feature}
Phase 1 confidence: {X%}
Plan confidence: {Y%}
```

Ask the user whether to update ticket state (e.g., move to "In Progress").

For failed executions, surface the error and suggested next steps (manual fix, re-plan, more
context).

### Step 5.write — Capture batch lessons

When the batch's own orchestration misfired, write a lesson so the next batch
does better — classify scope (universal → `global`; workspace-specific →
`repo::{owner}/{repo}`), dedup, then write:

```text
memory.search { q: "<lesson keywords>", scopes: ["repo::{owner}/{repo}", "global"], limit: 10 }     # no-op if memory.* not connected
memory.write { scope: "<global | repo::{owner}/{repo}>", key: "batch-lessons::<slug>", value: "<body>", tags: ["loop::batch-lessons", "source::phase-5"], source_agent: "batch-linear-tickets", trigger: "phase-5" }
```

Capture: a ticket whose type was wrong (label set → correct type), a
cross-ticket conflict Phase 2 correlation missed, or a chronically `Needs Info`
ticket shape. The write skips consent, not the privacy pre-flight. A lesson
recurring `seen_count >= 3` becomes promotion-eligible — see
[`rules/self-improvement-loop.md`](./rules/self-improvement-loop.md#write-lessons-phase-5).

---

## Self-Improvement

`/batch-linear-tickets` improves across batches through a **two-tier loop**
(full contract: [`rules/self-improvement-loop.md`](./rules/self-improvement-loop.md)).

- **Inherited for free:** the planning and implementation phases use the
  `aw-lessons` loop because Phase 4 dispatches `aw-planner` / `aw-executor`.
  **Serialization contract:** parallel executors return lesson candidates in
  their result payload; the orchestrator writes all lessons serially after
  fan-out completes. Executors MUST NOT write to shared lesson scopes directly
  during fan-out.
- **Fast tier (this skill):** `batch-lessons` (LoreKit `memory.*`, tag
  `loop::batch-lessons`) — read at Phase 1, written at Phase 5 — covers
  batch-level orchestration only (type classification, cross-ticket
  correlation, chronic `Needs Info`), classified to the `global` scope
  (universal patterns) or the `repo::{owner}/{repo}` scope (workspace-specific
  label conventions). Advisory; a silent no-op if LoreKit's `memory.*` tools
  are not connected.
- **Slow tier:** a lesson recurring `seen_count >= 3` (or tagged `structural`)
  is promoted via `/create-skill diagnose batch-linear-tickets`, which reads the
  [diagnostic surface](./rules/diagnostic-surface.md) and `batch-lessons`
  history and emits a confidence-gated diff (commonly into
  `ticket-type-classification.md` / `cross-ticket-correlation.md`) behind the
  `confidence(analysis) ≥ 90 %` + user-approval gate.

---

## Customization

### Domain Context

`linear-ticket-investigator` uses the project's domain context to ground its evidence
extraction. For monorepos this dramatically improves the accuracy of the Affected-Code table.

The agent looks for context in this order:

1. Top-level `CLAUDE.md` / `AGENTS.md`.
2. Component-specific `CLAUDE.md` / `AGENTS.md` in directories the ticket points at.
3. A project-shipped **domain navigator skill** (invoked via `Skill()`).
4. Top-level `README.md`.

To add a domain navigator for your project, create a skill named e.g.
`<project>-domain-navigator` that maps ticket terminology to component directories. The
investigator picks it up automatically as long as it is in the host project's installed skills.

See the [`linear-ticket-investigator`](../../../agents/linear-ticket-investigator.md) agent file
for the exact lookup procedure.

### Type Classification Overrides

If your workspace uses non-standard labels (e.g., `type:bug` instead of `bug`), edit
[ticket-type-classification](./rules/ticket-type-classification.md)'s default label list or
always pass `--type=bug` / `--type=feature` explicitly.

---

## Key Principles

1. **Type-aware orchestration.** Bugs run through investigator + holistic-analysis. Features run
   through investigator only. Both gate on `confidence` (different modes). Phase 4 and Phase 5
   are type-agnostic.
2. **Single user gate (Phase 3 approval).** No checkpoint/resume machinery. Below-gate plan
   surfacing in Phase 4 is per-planner, not a separate batch gate.
3. **Analyse once, execute once.** Phase 1 is the only place analysis runs per ticket. Phase 4
   dispatches `aw-planner` directly using that analysis — no re-investigation.
4. **Parallelize every fan-out — but serialize lesson writes.** Label fetches, investigators,
   holistic-analyses, planners, and executors all launch in one message each (per homogeneous
   group). Parallel executors return lesson candidates in their result payload; the orchestrator
   writes all lessons serially after fan-out completes. Executors MUST NOT write to shared lesson
   scopes directly during fan-out.
5. **Correlate before executing.** Detect shared root causes, shared files, and conflicts so one
   plan can resolve multiple tickets — across types.
6. **Handle partial failures at every phase.** If some agents fail, present what you have and
   offer to retry.
7. **User stays in control.** Every batch requires explicit approval at Phase 3. Information
   gaps and unclassified tickets must be resolved before approval.
8. **Learn across batches, but only advisory.** `batch-lessons` (read Phase 1,
   write Phase 5) biases type classification and correlation from prior misfires;
   it never auto-approves a ticket or overrides `--type`. Planning / implementation
   learning is inherited from `aw-lessons` via the Phase 4 fan-out. Recurring
   lessons (`seen_count >= 3`) promote into the skill's rules only through the
   confidence-gated `diagnose` apply.

