This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Detailed per-project conventions live in AGENTS.md files — read the relevant one before editing. They are the source of truth for style and rules; this file covers the cross-cutting architecture and commands.
AGENTS.md(root) — repo overviewcodedrift-frontend/AGENTS.md— frontend stack + rulescodedrift-backend/AGENTS.md— backend stack + rules
Key rules from those files worth repeating: don't install packages without explicit permission; kebab-case filenames, camelCase vars, PascalCase types; @/ (frontend) / @types (backend) import conventions; explicit return types; keep lines under 120 chars (aim for 80); after backend endpoint changes, create/update the Bruno collection under api-collection/Codedrift.
Codedrift is a code-intelligence / diff-review app. There is no root package.json — the two apps are developed and run independently from their own directories.
codedrift-backend/— Node + Fastify + TypeScript API. Reads a target git repo viasimple-git, computes diffs, and exposes both an HTTP/diffendpoint and AI tool endpoints.codedrift-frontend/— React 19 + Vite + TanStack Router/Query + Tailwind v4 + Shadcn UI. Renders the diff review UI.api-collection/Codedrift/— Bruno (OpenCollection) API collection; keep in sync with backend endpoints.
pnpm dev—tsx --watch src/main.ts, server on port 3000pnpm build—tscpnpm typecheck—tsc --noEmitpnpm start—node dist/main.js- No test runner is configured. Lint via
eslint .; Prettier runs on pre-commit (husky + lint-staged).
pnpm dev— Vite dev serverpnpm build—tsc -b && vite buildpnpm lint—eslint .pnpm preview— preview production build- No test runner. Prettier runs on pre-commit. After changes, the frontend AGENTS.md asks for
tsc+ prettier; do not run vite/the browser to check visuals unless asked.
The backend operates on a live git repository on disk — there is no database or persistence layer. The whole app is stateless: each request re-runs git operations.
- The target repo and refs being compared are hardcoded in
codedrift-backend/src/utils/temp-repo-info.ts(REPOSITORY_PATH,DIFF_BASE_REF,DIFF_HEAD_REF). This is temporary scaffolding — the/diff/selectfrontend route is the eventual place to choose branches. Update this file to point at a different repo/refs. src/services/diff-service.tsshells git throughsimple-git, parses raw diff output, normalizes paths, classifies each file (added / deleted / moved / changed), and fetches full file content at base and head. Shared shapes live insrc/@types/diff.ts(DiffFileData,DiffChangeType).src/main.tsis the Fastify entry point (CORS open).GET /diffreturns the fullDiffFileData[].src/tools/changeset-tools.tswraps git operations as AI tools (via theaiSDKtool()helper) — list commits, get hunks, get file content at base/head. These are exposed underPOST /tools/changeset/*and are validated to only accept repo-relative paths.
On the frontend:
- TanStack Router uses file-based routing — routes live in
src/routes/, andsrc/routeTree.gen.tsis auto-generated by@tanstack/router-plugin(do not edit by hand). Main routes:/,/diff/select(placeholder for branch selection),/diff/view(the main diff viewer). src/routes/diff/view/route.tsxfetchesGET ${VITE_DIFF_API_URL}(defaulthttp://localhost:3000/diff) via TanStack Query (["diff"]) using nativefetch(no Axios). Configure the URL incodedrift-frontend/.env.- The result is pushed into the Zustand store
src/store/diff-view-store.ts(diffFiles,selectedFileId). The store auto-selects the first file and keeps the selection valid across navigation. - The sidebar file tree (
src/components/sidebar/) renders changed files grouped by directory with color-coded change types; clicking a file setsselectedFileId, and the main pane renders it with@git-diff-view/react(split view).
- Frontend path alias
@/*→./src/*is set in bothtsconfigandvite.config.ts. The backend has nopathsalias —@typesthere is a real directory (src/@types/) imported by relative path. - Backend uses native ESM with
.tsimport extensions (allowImportingTsExtensions,rewriteRelativeImportExtensions); keep the.tsextension in relative imports. - Shared/reused types go in the
@typesfolder in each app. - The
aiSDK is wired for Anthropic/OpenAI/OpenRouter providers; when building or debugging LLM/tool features here, prefer the latest Claude models.