Skip to content

Claude engine ignores purchased/equipped skills (Codex uses them) — awareness signal is titles-only, not name+description #58

Description

@zo-sol

Summary

Observed: the Codex engine reaches for purchased/equipped skills well, but the Claude engine usually ignores them — even when a relevant skill (e.g. docx, pdf, pptx) is installed and the task obviously fits.

Disk placement is symmetric and correctbuyAndEquip writes the SKILL.md into both runtimes' skill dirs (installBoughtAllinstallBought("claude") + installBought("codex"), skill-market/ingest/index.ts:61‑64). So this is not an install bug. The gap is entirely in how each engine is made aware of the skills at session time.

How skills surface to each engine

flowchart TD
    Buy["buyAndEquip(skillId)"] --> A["installBought claude<br/>~/.claude/skills/&lt;slug&gt;/SKILL.md"]
    Buy --> B["installBought codex<br/>~/.codex/skills/&lt;slug&gt;/SKILL.md"]

    A --> C["Claude awareness"]
    B --> D["Codex awareness"]

    C --> C1["MEMORY.md managed line:<br/>TITLES ONLY<br/>'…installed and ready: docx, pdf, pptx.'"]
    C --> C2["SDK native discovery of ~/.claude/skills<br/>(settingSources omitted)"]

    D --> D1["AGENTS.md managed line (titles)"]
    D --> D2["NATIVE always-on '## Skills' list<br/>name + DESCRIPTION + path, every turn"]

    C1 -.weak signal.-> E["Claude rarely invokes the skill"]
    D2 == strong signal ==> F["Codex invokes the skill"]
Loading

Codex (works)

  • ~/.codex/skills/<slug>/SKILL.md is auto-discovered by Codex and injected into an always-on ## Skills list with name + description + path every turn (plans/skill-ingestion.md:61‑62, §3). The model sees what each skill does and when to use it on every turn → it reaches for them.

Claude (ignores them)

Claude's awareness today comes from only two things:

  1. A managed MEMORY.md one-liner that lists skill titles only — no descriptions. skillsSection.ts:44‑48 renders "The following skills are installed and ready — use one when it fits the task: <names>." Bare titles like docx, pdf, pptx are a weak trigger: the model can't tell what each does or when it's relevant.
  2. SDK native skill discovery of ~/.claude/skills, relying on settingSources being omitted so the SDK loads the user dir (spawn.ts:327‑330).

The Claude system prompt is kept vanilla ({ type: "preset", preset: "claude_code" }, spawn.ts:317) with nothing appended.

Root-cause candidates (the actionable part)

The code diverges from the settled design in plans/skill-ingestion.md §2–§3. The design specifies, for Claude:

  • enable skills via skills: ['verify','skill-shopping', …] in query() options, and
  • settingSources: ['project'], and
  • append the verify directive to the system prompt (preset:'claude_code', append: <verify-instruction>).

None of these are present in the actual spawn.ts claude engine options (lines 297‑331): there is no skills: array, no settingSources, no append. So Claude is left to implicitly discover skills, with only a titles-only memory line as the nudge.

Candidate causes, roughly in order of likelihood:

  1. No descriptions in Claude's awareness signal. The memory line lists titles only; Codex gets name+description. This alone plausibly explains the behavior — without descriptions the model doesn't connect "I'm editing a .docx" → "use the docx skill."
  2. SDK native discovery may not actually be surfacing the skills as Skill tools the way the comment assumes (no explicit skills:[…]/settingSources → discovery may be partial or off). Needs verification with a logged session: does the Claude turn actually receive the equipped skills as available Skill tools?
  3. Design/impl drift — the skills:[…] + settingSources:['project'] wiring from the design was never landed for the bought-skills path.

What to verify

Proposed fix directions

  • Enrich the awareness signal to match Codex: have skillsSection.ts render name + one-line description per skill (we already have description in the skill metadata / memory record), not just titles — so Claude gets the same "what/when" signal Codex's ## Skills list provides. This reuses the existing memory-splice setter (spliceMarkedBlock), just with a richer block.
  • And/or land the design's explicit wiring: pass skills: [<equipped names>] (+ settingSources as the design requires) into the Claude query() so equipped skills are first-class Skill tools, not just discovered.
  • Keep the system prompt vanilla (that decision was deliberate, spawn.ts:312‑316) — surface skills through memory/SDK options, not the prompt.

Key references

What File:line
Bought skill → both dirs packages/core/src/skill-market/ingest/index.ts:61‑64
Claude awareness = titles-only memory line packages/core/src/memory/skillsSection.ts:44‑48
Claude spawn options (no skills:/settingSources/append) packages/core/src/runtime/spawn.ts:297‑331
Vanilla system prompt (deliberate) packages/core/src/runtime/spawn.ts:312‑317
Codex native ## Skills list (name+description) plans/skill-ingestion.md:61‑62, §3
Settled design (skills:[]/settingSources/append) plans/skill-ingestion.md §2–§3

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions