How do you handle overlapping Codex skills in larger skill catalogs?

I have been experimenting with larger Codex skill catalogs and noticed that some skills can overlap semantically.

For example:

  • app polish vs frontend design
  • webapp testing vs browser/playwright workflows
  • game playtest vs implementation-specific game skills
  • broad GitHub workflows vs CI-specific workflows

In larger setups, this can sometimes create duplicate instruction loading, unclear task ownership, or unnecessary context usage.

I am curious how others structure their skills to avoid this.

Do you prefer:

  • fewer broad skills
  • many narrow specialist skills
  • manual selection per task
  • project-level routing rules
  • some kind of meta-routing pattern?

I have been experimenting with an instruction-only routing approach locally, but I am mainly interested in how other Codex users are solving this problem

Your question seems to be basically -

You found a bunch of skills that other people made in their codex journey and combined them.

People have different preferences, and not all those preferences align.

If you’re combining multiple skills, run them all through ChatGPT and have it investigate for conflicts…

Determine the conflicts, make the preference decisions that Chatgpt will ask you or direct you to…

and then have it print one skills doc, with all the conflicts resolved in that doc.

If I’ve misunderstood your issue, please clarify.

:clinking_beer_mugs:

That is close, but I think the part I am trying to separate is the difference between merging skills and routing skills.

If I merge everything into one resolved skills document, I get one clean instruction set, but it becomes static pretty quickly. It also loses some of the modularity that makes skills useful in the first place.

What I am experimenting with is more like a small decision layer that runs before the actual task starts:

  1. Look at the current task.

  2. Look at the currently available skills.

  3. Group skills that are effectively competing for the same job.

  4. Pick the smallest useful set for this specific request.

  5. Only then load/read the selected skill instructions.

So for example, if the task is “fix a failing GitHub Actions check”, I probably do not want a broad GitHub workflow, a codebase recon workflow, a generic testing workflow, and a CI-specific workflow all pulling context in different directions. I would rather select the CI specialist and let that own the job.

But for a larger browser game task, the best answer might be one stack-specific implementation skill plus one playtest/debug loop skill.

So the problem is not only “how do I resolve conflicts once?” but more:

How should an agent choose the right subset of specialist instructions dynamically, depending on the task?

That is the pattern I am curious about. Maybe the better long-term answer is built-in skill priority/scoping metadata, but for now I have been testing it as an instruction-only meta-routing approach.

Well, you seem to be taking the right posture.
My repos are very small compared to some of the big guys around here, but I know you can take what you just said to me, pop it into chatgpt like i suggested before…

And have it invent the priority docs you need according to your specific needs.

I think I understand better, and my advice is still to let the cheaper reasoning cost help you determine the best priority…

But then you’d likely want your agents.md to point to that priority list doc as well…

You’re basically just aiming to make a large tree of instructions… just make the tree well using the cheaper reasoning tokens…

That way, you don’t have to come drag all the proprietary stuff here to the forum for dissection?

That makes sense, and I agree that a generated priority document or routing guide can solve a lot of this.

Where I am still trying to think through the edge case is that the “best priority” is not always global. It can change depending on the task.,

For example, a broad GitHub skill might be the right top-level choice for general repository triage, but a CI-specific skill should probably win for failing Actions checks. A frontend polish skill might be the right owner for UI refinement, but a webapp testing skill should become the verification layer after implementation.

Another thing I am wondering about is what happens when the skill catalog changes over time.

If new skills are installed, old skills are removed, or plugin-provided skills change, a static priority document can become stale. The routing layer would need to either:

  • re-check the currently exposed skill catalog,

  • periodically regenerate its priority rules,

  • or keep the static rules small and combine them with runtime task-specific selection.

So instead of one permanent priority tree, I am thinking of it more like:

  • global rules for obvious conflicts

  • task-specific routing for the current request

  • awareness of the currently available skills

  • only loading the selected specialist docs

  • keeping AGENTS.md small enough that it points to the router/priorities without becoming the whole brain itself

I like your point about using cheaper reasoning tokens to generate and maintain those priority docs though. That might be the practical middle ground: use a model to periodically audit the skill catalog, update the routing rules, and then let the runtime instruction layer apply them per task.

The part I am most curious about is whether people prefer this as:

  1. static priority docs,

  2. AGENTS.md rules,

  3. explicit manual skill calls

  4. periodic skill-catalog audits

  5. or a small meta-skill/router that chooses dynamically from the currently available skills.

Yes, that distinction makes sense. I was treating it as an instruction-reconciliation problem, while you are describing task-time dispatch and ownership.

I think the strongest version of that pattern would avoid having the router read every full skill document. Each skill could expose a small manifest containing something like:

  • task scope and explicit triggers

  • exclusions or non-goals

  • priority and specificity

  • whether it can be the primary owner or only a supporting skill

  • compatible companion skills

  • expected context cost

The router reads only those manifests, chooses one primary owner, and adds supporting skills only when they provide a clearly separate function.

So for a failing GitHub Actions check:

  • CI skill owns the task.

  • Broad GitHub skill is excluded unless repository operations outside CI are required.

  • Testing skill is added only if reproducing the failure locally becomes necessary.

  • Codebase reconnaissance is added only if the failure cannot be localized cheaply.

That makes selection specificity-first and default-deny rather than “load everything plausibly related.”

Project-level rules could then override global routing—for example, declaring that a particular framework skill always owns implementation work in that repository.

I suspect the important rule is that overlapping skills should not merely have priorities; they need declared ownership boundaries. Otherwise the router still has to infer too much from prose.

Your instruction-only router sounds like a reasonable way to prototype the system before native priority, scope, exclusion, and compatibility metadata exist.

Keyword being prototype…

There might not be people with preferences…

I know not what the other guys have created, but this is the first time I think I’ve seen your question asked here.

Yes I think that is very close to what I was trying to get at.

The more I think about it, the more I feel that priorities alone are not enough. If two skills both appear relevant, the router still has to infer too much from prose. Ownership boundaries seem like the missing piece. A skill should be able to say not only what it is good at, but also what it explicitly does not own and when another skill should take over.

I also really like the idea of small manifests. My original thought process started because I was experimenting with a small instruction-only “Skill Orchestrator” locally. The goal was not to replace skills, but to reduce noise when larger catalogs start growing. Once enough skills exist, I found that some of them naturally begin competing for the same task, even though each one is useful on its own.

What I found interesting is that the problem changes over time. New skills get installed, old ones disappear, plugins add their own workflows, and suddenly a static priority list starts drifting away from reality. That is why I became interested in task-time routing rather than just instruction reconciliation. The question I kept coming back to was: “Given the skills that actually exist right now, which one should own this task?”

Your manifest idea feels like a much stronger version of that pattern. Instead of loading large instruction sets and trying to infer intent, a router could inspect lightweight metadata, identify a primary owner, add supporting skills only when they provide a clearly separate function, and then load the full instructions only for the selected set.

At that point the router becomes much smaller, more deterministic, and easier to maintain. Project-level rules could still override global behavior when needed, but the system would no longer depend entirely on long descriptions and conventions.

So I think we are converging on a similar idea from different directions. I started by treating it as a routing problem, while you approached it as an instruction-reconciliation problem. The manifest approach seems like a nice bridge between the two.

Yes, I think we have reached the same model now.

The dynamic-catalog point is especially important. A router should not assume that the skill environment is stable. It should inventory what actually exists at task time, reason over lightweight manifests, and treat project rules as overrides rather than hard-coding one permanent hierarchy.

A minimal manifest might only need:

  • owns

  • does_not_own

  • hands_off_to

  • supports

  • conflicts_with

  • activation_conditions

  • context_cost

Then the router could follow a few strict rules:

  1. Select one primary owner whenever possible.

  2. Add another skill only when it contributes a separate capability.

  3. Prefer explicit ownership and handoff declarations over semantic similarity.

  4. Exclude broad skills when a narrower skill fully owns the task.

  5. Record why each skill was selected or rejected.

That last part may matter more than it initially appears. A small routing trace would make failures diagnosable: “CI skill selected because the task concerns a failing Actions check; broad GitHub skill rejected because repository administration was not required.”

The difficult remaining case is probably incomplete or inaccurate manifests. The router still needs a conservative fallback when no skill clearly claims ownership, or when two skills claim it equally. But even then, it would be resolving a small metadata conflict rather than interpreting several large instruction documents.

That seems substantially more maintainable than either merging everything or relying on a static priority list.

It sounds like you’re going to have to do a lot of decision-making, but that’s why I suggest using ChatGPT in the loop. It’s way better at marking what decisions need to be met still.

Yes, that is a really good formulation. I think the routing trace part is especially important, because it turns the router from a black box into something inspectable.

If the system can say “I selected this skill because it owns the task, rejected this broader skill because a narrower one fully covers it, and added this support skill only for verification,” then debugging bad routing decisions becomes much easier. Without that trace, it is very hard to know whether the router made a good decision or just guessed based on similar wording.

The incomplete-manifest case is probably the hardest part, as you said. I would rather have the router be conservative there: if no skill clearly owns the task, either use no skill, ask for clarification, or fall back to a very small general workflow instead of pulling in everything that sounds related.

That is also why I think the dynamic catalog point matters so much. The router should not assume a fixed skill universe. It should be able to inspect what exists right now, reason over lightweight metadata, and then apply project-level overrides when needed.

My current “Skill Orchestrator” experiment is basically a rough userland prototype of this idea without native manifests. It tries to infer ownership from descriptions, naming, and known overlap patterns, but I agree that the cleaner long-term model would be explicit metadata like owns, does_not_own, hands_off_to, supports, and conflicts_with.

So maybe the useful prototype path is:

First, use an instruction-only router to test whether task-time selection actually improves larger skill catalogs.

Then, if the pattern proves useful, move the fragile prose-based parts into explicit skill manifests and routing traces.

That feels much more maintainable than one giant merged instruction document, while still avoiding the “load every plausible skill” problem :laughing:

Let us know how it works!

You may also want to take a look at the GitHub Agent Skills repository:

It has an active issue tracker as well:

Several of the issues there touch on topics related to skill discovery, organization, overlap, and management. One issue in particular that I have been following is:


The OP has already done this for just OpenAI skills repository

but noting for others finding this topic.

If you prefer to keep the discussion focused specifically on OpenAI Skills, you may also want to refer to the official GitHub repository:

The repository’s issue tracker is available here:

It is a good place to review existing requests, report problems, and follow development related to OpenAI Skills.

Thanks for pointing this out. That broader Agent Skills discussion looks very relevant.

I opened the issue in the OpenAI skills repository because my current experiment is specifically built around Codex skills and the way larger Codex skill catalogs can start to overlap. But the general problem seems very similar: discovery alone is not enough if the agent still has to decide which skill should actually own the task at runtime.

The RFC you linked sounds close to the more general version of the same idea: bridging the gap between “these skills exist” and “this is the right skill or skill combination for this specific request.”

My current Skill Orchestrator is only an instruction-only prototype, so it has to infer ownership from descriptions, naming, and known overlap patterns. The cleaner long-term version would probably be something more explicit, such as lightweight manifests, activation conditions, ownership boundaries, exclusions, compatibility metadata, and a routing trace explaining why a skill was selected or rejected.

I will take a closer look at that RFC. It seems like the same pattern could apply beyond OpenAI/Codex-specific skills as well.

I’ve been thinking about this further while working through one of my own larger local catalogues.

The thing I’m increasingly landing on is that overlapping skills are not only a catalogue-organisation problem. Once the catalogue gets large enough, it becomes a loop-routing and authority problem.

In other words, I don’t think the core question is always:

Which skill should load?

It is often more like:

  • What loop is Codex being asked to run?
  • Which skill owns the current phase of that loop?
  • Which skills are only supporting context?
  • Which skills should explicitly stay out?

That distinction has helped me a lot.

For example, a broad GitHub workflow skill, a CI failure skill, a testing/coverage skill, and a release-evidence skill may all be semantically related. But they should not all act as equal owners.

A failing GitHub Actions task might route like this:

  • Primary owner:
    • ci-actions-owner
  • Supporting:
    • test-and-coverage, only if local reproduction or coverage interpretation is required
  • Context only:
    • github-ops, for repo/PR conventions
  • Rejected:
    • release-evidence, because we are not at closeout yet
    • codebase-recon, unless the failure cannot be localised

So I’m starting to think larger catalogues need metadata that describes role and phase, not just priority.

Useful fields might be things like:

  • owns_loop_phases
  • primary_for
  • supports
  • hands_off_to
  • does_not_own
  • activation_conditions
  • local_overlay_required
  • conflicts_with
  • context_cost
  • evidence_expected
  • stop_conditions

The local_overlay_required I’m finding is shaping up as specially important. A reusable testing skill can define general behaviour, but it should not invent the project’s test commands, coverage thresholds, source/output boundaries or release rules. Those should come from the repo-local overlay, usually something like AGENTS.md, local runbooks, or project instructions.

The other thing I now think is essential is a routing trace.

Something as simple as:

Selected:

  • ci-actions-owner: primary owner for failing CI checks

Added:

  • test-and-coverage: support role because the CI failure requires local pytest reproduction

Used as local overlay:

  • repo AGENTS.md: provides commands and quality gates

Rejected:

  • broad-github-ops: covered by narrower CI owner
  • release-evidence: closeout loop has not started

That makes the decision reviewable. If the wrong skill loaded, you can fix the manifest or overlay rather than guessing why the agent behaved strangely.

The pattern I’m moving towards is:

  1. A thin constitutional entry point that defines authority, precedence and stop conditions.

  2. Skill manifests that say what each skill owns, supports and must not touch.

  3. Repo-local overlays that bind generic skills to actual commands, thresholds and paths.

  4. A task-time router that chooses one primary owner for the current loop phase.

  5. A routing trace so the selection can be audited later.

That seems safer than merging overlapping skills into giant documents, but also cleaner than letting every semantically related skill load at once.

The main mental shift for me is that skills are not just snippets of reusable instruction. In a large catalogue, they become part of a governed execution loop. The routing layer has to know not only what a skill is about, but what authority it has, when it should defer, and what evidence it is expected to produce.

This is a really useful framing. The “loop-routing and authority” wording captures the problem better than my original “overlapping skills” phrasing.

I agree that once a catalogue grows, the issue is not just which skill is semantically related to the task. It becomes a question of which loop Codex is currently running, who owns that phase, which skills are allowed to support it, and which skills should explicitly stay out.

The part about local overlays is especially important. A generic testing or CI skill should know how to reason about tests, failures, reproduction and evidence, but it should not invent the project’s actual commands, thresholds, release rules or directory boundaries. Those should come from the repo-local layer, such as AGENTS.md or project runbooks. That gives the generic skill reusable expertise while keeping project authority local.

I also strongly agree on routing traces. Without a trace, a bad routing decision is almost impossible to debug. With a trace, the agent can say: this skill was selected as primary owner, this one was added only as support, this project overlay was used for commands, and these other skills were rejected because they were out of phase or covered by a narrower owner. That turns skill selection from hidden intuition into something reviewable.

This is basically the direction my small “Skill Orchestrator” experiment is trying to approximate in userland, but without native manifests. Right now it has to infer ownership and conflicts from descriptions, naming patterns and known overlaps. I added the project to my profile rather than linking it directly here, since I do not want to turn the thread into repo promotion.

Your model would make that much cleaner: manifests define authority and boundaries, overlays bind generic behavior to the project, and the router only dispatches the smallest useful set for the current loop phase.

I like the idea that skills should not just be treated as reusable instruction snippets. In larger catalogues, they become participants in a governed execution loop. That means the system needs not only discovery, but also authority, phase, evidence expectations, stop conditions and auditability.

So the pattern I’m seeing now is roughly: a small entry point defines precedence and safety rules, skill manifests define ownership and boundaries, project overlays define local truth, a task-time router chooses one primary owner and only adds support skills with separate responsibility, and the routing trace explains the decision.

That feels much more maintainable than merging everything into one giant instruction document, and much safer than letting every related skill load at once.

That is exactly the distinction I was trying to get at.

Your “Skill Orchestrator” experiment sounds like it is already proving the shape of the missing layer. The hard part, as you say, is that without native manifests the orchestrator has to infer too much from descriptions, names and convention. That works for a small catalogue, but it gets fragile once skills become numerous or similarly worded.

I think the failure mode is something like:

semantic similarity looks like authority

A skill may be “about” testing, CI, GitHub, packaging or release evidence, but that does not mean it should own the current task. The router needs to know whether the skill is a primary owner, support skill, local overlay consumer, evidence producer, or explicitly out of phase.

So I wonder whether the useful minimal manifest is not very large. Something like:

skill_id: test-and-coverage

owns:
  - local-test-reproduction
  - coverage-gap-analysis

supports:
  - ci-failure-investigation
  - release-evidence-closeout

does_not_own:
  - github-pr-mutation
  - release-approval

requires_overlay:
  - test_commands
  - coverage_thresholds
  - source_roots

evidence_outputs:
  - commands_run
  - test_results
  - residual_failures

stop_conditions:
  - missing local test command
  - coverage threshold unclear
  - failure requires broader design change

context_budget: medium

That would let the human, the primary agent, and any sub-agents stop guessing quite so much. The manifest makes ownership, support roles, exclusions, required overlays, evidence expectations and stop conditions explicit rather than inferred from naming and prose descriptions.

It would also let the routing trace become deterministic enough to review:

  • selected because it owns local-test-reproduction
  • added under ci-failure-investigation as support
  • used AGENTS.md for project commands
  • stopped because coverage threshold was not discoverable

The bit I’m still thinking through is conflict resolution. Priority alone feels too blunt. I suspect the router needs to prefer the narrowest skill that owns the current loop phase, then add broader skills only as context or support. Otherwise broad “GitHub”, “testing” or “repo operations” skills will keep crowding out sharper specialist skills.

So maybe the hierarchy is:

current loop phase
→ narrowest primary owner
→ required local overlay
→ supporting skills with separate responsibility
→ routing trace and stop conditions

That would make native skill orchestration much easier to reason about, but experiments like yours are probably the right proving ground for the pattern before anything heavier exists.

This thread is only a few posts, and it’s a little bit of a nightmare of ai assisted rewrites because the solution itself is multi-layered and complex.

I may have read the issue incorrectly, but it seemed like he had been digging around in a lot of various people’s solutions, such as those, and he was still having problems.

That being said, I have no actual knowledge if any of the repos you linked would suit…

And there is still the chance that our friend Vanir here simply has one or more skills that force contradiction with a number of other skills.

At the end of the day, I think what quietly surfaced here is that when we produce skills, we should include ownership specifics, use case specifics, within the skill itself.

I’m thinking of a sort of pre-emptive hygiene that goes into play at skill creation because we’re going to start seeing, potentially, a slightly exponentially larger catalog of skills on GitHub…

And this user might be surfacing a problem we’ll find more often in the future if the ownership and best use cases aren’t specifically captured in the skills themselves.

But again… I’m just an otter, and this is all hypothetical to me.

:clinking_beer_mugs:

.md’s are suggestions at best. Convince me otherwise… If you want adherence to a capability or flow, architect for it vs just asking for it semantically. Like, does anyone really believe LLMs are adhering to .md instructions over .toml, .yaml, .yml, config programs, runner constraints, shell/sandbox/workspace limitations, etc., etc.? I really hope not… People love throwing buzzwords like “continuity,” “governance,” “orchestration,” etc., etc. into .md’s, forgetting that it doesn’t matter what you ask for if the environment doesn’t support it, or if a higher order Policy or Governance structure conflicts with it… just look at the non-local Codex shells… The user’s initial environment is bootstrapped into the initial shell, main project and subproject .toml’s unfold, dependencies download, etc., etc., THEN the prompt is read, THEN the AGENTS.md is read, THEN SKILLS.md’s mentioned in AGENTS.md get read, or read when they become applicable in the flow, AND THEN sub-shells/sandboxes are spun for testing and executing… the hierarchy is clear and the issues mentioned throughout this thread illustrate .md’s lack of potency, especially when dealing with large codebases, so I’m at a loss as to why everyone is still obsessing over .mds… jump on the .toml train!!!

I think this captures the issue very well.

The “semantic similarity looks like authority” failure mode is probably the main thing that makes larger catalogues hard to reason about. A skill can be related to CI, testing, GitHub, packaging, or release evidence without being the right owner for the current loop phase.

The manifest shape you suggest also seems small enough to be practical. Fields like “owns”, “supports”, “does_not_own”, “requires_overlay”, “evidence_outputs”, and “stop_conditions” would already make selection much less ambiguous without turning the manifest into another giant instruction document.

The “requires_overlay” part feels especially important. Generic skills should not invent project-specific commands, paths, thresholds, or release gates. Those should come from the local project layer. That separation keeps reusable expertise reusable, while keeping project authority local.

I also agree that the routing trace is not just nice to have. It is what makes the whole system debuggable. If the agent can explain what it selected, what it rejected, what local overlay it used, and why it stopped, then routing mistakes become something you can inspect and fix instead of just weird model behavior.

The config skepticism is fair too. A manifest is not enforcement by itself. It does not magically guarantee behavior. But it can make the selection process explicit enough that the router can default to conservative choices: pick one primary owner, add support only when the support role is distinct, and avoid loading everything that merely sounds related.

So the useful direction might be less about “more instructions” and more about better boundaries: authority, phase, overlay requirements, evidence expectations, and stop conditions.

I started with lots of narrow skills, but as the catalog grew I ran into the same overlap problem. What worked better was treating skills like layers: broad skills define standards and workflows, while specialist skills handle implementation details.

The biggest improvement came from adding simple routing rules and clear ownership boundaries. If two skills can reasonably answer the same task, one of them is probably too broad. I’d rather have a small amount of duplication than constantly load multiple overlapping skills and waste context.

One rule that has worked well for me is to separate ownership from support. A skill should own the task only when it can define the next action and the acceptance check. A support skill should be loaded only when it adds a separate capability, such as verification, publishing, or browser control.

For overlaps, I would log three fields in the routing trace: selected owner, rejected near-matches, and why the owner is narrower or safer. That makes bad routing debuggable without merging every skill into one large instruction file.