Skip to content

Commit 65a4b4e

Browse files
document local explorer via agent skill (#13987)
Co-authored-by: Dario Piotrowicz <dario@cloudflare.com>
1 parent 90092c0 commit 65a4b4e

4 files changed

Lines changed: 132 additions & 12 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
name: local-explorer
3+
description: How to add products/resources to the local explorer or local API. Use when implementing new local APIs, or UI routes under packages/miniflare/src/workers/local-explorer or packages/local-explorer-ui.
4+
---
5+
6+
# Cloudflare Local Explorer Products
7+
8+
Use this skill when adding a new product or resource type to the local API and/or local explorer.
9+
10+
## Start Here
11+
12+
Read these files before editing:
13+
14+
- `packages/miniflare/src/workers/local-explorer/explorer.worker.ts`
15+
- `packages/miniflare/src/plugins/core/explorer.ts`
16+
- `packages/miniflare/src/plugins/core/types.ts`
17+
- One existing resource implementation in `packages/miniflare/src/workers/local-explorer/resources/`, preferably the product most similar to the new one
18+
- One matching test in `packages/miniflare/test/plugins/local-explorer/`
19+
20+
If there are UI changes, also read:
21+
22+
- `packages/local-explorer-ui/src/components/Sidebar.tsx`
23+
- Existing route files under `packages/local-explorer-ui/src/routes/`
24+
- Existing product e2e tests under `packages/local-explorer-ui/src/__e2e__/`
25+
26+
## Workflow
27+
28+
1. Add the API surface to `packages/miniflare/scripts/openapi-filter-config.ts`.
29+
2. Generate Miniflare's filtered spec and backend types from a full Cloudflare OpenAPI spec:
30+
31+
```bash
32+
OPENAPI_INPUT_PATH=<path-to-full-openapi-spec> pnpm --dir packages/miniflare generate:api
33+
```
34+
35+
3. Inspect `packages/miniflare/src/workers/local-explorer/openapi.local.json` and generated types. If the generated schemas include fields local explorer will not support, add ignores in `openapi-filter-config.ts` and regenerate.
36+
4. The explorer worker should have access to all user resource bindings. Ensure `proxyBindings` include bindings to the new product and that `getExplorerServices()` exposes any extra bindings the explorer worker needs. Wire product bindings through `constructExplorerBindingMap()` and `constructExplorerWorkerOpts()` in `packages/miniflare/src/plugins/core/explorer.ts`.
37+
5. Add or extend resource binding metadata in `packages/miniflare/src/plugins/core/types.ts`.
38+
6. Implement handlers in `packages/miniflare/src/workers/local-explorer/resources/<product>.ts`. Make sure to account for cross-instance aggregation, if applicable.
39+
7. Register Hono routes in `packages/miniflare/src/workers/local-explorer/explorer.worker.ts`.
40+
8. Validate request bodies and query params with generated Zod schemas from `generated/zod.gen.ts` using `validateRequestBody()` and `validateQuery()`.
41+
9. Return Cloudflare API envelope responses using `wrapResponse()` and `errorResponse()` from `common.ts` unless an existing endpoint for that product uses a different response shape.
42+
10. Add Miniflare tests in `packages/miniflare/test/plugins/local-explorer/<product>.spec.ts`.
43+
11. Regenerate the UI API client:
44+
45+
```bash
46+
pnpm --dir packages/local-explorer-ui build
47+
```
48+
49+
12. Add UI routes/components. Use Kumo components for new UI. See https://github.com/cloudflare/kumo/blob/main/AGENTS.md.
50+
13. Add Playwright e2e tests under `packages/local-explorer-ui/src/__e2e__/<product>/` for new visible product flows.
51+
52+
## OpenAPI Rules
53+
54+
- Do not edit generated files like `packages/miniflare/src/workers/local-explorer/openapi.local.json` or `packages/miniflare/src/workers/local-explorer/generated/` directly.
55+
- Prefer upstream Cloudflare API paths when a public API exists.
56+
- Use `extensions.paths` in `openapi-filter-config.ts` only for local-only APIs or APIs that do not exist in the public Cloudflare API.
57+
- Add ignores for unsupported params, headers, request body properties, and response fields rather than pretending to support them.
58+
59+
## Backend Patterns
60+
61+
- Local list endpoints such as listing KV namespaces should not implement pagination as this may require cross-instance aggregation. Pagination should be supported when targeting individual resources, such as listing KV keys within a specific namespace.
62+
- For cross-worker aggregation, use `aggregateListResults()`, `getPeerUrlsIfAggregating()`, and `fetchFromPeer()` from `aggregation.ts`; do not hand-roll peer discovery. Add tests for both local-only behavior and aggregated behavior when the product can span multiple instances.
63+
- If an API needs direct filesystem access, call through the loopback service (`c.env.MINIFLARE_LOOPBACK`) to a Node.js endpoint. The local explorer API runs inside workerd, so it cannot access the host filesystem directly.
64+
- If an endpoint needs metadata that is not available on the runtime binding itself, put that metadata in `BindingIdMap` and pass it through `CoreBindings.JSON_LOCAL_EXPLORER_BINDING_MAP`.
65+
- If a product should appear in `/api/local/workers`, add it to `WorkerResourceBindings` and populate it in `constructExplorerWorkerOpts()`.
66+
67+
## UI Patterns
68+
69+
- The UI API client is generated from `packages/miniflare/src/workers/local-explorer/openapi.local.json` into `packages/local-explorer-ui/src/api/generated/`.
70+
- Sidebar resources come from `/api/local/workers`; update `LocalExplorerWorkerBindings` usage and `Sidebar.tsx` when the product should appear in navigation.
71+
- Add route files under `packages/local-explorer-ui/src/routes/`. TanStack Router regenerates `src/routeTree.gen.ts` during UI build/dev.
72+
- Preserve worker selection by carrying the `worker` search param through product links when following sidebar patterns.
73+
- Use Kumo for new UI components wherever possible. Do not introduce a parallel component system.
74+
- Do not use tailwindCSS color tokens, use Kumo color tokens instead.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
```mermaid
2+
flowchart TB
3+
Client["client"] --> Incoming["incoming request"]
4+
Incoming --> EntryA["entry worker"]
5+
EntryA -->|/cdn-cgi/explorer| ExplorerA["explorer worker<br/>(Hono)"]
6+
7+
subgraph Runtime["running Miniflare instances"]
8+
direction LR
9+
10+
subgraph A["miniflare A"]
11+
direction TB
12+
EntryA
13+
ExplorerA
14+
Frontend["frontend<br/>(TanStack Router + React)"]
15+
UserWorker["user worker"]
16+
KV["KV, R2, D1"]
17+
Wrapper["wrapped<br/>DO/Workflow class"]
18+
19+
EntryA --> UserWorker
20+
ExplorerA -->|disk service to serve assets| Frontend
21+
ExplorerA -->|binding| KV
22+
ExplorerA -->|binding| Wrapper
23+
UserWorker -->|binding| KV
24+
UserWorker -->|binding| Wrapper
25+
end
26+
27+
subgraph B["miniflare B"]
28+
direction TB
29+
EntryB["entry worker"]
30+
ExplorerB["explorer worker"]
31+
Etc["etc."]
32+
33+
EntryB --> ExplorerB
34+
ExplorerB --> Etc
35+
end
36+
end
37+
38+
Frontend -->|fetch /cdn-cgi/explorer/api| Incoming
39+
ExplorerA -->|fetch /cdn-cgi/explorer/api/resource with NO_AGGREGATE_HEADER| EntryB
40+
41+
subgraph FS["filesystem"]
42+
Registry["dev registry"]
43+
DOState[".wrangler/state/durable-objects<br/>(list DOs, delete workflows, etc.)"]
44+
end
45+
46+
ExplorerA -->|node loopback binding| FS
47+
48+
classDef miniflareA stroke:#f08c00,fill:#fff7ed,color:#1e1e1e;
49+
classDef userResource stroke:#1971c2,fill:#eff6ff,color:#1e1e1e;
50+
classDef entry stroke:#e03131,fill:#fff5f5,color:#1e1e1e;
51+
classDef neutral stroke:#1e1e1e,fill:#ffffff,color:#1e1e1e;
52+
53+
class EntryA entry;
54+
class ExplorerA,Frontend,Wrapper miniflareA;
55+
class UserWorker,KV userResource;
56+
class Client,Incoming,Runtime,FS,Registry,DOState,EntryB,ExplorerB,Etc neutral;
57+
```

packages/miniflare/scripts/check-generate-api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ async function main(): Promise<void> {
6464
"\n" +
6565
` OPENAPI_INPUT_PATH=<path-to-openapi.json> pnpm -F miniflare generate:api\n` +
6666
"\n" +
67-
"See packages/miniflare/src/workers/local-explorer/README.md for details.\n" +
67+
"See .opencode/skills/local-explorer/SKILL.md for details.\n" +
6868
`The CI check uses the spec pinned at commit ${OPENAPI_COMMIT}.\n`
6969
);
7070
process.exit(1);

packages/miniflare/src/workers/local-explorer/README.md

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)