# CLAUDE.md: Clojure

## Commands
- Detect the build tool: `deps.edn` → Clojure CLI (`clojure -M:test`, `clojure -T:build`), `project.clj` → Leiningen (`lein test`, `lein uberjar`). Use the aliases already defined; don't add a second tool.
- Lint: `clj-kondo --lint src test` · Format: `cljfmt check` (or `cljfmt fix` on changed files) if configured.
- Run focused tests by namespace (`clojure -M:test -n my.app.core-test` with Kaocha/Cognitect runner as configured).

## Code
- Namespaces mirror paths (`src/my/app/orders.clj` → `my.app.orders`, dashes in names, underscores in file paths). Keep `:require` sorted with explicit `:as` aliases; no `:use` or `:refer :all`.
- Prefer pure functions on plain maps and vectors. Push side effects (DB, HTTP, time, randomness) to the edges and pass dependencies in, so functions are testable from the REPL.
- Use namespaced keywords for domain data (`:order/id`). Validate data at system boundaries with the project's choice (malli or clojure.spec), not throughout the core.
- State: no global `def` atoms for app state. Use the project's lifecycle library (Integrant, Component, mount) and keep reloadable namespaces free of side effects at load time.
- Errors: throw `ex-info` with a message and a data map (`{:type ::not-found :id id}`); catch at the boundary and translate to responses.
- Threading macros (`->`, `->>`, `some->`, `cond->`) for pipelines; keep functions short; avoid deep nesting of `let` and `if`.
- Laziness: realize sequences that touch resources inside the `with-open` (`doall`, `into`, `run!`). Never return a lazy seq over a closed resource.
- Java interop with type hints where reflection warnings appear (`(set! *warn-on-reflection* true)` in hot namespaces).
- ClojureScript (if present): shadow-cljs builds via `npx shadow-cljs compile <build>`; keep `.cljc` for shared code with reader conditionals.

## Done when
clj-kondo shows no new warnings and the relevant tests pass. Say if you evaluated code in a REPL versus ran the test suite.
