DEV Community

Cover image for Your product has an API. It still doesn't speak agent
pratikbin
pratikbin

Posted on • Edited on

Your product has an API. It still doesn't speak agent

Most developer tools are built for two audiences: humans and software. Humans get docs and dashboards. Software gets APIs, SDKs, and CLIs. Agents sit awkwardly in the middle. They can read, they can call APIs, they can follow instructions, but they still can't answer a basic question when they land on your domain: what does this product actually know how to help me do? Ready to copy prompt at the end

I think that's a real gap. We just closed it on CreateOS, and more companies should do the same.

Agents still need to be told everything

If Claude Code or OpenCode needs to deploy an app, it doesn't automatically know your platform exists. You can put instructions in CLAUDE.md; we do that too. But that only helps inside a specific repo. An MCP server helps, but only after someone installs it. llms.txt is useful, but it's descriptive. It tells an agent what your product is, not how to use it.

So today, most agents are still operating on tribal knowledge and prompt glue. That's not a great long-term interface.

The Agent Skills Discovery RFC is a clean fix for this. Think robots.txt, but for product capabilities.

What we shipped

Starting today, https://createos.nodeops.network/.well-known/agent-skills/index.json returns a machine-readable index of every skill our platform offers:

{
  "$schema": "<https://schemas.agentskills.io/discovery/0.2.0/schema.json>",
  "skills": [
    {
      "name": "createos",
      "type": "archive",
      "description": "Deploy ANYTHING to production on CreateOS cloud platform...",
      "url": "/.well-known/agent-skills/createos.tar.gz",
      "digest": "sha256:740b1bf8c464aa6148a3eb9d666f2542..."
    },
    {
      "name": "nodeops-auth",
      "type": "skill-md",
      "description": "Add NodeOps PKCE OAuth authentication to a Next.js app...",
      "url": "/.well-known/agent-skills/nodeops-auth/SKILL.md",
      "digest": "sha256:ca197a7ca9fbc5561a6b71c02ea3652..."
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

An agent fetches one URL and gets the shortlist. Roughly 100 tokens per skill. No repo cloning, no scraping docs, no custom integration work just to understand what the platform can do.

When the task matches something specific like "deploy my app" or "add NodeOps auth," the agent pulls only that skill, verifies the sha256 digest, and moves on.

Progressive disclosure is the part they got right

The smartest part of the RFC is that it doesn't force you to dump everything into context up front.

Level What When Cost
1 name + description from index.json Startup / probing ~100 tokens/skill
2 Full SKILL.md body When skill is activated <5k tokens
3 Scripts, references, configs On demand As needed

Our createos skill bundles deployment scripts, API references, and config templates at about 28 KB. An agent working on a simple auth task never has to touch any of that. It grabs nodeops-auth/SKILL.md at about 6 KB and moves on. That's the whole point. Context is expensive. Don't waste it.

How we built it

We kept the implementation boring on purpose: one build-time script and static files.

No route handlers. No cold starts. No database read just to answer a well-known URL.

Build pipeline (scripts/build-agent-skills.mts, about 200 lines):

  1. git clone --depth 1 the skills repo into .agent-skills-src/
  2. For each skill directory, read SKILL.md, parse frontmatter (name, description)
  3. If the skill is just a SKILL.md → copy it. If it has supporting files → tar.gz it
  4. Compute sha256 digests, write index.json

It runs as a prebuild hook before every next build and build:cloudflare, so the published skills stay in sync with upstream.

Serving is just static files in public/.well-known/agent-skills/ behind Cloudflare Pages. Three header rules in next.config.ts handle the RFC requirements:

  • index.jsonapplication/json; charset=utf-8 + CORS + max-age=60, s-maxage=300
  • .mdtext/markdown; charset=utf-8 + CORS + max-age=300, s-maxage=3600
  • .tar.gzapplication/gzip + CORS + max-age=300, s-maxage=3600

We keep the index TTL short so new skills show up quickly. Artifacts get a longer TTL because they're digest-pinned. If the sha256 matches, the file is still the file.

Serving cost is basically zero because it's static content on a CDN.

Why more companies should publish this

If you run a platform, an API, or a developer tool, you should seriously consider publishing /.well-known/agent-skills/.

First, it's cheap. A SKILL.md, some frontmatter, a small build step, and a few headers. We did the first version in an afternoon.

Second, it's standard. You're not inventing another one-off agent integration. You're publishing something any RFC-compliant client can understand.

Third, it composes well. Our createos skill teaches an agent how to deploy. Our nodeops-auth skill teaches it how to wire auth. Another vendor can publish observability or billing or incident-response skills the same way. The agent can mix and match without every platform building a separate integration for every other platform.

And finally, it's probably where this goes anyway. Claude Code doesn't auto-probe /.well-known/agent-skills/ yet. OpenCode doesn't either. Fine. robots.txt was useful before every crawler agreed on it too. Standards usually show up before the tooling catches up.

The trade-off

This is still pull, not push. Agents need to know your domain exists before they can ask for /.well-known/agent-skills/index.json.

So no, this doesn't solve discovery all by itself. There's no master directory yet. In practice, the bridge is simple: mention the URL in your docs, your AGENTS.md, your MCP server docs, or your llms.txt. That's enough to make it usable today while clients catch up.

How to add it to your product

  1. Write your skills. Create a directory per skill with a SKILL.md. The frontmatter needs name and description. The body is instructions for the agent. That's the whole format.
  2. Package and serve. Solo skills ship as plain SKILL.md. Skills with supporting files (scripts, references) ship as .tar.gz. Compute sha256 digests. Write index.json.
  3. Add headers. Content-Type, Access-Control-Allow-Origin: *, and tiered Cache-Control. Three URL patterns.
  4. Publish. Put it behind your domain. https://your-domain.com/.well-known/agent-skills/index.json. Done.

RFC implementation on https://nodeops.networ

The RFC is here. The schema is here.

How to use it

# this will fail
npx skills add https://createos.nodeops.network -y
Enter fullscreen mode Exit fullscreen mode

there is active issue on skills to add support for RFC v0.2.0

Or just hand this to your coding agent

Don't feel like reading a build script? Fill in the four inputs at the top, paste this into Claude Code, Cursor, or Copilot inside the target repo, and let it wire everything up.

Add [Agent Skills Discovery RFC v0.2.0](https://github.com/cloudflare/agent-skills-discovery-rfc) to this site so agents auto-discover our skills at `/.well-known/agent-skills/index.json`.

**Inputs** (fill in before pasting):
- **Skills source**: `<git URL of repo holding skills>` on branch `<ref>`, skills live under path `<skills/skills>` (each subdir = one skill with a `SKILL.md` containing `name` + `description` frontmatter).
- **Host framework**: `<Next.js app router | Astro | SvelteKit | plain static | Express | other>`.
- **Public dir**: `<public | static | dist | ...>`.
- **Production origin**: `<https://example.com>`.

**Deliverables** (do all):

1. **Build script** (zero new deps; Node built-ins + system `git` + system `tar`):
   - Clone the skills repo shallow (`git clone --depth 1 --branch <ref>`) into a gitignored `.agent-skills-src/`. Re-runs do `git fetch && git reset --hard FETCH_HEAD`.
   - Iterate each skill dir under the configured path. Read `SKILL.md`, parse YAML frontmatter, require `name` + `description`. Validate `name` against `^[a-z0-9]+(-[a-z0-9]+)*$`, length 1–64. Fail build on violation.
   - If dir contains only `SKILL.md` → copy to `<public>/.well-known/agent-skills/<name>/SKILL.md`, `type: "skill-md"`.
   - Else → `tar -czf <public>/.well-known/agent-skills/<name>.tar.gz --sort=name --mtime=@<upstream-commit-ts> -C <skill-dir> .`, `type: "archive"`. Fall back without repro flags on BSD tar.
   - Compute `sha256:<hex>` over the served artifact bytes.
   - Write `<public>/.well-known/agent-skills/index.json`:
     ```

json
     { "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json",
       "skills": [{ "name": "...", "type": "skill-md|archive", "description": "...", "url": "/.well-known/agent-skills/...", "digest": "sha256:..." }] }


     ```
   - Sort skills alphabetically by `name` (stable digest of `index.json`).

2. **Wire as prebuild hook** for the host framework (e.g. npm `prebuild` script, Astro integration, CI step) so output regenerates on every deploy.

3. **HTTP response headers** (per framework's config — `next.config.ts` `headers()`, `astro.config` headers adapter, `_headers` for Pages/Netlify, nginx/express middleware, etc.):
   - `/.well-known/agent-skills/index.json``Content-Type: application/json; charset=utf-8`, `Access-Control-Allow-Origin: *`, `Cache-Control: public, max-age=60, s-maxage=300`.
   - `/.well-known/agent-skills/*.md``Content-Type: text/markdown; charset=utf-8`, `Access-Control-Allow-Origin: *`, `Cache-Control: public, max-age=300, s-maxage=3600`.
   - `/.well-known/agent-skills/*.tar.gz``Content-Type: application/gzip`, `Access-Control-Allow-Origin: *`, `Cache-Control: public, max-age=300, s-maxage=3600`.

4. **Gitignore**: `.agent-skills-src/` and `<public>/.well-known/agent-skills/`.

5. **Verify locally**:
   - `curl -sS http://localhost:<port>/.well-known/agent-skills/index.json | jq .` returns valid JSON with `$schema` + `skills[]`.
   - Re-hash every served artifact and confirm match against `digest` in the index.
   - Response headers match section 3.

6. **Post-deploy check**: same three `curl` calls against the production origin.

**Constraints**:
- Do not add runtime dependencies. Hand-parse the two frontmatter fields (`name:` and `description:`) with a regex — full YAML is overkill here.
- Static output only. No server route handler — agents must be able to fetch from edge/CDN with no origin cold start.
- Never commit generated artifacts or the cloned skills repo.
- Skip skills with missing/invalid frontmatter with a warning. Hard-fail on bad `name` format.

**Reference implementation** (adapt, don't copy-paste): https://github.com/cloudflare/agent-skills-discovery-rfc/tree/main/examples

Return a summary of: files created, files modified, verification commands run, and production URL of the new `index.json`.
```

`

Four inputs in, working `/.well-known/agent-skills/` out. No runtime deps, static output, deploy hook wired.

Agents are already reading `llms.txt`. They're already talking to MCP servers. This fills a different gap: a standard way to publish what your product can help an agent do.

If you build developer tools, I think you should publish one.

Agents are already reading `llms.txt`. They're already talking to MCP servers. This fills a different gap: a standard way to publish what your product can help an agent do.

If you build developer tools, I think you should publish one.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)