Skip to content

Commit de4bb30

Browse files
authored
Add AGENTS.md guide for AI agent template review and maintenance (#881)
1 parent 63b13f6 commit de4bb30

File tree

1 file changed

+387
-0
lines changed

1 file changed

+387
-0
lines changed

AGENTS.md

Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
# AGENTS.md
2+
3+
This guide helps AI agents review, maintain, and contribute to Cloudflare Worker templates. It documents patterns, common issues, and testing strategies learned from real PR reviews.
4+
5+
## Quick Reference
6+
7+
### Essential Commands
8+
9+
```bash
10+
# Validate everything before starting work
11+
pnpm run check
12+
13+
# After making changes, auto-fix what's possible
14+
pnpm run fix
15+
16+
# Run template-specific tests
17+
cd <template-dir> && pnpm test
18+
19+
# Lint templates for compliance
20+
pnpm run check:templates
21+
```
22+
23+
### PR Review Checklist
24+
25+
When reviewing a template PR, verify these items in order:
26+
27+
1. **package.json** - Has all required fields
28+
2. **README.md** - Has dashboard markers and deploy button at top
29+
3. **Tests** - Minimum 5 tests exist and pass
30+
4. **Template Linter** - `pnpm run check:templates` passes
31+
5. **Build** - Template compiles without errors
32+
33+
---
34+
35+
## Common Issues and Fixes
36+
37+
### 1. Missing `description` in package.json
38+
39+
**Symptom**: Template linter fails with missing description error.
40+
41+
**Fix**: Add a one-line description to package.json:
42+
43+
```json
44+
{
45+
"name": "my-template",
46+
"description": "Brief description of what this template does."
47+
}
48+
```
49+
50+
### 2. Missing Dashboard Content Markers
51+
52+
**Symptom**: Dashboard won't display template details correctly.
53+
54+
**Fix**: Add markers around the content that should appear in Cloudflare Dashboard:
55+
56+
```markdown
57+
[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](...)
58+
59+
<!-- dash-content-start -->
60+
61+
## Overview
62+
63+
This template demonstrates...
64+
65+
<!-- dash-content-end -->
66+
67+
## Getting Started
68+
69+
...
70+
```
71+
72+
**Important**: The Deploy to Cloudflare button should be at the TOP of the README, before the dash-content markers.
73+
74+
### 3. Deploy Button in Wrong Location
75+
76+
**Symptom**: Users can't easily find the deploy button.
77+
78+
**Fix**: Move the Deploy to Cloudflare button to the very top of README.md, before any other content.
79+
80+
### 4. Missing or Insufficient Tests
81+
82+
**Symptom**: Template has fewer than 5 tests or no test file.
83+
84+
**Fix**: Create tests using `@cloudflare/vitest-pool-workers`. See [Testing Patterns](#testing-patterns) below.
85+
86+
### 5. Using wrangler.toml Instead of wrangler.json
87+
88+
**Symptom**: Template linter fails with configuration format error.
89+
90+
**Fix**: Convert `wrangler.toml` to `wrangler.json` or `wrangler.jsonc`.
91+
92+
### 6. Missing package-lock.json
93+
94+
**Symptom**: Slower deployments, potential dependency issues.
95+
96+
**Fix**: Run from repo root:
97+
98+
```bash
99+
pnpm run fix:lockfiles
100+
```
101+
102+
---
103+
104+
## Testing Patterns
105+
106+
### Basic Test Setup
107+
108+
Every template needs a `vitest.config.ts` and test file(s). The simplest setup:
109+
110+
```typescript
111+
// vitest.config.ts
112+
import { defineWorkersProject } from "@cloudflare/vitest-pool-workers/config";
113+
114+
export default defineWorkersProject({
115+
test: {
116+
poolOptions: {
117+
workers: {
118+
singleWorker: true,
119+
wrangler: {
120+
configPath: "./wrangler.json",
121+
},
122+
},
123+
},
124+
},
125+
});
126+
```
127+
128+
```typescript
129+
// test/index.test.ts
130+
import { SELF } from "cloudflare:test";
131+
import { describe, it, expect } from "vitest";
132+
133+
describe("Template Name", () => {
134+
it("returns 200 on homepage", async () => {
135+
const response = await SELF.fetch("https://example.com/");
136+
expect(response.status).toBe(200);
137+
});
138+
139+
it("returns HTML content", async () => {
140+
const response = await SELF.fetch("https://example.com/");
141+
const html = await response.text();
142+
expect(html).toContain("<!DOCTYPE html>");
143+
});
144+
145+
// Add at least 3 more meaningful tests...
146+
});
147+
```
148+
149+
### Testing with Service Bindings (Stub Workers)
150+
151+
When a template uses Service Bindings to call other Workers, you need stub workers for testing. Define them inline in vitest.config.ts:
152+
153+
```typescript
154+
// vitest.config.ts
155+
import { defineWorkersProject } from "@cloudflare/vitest-pool-workers/config";
156+
157+
// Define stub worker as inline JavaScript
158+
const stubWorkerScript = /* javascript */ `
159+
export default {
160+
async fetch(request) {
161+
const url = new URL(request.url);
162+
return new Response(\`Stub response for: \${url.pathname}\`, {
163+
headers: { "Content-Type": "text/plain" },
164+
});
165+
},
166+
};
167+
`;
168+
169+
export default defineWorkersProject({
170+
test: {
171+
poolOptions: {
172+
workers: {
173+
singleWorker: true,
174+
wrangler: {
175+
configPath: "./wrangler.json",
176+
},
177+
miniflare: {
178+
workers: [
179+
{
180+
name: "my-service-binding-name", // Must match binding name in wrangler.json
181+
modules: [
182+
{
183+
type: "ESModule",
184+
path: "index.js",
185+
contents: stubWorkerScript,
186+
},
187+
],
188+
compatibilityDate: "2024-01-01",
189+
},
190+
],
191+
},
192+
},
193+
},
194+
},
195+
});
196+
```
197+
198+
### Testing Different Binding Types
199+
200+
**KV Namespace**: Automatically available via wrangler.json config, use `env.MY_KV` in tests.
201+
202+
**D1 Database**: Define migrations in wrangler.json, database is auto-created for tests.
203+
204+
**R2 Bucket**: Automatically available via wrangler.json config.
205+
206+
**Durable Objects**: Define in wrangler.json, accessible in tests.
207+
208+
**Service Bindings**: Use inline stub workers as shown above.
209+
210+
### What to Test
211+
212+
Aim for at least 5 tests covering:
213+
214+
1. **Happy path** - Main functionality works
215+
2. **Error handling** - Invalid inputs return appropriate errors
216+
3. **Edge cases** - Empty data, missing parameters
217+
4. **API endpoints** - Each endpoint returns expected status/data
218+
5. **HTML/UI** - Key elements are present in responses
219+
220+
---
221+
222+
## Code Review Patterns
223+
224+
### Logic Bug Detection
225+
226+
When reviewing template code, watch for these common issues:
227+
228+
**Request Interception Order**: Middleware or special endpoints must be checked BEFORE forwarding to upstream services.
229+
230+
```typescript
231+
// WRONG - Check happens after fetch, never executes
232+
const response = await upstream.fetch(request);
233+
if (url.pathname === "/__special") {
234+
return new Response("special");
235+
}
236+
237+
// CORRECT - Check happens before fetch
238+
if (url.pathname === "/__special") {
239+
return new Response("special");
240+
}
241+
const response = await upstream.fetch(request);
242+
```
243+
244+
**Environment Variable Access**: Bindings must be accessed from the `env` parameter, not global scope.
245+
246+
```typescript
247+
// WRONG - Won't work in Workers
248+
const db = globalThis.DB;
249+
250+
// CORRECT - Access from env parameter
251+
export default {
252+
async fetch(request, env) {
253+
const db = env.DB;
254+
},
255+
};
256+
```
257+
258+
### README Quality
259+
260+
A good template README should have:
261+
262+
1. Deploy button at the very top
263+
2. Dashboard content section with overview (between markers)
264+
3. Screenshot or demo link
265+
4. Local development instructions
266+
5. Environment variables/secrets documentation
267+
6. Links to relevant Cloudflare docs
268+
269+
---
270+
271+
## Pushing Changes to PRs
272+
273+
When updating a PR that exists on a different branch:
274+
275+
```bash
276+
# Find the PR's actual branch name
277+
gh pr view <PR_NUMBER> --json headRefName
278+
279+
# Push to the PR branch (not your local branch name)
280+
git push origin HEAD:<pr-branch-name> --force-with-lease
281+
```
282+
283+
Example:
284+
285+
```bash
286+
# PR #877 is on branch "brayden/mfe"
287+
git push origin HEAD:brayden/mfe --force-with-lease
288+
```
289+
290+
---
291+
292+
## Workflow for Reviewing Template PRs
293+
294+
### 1. Initial Assessment
295+
296+
```bash
297+
# Checkout the PR
298+
gh pr checkout <PR_NUMBER>
299+
300+
# Run template linter first - catches most issues
301+
pnpm run check:templates
302+
303+
# Run template's own tests
304+
cd <template-dir> && pnpm test
305+
```
306+
307+
### 2. Fix Common Issues
308+
309+
Address issues in this order (most common first):
310+
311+
1. Add missing `description` to package.json
312+
2. Add/fix dashboard content markers in README.md
313+
3. Move Deploy button to top of README.md
314+
4. Add or fix tests to meet minimum of 5
315+
5. Fix any code bugs discovered during testing
316+
317+
### 3. Verify Fixes
318+
319+
```bash
320+
# From repo root
321+
pnpm run check:templates
322+
cd <template-dir> && pnpm test
323+
```
324+
325+
### 4. Commit and Push
326+
327+
```bash
328+
# Commit with descriptive message
329+
git add -A
330+
git commit -m "Add tests and address review feedback for <template-name>"
331+
332+
# Push to PR branch
333+
git push origin HEAD:<pr-branch-name> --force-with-lease
334+
```
335+
336+
---
337+
338+
## Template Compliance Summary
339+
340+
**For the full list of template requirements, see [CONTRIBUTING.md](./CONTRIBUTING.md).**
341+
342+
The CONTRIBUTING.md file contains the authoritative checklist for template compliance, including:
343+
344+
- `package.json` required fields and `cloudflare` metadata
345+
- `README.md` content requirements and dashboard markers
346+
- `package-lock.json` generation
347+
- `.gitignore` requirements
348+
- Playwright E2E test requirements
349+
- Worker secrets and environment variables
350+
351+
### Waiting on Cloudflare Team
352+
353+
These items cannot be completed by external contributors:
354+
355+
- `cloudflare.preview_image_url` - Screenshot uploaded by Growth team
356+
- `cloudflare.preview_icon_url` - Icon uploaded by Growth team
357+
- `cloudflare.publish: true` - Set by Cloudflare team when ready to publish
358+
359+
---
360+
361+
## Debugging Tips
362+
363+
### Template Linter Not Finding Issues
364+
365+
The linter doesn't catch everything. Manual checks needed for:
366+
367+
- Dashboard content marker placement
368+
- Deploy button position
369+
- Code logic bugs
370+
- Test quality (only checks count, not coverage)
371+
372+
### Tests Failing with Binding Errors
373+
374+
If tests fail with "binding not found" errors:
375+
376+
1. Check wrangler.json has the binding defined
377+
2. For Service Bindings, add stub workers in vitest.config.ts
378+
3. Ensure binding names match exactly (case-sensitive)
379+
380+
### Compatibility Date Warnings
381+
382+
```
383+
The latest compatibility date supported by the installed Cloudflare Workers Runtime is "2025-09-06",
384+
but you've requested "2025-10-08". Falling back to "2025-09-06"...
385+
```
386+
387+
This warning is normal during local testing. The template linter enforces a specific compatibility date that may be newer than the locally installed runtime. Tests will still pass.

0 commit comments

Comments
 (0)