# Self-Host Agent Skills on Your Website

Your website can host installable AI skills — you don't need GitHub. I set this up with Next.js on a production app; the tricky part was getting the www redirect right so npx skills add works, and giving agents persistent product context instead of making things up.

## Context

If you already ship llms.txt, you gave agents a **map** of your documentation. **Agent skills** go further: installable packages a developer adds to Cursor, Claude Code, Copilot, or other editors with one command:

```bash
npx skills add https://www.yoursite.com
```

The CLI downloads a manifest from your domain, reads each SKILL.md, and installs it into the user's editor. You do not need GitHub or skills.sh — **your website is the registry**.

I implemented this on a production Next.js app, but the mechanism works on any host: any server that exposes static files at /.well-known/agent-skills/ works (Vite, Astro, Nginx, S3 + CloudFront, etc.). Next.js just makes deploy easy because public/ is served as-is.

## Why it can matter

It is not mandatory for every site. But if you ship a product, an API, or a platform where **developers integrate before signing up**, it starts to matter.

Many people no longer open docs in a browser — they ask their editor's agent. If your product is not installed as a skill, the model answers from generic knowledge: mixed versions, invented endpoints, or stale pages even when your docs are fine online. I saw that with concrete integration questions before shipping a public skill.

Self-hosting a skill on your domain gives you things a GitHub repo or a loose link does not cover as well:

- **One-command onboarding** — people trying your product don't hunt through docs first; they install and the editor knows where to start.
- **Persistent context** — llms.txt guides one browsing session; a skill stays in the editor for every coding conversation.
- **You control the version** — update SKILL.md, deploy, and reinstalls pick up the new guide. No waiting for a third-party registry to index your repo.
- **Your own distribution channel** — the same domain you already use for docs also serves the install.
- **Fewer invented answers** — a well-written skill bounds stack, auth, limits, and real flows. The agent improvises less.

For a personal blog or portfolio it may be overkill. For SaaS, an SDK, or integration docs you want agents to **cite correctly**, it is worth considering — and the technical cost is low if you already have a static site or Next.js.

## How this differs from llms.txt

- **\`llms.txt\`** (/llms.txt) — Curated link index so agents know what to read.
- **Agent skills** (/.well-known/agent-skills/ or /.well-known/skills/) — Installable packages with embedded workflows and context.

They complement each other. Use both if you want discoverability **and** one-command install.

## Discovery flow

When someone runs npx skills add https://www.yoursite.com, the CLI:

- Fetches the manifest at /.well-known/agent-skills/index.json or /.well-known/skills/index.json (the CLI tries both)
- Reads the skill list (name, description, files)
- Downloads each SKILL.md (and extra files if declared)
- Installs them into the editor's skills folder

Your job: serve that JSON and Markdown stably, with consistent absolute URLs and **no redirect surprises**.

## The problem that cost me the most time: www vs apex

The bug was not Next.js or JSON shape. It was the **canonical host**.

I had apex (yoursite.com) redirecting to www.yoursite.com at Vercel/DNS. The landing hero showed:

```bash
npx skills add yoursite.com
```

Then https://yoursite.com. The CLI still failed or behaved oddly because:

- The first fetch hit apex
- Vercel returned **301/308** to www
- Some clients mishandle redirect chains, change the base host, or resolve paths against the wrong host
- The manifest might exist on both hosts in theory, but the **install URL** must point to the host that returns **200 directly**

**Fix:** pick one canonical host (https://www.yoursite.com) and use it **everywhere** — install command, env vars, llms.txt, sitemap, OG tags, docs.

**Verify before publishing the command:**

```bash
curl -sI https://www.yoursite.com/.well-known/agent-skills/index.json   # expect 200
curl -sI https://yoursite.com/.well-known/agent-skills/index.json       # if 301/308, do NOT use apex in npx
curl -s https://www.yoursite.com/.well-known/agent-skills/index.json | jq .
```

If apex redirects and www returns 200, your public npx skills add URL **must be www**.

## File layout

```text
public/
└── .well-known/
    └── agent-skills/
        ├── index.json
        └── my-first-skill/
            └── SKILL.md
```

Public installable skills live here. Internal dev skills can stay in .agents/skills/ (see note 006).

## Steps to implement

### 1. Create folders and manifest

public/.well-known/agent-skills/index.json:

```json
{
  "skills": [
    {
      "name": "my-first-skill",
      "description": "Product onboarding guide for developers starting from zero.",
      "files": ["SKILL.md"]
    }
  ]
}
```

### 2. Write SKILL.md with YAML frontmatter

```markdown
---
name: my-first-skill
description: "Product onboarding guide for developers starting from zero."
user-invocable: true
---

# My product — Getting started
```

Frontmatter is **required** for the npx skills ecosystem.

### 3. CORS headers (Next.js example)

```typescript
{
  source: '/.well-known/:path*',
  headers: [
    { key: 'Access-Control-Allow-Origin', value: '*' },
    { key: 'Access-Control-Allow-Methods', value: 'GET, OPTIONS' },
  ],
},
```

### 4. Pin canonical URL in code

One env-backed constant (WEBSITE\_URL) used across sitemap, metadata, and docs — always the host that returns 200 without redirects.

### 5. Ship the install command on your site

```bash
npx skills add https://www.yoursite.com
```

### 6. Deploy and end-to-end test

```bash
curl -s https://www.yoursite.com/.well-known/agent-skills/index.json
npx skills add https://www.yoursite.com
```

If it fails, check in order: **www redirect** → valid JSON → YAML frontmatter → CORS → CDN cache.

## Common mistakes

- **CLI finds no skills** — The install URL often uses apex (yoursite.com) while that host redirects to www. Use the canonical host that returns **200** without a redirect hop.
- **404 on \`index.json\`** — Files are missing from public/ or the path is wrong. Compare the local folder with the production URL.
- **Missing metadata** — YAML frontmatter is missing at the top of the file. Add name, description, and user-invocable.
- **curl works, browser fails** — CORS is missing on /.well-known/\*. Add headers in next.config.ts, Nginx, or CloudFront.
- **Skill update does not show up** — The CDN cached the old response. Purge cache or lower Cache-Control on those routes.

## Quick reference

```text
Manifest:  /.well-known/agent-skills/index.json
Skill:     /.well-known/agent-skills/{name}/SKILL.md
Install:   npx skills add https://www.yoursite.com
Next.js:   public/.well-known/... + CORS in next.config.ts
Canonical: one host everywhere — code, docs, install command
Verify:    curl -sI manifest → 200; then npx skills add
```
