writing-skills
writing-skills
Use when creating new skills, editing existing skills, or verifying skills work before deployment
aixyzBuild, run, and deploy an AI agent using the aixyz framework. Use this skill when creating a new agent, adding tools, wiring up A2A/MCP protocols, configuring x402 micropayments, or deploying to Vercel.
Independent GitHub snapshot · Automated classification · Original documentation governs
Use this skill when:
All CLI commands support --help for full usage details. Use --help to discover available options.
# See all options
bunx create-aixyz-app --help
# Interactive (TTY)
bunx create-aixyz-app my-agent
# Non-interactive (recommended for AI/CI)
bunx create-aixyz-app my-agent --yes
bunx create-aixyz-app my-agent --erc-8004 --pay-to 0x... --no-install
--openai-api-keyis optional — if omitted, setOPENAI_API_KEYin.env.localbefore running the agent. The scaffolded template uses@ai-sdk/openaiby default, but you can swap it for any Vercel AI SDK provider adapter (e.g.@ai-sdk/anthropic,@ai-sdk/google,@ai-sdk/amazon-bedrock).
This creates the standard project layout:
my-agent/
aixyz.config.ts # Agent metadata and skills
app/
agent.ts # Agent definition
tools/ # One file per tool
icon.png # Agent icon (optional)
package.json
vercel.json
aixyz.config.ts)Every agent needs a config file at the project root. Declare identity, payment address, and skills:
import type { AixyzConfig } from "aixyz/config";
const config: AixyzConfig = {
name: "My Agent",
description: "A short description of what this agent does.",
version: "0.1.0",
x402: {
payTo: process.env.X402_PAY_TO!,
network: process.env.NODE_ENV === "production" ? "eip155:8453" : "eip155:84532",
},
skills: [
{
id: "my-skill",
name: "My Skill",
description: "What this skill does for callers.",
tags: ["example"],
examples: ["Do something with my skill"],
},
],
};
export default config;
accepts export (aixyz/accepts)Every agent and tool controls whether it requires payment by exporting accepts from aixyz/accepts.
Without this export, the endpoint is not registered for payment gating.
import type { Accepts } from "aixyz/accepts";
// Require x402 micropayment
export const accepts: Accepts = {
scheme: "exact",
price: "$0.001", // USD-denominated
network: "eip155:8453", // optional — defaults to config.x402.network
payTo: "0x...", // optional — defaults to config.x402.payTo
};
// Or make the endpoint free
export const accepts: Accepts = {
scheme: "free",
};
Export accepts from app/agent.ts to gate the A2A endpoint, or from a tool file to gate that tool via MCP.
app/tools/<name>.ts)Each file in app/tools/ exports a Vercel AI SDK tool as its default export:
import { tool } from "ai";
import { z } from "zod";
import type { Accepts } from "aixyz/accepts";
export const accepts: Accepts = { scheme: "exact", price: "$0.001" };
export default tool({
description: "A short description of what this tool does.",
inputSchema: z.object({
query: z.string().describe("Input to the tool"),
}),
execute: async ({ query }) => {
// your logic here
return { result: query };
},
});
Files prefixed with _ (e.g. _helpers.ts) are ignored by the auto-generated server.
app/agent.ts)The default template uses @ai-sdk/openai, but you can use any Vercel AI SDK provider adapter:
// OpenAI (default in template)
import { openai } from "@ai-sdk/openai";
// Or swap the model provider — install the adapter and change the import:
// import { anthropic } from "@ai-sdk/anthropic"; // set ANTHROPIC_API_KEY
// import { google } from "@ai-sdk/google"; // set GOOGLE_GENERATIVE_AI_API_KEY
import { stepCountIs, ToolLoopAgent } from "ai";
import type { Accepts } from "aixyz/accepts";
import myTool from "./tools/my-tool";
export const accepts: Accepts = { scheme: "exact", price: "$0.005" };
export default new ToolLoopAgent({
model: openai("gpt-4o-mini"), // replace with anthropic("claude-..."), google("gemini-..."), etc.
instructions: "You are a helpful assistant.",
tools: { myTool },
stopWhen: stepCountIs(10),
});
app/agents/<name>.ts)Place additional agent files in app/agents/ to expose multiple independent A2A endpoints from one deployment.
Each filename becomes a URL prefix:
app/
agent.ts # → /agent (main)
agents/
math.ts # → /math/agent
text.ts # → /text/agent
Each sub-agent file has the same structure as app/agent.ts:
import { openai } from "@ai-sdk/openai";
import { stepCountIs, ToolLoopAgent } from "ai";
import type { Accepts } from "aixyz/accepts";
import calculate from "../tools/calculate";
export const accepts: Accepts = { scheme: "exact", price: "$0.001" };
export default new ToolLoopAgent({
model: openai("gpt-4o-mini"),
instructions: "You are a math specialist. Use the calculate tool for arithmetic.",
tools: { calculate },
stopWhen: stepCountIs(5),
});
Sub-agents share the same /mcp endpoint for tools and each get their own agent card:
/math/.well-known/agent-card.json/math/agentSee examples/agent-with-sub-agents for a working example with a coordinator + two specialists.
.env files)Environment variables are loaded in the same priority order as Next.js:
.env.<NODE_ENV>.local (highest priority; not loaded when NODE_ENV=test).env.local.env.<NODE_ENV> (e.g. .env.production, .env.development).envCommon variables:
| Variable | Description |
|---|---|
X402_PAY_TO | Default EVM address to receive payments |
X402_NETWORK | Default payment network (e.g. eip155:8453) |
X402_FACILITATOR_URL | Custom facilitator URL (default: https://x402.use-agently.com/facilitator) |
OPENAI_API_KEY | OpenAI API key |
app/icon.png)Place an icon file at app/icon.png (also accepts .svg, .jpeg, .jpg). During aixyz build it is:
icon.pngfavicon.ico (32×32) and placed in public/No configuration needed — the build step auto-detects and processes the icon.
app/accepts.ts)By default, aixyz uses https://x402.use-agently.com/facilitator to verify payments. To use a different
facilitator, create app/accepts.ts and export a facilitator:
import { HTTPFacilitatorClient } from "aixyz/accepts";
export const facilitator = new HTTPFacilitatorClient({
url: process.env.X402_FACILITATOR_URL ?? "https://www.x402.org/facilitator",
});
bun run dev # aixyz dev — starts at http://localhost:3000 with hot reload
bun run dev -- -p 4000 # custom port
Endpoints served automatically:
| Endpoint | Protocol | Description |
|---|---|---|
/.well-known/agent-card.json | A2A | Agent discovery |
/agent | A2A | JSON-RPC, x402 payment gate |
/mcp | MCP | Tool sharing with MCP clients |
app/server.ts)For full control, create app/server.ts. It takes precedence over auto-generation.
The accepts field in mcp.register is optional — omit it to expose the tool without payment gating:
import { AixyzServer } from "aixyz/server";
import { useA2A } from "aixyz/server/adapters/a2a";
import { AixyzMCP } from "aixyz/server/adapters/mcp";
import * as agent from "./agent";
import myTool from "./tools/my-tool";
const server = new AixyzServer();
await server.initialize();
server.unstable_withIndexPage();
useA2A(server, agent);
const mcp = new AixyzMCP(server);
await mcp.register("myTool", {
default: myTool,
// accepts is optional — omit to expose without payment
accepts: { scheme: "exact", price: "$0.001" },
});
await mcp.connect();
export default server;
bun run build # aixyz build — outputs Vercel Build Output API v3 to .vercel/output/
vercel deploy
Working examples in the repo: examples/agent-boilerplate, examples/agent-price-oracle,
examples/agent-byo-facilitator, examples/agent-with-sub-agents.
A scaffolded agent project uses these key packages:
| Package | Purpose |
|---|---|
aixyz | Framework core: server, adapters (A2A, MCP), x402 payment gating |
ai | Vercel AI SDK v6 — ToolLoopAgent, tool(), stepCountIs() |
@ai-sdk/openai | Default model adapter (swap for any AI SDK provider adapter) |
zod | Schema validation for tool inputs (z.object, z.string, etc.) |
@aixyz/erc-8004 | ERC-8004 Agent Identity (optional, added with --erc-8004) |
To use a different LLM provider, install its AI SDK adapter and update the import in app/agent.ts:
bun add @ai-sdk/anthropic # Anthropic Claude
bun add @ai-sdk/google # Google Gemini
bun add @ai-sdk/amazon-bedrock # AWS Bedrock
See the Vercel AI SDK providers for the full list.
x402.network — always provide x402.network; it has no fallback.x402.payTo — set X402_PAY_TO in .env.local or provide it directly in config._ are excluded; rename to remove the prefix.skills defaults to []; add at least one entry to be discoverable.accepts: { scheme: "free" } to expose an endpoint without payment.aixyz dev -p <port> to change the default port (3000).All CLI commands are designed for non-interactive use. When stdin is not a TTY, prompts are skipped — values come from CLI flags, environment variables, or sensible defaults. Use --help on any command for full usage.
create-aixyz-appbunx create-aixyz-app --help
| Flag | Description | Default |
|---|---|---|
[name] | Agent name (positional argument) | my-agent |
-y, --yes | Use all defaults, skip prompts | |
--erc-8004 | Include ERC-8004 Agent Identity support | false |
--openai-api-key <key> | OpenAI API key for .env.local | empty |
--pay-to <address> | x402 payTo Ethereum address | 0x0799872E07EA7a63c79357694504FE66EDfE4a0A |
--no-install | Skip bun install |
aixyz dev / aixyz buildaixyz dev --help
aixyz build --help
aixyz erc-8004 registeraixyz erc-8004 register --help
| Flag | Description | Required in non-TTY |
|---|---|---|
--url <url> | Agent deployment URL | Yes |
--chain-id <id> | Target chain numeric ID | Yes |
--supported-trust <list> | Comma-separated trust mechanisms | If no erc-8004.ts |
--keystore <path> | Keystore file path | One of keystore, |
--browser | Use browser wallet | browser, or |
PRIVATE_KEY env | Private key for signing | PRIVATE_KEY |
--broadcast | Execute on-chain (default is dry-run) | No |
--rpc-url <url> | Custom RPC endpoint | For custom chains |
--registry <address> | Registry contract address | For custom chains |
--out-dir <path> | Write result JSON to directory | No |
aixyz erc-8004 updateaixyz erc-8004 update --help
| Flag | Description | Required in non-TTY |
|---|---|---|
--url <url> | New agent deployment URL | Yes |
--agent-id <id> | Agent ID to update | If multiple registrations |
--keystore <path> | Keystore file path | One of keystore, |
--browser | Use browser wallet | browser, or |
PRIVATE_KEY env | Private key for signing | PRIVATE_KEY |
--broadcast | Execute on-chain (default is dry-run) | No |
--rpc-url <url> | Custom RPC endpoint | For custom chains |
--registry <address> | Registry contract address | For localhost only |
--out-dir <path> | Write result JSON to directory | No |