From cappy-toolkit
Phase 2 triage orchestration for CAPPY TAC investigations — searches the pattern database, Cortex docs, similar closed TAC cases, and Confluence KB for symptom matches, scores confidence, and checks the Phase 2 gate. Invoke during an active investigation when pattern matching and reference lookup are needed.
npx claudepluginhub thelightarchitect/cappy-toolkit --plugin cappy-toolkitThis skill uses the workspace's default tool permissions.
<!-- Copyright (C) 2025-2026 Kevin Francis Tan (github.com/theLightArchitect) | SPDX-License-Identifier: AGPL-3.0-or-later -->
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Version: 3.0.0
Phase: 2 — Triage
MCP Tools: pattern-match, case-get (primary when MCP server available)
Gate: confidence ≥ 70% (see skills/gate/SKILL.md)
Reasoning Libraries: skills/curator/SKILL.md, skills/gate/SKILL.md
At the very start of execution, output this exact block:
[ Phase 2 — Triage ]
Tools: pattern DB search (jq), case context (websearch/SF CLI)
Then before each tool call, output a one-liner:
→ {tool-name} {key parameter}
Execute Phase 2 triage. Search the local pattern database for symptom matches, retrieve SF case context, correlate results, register verified claims, and check the Phase 2 gate.
If this skill is invoked via SP-LOOP-2 (loop re-triage), the spawn prompt will contain a <loop_context> block. Before executing any step, read it:
loop_iteration ← current iteration number
previous_pattern_ids ← JSON array of pattern IDs already found (exclude these)
refined_symptom ← use this instead of the original {symptom} for Step 2
loop_reason ← why the loop was triggered (guides keyword strategy)
If no <loop_context> block is present, this is a first-pass triage — proceed normally.
Loop keyword strategy (when refined_symptom is provided):
refined_symptom as the primary search termevidence_ceiling_hit: true in inv_context.json and mark gate_status: "CEILING" in return JSONPrimary (MCP available):
call_tool({ operation: "execute", tool: "case-get",
params: { case_number: "{sf_number}" }})
Fallback (native): Use case context already gathered in Phase 0-1, passed in the spawn prompt <case_context> block. If missing, ask Main Claude via the HITL checkpoint before proceeding.
Extract: customer name, product, version, build, symptom description, severity.
Write to inv_context.json case and environment sections.
Primary (MCP available):
call_tool({ operation: "execute", tool: "pattern-match",
params: { symptom: "{symptom}", product: "{product}", version: "{version}" }})
Fallback (native) — weighted keyword search via the pattern search script:
# Primary native: weighted scoring across symptoms, match_patterns, error_pattern
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/pattern_search.py" \
"{refined_symptom_or_symptom}" \
--product "{product}" \
--top 10 \
--db "${CLAUDE_PLUGIN_ROOT}/databases/cappy-cache_latest.json" \
--json
The script scores patterns by:
match_patterns[] error codes (20pts/token)error_pattern field (15pts/token)Loop iterations: Pass --product to narrow results. The script auto-excludes zero-score patterns so previous IDs don't need explicit exclusion — just use the refined symptom.
Evidence ceiling check (loop iterations only): If the script returns zero results, retry with 2 alternative keyword sets derived from error messages or component names found in Phase 3 evidence. If all 3 attempts return zero new patterns:
jq '.investigation.evidence_ceiling = true' inv_context.json > tmp.json && mv tmp.json inv_context.json
Fallback-of-fallback (if Python unavailable): raw jq keyword search:
DB="${CLAUDE_PLUGIN_ROOT}/databases/cappy-cache_latest.json"
SYMPTOM="{refined_symptom_or_symptom}"
PRODUCT="{product}"
jq --arg s "$SYMPTOM" --arg p "$PRODUCT" '
.patterns[] | select(
($p == "" or $p == "ALL" or .product == $p or .product == "ALL") and
((.symptoms // [] | any(ascii_downcase | test($s | ascii_downcase))) or
(.match_patterns // [] | any(ascii_downcase | test($s | ascii_downcase))))
) | {id, product, confidence, symptoms: .symptoms[:2]}
' "$DB"
List every pattern returned. For each record:
id, confidence, product, symptoms[], match_patterns[]Do not interpret — list exactly what the query returned.
Group patterns into:
Also search JIRA for related engineering tickets:
mcp__mcp-gateway__mcp_jira__jira_search({
jql: "project = XSUP AND text ~ \"{symptom}\" ORDER BY updated DESC",
fields: "summary,status,resolution",
limit: 5
})
Always run this in parallel with pattern matching. Cortex docs often contain the authoritative answer for documentation gaps, deprecated features, and version-specific behavior changes — categories that may have zero patterns in the DB.
~/.cappy/tools/web-fallback/websearch.sh "site:docs-cortex.paloaltonetworks.com {symptom} {product}" 5
Record any doc results that:
These doc findings feed directly into the confidence score (TERTIARY evidence) and issue classification. A doc match confirming a deprecation or behavior change is sufficient for product_bug or known_issue classification even at low pattern confidence.
Also run in parallel — Similar TAC cases (KCS precedent):
SF CLI (closed TAC cases — primary):
SANDBOX_OK=$(docker ps --filter name=cappy-client --format "{{.Status}}" 2>/dev/null | grep -c "Up")
if [ "$SANDBOX_OK" -gt 0 ]; then
docker exec cappy-client sf data query \
--query "SELECT CaseNumber, Subject, Product__c, Status, Cause__c, Resolution_Steps__c FROM Case WHERE (Subject LIKE '%{symptom}%' OR Description LIKE '%{symptom}%') AND Status = 'Closed' LIMIT 5" \
--target-org panw --json 2>/dev/null
fi
If auth is expired: ~/.cappy/tools/sandbox-auth.sh or sf org login web -a panw --instance-url https://paloaltonetworks.my.salesforce.com
Fallback (sandbox unavailable or auth expired):
mcp__mcp-gateway__mcp_jira__jira_search({
jql: "project IN (XSUP, XSOAR) AND text ~ \"{symptom}\" AND status = Closed ORDER BY updated DESC",
fields: "summary,status,resolution",
limit: 5
})
Also run — TAC playbooks and KCS articles (Confluence):
mcp__mcp-gateway__confluence__confluence_search({
query: "{symptom} {product}",
limit: 10
})
Fallback (native):
mcp__mcp-gateway__confluence__confluence_search({
query: "{symptom} {product}",
limit: 10
})
A resolved similar case or KCS article that documents the same root cause raises confidence directly to STRONG — cite it as SECONDARY evidence.
skills/curator/SKILL.md)For each STRONG or PARTIAL pattern:
<claim id="C-{N}">
STATEMENT: "Pattern {id} matches symptom because {reason}"
<verify>
Q: Do this pattern's symptoms overlap with the reported symptom?
A: {specific symptom overlap, yes/no}
Q: Is this pattern scoped to the correct product?
A: {product check}
</verify>
STATUS: VERIFIED | REJECTED
</claim>
Register only VERIFIED claims. REJECTED claims are discarded.
If pattern-match (MCP) returns an overall_confidence field, use it directly.
Otherwise derive: (STRONG_count × 1.0 + PARTIAL_count × 0.5) / max(total_patterns_searched, 1) × 100
Cap at 95% unless a DEFINITIVE-confidence pattern matches exactly.
skills/gate/SKILL.md)IF confidence ≥ 70%: gate PASSES → return result to Main Claude.
IF confidence < 70%:
{
"phase": 2,
"gate_status": "PASS | FAIL | CEILING",
"confidence_score": 0,
"threshold": 70,
"patterns_found": [
{ "id": "P-XXX", "confidence": "DEFINITIVE | STRONG | MODERATE", "match_strength": "STRONG | PARTIAL | WEAK" }
],
"patterns_found_ids": ["P-XXX"],
"sf_context": { "customer": "...", "product": "...", "version": "...", "severity": "..." },
"claims_registered": 0,
"claims_rejected": 0,
"evidence_ceiling_hit": false,
"loop_iteration": 0,
"recommendation": "Proceed to Phase 3 | Gate blocked: {reason} | Ceiling: no new patterns found",
"recovery_options": []
}
patterns_found_ids accumulates across loop iterations — handoff reads inv_context.json → investigation.all_pattern_ids_found[] (a running list) and passes it to SP-LOOP-2 as {previous_pattern_ids_json} to prevent re-matching.
Do NOT proceed to Phase 3. Return this JSON to Main Claude.