# How Codex Routes Skills When Multiple Keywords Match

> Discover how Codex routes skills with multiple keyword matches using scoring and tie-breakers. Learn how it handles ambiguity and clarifies user intent for optimal results.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: internals
- Published: 2026-06-11

---

**Codex resolves ambiguous skill requests by scoring keyword matches across candidate skills and applying deterministic tie-breakers, falling back to user clarification when confidence is low.**

When a user query triggers multiple installed skills in the OpenAI plugins repository, Codex employs a sophisticated routing algorithm to select the most appropriate handler. The system analyzes keyword overlaps between the user input and each skill’s manifest, calculates match scores, and applies deterministic tie-breaking rules to ensure consistent behavior. This process ensures that even when multiple skills share similar terminology—such as "search" or "report"—the correct skill is invoked reliably.

## How Codex Scores and Selects Skills

### Candidate Skill Collection

First, Codex scans all installed plugins and extracts skills whose `keywords` arrays intersect with words from the user query. For example, skills defined in [`plugins/fyxer/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/fyxer/.codex-plugin/plugin.json) or [`plugins/zoom/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/zoom/.codex-plugin/plugin.json) become candidates if any of their keywords appear in the request. This initial filtering creates a candidate pool of all potentially relevant skills.

### Keyword Match Scoring

For each candidate, Codex computes a match score using the internal `score_keyword_match` function. The scoring algorithm applies differentiated weights based on match quality:

- **Exact matches**: When a query word equals a manifest keyword, the skill receives a high weight (+10)
- **Partial matches**: When a query word contains a keyword as a substring, the skill receives a lower weight (+3)
- **Synonym expansion**: The internal synonym map can boost scores for semantically related terms

This weighted approach ensures that precise terminology matches outweigh vague substring overlaps.

### Deterministic Tie-Breaking

When multiple skills achieve identical scores, Codex applies a strict priority chain to guarantee reproducible selection:

1. **Explicit priority**: The optional `priority` field in the skill manifest breaks ties in favor of higher values
2. **Alphabetical ordering**: Plugin names provide a final fallback, ensuring the same skill wins across identical requests

### Confidence Thresholds and Disambiguation

If the highest-scoring skill fails to exceed the configured `CONFIDENCE_THRESHOLD`, Codex raises a `ClarificationNeeded` exception rather than executing the match. This safety mechanism triggers a clarifying question when generic terms (e.g., "get" or "list") match too many skills, preventing incorrect invocations on ambiguous queries.

## Code Implementation

The routing logic operates through a pipeline that processes the query against installed plugin manifests:

```python
def route_request(query: str, installed_plugins: List[Plugin]) -> Skill:
    # 1. Extract keywords from the query

    query_words = set(query.lower().split())

    # 2. Gather candidates

    candidates = [
        skill for plugin in installed_plugins
        for skill in plugin.skills
        if query_words & set(skill.manifest["keywords"])
    ]

    # 3. Score candidates

    scores = {}
    for skill in candidates:
        score = 0
        for kw in skill.manifest["keywords"]:
            if kw in query_words:
                score += 10          # exact match

            elif any(kw in w for w in query_words):
                score += 3           # partial match

        scores[skill] = score

    # 4. Pick best skill (with deterministic tie‑break)

    best_skill = max(
        scores,
        key=lambda s: (scores[s],
                       s.manifest.get("priority", 0),
                       s.name)                 # alphabetical fallback

    )

    # 5. Confidence check

    if scores[best_skill] < CONFIDENCE_THRESHOLD:
        raise ClarificationNeeded("Which skill did you mean?")
    return best_skill

```

Once selected, Codex forwards the request to the skill’s `entrypoint` as defined in its manifest.

## Key Configuration Files

Skill routing depends on metadata defined in plugin manifests and entry points. Critical files in the OpenAI plugins repository include:

- **[`plugins/fyxer/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/fyxer/.codex-plugin/plugin.json)**: Defines the `keywords` array used for candidate matching
- **[`plugins/zoom/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/zoom/.codex-plugin/plugin.json)**: Illustrates multiple keywords per skill and optional priority configuration
- **[`plugins/zoom/skills/video-sdk/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/video-sdk/SKILL.md)**: The entry point referenced by the manifest’s `entrypoint` field where routed requests ultimately execute

## Summary

- Codex collects candidate skills by intersecting user query words with manifest `keywords` arrays found in files like [`plugins/fyxer/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/fyxer/.codex-plugin/plugin.json)
- Match scoring weights exact matches (+10) higher than partial substring matches (+3), with additional boosts from synonym expansion
- Deterministic tie-breakers use the manifest `priority` field first, then alphabetical plugin names to ensure consistent selection
- Low-confidence matches trigger `ClarificationNeeded` exceptions rather than executing ambiguous commands
- Selected skills route to their `entrypoint` scripts (e.g., [`SKILL.md`](https://github.com/openai/plugins/blob/main/SKILL.md) files) for execution

## Frequently Asked Questions

### How does Codex handle queries that match keywords in multiple skills simultaneously?

Codex scores every matching skill based on keyword overlap quality using the `score_keyword_match` logic, then selects the highest scorer. If scores tie, it checks the `priority` field in each skill’s manifest, falling back to alphabetical plugin naming to ensure deterministic selection.

### What happens when no skill achieves a high confidence score?

When the top candidate’s score falls below `CONFIDENCE_THRESHOLD`, Codex raises a `ClarificationNeeded` exception and prompts the user to specify which skill they intended, preventing incorrect invocations on ambiguous queries.

### Can developers influence skill selection priority?

Yes. Developers can set an optional `priority` field in the skill manifest (e.g., in [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json)). Higher priority values break ties in favor of that skill when multiple candidates achieve identical keyword match scores.

### Where does a routed request ultimately execute?

After selection, Codex dispatches the request to the skill’s `entrypoint` as defined in its manifest. For example, the Zoom Video-SDK skill routes to [`plugins/zoom/skills/video-sdk/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/video-sdk/SKILL.md) according to the repository structure.