Agent Plugins 1.0 is on daily.dev. Ask Ayush still swallows one FACTS dump

Amazon, Cursor, Google, Microsoft, OpenAI, and Vercel agreed on a plugin folder. I still paste the whole site into Gemini on every question. Here is the first file I would extract — and the one plugin I would not install.

I opened daily.dev this morning and the feed was the same argument in ten tabs. Agent Plugins 1.0. Skills. MCP. A vendor-neutral folder. Then I opened server/knowledge.ts. buildAssistantKnowledge() still concatenates projects, blog notes, and experience into one string and I send that string on every chat turn. That is not a plugin. That is a paste.

The spec is small on purpose. A plugin is a directory. plugin.json at the root. Skills live in skills/, one folder each, in the Agent Skills format people already ship. MCP servers are declared in mcp.json with an explicit type so a client does not have to guess stdio from the shape of a config object. Cursor, VS Code, Copilot, ChatGPT, and Codex all check the same places. Amazon, Cursor, Google, Microsoft, OpenAI, and Vercel sit on the steering committee. I have not read a contract. I have read the folder layout. That is enough to be embarrassed.

The spec packages skills and MCP servers. It does not install them, bless them, or decide what they are allowed to touch.

Agent Plugins 1.0, the part the feed keeps skipping

Vercel started the proposal. Google joined the committee the same day and shipped Agents CLI plus a Data Agent Kit in the format. The interesting part is not who announced it. It is that five companies that sell agents agreed on a directory.

Step 1: Stop sending the whole site for “is this a name?”

Ask Ayush already classifies work. Name checks should not see SyBazar. A hire question should see the FACTS. A NestJS question can leave the portfolio dump behind. I wrote that split last week and then left knowledge.ts as one function. Agent Plugins just gave me a name for the file I should have extracted.

# Portfolio facts

Use this skill only when the visitor asks about Ayush,
this site, hiring, or a shipped project.

Do not invent rates, clients, or work that is not listed.
If a fact is missing, say so and point to
adhikariayush19@gmail.com.

## Load
- name, title, stack, and license
- project list with URLs
- blog slugs as /blog/<slug>
- never the full article bodies

That is a skill. It is instructions plus a boundary. I can keep generating the live facts from the same TypeScript that already builds the site. I just stop gluing them to the system prompt when the visitor typed asdfghjk in the name field.

Step 2: Give Ask Ayush a plugin.json I can open

I am not publishing this to a marketplace this week. I want a folder on this repo that Cursor and a future MCP client can both read without me inventing a second format. The $schema line is the whole point of 1.0 — a client knows which version I meant.

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "ask-ayush",
  "version": "0.1.0",
  "description": "Read-only facts about this portfolio. No filesystem. No cloud wipe."
}
{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
  "mcpServers": {
    "portfolio-facts": {
      "type": "stdio",
      "command": "node",
      "args": ["server/portfolio-mcp.js"]
    }
  }
}

The server, if I write it, answers three tools: listProjects, getPost, and getContact. It does not get a shell. It does not get AWS. It does not get --trust-all-tools. That flag is how a prompt becomes a wipe, and I do not want it anywhere near a chat that already sits on this domain.

What I will not install daily.dev also recirculated the Amazon Q Developer story this week. A malicious commit reached a VS Code extension. The payload was a prompt that told an agent to clear a machine and delete cloud resources. AWS says a syntax error stopped it. That is luck, not a design. I will not load a plugin I cannot open, and I will not give Ask Ayush a tool that can write the disk.

Step 3: Keep FACTS as data, not as prompt folklore

buildAssistantKnowledge() is useful. It is also the reason the name-check path is expensive. I would split it so the skill file and the chat prompt read the same object. One source. Two doors.

import { projects } from "../src/data/projects.js";
import { blogPosts } from "../src/data/blog.js";

export type PortfolioFacts = {
  name: string;
  email: string;
  stack: string;
  projects: { name: string; url: string | null }[];
  notes: { slug: string; title: string }[];
};

export function portfolioFacts(): PortfolioFacts {
  return {
    name: "Er. Ayush Adhikari",
    email: "adhikariayush19@gmail.com",
    stack: "Node.js, NestJS, MERN, PostgreSQL, Prisma",
    projects: projects.map((project) => ({
      name: project.name,
      url: project.url,
    })),
    notes: blogPosts.map((post) => ({
      slug: post.slug,
      title: post.title,
    })),
  };
}

export function factsFor(task: "name-check" | "portfolio" | "general") {
  if (task === "name-check") return null;
  if (task === "general") return { stack: portfolioFacts().stack };
  return portfolioFacts();
}

Step 4: What I am not doing because of a headline

The feed will move on. The useful part is boring. Skills are instructions with a boundary. MCP is a tool list with a transport. Agent Plugins is just those two things in places every client already agreed to look. I already have the facts. I have been pasting them. That is the change.