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:
npx skills add https://www.yoursite.comThe 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:
npx skills add yoursite.comThen 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:
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
public/
└── .well-known/
└── agent-skills/
├── index.json
└── my-first-skill/
└── SKILL.mdPublic 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:
{
"skills": [
{
"name": "my-first-skill",
"description": "Product onboarding guide for developers starting from zero.",
"files": ["SKILL.md"]
}
]
}2. Write SKILL.md with YAML frontmatter
---
name: my-first-skill
description: "Product onboarding guide for developers starting from zero."
user-invocable: true
---
# My product — Getting startedFrontmatter is required for the npx skills ecosystem.
3. CORS headers (Next.js example)
{
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
npx skills add https://www.yoursite.com6. Deploy and end-to-end test
curl -s https://www.yoursite.com/.well-known/agent-skills/index.json
npx skills add https://www.yoursite.comIf 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
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