How reverse-skill Prioritizes Routes in `routing.json`: Keyword Matching, Scoring, and Tie-Breaking Explained

reverse-skill uses a three-step deterministic process: keyword regex matching builds a candidate pool, the highest match count wins, and the "priority" array resolves ties, with "fallbackId" as a last resort.

The zhaoxuya520/reverse-skill repository implements a skill routing system that directs user prompts to specialized reverse-engineering modules. At its core, skills/config/routing.json defines how reverse-skill prioritizes routes through explicit scoring rules and an ordered precedence list. This article breaks down the exact algorithm using the source code implementation.


The Three-Step Routing Algorithm

The master routing scripts—master-route.ps1 (Windows) and master-route.sh (Linux/macOS)—execute the same logic defined in routing.json. The process follows three distinct phases.

Step 1: Keyword Matching Builds the Candidate Pool

Each route (R1, R2, … R41) contains a keywords array with regex-driven matching rules. The router evaluates every route against the input hint using three match types:

  • "must" — Required regex pattern; must match for the keyword to count
  • "exclude" (optional) — If matched, disqualifies this keyword
  • "mustAll" (optional) — Array of patterns; all must match for the keyword to count

In skills/config/routing.json, each matching keyword contributes +1 to that route's score. Routes with zero matches are excluded from the candidate pool.

{
  "R1": {
    "keywords": [
      {
        "must": "android|apk|dalvik|smali|certificate.?pinning",
        "exclude": "ios|swift|frida-ios",
        "mustAll": ["bypass", "pinning"]
      }
    ],
    "skill": "apk-reverse/SKILL.md"
  }
}

Step 2: Highest Score Wins, Priority Array Breaks Ties

Once all routes are scored, the selection follows the meta rule documented at line 5-7 of routing.json:

"每条关键字规则命中后计入候选集;priority 数组顺序取 ‘命中分数最高’ 的为 PRIMARY;分数并列时 priority 靠前者胜出;未命中任何规则时回退 fallbackId."

Translation: After keyword evaluation, the route with the maximum match count becomes PRIMARY. When multiple routes share the highest score, the "priority" array determines the winner—the earlier the appearance, the higher the precedence.

The current priority ordering (lines 16-21) places R4 first and R0 last:

"priority": [
  "R4","R1","R2","R3","R30","R31","R33","R5","R9","R21",
  "R22","R6","R7","R8","R34","R28","R17","R16","R18","R24",
  "R37","R23","R35","R25","R36","R29","R38","R32","R26","R27",
  "R10","R11","R12","R13","R14","R15","R19","R40","R20","R39",
  "R41","R0"
]

This explicit ordering allows fine-grained control over route precedence independent of score distribution.

Step 3: Fallback Routing

If no keywords match across all routes, the router selects the route specified by "fallbackId" (line 4-6). By default, this is "R0"—a generic reverse-engineering skill ensuring the system always produces a response.

"meta": {
  "fallbackId": "R0",
  "description": "Default routing when no keywords match"
}

Practical Example: Routing a Certificate Pinning Query

Consider an input hint: "How do I bypass Android certificate pinning?"

The execution flow in master-route.sh proceeds as follows:


# Invoke the router with a hint

bash skills/scripts/master-route.sh --hint "How do I bypass Android certificate pinning?"

Internal logic (conceptual):

import json, re, sys

routing = json.load(open('skills/config/routing.json'))
hint = sys.argv[1].lower()

scores = {}
for rid, rdata in routing['routes'].items():
    match_cnt = 0
    for kw in rdata['keywords']:
        if re.search(kw['must'], hint):
            # Check exclusion patterns

            if 'exclude' in kw and re.search(kw['exclude'], hint):
                continue
            # Check mustAll conjunction

            if 'mustAll' in kw and not all(re.search(p, hint) for p in kw['mustAll']):
                continue
            match_cnt += 1
    if match_cnt:
        scores[rid] = match_cnt

# Selection phase

if not scores:
    selected = routing['meta']['fallbackId']  # "R0"

else:
    max_score = max(scores.values())
    candidates = [r for r, s in scores.items() if s == max_score]
    # Tie-breaker: walk priority array in order

    for rid in routing['priority']:
        if rid in candidates:
            selected = rid
            break

print(f"Selected: {selected}{routing['routes'][selected]['skill']}")

For this hint, R1 wins because:

  • "certificate.?pinning" matches (score 1)
  • No other route achieves a higher match count
  • R1 appears second in the priority array, securing victory if tied

Key Source Files and Their Roles

File Purpose
skills/config/routing.json Central configuration—routes, keywords, priority array, fallbackId
skills/scripts/master-route.sh / master-route.ps1 Cross-platform entry points implementing the three-step algorithm
skills/scripts/verify-routing-coherence.ps1 Validates that priority ordering matches MASTER-ROUTING.md documentation
skills/scripts/test-routing.sh / test-routing.ps1 Automated test suite exercising all route combinations

The verify-routing-coherence.ps1 script ensures the priority array remains synchronized with human-readable documentation—a critical check given that the array order directly affects runtime behavior.


Summary

  • Keyword regex matching filters routes into a scored candidate pool using must, exclude, and mustAll patterns
  • Highest score selection promotes the most specific match; multiple hits accumulate
  • "priority" array tie-breaking provides deterministic precedence when scores equal
  • "fallbackId" guarantees a default route (R0) when no keywords match
  • The algorithm is implemented identically in master-route.ps1 and master-route.sh, with validation via verify-routing-coherence.ps1

Frequently Asked Questions

What happens if two routes have the same keyword match count?

The router consults the "priority" array in skills/config/routing.json. The route appearing earlier in this ordered list wins. For example, if both R4 and R1 score 2 matches, R4 wins because it occupies index 0 versus R1 at index 1.

Can I change route priority without modifying keyword patterns?

Yes. The "priority" array is designed for this exact use case. Rearranging route IDs in this list changes tie-breaking behavior without touching individual keyword definitions. Run verify-routing-coherence.ps1 after edits to ensure documentation consistency.

What is R0 and why is it always last in priority?

R0 is the fallback route—a generic reverse-engineering skill triggered when no keywords match. It appears last in the "priority" array so it never wins a tie against specific matches, yet remains available via fallbackId for unmatched inputs.

How do I test routing behavior for a new skill?

Use skills/scripts/test-routing.sh (or .ps1 on Windows). This suite validates scoring and priority resolution across all routes. Add your hint to the test matrix to verify correct dispatch before deployment.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →