# How Skills Are Defined and Executed in the OpenSEO Audit System

> Discover how OpenSEO defines and executes SEO skills using Markdown and a type-safe catalog. Learn how the SAM chat agent activates these reusable workflows for powerful audits.

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

---

**OpenSEO bundles reusable SEO workflows as Markdown-based skills that are parsed at build time into a type-safe catalog and executed by the SAM chat agent through the `activate_skill` tool call.**

The open-seo repository from every-app implements a declarative skill system where SEO audit workflows are defined as Markdown documents, compiled into a searchable catalog during the Vite build process, and invoked by AI agents through a controlled execution environment. This architecture allows the platform to maintain a curated library of SEO techniques while ensuring that automated agents operate within strict sandboxed boundaries.

## Skill Definition Structure

OpenSEO skills are not hard-coded TypeScript functions but rather declarative Markdown files stored in the hidden `.agents/skills/` directory. Each skill follows a standardized format that separates metadata from execution instructions.

### Markdown Files with YAML Frontmatter

Every skill resides in its own subdirectory (e.g., [`/.agents/skills/keyword-research/SKILL.md`](https://github.com/every-app/open-seo/blob/main//.agents/skills/keyword-research/SKILL.md)) and begins with a YAML frontmatter block containing a mandatory `name` and `description`. An optional `metadata.internal` boolean flag marks skills as internal-only, preventing them from appearing in the public catalog.

```yaml
---
name: Keyword Research
description: Generate a list of keyword ideas for a domain.
metadata:
  internal: false
---

```

The remainder of the file contains step-by-step instructions that guide the AI agent through the SEO workflow. These instructions are plain text directives that the agent interprets, such as "Fetch the target URL" or "Run Lighthouse audit with strategy `mobile`."

### Internal vs Public Skills

Skills marked with `metadata.internal: true` are automatically filtered out during the build process in [`src/server/features/sam/samSkills.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/samSkills.ts). Additionally, the system specifically excludes the special "simple-issue-description" skill from public exposure, ensuring that only vetted, user-facing workflows appear in the catalog returned by `SkillSource.list()`.

## Build-Time Bundling and Validation

The transformation of Markdown files into executable skill objects happens during the Vite build via the [`samSkills.ts`](https://github.com/every-app/open-seo/blob/main/samSkills.ts) module. This process ensures type safety and prepares the skills for runtime consumption.

### Globbing Skill Files with Vite

The build system uses `import.meta.glob<string>("/.agents/skills/*/SKILL.md", { query: "?raw", eager: true })` to eagerly load all skill files as raw text strings. This Vite-specific glob pattern captures every [`SKILL.md`](https://github.com/every-app/open-seo/blob/main/SKILL.md) file nested within skill-specific directories under `.agents/skills/`.

### Parsing and Schema Validation with Zod

The `parseSkill()` function processes each raw Markdown file using regular expressions to extract the YAML frontmatter. The extracted metadata undergoes strict validation against a Zod schema (`frontmatterSchema`) that enforces the presence of required fields like `name` and `description`. Any file failing validation is discarded, ensuring that only well-formed skills enter the catalog.

### The SAM Surface Note Injection

Before skills are stored in the catalog, the system prefixes each skill body with a SAM surface note (lines 21-33 of [`samSkills.ts`](https://github.com/every-app/open-seo/blob/main/samSkills.ts)). This programmatically injected header instructs the AI agent to skip steps that require external verification, local filesystem operations, or MCP connection checks—actions that are irrelevant or unsafe within the OpenSEO UI context. This transformation ensures that skills execute safely within the platform's sandboxed environment.

## The SkillSource API Interface

Once parsed, skills are exposed through a standardized `SkillSource` interface constructed by `buildSamSkillSource()`. This abstraction layer decouples the storage mechanism from the execution runtime.

### Building the Catalog with buildSamSkillSource

The `buildSamSkillSource()` function returns an object adhering to the following interface:

```typescript
{
  id: "openseo-public-skills",
  fingerprint: "<hash>",
  list: () => Promise.resolve([{ name, description }]),
  load: (name) => Promise.resolve(skills.find(s => s.name === name) ?? null)
}

```

The `list()` method provides the UI and CLI tools (such as `npx skills add`) with an alphabetically sorted array of available public skills. The `load(name)` method retrieves the complete skill body—including the prepended SAM surface note—for execution when a specific skill is requested by name.

### Fingerprinting for Deployment Detection

To support cache invalidation and deployment tracking, the system computes a DJB2 content hash (`fingerprint`) across all parsed skill definitions. Think's registry uses this fingerprint to detect when a new deployment changes the skill catalog, ensuring that distributed clients always reference the current skill definitions and invalidate stale caches when the hash changes.

## Runtime Execution Flow

Skill execution occurs through the SAM (Search-Agent-Mode) chat system, where AI agents invoke skills via structured tool calls rather than direct function execution.

### Activating Skills via Tool Calls

When a user or automated workflow requests a skill, the AI agent generates a tool call named `activate_skill` with the target skill name as an argument. This indirection layer allows the system to intercept skill requests and apply runtime policies before execution begins.

### Handling Execution in SamChatAgent

The `SamChatAgent` class in [`src/server/features/sam/SamChatAgent.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/SamChatAgent.ts) listens for the `sam:skill_activated` event. Upon receiving an activation request, the agent:

1. Extracts the skill name from the tool call arguments.
2. Invokes `SkillSource.load(name)` to retrieve the prepared skill body.
3. Forwards the content to the MCP client (e.g., Claude Code).

Because the skill body already contains the SAM surface note, the executing agent automatically bypasses steps requiring local filesystem access or external authentication flows. Instead, the agent writes durable outputs using `update_project_context`, storing results directly in the project's database.

### Runtime Constraints and Context Updates

The surface note guarantees that skills executed inside OpenSEO respect platform boundaries: no direct filesystem access, no additional authentication flows, and all persistent data storage occurs through the sanctioned `update_project_context` mechanism. This constraint model allows the same skill definitions to run safely in both local development environments (where filesystem access might be permitted) and the production OpenSEO platform.

## Adding Custom Skills to OpenSEO

Creating new audit capabilities requires only adding a Markdown file to the skills directory. For example, to create a custom Lighthouse audit skill:

```markdown
---
name: My Custom Skill
description: Demonstrates a new workflow.
metadata:
  internal: false
---
1. Fetch the target URL.
2. Run Lighthouse audit with strategy `mobile`.
3. Store results using `update_project_context`.

```

After rebuilding the application, [`samSkills.ts`](https://github.com/every-app/open-seo/blob/main/samSkills.ts) automatically re-runs the glob pattern, parses the new skill, updates the DJB2 fingerprint, and exposes the skill through the `SkillSource` interface without requiring changes to the TypeScript source code.

## Summary

- **Skills are Markdown-based**: OpenSEO defines SEO workflows as Markdown files with YAML frontmatter stored in `/.agents/skills/*/SKILL.md`, separating metadata from execution logic.
- **Build-time validation**: The [`samSkills.ts`](https://github.com/every-app/open-seo/blob/main/samSkills.ts) module uses `import.meta.glob` to collect files, Zod schemas to validate frontmatter, and injects runtime constraints via the SAM surface note.
- **Type-safe catalog**: The `SkillSource` interface exposes skills through `list()` and `load()` methods, with DJB2 fingerprinting for deployment tracking.
- **Controlled execution**: The `SamChatAgent` handles `activate_skill` tool calls, retrieves prepared skill bodies, and forwards them to MCP clients while enforcing sandbox boundaries.
- **Context persistence**: All skill outputs are written using `update_project_context` rather than filesystem operations, ensuring durability within the OpenSEO platform.

## Frequently Asked Questions

### Where are skill files stored in the OpenSEO repository?

Skill files reside in the hidden `.agents/skills/` directory at the repository root. Each skill occupies its own subdirectory (e.g., `/.agents/skills/keyword-research/`) and must be named [`SKILL.md`](https://github.com/every-app/open-seo/blob/main/SKILL.md). The build system in [`src/server/features/sam/samSkills.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/samSkills.ts) specifically looks for this pattern using the glob `/.agents/skills/*/SKILL.md`.

### How does OpenSEO prevent internal skills from being exposed publicly?

The system checks the `metadata.internal` flag in each skill's YAML frontmatter during the parsing phase in [`samSkills.ts`](https://github.com/every-app/open-seo/blob/main/samSkills.ts). Skills marked with `internal: true` are filtered out of the public catalog and excluded from the `SkillSource.list()` results. The system also explicitly filters out the "simple-issue-description" skill regardless of its metadata flags.

### What is the purpose of the SAM surface note in skill execution?

The SAM surface note is programmatically injected into skill bodies during build time (lines 21-33 of [`samSkills.ts`](https://github.com/every-app/open-seo/blob/main/samSkills.ts)) to modify agent behavior at runtime. It instructs the AI to skip steps involving local filesystem verification, MCP connection checks, or project selection dialogs—operations that are unnecessary or unsafe within the OpenSEO UI—ensuring skills execute safely using only the `update_project_context` mechanism for data persistence.

### How does the system detect when new skills are deployed?

OpenSEO computes a DJB2 content hash (`fingerprint`) across all parsed skill definitions during the build process. This fingerprint is exposed through the `SkillSource` interface and consumed by Think's registry. When the fingerprint changes between deployments, the registry detects the new catalog version and invalidates cached skill lists accordingly.