Skip to content

add claude file#44

Merged
maanlamp merged 4 commits into
mainfrom
claude
May 7, 2026
Merged

add claude file#44
maanlamp merged 4 commits into
mainfrom
claude

Conversation

@publicJorn
Copy link
Copy Markdown
Member

@publicJorn publicJorn commented Apr 13, 2026

Suggestion by Ivan, let's make it nice and merge.

Part of #42

@publicJorn publicJorn assigned publicJorn and unassigned publicJorn Apr 13, 2026
@Atchferox
Copy link
Copy Markdown
Contributor

I'll test this claude.md in Omgevingschat, and make changes accordingly :)

Copy link
Copy Markdown
Collaborator

@maanlamp maanlamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've not scrutinised this completely, but I saw two things that I thought didn't align with our dev approach.

I might have a more detailed look later if we think of more changes/additions

Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
Comment thread .claude/claude.md Outdated
@Atchferox
Copy link
Copy Markdown
Contributor

Atchferox commented Apr 13, 2026

Yhea i wasn't a big fan of the claude.md Ivan suggested, it states things that the model already knows, and maybe its even too deep. https://www.humanlayer.dev/blog/writing-a-good-claude-md
only issue with our pre commit verification, is that changes are going to be commited, thats not always what you want to do before linting formatting etc.

@Atchferox
Copy link
Copy Markdown
Contributor

Atchferox commented Apr 14, 2026

CLAUDE.md

Commands

  • Dev: bun run dev (generates API client + starts Vite)
  • Build: bun run build (generates client + Vite build + tsc)
  • Lint: bun run lint (Biome for TS/TSX + Prettier for SCSS)
  • Regenerate API client: bun run gen (hey-api from openapi.jsonsrc/lib/api/heyapi/)

Generated files in src/lib/api/heyapi/ are created by @hey-api/openapi-ts. Never edit them manually. The directory is excluded from Biome.

Stack

Vite 7 + React 19 + TypeScript 5.9 (strict) + Zod 4. Bun as package manager.

React Compiler is enabled — do not manually add useMemo/useCallback unless solving a specific problem the compiler can't handle.

Architecture

src/
  components/    Reusable UI (form/, heading/, error-text/, etc.)
  pages/         Page components (one dir per page, default export)
  layouts/       App and Auth layout shells (react-router Outlet)
  router/        BrowserRouter config + lazy page loading
  lib/
    api/         API client setup, middleware, and heyapi generated code
    auth.tsx     Auth context (token in localStorage)
    i18n.ts      i18next setup
    page-title.tsx
    location-state.ts
  style/         Global SCSS + design variables
  i18n/          Translation JSON files (nl-NL, en-US)
  env.ts         Zod-validated env vars from import.meta.env

Key patterns

Imports

Path alias * maps to src/*. Use bare paths:

import { useAuth } from "lib/auth";
import { Button } from "components/form";

Pages

Each page is a directory under src/pages/ with:

  • <name>-page.tsx (default export)
  • <name>-page.module.scss + auto-generated .d.ts

Pages are lazy-loaded via lazyComponent() in src/router/page-loader.tsx. Register new pages there.

Routing

React Router 7 with BrowserRouter. Routes in src/router/routes.tsx.

  • AuthLayout wraps public routes (login, forgot-password)
  • AppLayout wraps authenticated routes
  • ProtectedRoute guards auth-required pages (redirects to /login)

Data fetching

hey-api generates a typed SDK from openapi.json. Use the generated functions directly:

import { postApiAuthLogin, type ValidationError } from "lib/api/heyapi";

const { data, error } = await postApiAuthLogin({ body: { email, password } });

For queries/mutations in components, use TanStack React Query (also generated by hey-api). The QueryClient is configured in src/lib/api/api.tsx.

Auth token is injected via request middleware in src/lib/api/middleware.ts.

Forms

No form library — use controlled inputs with backend validation:

const [error, setError] = useState<ValidationError>();

// After API call:
if (error) setError(error);

// In JSX:
<Input isInvalid={!!error?.errors?.fieldName} />
<ErrorText>{error?.errors?.fieldName}</ErrorText>

ErrorText accepts string | string[] and renders nothing if children is falsy.

Auth

useAuth() returns [token, setToken]. Token lives in localStorage. Presence of token = logged in.

Environment variables

Defined in .env (see .env.example), validated by Zod schema in src/env.ts:

import env from "env";
env.apiBaseUrl // typed and validated

Prefix with VITE_ for Vite exposure. Add new vars to both .env.example and the schema in src/env.ts.

i18n

All user-facing text goes through react-i18next:

const { t } = useTranslation();
t("pages.login.title")

Translation files: src/i18n/nl-NL.json, src/i18n/en-US.json.

Components

  • Props: extend native element props (React.ComponentPropsWithoutRef<"element"> or React.ComponentProps<"element">)
  • Styling: SCSS Modules (.module.scss), types auto-generated. Use classnames for conditional classes.
  • CSS variables for colors/fonts/spacing in src/style/variables/
  • Barrel exports in components/form/index.ts

Formatting & linting

Two tools with separate responsibilities:

  • Biome 2.3: TS/TSX linting + formatting (tabs, double quotes, semicolons, 60 char line width)
  • Prettier 3.6: SCSS only (tabs, CSS property ordering via prettier-plugin-css-order)

Biome rules to know:

  • noConsole is an error
  • noUnusedImports is a warning
  • Biome auto-organizes imports
  • Ignores *.d.ts, *.gen.ts, and src/lib/api/heyapi/

Pre-commit hooks via Lefthook run both Biome and Prettier on staged files.

Rules

  • Match existing patterns. Read nearby code before changing anything.
  • Keep changes small and focused.
  • No any. No console.log.
  • No new dependencies without good reason.

I think with this setup, claude wont get lost in its own claude.md, this is based on the example of Ivan, without repeating the same things multiple times, and also bit more template specific.

The philosophy

A CLAUDE.md should answer: "What would a new developer on this project get wrong on day one?" — not "What does the React docs say?"

@maanlamp
Copy link
Copy Markdown
Collaborator

maanlamp commented Apr 14, 2026

Forgive my absolute lack of knowledge on this part of the whole AI thing, but reading those best practises, would it be useful to separate the file into skills instead? Or should we find some that others made that do a better job?

I'm thinking the CLAUDE.md is just a general "map" for Claude to reference once in a while, but we should probably have a typescript skill, a react skill, etc. Right?

Idk if they're even applicable here 🙃

@Atchferox
Copy link
Copy Markdown
Contributor

Forgive my absolute lack of knowledge on this part of the whole AI thing, but reading those best practises, would it be useful to separate the file into skills instead? Or should we find some that others made that do a better job?

I'm thinking the CLAUDE.md is just a general "map" for Claude to reference once in a while, but we should probably have a typescript skill, a react skill, etc. Right?

Idk if they're even applicable here 🙃

claude.md gets referenced in every turn, its useful for easy stuff like architecture choices and other stuff, indeed stuff about typescript, react etc.. could be done in skills and invoked when needed!

@maanlamp
Copy link
Copy Markdown
Collaborator

maanlamp commented Apr 15, 2026

Well, one key paragraph from the article you linked stated:

"Claude will ignore the contents of your CLAUDE.md if it decides that it is not relevant to its current task. The more information you have in the file that's not universally applicable to the tasks you have it working on, the more likely it is that Claude will ignore your instructions in the file."

That sounds exactly like what we're trying to do, cramming all of these specific sections into the general CLAUDE.md, no? That means we're actively pushing Claude to ignore our instructions by expanding on it 🤔

@maanlamp
Copy link
Copy Markdown
Collaborator

maanlamp commented Apr 21, 2026

Update: I tried this out in Phase2.

My primary findings:

  • Telling Claude to use the linting/formatting strategy as defined in the project helped it deliver features that would pass build verification without manual intervention, although for some reason it really liked to use a python3 script to read the scripts property, instead of just opening package.json and having a look. I'm not sure what to do about that (if anything), but this is a great addition.
  • Claude's generally sound React capabilities means this md file didn't change much in it's approach to features in my opinion. It does use a lot more tokens to read the files around it and then applies the same codestyle, which is an improvement but has drawbacks (especially when using high effort mode, some easy changes suddenly take minutes). Maybe we can reduce the token usage by providing a custom react skill for our org, or by dropping those instructions and tightening our linter config since it should run that anyway.
  • A lot of the rules in the file seem to get skipped. Probably because it's generally quite contradictory (e.g. "Change only what is necessary for the requested outcome" -> "preserve or improve accessibility/type safety"). I understand we want to limit Claude from going off and doing unrelated things, but to improve current solutions we can't forbid it in one rule and require it in another.
  • It's probably best to be more specific regarding what our toolchain is. I understand the file as sent was a general one that should help with all codebases, but it lacks the specifics to be more useful. I think we should take some inspiration from Luuk's comment.

With those findings in mind, we updated the md file to the following:

# CLAUDE.md

You are working in a production TypeScript + React repository. Make safe, minimal, maintainable changes that fit the existing architecture.

**Primary rule**: before changing code, read the surrounding files and follow the patterns already present. Prefer the pattern used closest to the code you are editing.

---

## Stack

| Concern         | Tool                                                                |
| --------------- | ------------------------------------------------------------------- |
| Package manager | `bun`                                                               |
| Build           | Vite                                                                |
| Framework       | React 19 + TypeScript 5                                             |
| Routing         | `react-router-dom` v6                                               |
| Data fetching   | `openapi-fetch` + `openapi-react-query` + TanStack Query v5         |
| API types       | Generated — `src/lib/schema.gen.d.ts` + `src/lib/validators.gen.ts` |
| Forms           | `react-zorm` + `zod`                                                |
| UI primitives   | `@base-ui/react`                                                    |
| Styling         | CSS Modules + SCSS (`sass-embedded`)                                |
| i18n            | `i18next` + `react-i18next`                                         |
| Testing         | Playwright                                                          |

---

## Verification

Before finishing any task, run in order:

```
bun check:types   # Check types with tsc
bun fix           # Fixes all formatting issues with oxfmt
```

Never bypass hooks or suggest `--no-verify`.

---

## UI primitives — base-ui

Before implementing any interactive widget (dialog, popover, menu, select, checkbox, slider, tooltip, etc.), fetch `https://base-ui.com/llms.txt` and use the relevant `@base-ui/react` primitive. Do not hand-roll accessible widgets.

---

## Generated files

Do not edit these manually:

- `src/lib/schema.gen.d.ts` + `src/lib/validators.gen.ts` — regenerate with `bun setup:all`
- `*.module.scss.d.ts` — generated automatically by the build tool from CSS Modules; do not create or modify these files

---

## TypeScript

- No `any`
- No casts — help the compiler infer correctness through runtime logic. If a third-party type makes this impossible, cast with a comment explaining why. Last resort only.
- No non-null assertions — prefer type guards and narrowing
- No duplicate type definitions — reuse exported types from API, hooks, or shared modules
- Add JSDoc to util functions you create, including at least one example. Add docs to existing util functions you edit that are missing them. Keep types in typescript.

---

## React

- Extract into subcomponents or hooks when a component exceeds ~150–200 LOC
- No global state for local UI concerns
- No `useEffect` for logic that can run during render, in event handlers, or as derived/memoized values
- No `useMemo` / `useCallback` unless solving a real referential stability or performance problem
- No hardcoded user-facing copy — use i18n keys

---

## Data fetching

- Use the existing `openapi-react-query` / TanStack Query patterns
- Always handle loading, empty, and error states
- Never hardcode URLs, tokens, or environment-specific values

---

## Scope

- Change only what is necessary for the requested outcome
- Do not refactor files you are not already modifying
- Do not add dependencies unless clearly necessary — prefer what is already in `package.json`
- Do not add comments unless the _why_ is non-obvious to a future reader

@publicJorn publicJorn marked this pull request as ready for review May 6, 2026 09:24
@publicJorn publicJorn marked this pull request as draft May 6, 2026 09:27
@publicJorn
Copy link
Copy Markdown
Member Author

publicJorn commented May 6, 2026

WIP: made agreed on changes, but needs to be merged with the other claude file that was introduced with other PRs

@publicJorn publicJorn marked this pull request as ready for review May 7, 2026 08:38
@maanlamp maanlamp merged commit 5d5a7dc into main May 7, 2026
1 check passed
@maanlamp maanlamp deleted the claude branch May 7, 2026 08:48
publicJorn added a commit that referenced this pull request May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants