Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/add-agents-md-to-templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"create-cloudflare": minor
---

Add AGENTS.md to Workers templates for AI coding agent guidance

New Workers projects created via `create-cloudflare` now include an `AGENTS.md` file that provides AI coding agents with retrieval-led guidance for Cloudflare APIs. This helps agents avoid using outdated knowledge from their training data and instead consult current documentation.

The file includes:

- Links to Cloudflare documentation and MCP servers
- Essential wrangler commands (`dev`, `deploy`, `types`)
- Pointers to product-specific documentation for limits and APIs
7 changes: 7 additions & 0 deletions .changeset/cool-webs-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": minor
---

Improve autoconfig telemetry with granular event tracking

Adds detailed telemetry events to track the autoconfig workflow, including process start/end, detection, and configuration phases. Each event includes a unique session ID (`appId`), CI detection, framework information, and success/error status to help diagnose issues and understand usage patterns.
20 changes: 20 additions & 0 deletions .changeset/dull-clubs-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"wrangler": minor
---

Include all common telemetry properties in ad-hoc telemetry events

Previously, only command-based telemetry events (e.g., "wrangler command started/completed") included the full set of common properties. Ad-hoc events sent via `sendAdhocEvent` were missing important context like OS information, CI detection, and session tracking.

Now, all telemetry events include the complete set of common properties:

- `amplitude_session_id` and `amplitude_event_id` for session tracking
- `wranglerVersion` (and major/minor/patch variants)
- `osPlatform`, `osVersion`, `nodeVersion`
- `packageManager`
- `configFileType`
- `isCI`, `isPagesCI`, `isWorkersCI`
- `isInteractive`
- `isFirstUsage`
- `hasAssets`
- `agent`
1 change: 1 addition & 0 deletions fixtures/worker-with-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@cloudflare/eslint-config-shared": "workspace:*",
"@cloudflare/workers-tsconfig": "workspace:^",
"@cloudflare/workers-types": "catalog:default",
"miniflare": "workspace:*",
"typescript": "catalog:default",
"vitest": "catalog:default",
"wrangler": "workspace:*"
Expand Down
4 changes: 1 addition & 3 deletions fixtures/worker-with-resources/tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { resolve } from "path";
import { LOCAL_EXPLORER_API_PATH, LOCAL_EXPLORER_BASE_PATH } from "miniflare";
import { afterAll, beforeAll, describe, it } from "vitest";
import { runWranglerDev } from "../../shared/src/run-wrangler-long-lived";

const LOCAL_EXPLORER_BASE_PATH = "/cdn-cgi/explorer";
const LOCAL_EXPLORER_API_PATH = `${LOCAL_EXPLORER_BASE_PATH}/api`;

describe("local explorer", () => {
describe("with X_LOCAL_EXPLORER=true", () => {
let ip: string;
Expand Down
1 change: 1 addition & 0 deletions packages/create-cloudflare/e2e/helpers/workers-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export async function runC3ForWorkerTest(
`${isExperimental}`,
"--no-open",
"--no-git",
"--no-agents",
"--deploy",
`${runDeployTests}`,
...(argv ?? []),
Expand Down
25 changes: 23 additions & 2 deletions packages/create-cloudflare/e2e/tests/cli/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ describe("Create Cloudflare CLI", () => {
matcher: /Which language do you want to use\?/,
input: [keys.enter],
},
{
matcher: /Do you want to add an AGENTS\.md file/,
input: ["n"],
},
{
matcher: /Do you want to use git for version control/,
input: [keys.right, keys.enter],
Expand Down Expand Up @@ -107,6 +111,10 @@ describe("Create Cloudflare CLI", () => {
matcher: /Which language do you want to use\?/,
input: [keys.down, keys.enter],
},
{
matcher: /Do you want to add an AGENTS\.md file/,
input: ["n"],
},
{
matcher: /Do you want to use git for version control/,
input: ["n"],
Expand Down Expand Up @@ -163,6 +171,10 @@ describe("Create Cloudflare CLI", () => {
matcher: /Which template would you like to use\?/,
input: [keys.enter],
},
{
matcher: /Do you want to add an AGENTS\.md file/,
input: ["n"],
},
{
matcher: /Do you want to use git for version control/,
input: ["n"],
Expand Down Expand Up @@ -195,6 +207,7 @@ describe("Create Cloudflare CLI", () => {
"--template=https://github.com/cloudflare/workers-graphql-server",
"--no-deploy",
"--git=false",
"--no-agents",
],
[],
logStream,
Expand Down Expand Up @@ -227,6 +240,7 @@ describe("Create Cloudflare CLI", () => {
"--template=cloudflare/templates/multiplayer-globe-template",
"--no-deploy",
"--git=false",
"--no-agents",
],
[],
logStream,
Expand Down Expand Up @@ -264,6 +278,7 @@ describe("Create Cloudflare CLI", () => {
"--type=hello-world-python",
"--no-deploy",
"--git=false",
"--no-agents",
],
[],
logStream,
Expand All @@ -286,6 +301,7 @@ describe("Create Cloudflare CLI", () => {
"--type=hello-world",
"--no-deploy",
"--git=false",
"--no-agents",
],
[],
logStream,
Expand Down Expand Up @@ -332,7 +348,7 @@ describe("Create Cloudflare CLI", () => {
"Selecting template by description",
async ({ logStream, project }) => {
const { output } = await runC3(
[project.path, "--no-deploy", "--git=false"],
[project.path, "--no-deploy", "--git=false", "--no-agents"],
[
{
matcher: /What would you like to start with\?/,
Expand Down Expand Up @@ -367,7 +383,7 @@ describe("Create Cloudflare CLI", () => {
async ({ logStream, project }) => {
const testProjectPath = "/test-project-path";
const { output } = await runC3(
[testProjectPath, "--git=false", "--no-deploy"],
[testProjectPath, "--git=false", "--no-deploy", "--no-agents"],
[
{
matcher: /What would you like to start with\?/,
Expand Down Expand Up @@ -505,6 +521,7 @@ describe("Create Cloudflare CLI", () => {
"--existing-script=existing-script-test-do-not-delete",
"--git=false",
"--no-deploy",
"--no-agents",
],
[],
logStream,
Expand Down Expand Up @@ -574,6 +591,8 @@ describe("Create Cloudflare CLI", () => {
Deploy your application after it has been created
--git, --no-git
Initialize a local git repository for your application
--agents, --no-agents
Add an AGENTS.md file to provide AI coding agents with guidance for the Cloudflare platform
--open, --no-open
Opens the deployed application in your browser (this option is ignored if the application is not deployed)
--existing-script=<value>
Expand Down Expand Up @@ -678,6 +697,8 @@ describe("Create Cloudflare CLI", () => {
Deploy your application after it has been created
--git, --no-git
Initialize a local git repository for your application
--agents, --no-agents
Add an AGENTS.md file to provide AI coding agents with guidance for the Cloudflare platform
--open, --no-open
Opens the deployed application in your browser (this option is ignored if the application is not deployed)
--existing-script=<value>
Expand Down
31 changes: 31 additions & 0 deletions packages/create-cloudflare/src/__tests__/templates.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { existsSync, statSync } from "node:fs";
import { join } from "node:path";
import { spinner } from "@cloudflare/cli/interactive";
import degit from "degit";
import { mockSpinner } from "helpers/__tests__/mocks";
Expand All @@ -11,11 +12,13 @@ import {
writeJSON,
} from "helpers/files";
import { beforeEach, describe, test, vi } from "vitest";
import { getAgentsMd } from "../agents-md";
import {
addWranglerToGitIgnore,
deriveCorrelatedArgs,
downloadRemoteTemplate,
updatePackageName,
writeAgentsMd,
} from "../templates";
import type { PathLike } from "node:fs";
import type { C3Args, C3Context } from "types";
Expand Down Expand Up @@ -652,3 +655,31 @@ version = "0.1.0"`;
);
});
});

describe("writeAgentsMd", () => {
let writeFileMock: Mock;

beforeEach(() => {
vi.resetAllMocks();
writeFileMock = vi.mocked(writeFile);
});

test("should write AGENTS.md to the project directory", ({ expect }) => {
vi.mocked(existsSync).mockReturnValue(false);
const projectPath = join("/path/to/my-project");
writeAgentsMd(projectPath);

expect(writeFileMock).toHaveBeenCalledWith(
join(projectPath, "AGENTS.md"),
getAgentsMd(),
);
});

test("should not overwrite existing AGENTS.md", ({ expect }) => {
vi.mocked(existsSync).mockReturnValue(true);
const projectPath = join("/path/to/my-project");
writeAgentsMd(projectPath);

expect(writeFileMock).not.toHaveBeenCalled();
});
});
43 changes: 43 additions & 0 deletions packages/create-cloudflare/src/agents-md.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Generates AGENTS.md content for Cloudflare Workers projects.
*
* This file is injected into new Workers projects created via create-cloudflare
* to provide AI coding agents with retrieval-led guidance for Cloudflare APIs.
*
* @returns The AGENTS.md content as a string
*/
export const getAgentsMd = (): string => `# Cloudflare Workers

STOP. Your knowledge of Cloudflare Workers APIs and limits may be outdated. Always retrieve current documentation before any Workers, KV, R2, D1, Durable Objects, Queues, Vectorize, AI, or Agents SDK task.

## Docs

- https://developers.cloudflare.com/workers/
- MCP: \`https://docs.mcp.cloudflare.com/mcp\`

For all limits and quotas, retrieve from the product's \`/platform/limits/\` page. eg. \`/workers/platform/limits\`

## Commands

| Command | Purpose |
|---------|---------|
| \`npx wrangler dev\` | Local development |
| \`npx wrangler deploy\` | Deploy to Cloudflare |
| \`npx wrangler types\` | Generate TypeScript types |

Run \`wrangler types\` after changing bindings in wrangler.jsonc.

## Node.js Compatibility

https://developers.cloudflare.com/workers/runtime-apis/nodejs/

## Errors

- **Error 1102** (CPU/Memory exceeded): Retrieve limits from \`/workers/platform/limits/\`
- **All errors**: https://developers.cloudflare.com/workers/observability/errors/

## Product Docs

Retrieve API references and limits from:
\`/kv/\` · \`/r2/\` · \`/d1/\` · \`/durable-objects/\` · \`/queues/\` · \`/vectorize/\` · \`/workers-ai/\` · \`/agents/\`
`;
27 changes: 25 additions & 2 deletions packages/create-cloudflare/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
} from "@cloudflare/cli";
import { CancelError } from "@cloudflare/cli/error";
import { isInteractive } from "@cloudflare/cli/interactive";
import { cliDefinition, parseArgs } from "helpers/args";
import { isUpdateAvailable } from "helpers/cli";
import { cliDefinition, parseArgs, processArgument } from "helpers/args";
import { C3_DEFAULTS, isUpdateAvailable } from "helpers/cli";
import { runCommand } from "helpers/command";
import {
detectPackageManager,
Expand All @@ -33,6 +33,7 @@ import {
createContext,
updatePackageName,
updatePackageScripts,
writeAgentsMd,
} from "./templates";
import { validateProjectDirectory } from "./validators";
import { addTypes } from "./workers";
Expand Down Expand Up @@ -153,6 +154,12 @@ const create = async (ctx: C3Context) => {
await npmInstall(ctx);
await rectifyPmMismatch(ctx);

// Offer AGENTS.md for Workers templates that don't use a framework
// Framework templates may need framework-specific agent guidance
if (ctx.template.platform === "workers" && !ctx.template.frameworkCli) {
await offerAgentsMd(ctx);
}

endSection(`Application created`);
};

Expand Down Expand Up @@ -217,6 +224,22 @@ const printBanner = (args: Partial<C3Args>) => {
startSection(`Create an application with Cloudflare`, "Step 1 of 3");
};

const offerAgentsMd = async (ctx: C3Context) => {
ctx.args.agents ??= await processArgument(ctx.args, "agents", {
type: "confirm",
question:
"Do you want to add an AGENTS.md file to help AI coding tools understand Cloudflare APIs?",
label: "agents",
defaultValue: C3_DEFAULTS.agents,
});

if (!ctx.args.agents) {
return;
}

writeAgentsMd(ctx.project.path);
};

main(process.argv)
.catch((e) => {
if (e instanceof CancelError) {
Expand Down
6 changes: 6 additions & 0 deletions packages/create-cloudflare/src/helpers/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ export const cliDefinition: ArgumentsDefinition = {
type: "boolean",
description: "Initialize a local git repository for your application",
},
{
name: "agents",
type: "boolean",
description:
"Add an AGENTS.md file to provide AI coding agents with guidance for the Cloudflare platform",
},
{
name: "open",
type: "boolean",
Expand Down
1 change: 1 addition & 0 deletions packages/create-cloudflare/src/helpers/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const C3_DEFAULTS: C3Args = {
autoUpdate: true,
deploy: false,
git: true,
agents: true,
open: true,
lang: "ts",
template:
Expand Down
16 changes: 16 additions & 0 deletions packages/create-cloudflare/src/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import vikeExperimentalTemplate from "templates/vike/experimental-c3";
import vueTemplate from "templates/vue/c3";
import wakuTemplate from "templates/waku/c3";
import wakuExperimentalTemplate from "templates/waku/experimental-c3";
import { getAgentsMd } from "./agents-md";
import { isInsideGitRepo } from "./git";
import { validateProjectDirectory, validateTemplateUrl } from "./validators";
import type { Option } from "@cloudflare/cli/interactive";
Expand Down Expand Up @@ -777,6 +778,21 @@ export async function copyTemplateFiles(ctx: C3Context) {
s.stop(`${brandColor("files")} ${dim("copied to project directory")}`);
}

/**
* Writes AGENTS.md to the project directory if one doesn't already exist.
* This file provides AI coding agents with retrieval-led guidance for Cloudflare APIs.
* Remote templates may include their own AGENTS.md with custom guidance, which we preserve.
*
* @param projectPath - The path to the project directory
*/
export function writeAgentsMd(projectPath: string): void {
const agentsMdPath = join(projectPath, "AGENTS.md");
if (existsSync(agentsMdPath)) {
return;
}
writeFile(agentsMdPath, getAgentsMd());
}

export const processRemoteTemplate = async (args: Partial<C3Args>) => {
const templateUrl = await processArgument(args, "template", {
type: "text",
Expand Down
1 change: 1 addition & 0 deletions packages/create-cloudflare/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type C3Args = {
deploy?: boolean;
open?: boolean;
git?: boolean;
agents?: boolean;
autoUpdate?: boolean;
category?: string;
// frameworks specific
Expand Down
3 changes: 1 addition & 2 deletions packages/local-explorer-ui/src/api/client-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { LOCAL_EXPLORER_API_PATH } from "../constants";
import type { CreateClientConfig } from "./generated/client.gen";

export const createClientConfig: CreateClientConfig = (config) => ({
...config,
baseUrl: LOCAL_EXPLORER_API_PATH,
baseUrl: import.meta.env.VITE_LOCAL_EXPLORER_API_PATH,
throwOnError: true,
});
Loading
Loading