How Skills Are Defined and Executed in the OpenSEO Audit System

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) 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.

---
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. 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 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 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). 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:

{
  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 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:

---
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 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 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. The build system in 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. 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) 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →