How to write Claude Code skills depends on whether the flow repeats across tasks, whether it still needs on-the-spot judgment, and whether the project can observe a result after it runs. Facts that stay true in a repository belong in project rules. A one-off requirement belongs in the current task prompt. Actions that must run on an event belong in a hook. External services and data come from MCP or other tools.

A full-stack project that often changes an existing API contract has to find the real producer, confirm approved field meanings, sync direct consumers, run existing checks, and observe a page or a call. The fields and the range change every time. The judgment order stays stable. That flow belongs in a project skill. The field names, paths, and acceptance result for this run still come from the current prompt.

Decide whether this content is a skill

“I keep pasting a long prompt” only proves repetition. It does not prove a skill is needed. If the pasted text is “use pnpm” or “do not hand-edit generated files,” those are long-lived project facts and belong in AGENTS.md or CLAUDE.md. If the pasted text is this task’s state, screenshot, and range, it expires with the task and stays in the current prompt.

An API contract change cannot be a search-and-replace of one field. The producer may be a server type, a schema, or a generator. Consumers may include a frontend adapter, an admin UI, an SDK, and an async event. Finding the source of truth and walking the call chain to affected consumers can be reused even when the input and the diff change.

The input to an API-contract-sync skill is an approved contract change, the current project, and the software state that must appear. When it finishes, the producer and the direct consumers use the same field definitions, proven by existing tests or by the current page. If field meanings are not approved, the skill names the missing decision and stops. It does not invent the definition.

Repeated contentOwnerWhy
Repo map, project commands, architecture boundsRulesTrue across tasks; apply as soon as the agent enters the project
This run’s fields, present state, target, range, and authorizationPromptTrue only for this task; the next run usually changes them
Find the contract source, trace consumers, handle missing inputSkillReused across tasks; still needs reasoning at run time
Format after save, block before commit, notify on stopHook, formatter, or CIMust run on the event; the model remembering it is not enough
Read a ticket, query a database, drive a browser, call an external APIMCP or other toolsSupply ability and data; they do not replace method or authorization

A skill only owns a reusable method

Substitute the next contract change in the same project. “Read the project rules that apply to the current directory” is still true. “Change status to three enum values” is already dead. The first sentence belongs in the skill. The second stays in the task prompt.

Rules and skills can both hold instructions. They load at different times. Project rules describe facts and constraints that apply as soon as the agent is in that directory. A skill describes a method or reference needed only after a class of task appears. Claude Code’s extension overview(opens in a new tab) puts CLAUDE.md on always-on project conventions and skills on occasional reference or reusable workflows. A long procedure stuffed into rules rides into unrelated tasks. A project command copied into a skill becomes a second, stale fact when the command moves.

The difference between a hook and a skill is whether the action needs model judgment. Whether a contract change also needs a database change, whether a generator exists, and which clients are direct consumers all require reading code. That is a skill. Format after write, block a dangerous command, and notify when the agent stops are event-driven. They belong in a hook or in tools the project already runs.

MCP answers whether a connection exists. A skill answers how to finish the task after that connection is available. A skill may ask for a ticket or a design file. It must not assume the tool is present, and it must not bypass tool permissions. When a required connection is missing, it reports the missing ability and the unfinished result.

Where personal and project skills live

A method that depends only on generic input and holds in many repositories belongs at the personal level, such as turning a public technical document into a sourced summary. A flow that needs this project’s architecture, commands, generation chain, or team boundaries belongs at the project level. API contract sync depends on in-repo producers, consumers, and verification entries, so it should ship with the project, not with one laptop.

Claude Code currently discovers skills from the personal path ~/.claude/skills/<name>/SKILL.md and the project path .claude/skills/<name>/SKILL.md. A project skill can be shared through version control. Codex currently discovers skills from the user directory ~/.agents/skills and from .agents/skills in the repository. Both clients have personal and project scope. One client’s directory and override order cannot be copied onto the other. Use the current Claude Code skills(opens in a new tab) and Codex skills(opens in a new tab) docs when wiring a path.

The shared Agent Skills format can be reused. Discovery paths are not part of that open spec. If the team uses one client, put the skill in that client’s project directory. If both clients must load it, attach the same body to both discovery locations and test each one. Do not keep two copies that will drift. How those two locations point at one file should follow the project’s existing config management. That is not a prerequisite for creating the first skill.

A Codex project skill lands at .agents/skills/api-contract-sync/SKILL.md. A Claude Code project skill lands at .claude/skills/api-contract-sync/SKILL.md. Build one entry, prove trigger, then add the second client. When both exist, a body change must still be the same content at both entries. If the project has no reliable share, keep one entry rather than copy-and-hope.

A project skill must not hard-code an author’s absolute paths. It should read repository facts from the current working directory and the applicable project rules, and it should reference bundled resources with paths relative to the skill directory. After a laptop change or a worktree change, it still has to find the current repo’s rules and paths.

The agent sees the description before it loads the body

Skills use progressive disclosure so unrelated context stays out. Codex first gives the model available skills’ names, descriptions, and file paths, then reads the full SKILL.md after a selection. Claude Code also uses the description to decide when to load a skill; the body enters context only when the skill is used. description is therefore a trigger boundary, not a file blurb. The Agent Skills specification(opens in a new tab) requires name and description, and it leaves full instructions and bundled resources for later load stages.

“Handle APIs” is too wide: looking up docs, fixing an internal implementation, and changing a public contract could all match. “Use only when changing the user interface” does not say what the flow owns, so a relevant task may miss it. An API-contract-sync skill can read:

---
name: api-contract-sync
description: >-
  Trace and update an existing API contract and its direct consumers.
  Use when an approved contract change affects a producer plus frontend,
  admin, SDK, or event consumers. Do not use for local implementation
  changes that leave the contract unchanged.
---

The object is “an existing API contract and its direct consumers.” The trigger is “an approved contract change that crosses producer and consumers.” The exclusion is “a local implementation that leaves the contract unchanged.” Those three facts let a relevant task match and keep an implementation-only task out. The name is a stable identifier. Natural trigger depends on whether the description can tell adjacent tasks apart.

After a description change, explicit invoke usually still finds the skill. Natural trigger may not. When the flow’s scope, the client’s discovery, or the project’s ownership boundary changes, rerun relevant and irrelevant requests. Do not stop at “the file still exists.”

Automatic trigger is not tool authorization

description only helps the agent choose a skill. It does not grant file, terminal, or external-service permission. API contract sync may trigger on a relevant local change because the user already asked to change the current project. The skill still sits under current permissions and stop conditions. Deploying production, deleting data, sending outbound messages, or starting a payment has extra side effects. Those skills should require the user to name them. A similar description is not enough to run them.

Claude Code skills(opens in a new tab) allow disable-model-invocation: true in SKILL.md front matter so only the user can invoke the skill. Codex skills(opens in a new tab) put policy.allow_implicit_invocation: false in the skill’s agents/openai.yaml, keep explicit $skill invoke, and turn off implicit selection. Those fields are each client’s invocation policy. They are not a shared Agent Skills guarantee. A flow used on both sides needs both settings, and both need a test.

# Claude Code: SKILL.md
disable-model-invocation: true
# Codex: agents/openai.yaml
policy:
  allow_implicit_invocation: false

Turning off implicit invoke does not enlarge permissions. After a user names the skill, writes, commands, network access, and external side effects still follow the client’s permission policy and the current grant. When a higher grant is required, stop at that boundary. Skill text cannot skip confirmation.

How to write Claude Code skills from a repeated workflow

The smallest skill is a directory and a SKILL.md. Keep name and description from the open spec. The body states inputs, a non-swappable judgment order, stop conditions, and the completion result. Claude Code and Codex extras go in only when that client’s behavior is required. Do not treat one client’s fields as a cross-client contract.

api-contract-sync/
└── SKILL.md
---
name: api-contract-sync
description: >-
  Trace and update an existing API contract and its direct consumers.
  Use when an approved contract change crosses a producer-consumer boundary.
  Do not use for implementation-only changes that preserve the contract.
---

# API contract sync

## Required inputs

Require the approved contract change and an observable end state.
Read the project rules that apply to the current working directory.

## Workflow

1. Find the source of truth that produces the existing contract.
2. Trace the contract to its direct consumers before editing.
3. Change the owning source and only the affected consumers.
4. Run the project's existing deterministic checks.
5. Observe the affected consumer and the behavior that must remain unchanged.

## Stop conditions

Stop and name the missing input when the intended field meanings are not approved,
the source of truth cannot be identified, or the required consumer is unavailable.
Do not invent paths, commands, field meanings, or approval.

## Completion

Report the changed contract, affected consumers, project checks, observed result,
and any boundary that could not be verified.

This skill does not store project directories, test commands, or a field name. Those facts stay in the current repository’s rules and code. The skill requires reading applicable rules, then identifying the source of truth and the consumers from code. After a language change or a directory reshape, the skill does not need a path rewrite as long as the rules and the code stay in sync.

Split the old pasted prompt by lifetime. After the move, do not keep a giant prompt as a spare copy:

Sentence from the old promptNew ownerHow the next task uses it
“Generated code changes only through the schema.”Project rulesThe agent gets it after entering that directory; the skill does not copy it
“Find the contract producer, then trace direct consumers.”SkillLoads when a contract-change task matches
“This run adds a pending_review status.”Current promptAppears only with this approved requirement
“After the change, run the project’s contract checks.”Skill citing project rulesThe skill requires verification; the actual command stays in rules
“Formatting must pass before commit.”Hook or CIRuns on the event; it does not depend on a skill reminder

After the move, use a different contract change as the boundary test. The next prompt should only replace the approved field definitions, the range, and the target state. If the judgment order still has to be pasted, the skill missed a stable step. If the skill’s paths or commands have to change, project facts landed in the wrong file.

The step order is not interchangeable. Writing consumers before finding the source of truth puts compatibility code in the wrong place. Changing a contract before tracing consumers can leave server checks green while a UI or SDK still reads the old shape. Running tests without observing a consumer does not prove the consumer uses the new contract.

Stop conditions are part of the implementation. When field meanings are unapproved, the skill only names the missing decision. When the source of truth cannot be identified, it does not edit, and it says where the survey stopped. Guessing freezes an uncertain input into a public contract. Later tests then only prove that the guess was implemented consistently.

Split resources only when they cut repeated reads or actions

When SKILL.md grows, do not split by file type for the sake of a directory tree. The entry file must keep the trigger boundary, the core flow, what each resource is for, and the stop conditions. Split a file only when that content is not always needed at run time, or when an action must produce the same result every time.

ResourceWhat belongs thereWhat does not
scripts/Parse or check work whose output must be deterministic and is easy to get wrong by handJudgment that needs business rules, owner choice, or an approval range
references/Long protocol or project notes needed only on some branchesAlways-on project rules, or a pile of files with no read entry
assets/Templates and static files that will be copied, filled, or deliveredEmpty files created so the directory looks complete

If the project already has tests, generators, or format commands, the skill calls them through project rules. It does not wrap a same-named script around them. Add a script only when existing tools cannot express a stable action that will repeat. The script still has to handle input, dependencies, and failure codes. The model decides when to run it. The script returns a determined result.

Reference files must be linked from SKILL.md, with the branch that should read them. Cross-client sharing uses relative paths, not one machine’s absolute directory. The main file keeps the flow that every invoke needs. Scripts, references, and assets open when needed. If every invoke immediately reads every bundled file, the split only adds jumps. It does not shrink context.

When a project command changes, edit rules. When the judgment order changes, edit the skill. When this run’s fields change, edit the prompt. When a fixed event action changes, edit the hook. The same fact in several places leaves a conflicting copy after any one update.

How a skill connects to project rules and the task prompt

A contract change needs three inputs. Project rules supply repo shape, commands, generated-file bounds, and architecture constraints. The skill supplies the method for finding the source of truth, tracing consumers, handling missing input, and verifying the result. The task prompt only supplies this approved change, the known present, the range, and the target state.

The agent first sees the skill name and description, loads SKILL.md on a match, then reads scripts, references, or templates as the flow needs them; project rules and the task prompt supply facts and variables, and direct consumers prove the target state
Only a matching task reads the full flow. After the skill loads, still check the real producer and consumers.

An explicit invoke only adds this run’s variables:

Use api-contract-sync. Product already approved expanding the existing account-status contract from two states to three. The server currently returns two states. Admin and the user page both display account status; whether they consume the same contract still has to be confirmed from code. Keep the permission-denied behavior. Prove the result with the project’s existing checks and with what the two interfaces actually show.

api-contract-sync owns the stable flow. The three states, candidate consumers, and control behavior are this run’s variables. If the code shows the user page getting status through another adapter, the skill should follow the real call chain and still keep the user-page result the prompt required. It should not invent a missing dependency just to copy the candidate range.

A natural trigger does not name the skill:

An approved change to the existing account-status API must sync the affected admin and user displays. Confirm the source of truth and the direct consumers from project rules and current code. Keep the permission-denied behavior. Finish with the two interfaces as the result.

“Approved contract change,” “producer and direct consumers,” “project rules,” and “consumer result” are enough for description to treat this as a contract-sync task. If an external ticket also has to be read, MCP only fetches the ticket. Whether that ticket is an approved requirement, and how it maps onto code, still come from the prompt, the rules, and the skill together.

First confirm the skill loads on a relevant task

Explicit invoke first rules out discovery and naming. In a new client session, open the target project, select the current skill with Claude Code’s /<skill-name> or Codex’s $skill-name, then send a representative task that already has complete input. Use each client’s current invoke syntax. Do not copy one client’s prefix onto the other.

After an explicit invoke, the agent should read applicable project rules and the source of truth, then trace direct consumers. The edit range follows the call chain. Then it runs existing project checks and observes consumers. Naming the skill in the reply does not prove the flow ran. If an explicit invoke still skips those steps, the fault is in the skill body or in that client’s extra config, not in description.

Natural trigger uses another new session, the same project, and the same task, with the skill name removed. A new session avoids a previously loaded body staying in context. If the client exposes a skill-invocation record, check that. If it does not, check whether the agent actually ran the steps unique to this skill. One similar answer is not enough to prove a stable trigger.

If explicit invoke works and natural trigger fails, tighten or complete the object and trigger conditions in description. Do not stuff the whole flow into the description, and do not add every nearby synonym. The description only has to tell a relevant task from an adjacent one. The body owns the steps.

Irrelevant or incomplete tasks must not run the skill

A positive request only proves the skill can be selected. It does not prove the boundary. The adjacent task that does not change the contract is the usual leak: “optimize internal API caching without changing request or response shape.” api-contract-sync should stay out. If it still loads, the word “API” overran the exclusion. Rewrite it as an approved contract change that crosses a producer-consumer boundary.

A missing-input test omits one fact that must block edits:

Change the account-status API to a new shape and sync every page.

This request does not confirm new field meanings and has no observable target. The skill should confirm the current contract from project rules and existing code, then name the missing product decision. It may do a read-only survey. It must not pick a new enum, rename a public field, or edit consumers. After it names the gap, the user supplies the approved field definitions, then the flow continues.

Explicit invoke and a complete natural task enter the skill, an unrelated task does not load, unapproved field meanings stop edits, and after the flow runs the agent still observes direct consumers
Run only when the task is relevant and the input is complete. Stay silent on unrelated work. Stop when approval is missing.

A relevant task that never triggers, an unrelated task that keeps triggering, and a missing-input task that still edits are three different faults. The first two change description and discovery. The third changes the skill’s inputs and stop conditions. Making the description longer does not repair a body that lacks a stop boundary. It makes the trigger harder to judge.

After the skill runs, check the direct consumers

Once the skill is discovered, the agent only has a flow. Even if the steps run in order, whether the API contract is usable still depends on the producer, the direct consumers, and the control behavior that must stay. Run the project’s existing unit tests, type checks, contract tests, or build first. Then open the affected page, call the public API, or watch an event consumer. Confirm the approved state appears and the old permission behavior did not change.

On the next kind of contract change, if the skill still has to rewrite fixed files, fields, or commands, those project facts were written into the flow. If the next prompt only replaces this-run variables, the flow is reusable.

Format after save, block a dangerous command before a tool call, and notify when the agent stops should not rely on a skill reminder. Those deterministic actions belong in a hook. The skill keeps the part that has to read the present, choose an owner, and judge the result. That hook job is next.

What is the difference between a Claude Code skill and a task prompt? A skill stores a judgment flow reused across tasks. A task prompt only supplies this run’s goal, facts, range, and result. When the task ends, that prompt no longer applies. If the flow is unchanged, the skill can be reused.

Should a Claude Code skill live globally or in the project? A method that depends only on generic inputs and holds in many repositories belongs at the personal level. A flow that depends on this project’s architecture, commands, consumers, or team process belongs in the project and should read those facts from project rules.

What should I check first when a Claude Code skill does not trigger? Check that the skill sits in a directory the current client discovers, then check that description names both the object and the trigger situation. If the path is correct but the description only says “handle code,” a relevant request may not match.

Can one SKILL.md serve Claude Code and Codex? name, description, and Markdown instructions that follow the Agent Skills spec can be shared. Discovery directories, explicit invoke syntax, and extra policy fields are client-specific and must be configured and tested separately.

When how to write Claude Code skills for this repository is stable, the next prompt only replaces this run’s variables. If an action must still run on every matching event no matter how the model judges, that action leaves the skill and belongs in a hook.