# Skill Writing

> Create/scaffold/init a project-local agent skill under `.agents/skills` in an ordinary repository; defer to repository instructions that define a source catalog and lifecycle.

- Skill: `paulrberg/skill-writing` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds add paulrberg/skill-writing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/paulrberg/skill-writing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: paulrberg (https://skillmd.com/u/paulrberg)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/paulrberg/skill-writing

---


# Skill Writing

Bootstrap a project-local skill with a small observable contract, then symlink it into `.claude/skills/` so Claude Code
can discover it. Keep invariant workflow guidance in `SKILL.md`; move deterministic mechanics and conditional detail
into scripts and references.

## Model Optimization

Optimize every new skill and its content for GPT-6 Astra and Claude Fable 5.1. The summaries below are reminders, not
substitutes for the live guides. Read both guides before designing or writing a complex, long-running, multi-tool, or
orchestration-heavy skill because their recommendations may evolve.

- [GPT-6 Astra prompting guidance](https://developers.openai.com/api/docs/guides/latest-model/gpt-6-astra#prompting-best-practices):
  Complete authorized work under stated assumptions; make user-instruction precedence over skills explicit; specify
  writing and delegation preferences; and keep verification proportional to the change.
- [Claude Fable 5.1 prompting guidance](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1):
  Calibrate effort with evals; request progress updates; batch independent tool calls; preserve decisions across
  compaction; verify changing facts; and finish the requested scope with targeted edits and proportionate tests.

## Arguments

- **skill-name** (required): kebab-case name (e.g., `my-skill`). Stop if missing or invalid.

Reject `--global`, explicit destination paths, and other scope overrides. The invocation working directory is the only
supported scope.

## Repository Catalog Guard

Before resolving project-local paths, read the repository instructions applicable to the invocation working directory.
If they define a source catalog and lifecycle for skill creation, stop this workflow and follow that repository-owned
workflow. Do not create `.agents/skills/` or `.claude/skills/` paths in that repository.

## Resolved Paths

Set `<scope>` to the working directory where the skill was invoked. Create the source at
`<scope>/.agents/skills/<name>/` and the Claude Code symlink at `<scope>/.claude/skills/<name>`. Do not redirect the
scope to the repository root when invoked from a nested project or workspace. Never create or modify a skill under
`~/.agents`, `~/.claude`, `~/.codex`, or another global installation directory.

The symlink target is always the relative path `../../.agents/skills/<name>`.

## Skill Layout

```
<name>/
├── SKILL.md       # Required: frontmatter + lean workflow (aim for <500 lines)
├── agents/
│   └── openai.yaml # Required: Codex invocation policy derived from SKILL.md
├── scripts/       # Optional: helper code (prefer TypeScript via bun run; Python via uv)
├── references/    # Optional: long-form docs loaded on demand
└── assets/        # Optional: templates / fonts / images used in OUTPUT (never loaded into context)
```

Agents load skills via **progressive disclosure**, in three stages:

1. **Discovery** — only `name` + `description` are visible at startup. Front-load triggers in `description`.
2. **Activation** — the full `SKILL.md` body is read once a task matches.
3. **Execution** — `scripts/` run without being read into context; `references/` are read only when `SKILL.md`
   explicitly links to them.

Keep `SKILL.md` focused on workflow. Push bulk into `scripts/` (deterministic logic) or `references/` (documentation).

## Authoring Contract

Before choosing a layout, separate the content into:

- **Invariants** that every valid execution must preserve.
- **Preferred defaults** that explicit user intent or repository evidence may override.
- **Conditional examples and references** loaded only when their branch is active.

Define the outcome, authority boundaries, stopping conditions, and completion evidence. Do not prescribe an identical
execution path when several safe paths satisfy the same contract. For user-facing workflows, also define which kickoff,
progress, decision, blocker, and completion events deserve a message and the smallest useful shape for each.

When a workflow hands long-winded work to background jobs or agents, make polished progress monitoring part of the
contract. Judge whether the work is long-winded from its expected runtime and uncertainty, fan-out or waves, meaningful
milestones, and the visibility the host already provides rather than a universal time cutoff. Name the main agent as the
reporting owner and follow the long-winded background-work guidance in
[references/writing-great-skills.md](references/writing-great-skills.md).

Express outcomes, invariants, and completion evidence as positive, observable acceptance criteria; when affirmative
evidence is available, require it instead of accepting only the absence of listed failures or adding negative examples,
inverse restatements, or long blacklists. Retain a negative instruction only for an explicit user-requested exclusion or
when it is the clearest concise guard for a consequential safety, authority, destructive-action, scope, or likely model
failure boundary that positive criteria cannot enforce equivalently.

## When to Split Content

### Use `scripts/` when

- The same code would be rewritten on every invocation (e.g., PDF rotate, JSON transform, curl wrapper).
- Determinism matters more than flexibility (parsing, validation, codegen, idempotent setup).
- A shell pipeline grows past ~5 lines or needs real error handling.
- A long heredoc keeps appearing inside `SKILL.md`.

Scripts are token-efficient: the agent invokes them without reading them. Document the CLI signature in `SKILL.md` and
leave the implementation in `scripts/`.

Prefer `scripts/*.ts` run with `bun run scripts/<name>.ts`, unless there is a good reason TypeScript is the wrong fit
for the helper. Python is also a good choice for data, text, and file processing; run Python helpers through
`uv run scripts/<name>.py`, not raw `python` or `python3`.

Keep Bash helpers compatible with macOS `/bin/bash` 3.2.

### Use `references/` when

- A topic exceeds ~100 lines of prose, examples, or schemas.
- Content is conditionally relevant (variant-, framework-, or domain-specific) — splitting keeps irrelevant context out.
- Detailed API surfaces, DB schemas, policies, or large templates would otherwise dominate `SKILL.md`.
- A long explanation is needed only on one branch.

Rules of thumb:

- **One level deep** — link `references/placeholder.md` directly from `SKILL.md`, never reference-to-reference.
- Files >100 lines: include a table of contents at the top.
- Files >10k words: document grep patterns in `SKILL.md` so the agent can locate sections without reading the whole
  file.
- **No duplication** — each fact lives in `SKILL.md` _or_ a reference, never both. Keep skills self-contained rather
  than sharing references across independently installed skills.
- For every reference, write one line in `SKILL.md` that says _when_ to read it.

### Reference organization patterns

**Pattern A — High-level guide + topical references**

```
SKILL.md
references/
├── forms.md
├── api.md
└── examples.md
```

`SKILL.md` teaches the happy path; references hold deep-dive material.

**Pattern B — Domain or variant split**

```
SKILL.md           # workflow + selection logic
references/
├── aws.md
├── gcp.md
└── azure.md
```

The agent reads only the variant the user picked — irrelevant providers never enter context.

**Pattern C — Conditional details**

Inline the basic case in `SKILL.md`, link advanced files for edge cases (`tracked-changes.md`, `ooxml.md`, etc.).

### Exclude runtime-irrelevant files

Do not add repository-style support files (`README.md`, `INSTALLATION.md`, `CHANGELOG.md`, or `QUICK_REFERENCE.md`),
authoring notes, test logs, scratch files, or anything the agent will not use at runtime.

## Workflow

### 1. Read Format Docs

Resolve `scripts/fetch-agentskills-spec.sh` relative to this skill directory, run it once, and read the returned file
completely. The helper reuses an integrity-valid specification for 24 hours, conditionally revalidates older entries,
and may return a cache validated within seven days when live retrieval fails. Set `AGENTSKILLS_CACHE_DIR` when the
default user cache location is unavailable or unwritable.

Use `--refresh` for explicitly latest or change-sensitive work, disputed portable-format guidance, or a conflict with
validator behavior. A `stale` result is usable only after reading it; disclose its validation timestamp and retrieval
failure in the completion report. If the helper cannot return a valid file, stop before writing. Never fetch the
agentskills.io specification directly or create its cache in a repository or skill installation.

Fetch the current [Claude Code frontmatter reference](https://code.claude.com/docs/en/skills#frontmatter-reference) with
`WebFetch`. Confirm field shapes, naming rules, and progressive-disclosure conventions from both sources; do not guess
because the formats evolve.

### 2. Validate

- Reject names that are not kebab-case or collide with an existing skill at the resolved path.
- Confirm `<scope>` is the invocation working directory and is not a home-level or global skill directory.
- Stop if `<scope>/.agents/skills/<name>/` or `<scope>/.claude/skills/<name>` already exists.

### 3. Read the Authoring Guide and Define the Contract and Layout

Read [references/writing-great-skills.md](references/writing-great-skills.md) before choosing the contract or layout. It
defines the predictability levers and the prose-versus-code-or-schema decision.

Then define the observable outcome, invariants, preferred defaults, authority, routing, stop conditions, and completion
evidence. While defining routing, identify every skill that the workflow requires, invokes, or hands off to on any
supported branch. Exclude suggestions, examples, related-skill references, and underlying tool capabilities. Decide what
belongs where:

- Will the workflow invoke helper code? → Prefer `scripts/<name>.ts` run with `bun run`; use `scripts/<name>.py` through
  `uv run` when Python is a better fit.
- Machine-consumed schema with a real validator? → Bundle both and document the validation route.
- Reference-only schema documentation, long examples, variant guides, or domain knowledge? → `references/<topic>.md`
- Templates or files the skill writes into the user's output? → `assets/`
- None of the above? → ship only the required `SKILL.md` and `agents/openai.yaml`.

Sketch the directory tree first, then create only the subdirectories the layout actually needs.

### 4. Create the Skill

```bash
mkdir -p "<scope>/.agents/skills/<name>/agents"
# Add only the subdirectories the layout calls for:
# mkdir -p "<scope>/.agents/skills/<name>/scripts"
# mkdir -p "<scope>/.agents/skills/<name>/references"
```

Write `<scope>/.agents/skills/<name>/SKILL.md` with:

- Frontmatter sorted alphabetically, with `description` last. Front-load discovery-time trigger phrases in
  `description`.
- A `skill-dependencies` array when routing identified dependencies. Use bare names for skills in the same repository
  and `ORG/REPO#SKILL` for external skills. Sort by the target skill name (the bare name or substring after `#`), then
  by the complete identifier. Require unique strings, resolve every bare dependency in the same repository, and exclude
  the owning skill as a bare dependency. External repository existence is not validated. Omit the field when no
  dependencies exist.
- A short `# Title`.
- A one-line summary of what the skill does.
- Add `disable-model-invocation: true` or `user-invocable: false` only when the skill differs from Claude's defaults.
  Omit `disable-model-invocation: false` and `user-invocable: true` because absence already expresses those values.
- Set `coordination: exempt` only when the skill's declared default workflow writes no repository files or only
  repository metadata. When selected, add this ordinary prose declaration to the new skill's body; the fence below is
  documentation for this authoring skill, not its own declaration:

  ```text
  This skill is coordination-exempt: skip the ai-coord gate for its declared work.
  ```

  Explicitly authorized escalation beyond the declared behavior re-enters the gate.

- `## Arguments` (if any) and a lean imperative workflow. Use fixed steps only when order matters; otherwise state the
  contract and let repository evidence guide execution.
- Explicit links to every `references/` file the workflow may need, each with a one-line note describing _when_ to read
  it.
- CLI signatures for any bundled scripts, including the runtime command (`bun run scripts/<name>.ts` or
  `uv run scripts/<name>.py`), so the agent can call them without reading them.

Use imperative prose and resolve bundled `references/`, `scripts/`, `examples/`, and `assets/` paths relative to the
owning skill directory.

Aim for `SKILL.md` under 500 lines. If a section grows past ~50 lines and is not core workflow, move it to `references/`
and link it.

Write `<scope>/.agents/skills/<name>/agents/openai.yaml` with:

```yaml
policy:
  allow_implicit_invocation: true
```

Set `allow_implicit_invocation` to the inverse of `SKILL.md` `disable-model-invocation`. If later adding Codex UI
metadata or MCP/tool dependencies, merge them into the same file and keep the policy.

### 5. Create the Claude Code Symlink

Always create a relative symlink so Claude Code picks the skill up from its own discovery path:

```bash
mkdir -p "<scope>/.claude/skills"
ln -s "../../.agents/skills/<name>" "<scope>/.claude/skills/<name>"
```

### 6. Verify

- Patch tooling creates files at mode 0644. Before the first verification run, `chmod 755` every executable under
  `scripts/` and `tests/` (a scaffolded test failing its first run with `Permission denied (os error 13)` is this
  cause).
- `test -f "<scope>/.agents/skills/<name>/SKILL.md"`
- `test -f "<scope>/.agents/skills/<name>/agents/openai.yaml"`
- `readlink "<scope>/.claude/skills/<name>"` resolves to the source directory.
- `test -x` every `scripts/*` and `tests/*` executable so a missed `chmod` fails loudly instead of surfacing later as a
  permission error.
- `ai-skillet doctor --root "<scope>/.agents/skills/<name>"` exits 0. This is the canonical local schema and policy
  gate.
- Finish with `### 🧩 Skill created: <name>`, a tree of created paths, and `### ✅ Verified` with the exact checks. Link
  both absolute source and symlink paths.
- Offer to commit the new skill. When the host project's standing instructions require prompt commits, commit without
  further prompting.

## Notes

- The skills CLI parses `SKILL.md` frontmatter as YAML before publishing. A colon followed by a space inside a plain
  scalar, such as `leave: freeze` in `description`, makes that parser fail. Use an em dash or another safe separator, or
  quote the entire scalar.
- Keep helper stdout, commands, paths, frontmatter, and generated skill content undecorated unless that skill's own
  output contract requires otherwise.

