Spring til indhold
Værktøjer og AI

LLM-venligt projekt i Cursor

Min dyreste Cursor-vane var ikke modellen. Det var min egen rod.

Ikke dramatisk rod. Ikke “vi har mistet production-databasen i en skuffe”-rod. Bare almindelig udviklerrod: lidt for store filer, lidt for mange næsten-ens mapper, lidt for mange “du skal lige vide…”-beskeder til agenten. Den slags, der føles helt uskyldigt, indtil man har betalt for at få den samme AI-agent til at genopdage ens projektstruktur 47 gange.

Det her er ikke teori for mig. Jeg er Halfdan Harring, og min hverdag er en ret konkret blanding af React, Vite, Node.js, Tailwind, Capacitor, Firestore, TypeScript, en baby med sit eget release cadence, og Cursor med AI-agenter åbent det meste af dagen. Jeg bygger produkter solo — Quiz Fight, HeadToHead, TaskMondo, LostLead — og jeg arbejder typisk ud fra én React-codebase, der skal ende som web, iOS og Android. Praktisk. Også en glimrende måde at opdage, hvor hurtigt en agent kan misforstå en mappe med navnet utils.

Hvis du gør dit projekt LLM-venligt fra starten, gør du ikke bare AI’en glad. Du gør dit fremtidige selv mindre træt. Det er en undervurderet KPI.

Mere kontekst er ikke automatisk bedre

Den første fejl er at tro, at agenten bare skal have mere. Mere README. Mere arkitektur. Mere copy-paste fra dokumentationen. Mere “her er alt, du nogensinde kunne få brug for”.

Det lyder ansvarligt. Det er ofte bare dyr støj.

AGENTS.md er ved at blive en fælles konvention for coding agents: en Markdown-fil i repoet, typisk i roden, som fungerer som en slags README for agenten. Den officielle AGENTS.md-side beskriver den netop som et forudsigeligt sted til kontekst, instruktioner, build-kommandoer, test og konventioner — og formatet bruges ifølge siden i over 60.000 open source-projekter.

Det betyder ikke, at du skal skrive en novelle. Gerne ingen plot twist i tredje akt.

Et studie publiceret 12. februar 2026 af Gloaguen, Mündler, Müller, Raychev og Vechev kiggede på, om repository-level context files faktisk hjælper coding agents. Deres resultat er det gode, irriterende slags: LLM-genererede context files sænkede i gennemsnit performance med cirka 3%, mens developer-skrevne filer gav cirka 4% bedre performance. Samtidig øgede context files agentens antal steps og inference cost med over 20%. Forskerne konkluderer, at menneskeskrevne context files bør beskrive minimale krav — ikke alt, der teknisk set kan beskrives.

Det er pointen: agenten skal ikke fodres. Den skal styres.

Den LLM-venlige kodebase starter med filerne

Når jeg starter et projekt i Cursor, prøver jeg at gøre kodebasen let at læse for både mig selv og agenten. I den rækkefølge. En AI-agent er ret god til at finde rundt, hvis projektet faktisk er til at finde rundt i. Chokerende brancheindsigt. Vi kommer nok over det.

Det betyder først og fremmest små, fokuserede filer.

Jeg prøver at undgå komponenter, hooks eller service-filer, der bliver til små kommuner. Når en fil nærmer sig 250-300 linjer, begynder jeg at spørge: er det her stadig én ting? Hvis svaret er “ja, teknisk set”, er svaret ofte nej.

I en React/Vite/TypeScript-kodebase kan det se sådan her ud:

src/
  app/
    App.tsx
    routes.tsx
  features/
    quiz/
      components/
        QuizCard.tsx
        QuizResultPanel.tsx
      hooks/
        useQuizSession.ts
      services/
        quizSessionService.ts
      quiz.types.ts
    tasks/
      components/
      hooks/
      services/
      task.types.ts
  shared/
    ui/
      Button.tsx
      Modal.tsx
    lib/
      firebase/
        firestoreClient.ts
        firestoreConverters.ts
    hooks/
    types/

Det afgørende er ikke den præcise struktur. Det afgørende er, at agenten kan gætte rigtigt.

Hvis den skal ændre noget i quiz-flowet, skal den kigge i features/quiz. Hvis den skal rette Firestore-logik, skal den kigge i shared/lib/firebase. Hvis den skal style en knap, skal den ikke scrolle gennem App.tsx, som også indeholder onboarding, navigation, analytics og en lille eksistentiel krise.

Jeg navngiver filer efter ansvar, ikke efter håb. helpers.ts er et råb om hjælp. formatQuizScore.ts er en fil. api.ts kan være hvad som helst. taskService.ts fortæller i det mindste nogenlunde, hvor man skal grave.

Typer er kontekst, du ikke betaler ekstra for hver gang

TypeScript er ikke kun for mennesker med hang til røde streger i editoren. Det er også en måde at give agenten lokal, præcis kontekst.

En god type fortæller agenten, hvad noget er, uden at du skal forklare det i chatten:

export type QuizSession = {
  id: string
  status: 'pending' | 'active' | 'completed'
  playerIds: string[]
  currentQuestionIndex: number
  createdAt: Date
}

Det er meget bedre end at skrive “en session har sådan cirka nogle spillere og en status” til agenten hver gang. Den kan læse typen, bruge den, rette efter den og blive stoppet, når den gætter forkert. Lidt ligesom en juniorudvikler med compiler. Bare uden fredagskage.

Mine grundregler er simple:

  • Del domænetyper ud i *.types.ts, når de bruges flere steder.
  • Hold component props tæt på komponenten, hvis de kun bruges dér.
  • Lav Firestore converters og data-mapping eksplicit, så agenten ikke opfinder felter.
  • Brug enums/unions til statusser, roller og flows, hvor stringly-typed logik ellers begynder at yngle.

Det sparer tokens, fordi du ikke skal genforklare domænet. Det sparer tid, fordi agenten får færre frihedsgrader. Og det sparer frustration, fordi den ikke pludselig beslutter, at completed nok hedder done i dag. Kreativitet er dejligt. Ikke i statusfelter.

Lav et lille projektkort

Jeg kan godt lide at have en kort docs/project-map.md eller en sektion i AGENTS.md, der beskriver projektets vigtigste områder. Ikke en komplet rundvisning med brochure og gratis kuglepen. Bare nok til, at agenten starter det rigtige sted.

Eksempel:

## Project map
- `src/features/quiz/` — quiz flows, session state, quiz UI
- `src/features/tasks/` — task CRUD, task lists, filters
- `src/shared/ui/` — reusable presentational components
- `src/shared/lib/firebase/` — Firestore client, converters, shared queries
- `src/app/` — routes, providers, app shell

Do not add feature-specific logic to `shared/`.
If a component needs Firestore directly, reconsider the boundary first.

Det sidste er vigtigt. Et godt projektkort siger ikke kun, hvor ting ligger. Det siger også, hvor ting ikke skal ligge.

Agenten har brug for grænser. Ikke mange. Bare de rigtige.

AGENTS.md: skriv det, agenten ikke kan regne ud

Min foretrukne root-fil er AGENTS.md, fordi den er tool-agnostisk og efterhånden understøttes bredt. OpenAI Codex læser for eksempel AGENTS.md før arbejdet starter og bruger en hierarkisk model, hvor globale instruktioner kan kombineres med projektspecifikke filer og nærmere filer kan overstyre bredere guidance.

AGENTS.md-siden beskriver også “nearest wins”-ideen: i store repos kan du have nested AGENTS.md-filer i underprojekter, og den nærmeste fil får forrang. Det er præcis den slags, der gør en monorepo mindre som en svensk krimi.

En god AGENTS.md i mine projekter ville typisk være kort:

# AGENTS.md

## Project overview
React + Vite + TypeScript app using Tailwind, Capacitor and Firestore.
One codebase ships to web, iOS and Android.

## Commands
- Install: `npm install`
- Dev server: `npm run dev`
- Typecheck: `npm run typecheck`
- Lint: `npm run lint`
- Build: `npm run build`

## Architecture
- Feature code lives in `src/features/<feature>/`.
- Shared UI lives in `src/shared/ui/`.
- Firestore logic lives in `src/shared/lib/firebase/` or feature services.
- Do not put feature-specific business logic in `shared/`.

## Code style
- TypeScript first. Do not use `any` unless the alternative is worse and explain why.
- Prefer small components and explicit props.
- Use Tailwind classes for styling.
- Keep platform-specific Capacitor logic isolated.

## Agent workflow
- Before editing, identify the files you expect to touch.
- Prefer changing existing files over adding new abstractions.
- After edits, run typecheck and lint if relevant.
- Do not modify generated files, lockfiles or Capacitor platform folders unless asked.

## Do not touch without asking
- Production Firebase config
- App signing / native platform setup
- Payment, auth or analytics configuration

Det er ikke perfekt. Det er bare nyttigt. Og det er hele pointen.

Den skal ikke forklare React. Den skal ikke forklare, hvad npm install er. Den skal ikke indeholde Tailwinds dokumentation. Agenten ved allerede meget. Din opgave er at skrive det, den ikke kan udlede sikkert fra repoet.

Cursor-regler uden kontekstkompost

I Cursor bruger jeg samme princip: root-guidance skal være lille, og mere specifikke regler skal være scoped. Cursor beskriver selv Rules som persistent instructions via Project, Team og User Rules, og Cursor-dokumentationen nævner også AGENTS.md som del af den model.

Jeg ville ikke starte et nyt projekt med én gigantisk regel-fil, der gælder for alt. Det er sådan, man ender med at sende Firestore-regler med ind i en CSS-ændring. Hyggeligt, men dyrt.

I stedet:

.cursor/
  rules/
    project.mdc
    react-components.mdc
    firestore.mdc
    capacitor.mdc

Tanken er:

  • project.mdc er altid lille og generel.
  • react-components.mdc gælder for src/**/*.tsx.
  • firestore.mdc gælder for src/**/*firestore* og relevante service-filer.
  • capacitor.mdc gælder kun, når der arbejdes med native/platform-kode.

Claude Code bruger sin egen CLAUDE.md, men Claude-dokumentationen anbefaler, at man kan importere AGENTS.md i CLAUDE.md eller bruge et symlink, så instruktionerne ikke divergerer. Den nævner også, at CLAUDE.md bør være specifik og kort, fordi den læses ind i context window.

GitHub Copilot har tilsvarende repository-wide instruktioner i .github/copilot-instructions.md, path-specific .instructions.md-filer og understøtter også AGENTS.md, hvor den nærmeste fil i directory tree kan få forrang for agent-instruktioner.

Mit praktiske råd er derfor: vælg én canonical kilde. For mig er det typisk AGENTS.md. Lad andre tool-specifikke filer pege på den eller supplere meget smalt.

Ellers har du ikke agent-styring. Du har fire næsten ens sandheder. Det er en meget software-agtig måde at skabe løgne på.

llms.txt er til dokumentation, ikke din kodebase

llms.txt er værd at kende, men det løser et andet problem. Hvor AGENTS.md styrer agentens arbejde i dit repo, er llms.txt mere som en Markdown-indgang til docs og API’er. Forslaget bag llms.txt beskriver en /llms.txt-fil som en LLM-venlig Markdown-fil med kort baggrund, guidance og links til mere detaljerede Markdown-filer.

Det er nyttigt, når agenten skal bruge ekstern dokumentation uden at tygge sig gennem HTML, navigation, cookie-bannere og andet web-affald. En meget moderne buffet.

Jeg ville ikke kopiere hele Tailwind-, Firebase- eller Capacitor-dokumentationen ind i mit repo. Jeg ville hellere have en lille sektion:

## External docs protocol
When behavior depends on external docs:
1. Check the installed package version first.
2. Use official docs or llms.txt if available.
3. Summarize the relevant API/version assumption before editing.
4. Do not paste large external docs into project rules.

Det er igen samme disciplin: peg. Lad være med at proppe.

Sådan instruerer jeg agenten på et friskt projekt

Når jeg starter noget nyt i Cursor, giver jeg ikke agenten “byg en app”-prompten som det første. Det er fristende. Det føles produktivt. Det er også sådan, man får components2.

Jeg starter hellere med en setup-opgave:

Set this project up to be LLM-friendly before implementing features.

Create:
- A clear `src/features/` and `src/shared/` structure
- A short `AGENTS.md` with project commands, architecture boundaries and do-not-touch areas
- A small `docs/project-map.md`
- Cursor rules only if they add scoped value beyond AGENTS.md

Rules:
- Keep files small and single-purpose
- Use explicit TypeScript types for domain objects
- Do not generate generic AI instruction bloat
- Only document conventions that are specific to this project
- Ask before adding dependencies or changing platform/native config

Derefter beder jeg den implementere den første feature inden for de grænser. Ikke før.

Det er cirka en times arbejde i starten. Nogle gange mindre. Men det betaler sig, hver gang agenten ikke skal spørge, hvor Firestore-logikken bor. Hver gang den ikke læser halvdelen af repoet for at rette en knap. Hver gang den ikke genopfinder en naming convention, fordi jeg ikke lige havde fået sagt den højt i denne session.

Det hænger ret meget sammen med den måde, jeg bygger solo-produkter på fra Aarhus: så få gentagelser som muligt, så meget fremdrift som muligt, og helst uden at gøre fremtidige mig til en stakkels intern supportmedarbejder. Jeg har skrevet mere om min måde at bygge produkter på om-siden. Og det passer naturligt sammen med hvordan jeg vælger Cursor-modeller i praksis.

Mandag morgen-versionen

Hvis du allerede har et projekt, så gør det her:

  1. Find de fem filer, agenten oftest misforstår. Split dem, navngiv dem ordentligt, eller flyt ansvar ud.
  2. Lav en AGENTS.md på under 100 linjer.
  3. Skriv kun projektets egne konventioner: kommandoer, struktur, navne, grænser, do-not-touch.
  4. Lav et lille projektkort med de vigtigste mapper.
  5. Tilføj scoped Cursor-regler, hvis root-filen ellers bliver for bred.
  6. Slet alt, der lyder som “write clean code”.

Den sidste regel er vigtig. “Write clean code” er ikke en instruktion. Det er en bøn.

Og hvis du får lyst til at auto-generere en 900-linjers AGENTS.md, så gå en tur først. Gerne uden telefon. Måske se et afsnit af The Office. Ikke fordi Michael Scott er god til softwarearkitektur, men fordi han i det mindste minder os om, hvad der sker, når alle tror, de kommunikerer klart.

Det gør de sjældent. Det gør vores filer heller ikke, før vi tvinger dem til det.