From ticket-auto-pipeline
Investigation planner for a Linear ticket. Fetches the issue, creates the local directory structure, runs a complexity sweep, searches prior art, and traces the full codebase call chain. Writes findings to notes.md. Use when the user says "appraise ticket <ID>", "/ticket-appraise <ID>", or "take on ticket <ID>". After this completes, run /ticket-appraise-exec to create artifacts and update Linear.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ticket-auto-pipeline:ticket-appraiseThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You have been given a ticket ID as the argument (e.g. `WIL-42`). Execute the investigation sequence below in order. This skill ends with notes.md fully populated. The executor skill (`/ticket-appraise-exec`) handles artifact creation and Linear updates.
You have been given a ticket ID as the argument (e.g. WIL-42). Execute the investigation sequence below in order. This skill ends with notes.md fully populated. The executor skill (/ticket-appraise-exec) handles artifact creation and Linear updates.
If the arguments contain --from-auto, skip this guard — ticket-auto already verified the working directory.
Run basename "$(pwd)". If the result is NOT tickets, abort immediately and tell the user to cd to the tickets workspace and re-run.
/clear.Read CLAUDE.md and extract: {REPOS_ROOT} (parent path of all service dirs), {ISSUE_PREFIX} (issue ID prefix, e.g. CRE), {BE_SERVICES} (BE service dir names). Also extract {WIKI_ROOT} — look for a WIKI_ROOT = ... line. If not found, set to empty. Stop if no codebase map — this skill requires one.
If $LOG_FILE is set (passed by the ticket-auto orchestrator): read ~/.claude/skills/pipeline-log-format.md. After each major step below, write progress entries to $LOG_FILE using the format defined there. Phase is APPRAISE.
If --from-step {step-name} is in the arguments, this is a crash-recovery resume. Skip all steps up to and including the named step. Do not re-run skipped steps — restore any variables they would have set from existing files (notes.md, context.md, pipeline log). Proceed directly to the first step after the named step.
Also: if --from-step is set, suppress Resume Mode in Step 1 — the workspace exists by definition, and re-evaluation is not needed.
--from-step value | Skip to | Restore from |
|---|---|---|
setup-workspace | Step 2 (complexity sweep) | ticket-setup output already in notes.md |
complexity-sweep | Step 2.6 (prior art) | ## Complexity in notes.md |
prior-art | Step 3 (codebase investigation) | ## Prior Art in notes.md |
codebase-investigation | Step 5 (report/handoff) | ## Initial Investigation in notes.md |
handoff | End — skill already complete | — |
If --from-step is not provided, proceed normally from Step 1.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|setup-workspace|start|Creating ticket workspace" >> "$LOG_FILE"
Run /ticket-setup {TICKET-ID} and wait for it to complete.
The ticket-setup output provides: directory path, title, user, status, priority, labels, epic, environment. Use these values throughout the remaining steps — do not re-fetch from Linear.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|setup-workspace|done|Workspace ready" >> "$LOG_FILE"
Before proceeding further, create a TaskCreate for every remaining step in this skill (Steps 2 through 5 below). Each task subject = the step heading (e.g. "Step 2: Expand notes.md for appraisal"). This ensures no step is skipped even when context scrolls.
After each step is fully done (including all sub-steps), mark it completed with TaskUpdate. At session end, write a trace file to the ticket directory:
cat > {ticket-dir}/appraise-session.md << 'TRACE'
# appraise session — {ISSUE-ID}
**Date:** {today}
**Complexity:** {simple|complex}
## Step trace
- [x] Step 2: Expand notes.md — done
- [x] Step 2.5: Complexity sweep — {score}, axes: {list}
- [x] Step 2.6: Prior-art search — {hits} hits
- [x] Step 2.7: Readiness critique — {BLOCKED|WARNINGS|CLEAR}
- [x] Step 3: Investigate codebase — {N} files traced
- [x] Step 4: Label ticket — {complexity} label applied
- [x] Step 5: Hand off — reported to user
TRACE
ticket-setup writes a minimal notes.md stub. Replace it with the full appraisal template:
# Working Notes — {ISSUE-ID}
## Status
**Appraised:** {today's date}
**Current status:** {Linear status}
## Initial Investigation
{After completing Step 3, summarise your code findings here — relevant files, components, services, suspected root cause or implementation area.}
## Open Questions
- {List anything unclear from the ticket description}
## Next Steps
- {First concrete action to move this ticket forward}
## Session Log
### {today's date}
- Ticket appraised and local workspace created.
Activate the analyzer persona before scoring:
/buddy:persona-analyzer
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|complexity-sweep|start|Scoring complexity axes" >> "$LOG_FILE"
Score the ticket on the three axes below using only what ticket-setup already returned (title, description, labels, comments, epic). No codebase reads yet.
| Axis | Fires when |
|---|---|
| Multi-service | Description mentions more than one service, or the affected area is ambiguous (e.g. "payment flow", "attorney assignment", "reporting") |
| Cross-layer | Fix clearly requires both frontend AND backend changes, OR touches high-risk areas: DB migrations, Feign clients, payments, PDF generation, async jobs |
| Prior rejection | Comments contain a previous appraisal that was marked rejected, or the ticket description says "tried X, didn't work" |
If zero axes fire → proceed to Step 2.6, then Step 3 (inline).
If one or more axes fire → proceed to Step 2.6, then Step 3-Agent (delegated) instead.
Record the decision in notes.md under a ## Complexity heading:
## Complexity
**Score:** {simple | complex}
**Axes fired:** {list fired axes, or "none"}
**Reason:** {one sentence}
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|complexity-sweep|done|{simple|complex}, axes: {list}" >> "$LOG_FILE"
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|prior-art|start|Searching claude-mem" >> "$LOG_FILE"
Run the /claude-mem:mem-search skill with 2–3 keywords derived from the ticket title and description (e.g. component name, feature area, error message fragment). Keep the query tight — one focused search, not multiple.
Evaluate each hit:
| Confidence | Criteria |
|---|---|
| High (≥80%) | Same component/service, same symptom or change type, outcome recorded |
| Medium (40–79%) | Related area or similar pattern, but different scope or older context |
| Low (<40%) | Superficially related keyword match only |
Discard hits below 40% — do not record noise.
For each kept hit, append to notes.md under a ## Prior Art heading:
## Prior Art
### {hit title or session ID} — {High | Medium} confidence ({score}%)
**Relevance:** {one sentence: why this hit applies}
**Key finding:** {the specific decision, fix, or pattern from that session}
**Incorporate:** {how this should inform the current investigation or implementation}
If no hits score ≥40%, write:
## Prior Art
No relevant prior art found.
Also search local tickets:
Derive 2–3 file or component keywords from the affected area identified so far (e.g. progress-update, AttorneyProfileController, HandoverRepository). Use the ticket directory path from Step 1 as {TICKET-DIR}. Then run:
grep -rl "{keyword1}\|{keyword2}" . --include="notes.md" | grep -v "{TICKET-DIR}" | head -20
For each match, read just the ## Status, ## Initial Investigation, and ## Complexity sections of that notes.md. Evaluate confidence using the same High/Medium/Low criteria as the claude-mem hits above. Discard hits below 40%.
Append local hits to the same ## Prior Art section, tagged [local-ticket]:
### {TICKET-ID} ({directory name}) — {High | Medium} confidence ({score}%) [local-ticket]
**Relevance:** {one sentence: why this hit applies}
**Key finding:** {what was fixed or changed, with file path if found}
**Incorporate:** {how this affects the current investigation or implementation}
If no local hits score ≥40%, do not add a new entry — the section already reflects the claude-mem result.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|prior-art|done|{N} hits" >> "$LOG_FILE"
Proceed to Step 2.7.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|critique|start|Validating ticket completeness" >> "$LOG_FILE"
Run:
/ticket-critique {TICKET-ID} --from-appraise
needs-info.[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|critique|done|{BLOCKED|WARNINGS|CLEAR}" >> "$LOG_FILE"
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|blast-radius|start|Running impact analysis" >> "$LOG_FILE"
Derive target symbols from the ticket title, description, and labels. Extract at minimum: the primary component/module name, any mentioned API endpoints, and any class or file names referenced in the ticket. Use these as targets for impact().
Call mcp__gitnexus__impact for each target symbol:
target: the symbol name (function, class, file, or component)direction: "upstream" (what depends on this)maxDepth: 3If the symbol is ambiguous (multiple candidates), pick the highest-relevance result and record all candidates.
Record results in notes.md under a ## Blast Radius section:
## Blast Radius
| Target | Risk | d=1 (WILL BREAK) | d=2 (LIKELY AFFECTED) | Affected Flows |
|--------|------|-------------------|------------------------|----------------|
| `{symbol}` | LOW/MEDIUM/HIGH/CRITICAL | {count} callers | {count} indirect | {flow names} |
**Analysis:** {one sentence summarizing what the blast radius means for this ticket}
Re-evaluate complexity: If any target reports HIGH or CRITICAL risk, OR any target has 3+ d=1 callers, OR 2+ execution flows are affected — and the current classification from Step 2.5 is simple — override to complex and update the ## Complexity section in notes.md with the reason:
**Score:** complex (overridden from simple — blast radius: {reason})
Non-blocking fallback: If the mcp__gitnexus__impact tool is unavailable or returns an error, log a warning and proceed:
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|blast-radius|warn|GitNexus unavailable — falling back to manual tracing" >> "$LOG_FILE"
Do NOT block the pipeline on GitNexus availability. The complexity classification from Step 2.5 stands if blast radius data is unavailable.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|blast-radius|done|Risk: {highest-risk}, d=1: {max-d1-callers}" >> "$LOG_FILE"
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|codebase-investigation|start|Tracing call chain" >> "$LOG_FILE"
Based on the ticket's description and labels, identify which service(s) are involved. Use the codebase map from CLAUDE.md to find the right repository under {REPOS_ROOT} (resolved in Step 0.5).
Use the service(s) identified above to decide which wiki files to load.
If {WIKI_ROOT} is set (from Step 0.5):
{WIKI_ROOT}/index.md. It contains a Lookup by Topic section with keyword-to-file mappings, and a Lookup by Service table. Match the ticket's labels, title, and description against the topic keywords in the index to identify which wiki files to load. The index is the authoritative routing table — do not use any hardcoded keyword list.{WIKI_FLOW} = the first flow file loaded (or the most relevant). Each file contains pre-traced call chains with real class names, endpoints, and entity fields.{WIKI_ROOT}/services.md (service responsibilities and Feign wiring) and the relevant sections of {WIKI_ROOT}/domain/data-model.md (entity fields and relationships).**Wiki bootstrap:** {list of files loaded}{WIKI_FLOW} empty — fall through to full Serena discovery in 3c.If {WIKI_ROOT} is empty: skip to 3b. No wiki is available for this project.
Read the CLAUDE.md for every affected repository before touching any code. This sets the architectural context for everything that follows.
Path A — Wiki-bootstrapped ({WIKI_FLOW} was loaded in 3a):
For each layer listed in the wiki flow file, use Serena to confirm the file and method still exist at the listed paths. Read only the pinpointed method — do not scan whole files. After confirming each layer, append the confirmed path to Initial Investigation with: (wiki-confirmed).
If a class has been renamed or moved, note the discrepancy but continue. The wiki may be slightly stale — your job is to verify and update, not rediscover.
Skip the full traversal instructions below — you already have your roadmap.
Path B — No wiki ({WIKI_FLOW} is empty):
Use Serena for all code navigation — mandatory. Symbol search or go_to_definition to locate, find_references to trace downstream effects, symbols_overview for file structure. Only Read after Serena has pinpointed the location — never grep for symbols.
Do not stop at the first plausible file. Trace the feature end-to-end across all layers involved:
Frontend tickets: template → component → service → HTTP call → backend API endpoint Backend tickets: API endpoint → delegate/controller → service → repository/feign client → database or downstream service Full-stack tickets: trace both directions and identify where they meet
For each layer, use Serena to locate the specific file and method. Read only the relevant section after Serena has pinpointed it — do not scan whole files.
Write findings to notes.md as you go — do not wait until the end of the step. After each layer is traced, append what you found to the Initial Investigation section immediately.
Explicitly answer: Is the data already available at the point where the fix needs to happen?
Document the answer in notes.md. This determines whether the ticket is frontend-only, backend-only, or full-stack — and must be explicit, not assumed.
After drafting the Initial Investigation, run a second pass over every finding:
For each bullet point, ask: "Have I read the actual code that confirms this?"
Remove or demote anything that is assumption rather than confirmed evidence.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|codebase-investigation|done|{N} files traced" >> "$LOG_FILE"
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|codebase-investigation|start|Delegating to Explore agent" >> "$LOG_FILE"
Run exactly the same wiki-loading logic as Step 3a above: read {WIKI_ROOT}/index.md, match ticket labels/title/description against the Lookup by Topic and Lookup by Service sections, load every file the index points to, set {WIKI_FLOW} to the most relevant flow file or leave empty, then record findings in notes.md. This runs for BOTH paths — simple (3a) and complex (here).
Spawn an Explore subagent to perform the investigation in isolation. Give it no opinion about where the fix should be — only facts and questions.
Prompt the agent with:
You are investigating a codebase for a ticket. Your job is to trace the code and report only confirmed evidence — no speculation.
Ticket: {ISSUE-ID} — {title}
Description: {description}
Labels: {labels}
Repos to search (under {REPOS_ROOT} — resolved from the project CLAUDE.md codebase map):
{list repos from CLAUDE.md codebase map that are plausibly involved}
{If WIKI_FLOW was loaded above, include this paragraph verbatim:}
A wiki file at `{WIKI_FLOW}` contains a pre-traced call chain for this feature area. Read it now. It lists real class names, method signatures, endpoints, and entity fields. Start by CONFIRMING those paths — do not rediscover from scratch. If a class was renamed or moved, note it but follow the wiki's structure.
IMPORTANT — use Serena for all code navigation: symbol search or go_to_definition to locate, find_references to trace usages, symbols_overview for file structure. Only Read after Serena locates the exact spot — never scan whole files or grep for symbols.
Answer each question below with specific file paths and line numbers. If you cannot confirm an answer, say "NOT FOUND" — do not guess.
1. Trace the full call chain end-to-end (frontend → backend or backend → DB). For each layer: file path, method/function name, line number.
2. At the point where the fix needs to happen: is the required data already available, or does it need to come from somewhere else? Where exactly?
3. Are there any existing tests covering this area? If so, list them.
4. If the service uses MapStruct (look for `@Mapper` annotated interfaces): read every mapper file that touches the affected entity and list all `@Mapping` annotations, including any `expression = "java(...)"` strings. These are invisible to symbol-based reference search and must be read directly.
5. List anything you searched for but could not locate.
When the agent returns:
**Source:** Explore agent (isolated run) note[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|codebase-investigation|done|{N} files traced" >> "$LOG_FILE"
Delegate to the flow executor:
/ticket-flow {TICKET-ID} appraise-start --data complexity={simple|complex}
This sets state → Todo, assignee → me, and adds claimed + the complexity label in a single atomic call.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|handoff|start|Writing final report" >> "$LOG_FILE"
Tell the user:
## {TICKET-ID} — investigation complete
**Complexity:** {simple | complex}
**Axes fired:** {list or "none"}
**Key findings:**
{2-4 bullets from Initial Investigation}
**Open questions:**
{bullets or "None"}
notes.md is fully populated. Review it, then run:
/ticket-appraise-exec {TICKET-ID}
This will create the change artifacts and update Linear.
[ -n "$LOG_FILE" ] && echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|APPRAISE|handoff|done|Reported to user" >> "$LOG_FILE"
If ticket-setup reported workspace already exists in Step 1:
Read context.md and notes.md from the existing directory.
Fetch the current state from Linear: mcp__linear-server__get_issue + mcp__linear-server__list_comments for this ticket.
Diff comments — compare Linear's current comments against the Comments section in context.md:
context.md (count ** bold author lines under ## Comments). If Linear has more, or if any comment body/timestamp differs materially — new activity exists.Present new comments — show the user what's new (author, timestamp, body excerpt).
Append to notes.md under a new ### {today's date} — comments update session log entry:
### {today's date} — comments update
- New comments from Linear (N since last appraisal):
- **{author}** ({timestamp}): {body excerpt}
Re-evaluate complexity — run Step 2.5 (complexity sweep) again, considering the new comments as additional input. If the score changes, update the ## Complexity section in notes.md and note the change in the session log.
Check artifact staleness:
find {ticket-dir} -name "simple-fix.md"
ls openspec/changes/ | grep -i "{ticket-id-lowercase}"
If either exists, the plan may be stale. Append to notes.md session log:
- ⚠️ Artifacts exist (simple-fix.md / openspec change). New comments may require plan updates.
Record re-appraisal marker in notes.md. Append a ## Re-appraisal section:
markdown ## Re-appraisal **Date:** {today} **Changes detected:** {yes | no} **Reason:** {e.g. "N new comments since last appraisal" or "no new activity — nothing to update"}
Set Changes detected: yes if: new comments found, complexity score changed, or artifacts are stale. Otherwise no.
## {TICKET-ID} — re-appraisal
**Changes detected:** {yes | no}
{If yes: list what changed}
**Complexity:** {unchanged | changed: {old} → {new}}
**Artifacts:** {up to date | ⚠️ may be stale — re-run `/ticket-appraise-exec {TICKET-ID}` to regenerate}
Do NOT overwrite context.md. The comments section there is a snapshot from initial intake. You may append to notes.md.
npx claudepluginhub willard-pro/claude-plugins --plugin ticket-auto-pipelineGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.