diff --git a/.claude/commands/check-ci.md b/.claude/commands/check-ci.md new file mode 100644 index 0000000..9d8dccd --- /dev/null +++ b/.claude/commands/check-ci.md @@ -0,0 +1,8 @@ +Run the full CI gate checks locally before pushing. Run all four commands sequentially and report any failures: + +1. `cargo fmt --all -- --check` +2. `cargo clippy --workspace --all-targets --all-features -- -D warnings` +3. `cargo test --workspace --all-targets` +4. `cargo check --workspace --all-targets --features "fastly cloudflare"` + +If any step fails, show the errors and suggest fixes. Do not proceed to the next step until the current one passes. diff --git a/.claude/commands/review-changes.md b/.claude/commands/review-changes.md new file mode 100644 index 0000000..f37e218 --- /dev/null +++ b/.claude/commands/review-changes.md @@ -0,0 +1,15 @@ +Review the current uncommitted changes as a staff engineer would. Run: + +1. `git diff` to see all changes +2. `git diff --cached` to see staged changes +3. `git status` to see untracked files + +Then provide a thorough code review covering: + +- Correctness: are the changes logically sound? +- WASM compatibility: do changes avoid Tokio/runtime-specific deps in core/adapters? +- Convention compliance: matchit `{id}` syntax, `edgezero_core` imports, `#[action]` macros? +- Test coverage: are new code paths tested? +- Minimal scope: are there unnecessary changes beyond what was requested? + +Be critical. Flag anything that would fail CI or violate project conventions from CLAUDE.md. diff --git a/.claude/commands/test-all.md b/.claude/commands/test-all.md new file mode 100644 index 0000000..da48ebc --- /dev/null +++ b/.claude/commands/test-all.md @@ -0,0 +1,7 @@ +Run the full workspace test suite: + +``` +cargo test --workspace --all-targets +``` + +If tests fail, analyze the failures and suggest fixes. Group failures by crate for clarity. diff --git a/.claude/commands/test-crate.md b/.claude/commands/test-crate.md new file mode 100644 index 0000000..1594300 --- /dev/null +++ b/.claude/commands/test-crate.md @@ -0,0 +1,11 @@ +Run tests for a specific crate. Usage: /test-crate + +Run `cargo test -p $ARGUMENTS` and report results. If no crate name is provided, ask which crate to test from the workspace members: + +- edgezero-core +- edgezero-macros +- edgezero-adapter +- edgezero-adapter-fastly +- edgezero-adapter-cloudflare +- edgezero-adapter-axum +- edgezero-cli diff --git a/.claude/commands/verify.md b/.claude/commands/verify.md new file mode 100644 index 0000000..92d9c41 --- /dev/null +++ b/.claude/commands/verify.md @@ -0,0 +1,9 @@ +Prove that the current changes work correctly. Compare behavior between the current branch and main: + +1. Run `git diff main...HEAD --stat` to understand the scope of changes +2. Run `cargo test --workspace --all-targets` to verify tests pass +3. Run `cargo clippy --workspace --all-targets --all-features -- -D warnings` to verify no lint warnings +4. If changes touch handlers/routing, run the dev server and test affected endpoints +5. If changes touch adapters, run targeted tests: `cargo test -p ` + +Summarize what works, what doesn't, and any risks. Don't say "it works" without evidence. diff --git a/.gitignore b/.gitignore index 87a1ca3..ec03ad9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,8 @@ target/ .DS_Store # Editors -.claude +.claude/* +!.claude/commands/ .idea .specstory .vscode/* diff --git a/AGENTS.md b/AGENTS.md index 7b124a9..e6b1f56 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,83 +1,25 @@ # Agent Notes -This repository is currently tended by an automated assistant (Codex) that helps -craft the EdgeZero workspace. A few conventions are worth remembering when the -agent is asked to make additional changes: - -## Standard Workflow - -1. First think through the problem, read the codebase for relevant files, and write a plan to the file: TODO.md. If the TODO.md file does not yet exist, go ahead and create it. -2. The plan should have a list of todo items that you can check off as you complete them -3. Before you begin working, show me the full plan of the work to be done and get my approval before commencing any coding work -4. Then, begin working on the todo items, marking them as complete as you go. -5. As you complete each todo item, give me a high level explanation of what changes you made -6. If you cannot complete a todo, mark it as blocked in TODO.md and explain why. -7. Make every task and code change you do as simple as possible. We want to avoid making any massive or complex changes. Every change should impact as little code as possible. -8. Finally, add a review section to the TODO.md file with a summary of the changes you made, assumptions made, any unresolved issues or errors you couldn't fix, and any other relevant information. Add the date and time showing when the job was finished. - -## Tools - -### Context7 MCP - -- Use Context7 MCP to supplement local codebase knowledge with up-to-date library documentation and coding examples - -### Playwright MCP - -- use the Playwright MCP in order to check and validate any user interface changes you make -- you can also use this MCP to check the web browser console for any error messages which may come up -- iterate up to a maximum of 5 times for any one particular feature; an iteration = one cycle of code change + Playwright re-run -- if you can't get the feature to work after 5 iterations then you're likely stuck in a loop and you should stop and let me know that you've hit your max of 5 iterations for that feature -- Save any failing test cases or console errors in a debug.md file so we can review them together. - -## Testing - -always run `cargo test` after touching code. Individual crates -can be scoped via `cargo test -p ` when a partial run is faster. - -## Routing syntax - -route definitions must use matchit 0.8 style -parameters (`/resource/{id}` or `/static/{*rest}`); we intentionally do not -support legacy `:id` syntax. - -## Adapters – Fastly and Cloudflare adapters expose request context helpers - -in `context.rs` and translation helpers in `request.rs` / `response.rs`. -Tests for adapter behaviour live beside those modules. - -## Examples - -the demo crates under `examples/app-demo/` share router -logic via `app-demo-core`. Local smoke testing flows through -`cargo run -p edgezero-cli --features dev-example -- dev`, which serves the demo -router on http://127.0.0.1:8787. Build provider targets with -`app-demo-adapter-fastly` / `app-demo-adapter-cloudflare` when you need Fastly -or Cloudflare binaries. - -## Style– prefer colocating tests with implementation modules, favour - -async/await-friendly code that compiles to Wasm, and avoid runtime-specific -dependencies like Tokio. - -- Use the HTTP aliases exported from `edgezero_core` (`Method`, `StatusCode`, - `HeaderMap`, etc.) instead of importing types directly from the `http` crate. -- Prefer the `#[edgezero_core::action]` macro for new handlers so extractor - arguments (`Json`, `Query`, `ValidatedJson`, etc.) stay declarative. - Extractors live under `edgezero_core::` and integrate with the `validator` - crate for `Validated*` variants. - -## Logging - -- Platform logging helpers live in the adapters: use `edgezero_adapter_fastly::init_logger()` / `edgezero_adapter_cloudflare::init_logger()` and - fall back to something like `simple_logger` for local builds. - -## Proxy helpers - -- Use `edgezero_core::proxy::ProxyService` with the adapter clients - (`edgezero_adapter_fastly::FastlyProxyClient`, `edgezero_adapter_cloudflare::CloudflareProxyClient`) - when wiring proxy routes so streaming and compression handling stay consistent. -- Keep synthetic local proxy behaviour lightweight so examples can run without - Fastly/Cloudflare credentials; rely on the proxy test clients in `edgezero-core` for unit coverage. - -When in doubt, keep changes minimal, document behaviour in `README.md`, and -ensure the workspace stays Wasm-friendly. +**Before doing anything else, read `CLAUDE.md` in this repository root.** It +contains all project conventions, coding standards, build commands, workflow +rules, and CI requirements. Everything in `CLAUDE.md` applies to you. + +This file exists because Codex looks for `AGENTS.md` by convention. All shared +rules are maintained in `CLAUDE.md` to avoid duplication and drift. If you +cannot access `CLAUDE.md`, the critical rules are summarized below as a +fallback. + +## Fallback Summary + +If `CLAUDE.md` is unavailable, these are the minimum rules: + +1. Write a plan to `TODO.md` before coding. Get approval first. +2. Keep changes minimal — every change should impact as little code as possible. +3. Run `cargo test` after every code change. +4. Run `cargo fmt --all -- --check` and `cargo clippy --workspace --all-targets --all-features -- -D warnings`. +5. Run `cargo check --workspace --all-targets --features "fastly cloudflare"`. +6. Use matchit `{id}` syntax, never legacy `:id`. +7. Use `#[action]` macro for handlers, import types from `edgezero_core`. +8. Don't add Tokio deps to core/adapter crates — WASM compatibility first. +9. Append a review section to `TODO.md` when done (summary, assumptions, + unresolved issues, UTC timestamp). diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..9b2966d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,273 @@ +# CLAUDE.md — EdgeZero + +## Project Overview + +EdgeZero is a portable HTTP workload toolkit in Rust. Write once, deploy to +Fastly Compute, Cloudflare Workers, or native Axum servers. The codebase is a +Cargo workspace with 7 crates under `crates/`, an example app under +`examples/app-demo/`, a VitePress documentation site under `docs/`, and CI +workflows under `.github/workflows/`. + +## Workspace Layout + +``` +crates/ + edgezero-core/ # Core: routing, extractors, middleware, proxy, body, errors + edgezero-macros/ # Proc macros: #[action], #[app] + edgezero-adapter/ # Adapter registry and traits + edgezero-adapter-fastly/ # Fastly Compute bridge (wasm32-wasip1) + edgezero-adapter-cloudflare/# Cloudflare Workers bridge (wasm32-unknown-unknown) + edgezero-adapter-axum/ # Axum/Tokio bridge (native, dev server) + edgezero-cli/ # CLI: new, build, deploy, dev, serve +examples/app-demo/ # Reference app with all 3 adapters (excluded from workspace) +docs/ # VitePress documentation site (Node.js) +scripts/ # Build/deploy/test helper scripts +``` + +## Toolchain & Versions + +- **Rust**: 1.91.1 (from `.tool-versions`) +- **Node.js**: 24.12.0 (for docs site only) +- **Fastly CLI**: v13.0.0 +- **Edition**: 2021 +- **Resolver**: 2 +- **License**: Apache-2.0 + +## Build & Test Commands + +```sh +# Full workspace test (primary CI command) +cargo test --workspace --all-targets + +# Test a specific crate +cargo test -p edgezero-core +cargo test -p edgezero-adapter-fastly +cargo test -p edgezero-cli + +# Lint & format (must pass CI) +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features -- -D warnings + +# Feature compilation check +cargo check --workspace --all-targets --features "fastly cloudflare" + +# Run the demo dev server +cargo run -p edgezero-cli --features dev-example -- dev + +# Docs site +cd docs && npm ci && npm run dev +``` + +**Always run `cargo test` after touching code.** Use `-p ` for +faster iteration on a single crate. + +## Compilation Targets + +| Adapter | Target | Notes | +| ---------- | ------------------------ | ---------------------------------- | +| Fastly | `wasm32-wasip1` | Requires Viceroy for local testing | +| Cloudflare | `wasm32-unknown-unknown` | Requires `wrangler` for dev/deploy | +| Axum | Native (host triple) | Standard Tokio runtime | + +## Coding Conventions + +### Routing + +Use matchit 0.8+ brace syntax for path parameters: + +```rust +// CORRECT +"/resource/{id}" +"/static/{*rest}" + +// WRONG — legacy colon syntax is not supported +"/resource/:id" +``` + +### Handlers + +Use the `#[action]` macro for all new handlers: + +```rust +use edgezero_core::{action, Json, Path, Query, ValidatedJson, Response, EdgeError}; + +#[action] +async fn my_handler( + Json(body): Json, + Path(params): Path, +) -> Result { + // handler body +} +``` + +- Import HTTP type aliases from `edgezero_core` (`Method`, `StatusCode`, + `HeaderMap`, etc.) — never from the `http` crate directly. +- Extractors implement `FromRequest`. Use `ValidatedJson` / `ValidatedPath` / + `ValidatedQuery` for automatic `validator` crate integration. +- `RequestContext` can be destructured: `RequestContext(ctx): RequestContext`. + +### Error Handling + +- Use `EdgeError` with semantic constructors: `EdgeError::validation()`, + `EdgeError::internal()`, etc. +- Map to provider-specific errors only at the adapter boundary. +- Prefer `Result` as handler return type. + +### Middleware + +Implement the `Middleware` trait. Chain via `Next::run()`: + +```rust +struct MyMiddleware; +impl Middleware for MyMiddleware { + async fn handle(&self, ctx: RequestContext, next: Next) -> Result { + // before + let response = next.run(ctx).await?; + // after + Ok(response) + } +} +``` + +### Proxy + +Use `ProxyService` with adapter-specific clients (`FastlyProxyClient`, +`CloudflareProxyClient`). Keep proxy logic provider-agnostic in core. + +### Logging + +- Adapter-specific init: `edgezero_adapter_fastly::init_logger()`, + `edgezero_adapter_cloudflare::init_logger()`. +- Use `simple_logger` for local/Axum builds. +- Use the `log` / `tracing` facade, not direct dependencies. + +### Style Rules + +- **WASM compatibility first**: avoid Tokio and runtime-specific deps in core + and adapter crates. Use `async-trait` without `Send` bounds. Use `web-time` + instead of `std::time::Instant`. +- **Colocate tests** with implementation modules (`#[cfg(test)]` in the same file). +- **Async tests** use `futures::executor::block_on` (not Tokio) for WASM compat. +- **Minimal changes**: every change should impact as little code as possible. + Avoid unnecessary refactoring, docstrings on untouched code, or premature abstractions. +- **Feature gates**: platform-specific code goes behind `fastly`, `cloudflare`, + or `axum` features. Core stays `default-features = false` for WASM targets. +- **No direct `http` crate imports** in application code — use `edgezero_core` re-exports. + +## Adapter Pattern + +Each adapter follows the same structure: + +- `context.rs` — platform-specific request context +- `request.rs` — platform request → core request conversion +- `response.rs` — core response → platform response conversion +- `proxy.rs` — platform-specific proxy client +- `logger.rs` — platform-specific logging init +- `cli.rs` — build/deploy commands (behind `cli` feature) + +Contract tests live in `tests/contract.rs` within each adapter crate. + +## Manifest (`edgezero.toml`) + +The manifest drives routing, env bindings, and per-adapter build/deploy config. +Key sections: `[app]`, `[[triggers.http]]`, `[environment]`, `[adapters]`. + +## CI Gates + +Every PR must pass: + +1. `cargo fmt --all -- --check` +2. `cargo clippy --workspace --all-targets --all-features -- -D warnings` +3. `cargo test --workspace --all-targets` +4. `cargo check --workspace --all-targets --features "fastly cloudflare"` + +Docs CI additionally runs ESLint + Prettier on the `docs/` directory. + +## Standard Workflow + +1. **Read & plan**: think through the problem, read the codebase for relevant + files, and write a plan to `TODO.md` (create it if it doesn't exist). The + plan should be a checklist of todo items you can check off as you complete + them. +2. **Get approval first**: show the full plan and get approval before commencing + any coding work. +3. **Implement incrementally**: work on the todo items, marking them complete as + you go. Make every task and code change as simple as possible — every change + should impact as little code as possible. +4. **Test after every change**: run `cargo test` (or scoped `-p `) after + touching any code. +5. **Explain as you go**: after completing each todo item, give a high-level + explanation of what changes you made. +6. **If blocked**: mark the item as blocked in `TODO.md` and explain why. +7. **Review section**: when finished, append a review section to `TODO.md` with: + a summary of the changes made, assumptions made, any unresolved issues or + errors, and the date/time (UTC) when the work was completed. + +## Verification & Quality + +- **Verify, don't assume**: after implementing a change, prove it works. Run + tests, check `cargo clippy`, and compare behavior against `main` when relevant. + Don't say "it works" without evidence. +- **Plan review**: for complex tasks, review your own plan as a staff engineer + would before implementing. Ask: is this the simplest approach? Does it touch + too many files? Are there edge cases? +- **Escape hatch**: if an implementation is going sideways after multiple + iterations, step back and reconsider. Scrap the approach and implement the + simpler solution rather than patching a flawed design. +- **Use subagents**: for tasks spanning multiple crates or requiring broad + codebase exploration, use subagents to parallelize investigation and keep the + main context clean. + +## Slash Commands + +Custom commands live in `.claude/commands/`: + +| Command | Purpose | +| ----------------- | -------------------------------------------------- | +| `/check-ci` | Run all 4 CI gate checks locally | +| `/test-all` | Run full workspace test suite | +| `/test-crate` | Run tests for a specific crate | +| `/review-changes` | Staff-engineer-level review of uncommitted changes | +| `/verify` | Prove current changes work vs main | + +## Available MCPs + +- **Context7 MCP**: use for up-to-date library docs and coding examples. + +## Key Files Reference + +| Purpose | Path | +| ------------------ | --------------------------------------- | +| Workspace manifest | `Cargo.toml` | +| Core crate entry | `crates/edgezero-core/src/lib.rs` | +| Router | `crates/edgezero-core/src/router.rs` | +| Extractors | `crates/edgezero-core/src/extractor.rs` | +| Action macro | `crates/edgezero-macros/src/action.rs` | +| CLI entry | `crates/edgezero-cli/src/main.rs` | +| Demo app | `examples/app-demo/` | +| Demo manifest | `examples/app-demo/edgezero.toml` | +| CI tests | `.github/workflows/test.yml` | +| CI format/lint | `.github/workflows/format.yml` | +| Docs site | `docs/` | +| Test script | `scripts/run_tests.sh` | +| Roadmap | `ROADMAP.md` | +| Backlog | `TODO.md` | + +## Dependencies Philosophy + +- Workspace-level dependency management via `[workspace.dependencies]` in root `Cargo.toml`. +- Minimal, carefully curated for WASM compatibility. +- `Cargo.lock` is committed for reproducible builds. +- Key crates: `matchit` (routing), `tower` (middleware), `async-trait`, + `async-compression`, `serde`/`serde_json`, `validator`, `clap` (CLI), + `handlebars` (templates). + +## What NOT to Do + +- Don't use legacy `:id` route syntax — always use `{id}`. +- Don't import from `http` crate directly — use `edgezero_core` re-exports. +- Don't add Tokio dependencies to core or adapter crates. +- Don't write tests that require a network connection or platform credentials. +- Don't make large, sweeping refactors — keep changes minimal and focused. +- Don't commit without running `cargo test` first. +- Don't skip `cargo fmt` and `cargo clippy` — CI will reject the PR. diff --git a/TODO.md b/TODO.md index 384a7d6..e0d1ace 100644 --- a/TODO.md +++ b/TODO.md @@ -613,3 +613,15 @@ High-level backlog and decisions to drive the next milestones. - Summary: Canonicalized Apache-2.0 appendix wording in `LICENSE`, aligned docs package root license metadata by regenerating `docs/package-lock.json`, and standardized user-facing license text to "Apache License 2.0" in `README.md` and `docs/.vitepress/config.mts`. - Assumptions: Keeping transitive dependency `license` fields unchanged in `docs/package-lock.json` is correct; only the root package license needed alignment. - Outstanding: No functional issues found; `cargo test` passes when run without sandbox socket restrictions. + +## Codex Plan (2026-02-20 - AGENTS Fallback CI Alignment) + +- [x] Update `AGENTS.md` fallback formatting/linting guidance to use the exact CI command forms. +- [x] Add the missing fallback feature-compilation gate command used in CI. +- [x] Re-check `AGENTS.md` for consistency and append a review entry with UTC timestamp. + +## Review (2026-02-20 05:32:00 UTC) + +- Summary: Updated `AGENTS.md` fallback rule #4 to use the exact CI `cargo fmt --all -- --check` and `cargo clippy --workspace --all-targets --all-features -- -D warnings` commands, and added fallback rule #5 for `cargo check --workspace --all-targets --features "fastly cloudflare"`. +- Assumptions: This request only targeted documentation guidance alignment; no runtime or crate code behavior changed. +- Outstanding: No unresolved issues. `cargo test` was not run because no Rust source code changed.