# How to Develop New OpenSEO Skills: The Complete Workflow Guide

> Learn the complete workflow to develop new OpenSEO skills. Create canonical skill files, declare them, and integrate them into AI agent execution for seamless development.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-21

---

**Developing a new OpenSEO skill requires creating a canonical [`SKILL.md`](https://github.com/every-app/open-seo/blob/main/SKILL.md) file in `.agents/skills/<kebab-name>/`, declaring it as internal or public, and wiring it into the Claude Code symlinks, test rosters, documentation, and plugin manifests to ensure the AI agent can execute it.**

OpenSEO skills are reusable, markdown-driven workflow definitions that AI agents—including Claude Code, Codex, and the in-app SAM—can execute to perform SEO tasks. In the `every-app/open-seo` repository, adding a new skill follows a strict pipeline that keeps definitions **canonical**, **discoverable**, and **synchronized** across the entire codebase.

## Establishing the Canonical Skill Location

All skill definitions live under `**/.agents/skills/<kebab-name>/SKILL.md**`. This path serves as the single source of truth for both internal tooling and public product features. The `name` field in the front-matter must exactly match the kebab-case folder name.

### Creating the Skill Skeleton

Begin by creating the directory and the main definition file:

```bash
mkdir .agents/skills/my-new-skill

```

Create [`SKILL.md`](https://github.com/every-app/open-seo/blob/main/SKILL.md) with the required YAML front-matter and markdown body:

```markdown
---
name: my-new-skill
description: Performs a specific SEO workflow. Use when the user requests competitive analysis.
metadata:
  internal: true   # Omit this line for public product skills

---

# My New Skill

## Context

{{ get_project_context(projectId) }}

## Steps

1. Analyze the input...
2. Generate recommendations...

```

The complete template structure is documented in [`.agents/skills/create-repo-skill/SKILL.md`](https://github.com/every-app/open-seo/blob/main/.agents/skills/create-repo-skill/SKILL.md).

### Internal vs. Public Skills

You must declare the skill type using the `metadata.internal` flag:

- **Internal repo skills**: Set `metadata.internal: true`. These require only a symlink in `.claude/skills/` so Claude Code agents can load them, with no public documentation required.
- **Public product skills**: Omit the `internal` flag entirely. These must be registered in every user-facing location including documentation, UI lists, and plugin manifests so end-users can discover and install them.

## Wiring Skills into the Ecosystem

After establishing the canonical file, register the skill across seven destinations to make it discoverable and executable.

### Claude Code Integration via Symlinks

For internal skills, create a symbolic link from the Claude Code skills directory to the canonical source:

```bash
ln -s ../../.agents/skills/my-new-skill .claude/skills/my-new-skill

```

This ensures Claude Code loads the skill definition directly from `.agents/skills/` without maintaining stale copies.

### Test Registry and SAM Integration

Add the skill name to the roster in [`src/server/features/sam/samSkills.test.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/samSkills.test.ts). The test suite validates that this list remains current and will fail if it drifts from the actual skill implementations, preventing broken deployments.

### Documentation and UI Registration

For public skills, create a documentation page at `web/content/docs/skills/<kebab-name>.mdx` and update [`web/content/docs/skills/meta.json`](https://github.com/every-app/open-seo/blob/main/web/content/docs/skills/meta.json) to add navigation entries. Additionally, insert the skill slug into the `SKILL_NAMES` array in [`src/routes/_app/ai.tsx`](https://github.com/every-app/open-seo/blob/main/src/routes/_app/ai.tsx) to expose it in the web interface dropdown.

### Plugin Bundling

Add the skill directory to `plugins/openseo/skills/` and execute the synchronization command:

```bash
pnpm sync-plugin-skills

```

The `scripts/sync-plugin-skills.mjs` script copies canonical files into the Claude Code and Codex plugin bundles, ensuring published plugins contain the latest definitions.

## Maintaining Synchronization

To prevent configuration drift between the canonical source and deployed instances, always validate your changes after editing.

### Validating with Sync-Check

Run the format step and the drift detection loop to verify that every entry in `.claude/skills/*` is a symlink pointing to a valid source in `.agents/skills/`:

```bash
pnpm format:write

for d in .claude/skills/*/; do
  n=$(basename "$d")
  [ -L "${d%/}" ] || echo "DRIFT RISK — not a symlink: $n"
  [ -e ".agents/skills/$n" ] || echo "BROKEN — no canonical source: $n"
done

```

This validation catches hardcoded copies that could become outdated and ensures the repository remains the single source of truth.

## Publishing and Installation

Once committed and pushed, users can install the new skill using the standard command:

```bash
npx skills add every-app/open-seo --skill my-new-skill

```

To install all available OpenSEO skills at once, use the wildcard syntax:

```bash
npx skills add every-app/open-seo --skill '*'

```

These commands pull the canonical definitions from the repository and make them available to local AI agents immediately.

## Summary

- **Canonical location**: Place all skills in `.agents/skills/<kebab-name>/SKILL.md` as the single source of truth.
- **Type declaration**: Set `metadata.internal: true` for internal tools; omit entirely for public features requiring full registration.
- **Ecosystem wiring**: Register skills in Claude Code symlinks, SAM test files ([`src/server/features/sam/samSkills.test.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/samSkills.test.ts)), UI registries ([`src/routes/_app/ai.tsx`](https://github.com/every-app/open-seo/blob/main/src/routes/_app/ai.tsx)), documentation (`web/content/docs/skills/`), and plugin manifests.
- **Synchronization**: Run `pnpm sync-plugin-skills` and validation loops to prevent drift between canonical sources and deployed instances.
- **Installation**: Users consume skills via `npx skills add every-app/open-seo --skill <kebab-name>`.

## Frequently Asked Questions

### What file format does an OpenSEO skill use?

OpenSEO skills are markdown files with YAML front-matter containing `name`, `description`, and `metadata` fields. The workflow logic is written in the markdown body using templated instructions that AI agents interpret and execute.

### Where should I place a new skill in the repository?

Place the canonical [`SKILL.md`](https://github.com/every-app/open-seo/blob/main/SKILL.md) inside `.agents/skills/<kebab-name>/`, where `<kebab-name>` is a kebab-case identifier matching the `name` field in the front-matter. This location acts as the single source of truth referenced by symlinks, tests, and plugin bundles.

### How do I make a skill available to Claude Code?

Create a symbolic link from `.claude/skills/<kebab-name>` pointing to `../../.agents/skills/<kebab-name>`. This symlink allows Claude Code agents to load the skill definition directly from the canonical source rather than from a potentially stale copy.

### How do I prevent skills from drifting out of sync?

Run the sync-check validation script to ensure all entries in `.claude/skills/` are symlinks pointing to valid directories in `.agents/skills/`. Additionally, the test suite in [`src/server/features/sam/samSkills.test.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/samSkills.test.ts) will fail if the skill roster does not match the actual available skills, catching registration errors before deployment.