diff --git a/CLAUDE.md b/CLAUDE.md index 5835cdb..48221dd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,7 +39,13 @@ tools.versions Pinned tool versions (sourced by Makefile and pre-push - **Module imports** — always use the full module path `gitea.djmil.dev/go/template/...` - **Packages** — keep `cmd/` thin (wiring only); business logic belongs in `internal/` - **Types** — expose concrete types from constructors (`New(...) *Type`); never wrap in an interface at the implementation site. Consumers define their own interfaces if they need one (Go's implicit satisfaction makes this free) -- **Errors** — wrap with `fmt.Errorf("context: %w", err)`; never swallow errors silently +- **Errors** — `pkg/result` is the default error-handling mechanism for all code in this repo, including public APIs: + - functions return `result.Expect[T]` instead of `(T, error)` + - callers unwrap with `.Expect("context")` (panics with annotated error + stack trace) or `.Must()` (panics with raw error) + - top-level entry points (e.g. `cmd/` functions, HTTP handlers) defer `result.Catch(&err)` to convert any result panic into a normal Go error; genuine runtime panics (nil-deref, etc.) are re-panicked + - bridge existing `(T, error)` stdlib/third-party calls with `result.Of(...)`: `result.Of(os.ReadFile("cfg.json")).Expect("read config")` + - use `result.StackTrace(err)` to retrieve the capture-site stack from a caught error + - still use `fmt.Errorf("context: %w", err)` when wrapping errors *before* constructing a `result.Fail` - **Logging** — use `log.WithField("key", val)` for structured context; never `fmt.Sprintf` in log messages; `log/slog` is the backend - **Config** — all configuration through `internal/config` (flag-parsed); no hard-coded values in logic packages