@mkappelhof/agent-instructions 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # @mkappelhof/agent-instructions
2
+
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3c4c6b4: Add `nest.md` with general best-practice conventions for NestJS services (project structure, DI, DTOs/validation, error handling, config/logging, testing).
8
+
9
+ ### Patch Changes
10
+
11
+ - 3c4c6b4: Make `base.md` a generic, standalone baseline instead of assuming it's always paired with this repo's other `@mkappelhof/*` config packages. Following a matching config package's `AGENTS.md` is now framed as conditional on the project actually using it, not assumed.
12
+
13
+ ## 1.0.1
14
+
15
+ ### Patch Changes
16
+
17
+ - eb2577f: Add new configs
package/README.md CHANGED
@@ -1,3 +1,38 @@
1
- # Temporary Holding Version
1
+ # Shared agent instructions
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Project-level instructions for AI coding agents, covering code structure and conventions rather
4
+ than tool configuration. If the project also uses one of this repo's config packages (TypeScript,
5
+ Biome, ESLint, Stylelint), pair these with the `AGENTS.md` it ships, which describes that tool's
6
+ rules — but these files don't assume that pairing, and `base.md` works as generic baseline
7
+ instructions on its own for a project that doesn't match any of the more specific files below.
8
+
9
+ | File | For |
10
+ | ---------- | -------------------------------------------------------------------------------------------------------------------- |
11
+ | `base.md` | Any project, any stack: verifying instead of assuming, workflow, git, imports, TypeScript, design tokens, versioning |
12
+ | `react.md` | React and Next.js projects (components, contexts, i18next, SCSS modules, Vitest) |
13
+ | `astro.md` | Static Astro sites (rendering, styling, data, images) |
14
+ | `nest.md` | NestJS services (modules, DI, DTOs/validation, error handling, testing) |
15
+
16
+ `react.md`, `astro.md` and `nest.md` all tell agents to read `base.md` first, so you only need to
17
+ reference the file for your project type. For a project that's none of these (a plain script,
18
+ a different framework, etc.), reference `base.md` directly.
19
+
20
+ ## Installation
21
+
22
+ ```sh
23
+ pnpm add -D @mkappelhof/agent-instructions
24
+ ```
25
+
26
+ Reference the file for your project type from the `AGENTS.md` at the root of your project:
27
+
28
+ ```md
29
+ # AGENTS.md
30
+
31
+ ## Conventions
32
+
33
+ - Follow `node_modules/@mkappelhof/agent-instructions/react.md`
34
+ ```
35
+
36
+ Put anything project-specific (architecture, extra commands, exceptions to the shared conventions)
37
+ in your own `AGENTS.md`. The shared files tell agents that the project's own instructions take
38
+ precedence.
package/astro.md ADDED
@@ -0,0 +1,34 @@
1
+ # Astro — agent instructions
2
+
3
+ Conventions for static Astro sites written in TypeScript and styled with SCSS. Everything in
4
+ [`base.md`](./base.md) applies as well; read it first.
5
+
6
+ The site ships static HTML/CSS with no client-side framework. Use small inline `<script>` tags only
7
+ where genuinely needed (e.g. a mobile nav toggle).
8
+
9
+ ## Rendering
10
+
11
+ - Keep `output: 'static'` in `astro.config.mjs`: no server rendering and no framework islands
12
+ (`@astrojs/react` etc.). Reach for an inline `<script>` before adding a framework.
13
+
14
+ ## Styling
15
+
16
+ - Write styles in component-scoped `<style lang="scss">` blocks.
17
+ - Import the design token stylesheet (see `base.md`) once, in the base layout.
18
+
19
+ ## Data
20
+
21
+ - Keep content data in `src/data/` as typed TypeScript modules. Each data set (features, pricing,
22
+ FAQ, etc.) has a single source of truth there; pages render from it instead of repeating it.
23
+ - Generate derived output such as `llms.txt` and JSON-LD structured data from the same data
24
+ modules, so they can't drift from what the pages show.
25
+ - Values that come from outside the site (e.g. a product version or description from another
26
+ `package.json`) are read once in `astro.config.mjs` and exposed through `vite.define` constants.
27
+ Read them in the config file, because its `import.meta.url` stays reliable while app modules get
28
+ bundled and relocated. Never hardcode such values elsewhere.
29
+
30
+ ## Images
31
+
32
+ - Keep images in `src/assets/` and render them with Astro's `<Image>` (or `<Picture>`) component
33
+ from `astro:assets` so they're optimized at build time. Never reference them as raw
34
+ `<img src>` paths.
package/base.md ADDED
@@ -0,0 +1,88 @@
1
+ # Base — agent instructions
2
+
3
+ My personal baseline conventions for any project I work on, regardless of stack and regardless of
4
+ whether the project uses any other `@mkappelhof/*` package. `react.md`, `astro.md` and `nest.md`
5
+ build on this file for their respective project types, but this file is also meant to stand alone
6
+ as generic `AGENTS.md` content for projects that don't match one of those.
7
+
8
+ This file is a starting point, not a mandate: where the project's own `AGENTS.md` (or anything the
9
+ user says) differs from what's here, that project-specific instruction wins.
10
+
11
+ If the project happens to use one of my shared `@mkappelhof/*` config packages (for TypeScript,
12
+ linting, formatting, etc.), that package's own `AGENTS.md` describes the rules its tool enforces —
13
+ follow those too. Don't assume one is in use, though; check the project's `package.json` and
14
+ config files (`tsconfig.json`, `.eslintrc*`, `biome.json`, `.stylelintrc*`, ...) to see what
15
+ tooling is actually there before applying tool-specific conventions from anywhere.
16
+
17
+ ## Don't assume, verify or ask
18
+
19
+ - Base every claim and every change on what you have actually read: the code, the config, the
20
+ installed packages' docs, or the user's instructions. Do not invent files, functions, props,
21
+ scripts, config options, package APIs or CLI flags.
22
+ - Before you use an API, component, helper or token, check that it exists and how it is used in
23
+ this project (search the codebase, read the type definitions or the package's docs in
24
+ `node_modules`). Your training data may describe a different version.
25
+ - When the request is ambiguous, information is missing, or several reasonable interpretations
26
+ lead to different results, stop and ask the user a clarifying question instead of guessing.
27
+ Don't ask about things you can find out yourself by reading the code.
28
+ - If you make an assumption anyway (e.g. for a small detail that doesn't block the work), state it
29
+ explicitly in your reply so the user can correct it.
30
+ - Say "I don't know" or "I couldn't verify this" rather than presenting a guess as fact. Report
31
+ results honestly: if a check fails or a step was skipped, say so.
32
+ - Stay within the scope of the request. Don't add features, refactors or dependencies that weren't
33
+ asked for; suggest them instead.
34
+
35
+ ## Working on a task
36
+
37
+ - Check the project's `package.json` for the available scripts (`dev`, `build`, `test`, lint and
38
+ type-check scripts) instead of guessing commands.
39
+ - A change is done when the type check, tests and linters pass for the files you changed.
40
+ - Never run `git commit`, create a branch, or push, unless you are explicitly asked to. Leave
41
+ changes as uncommitted working-tree edits and let the user commit, branch and push themselves.
42
+
43
+ ## Imports
44
+
45
+ - Use **path aliases** for cross-directory imports, never relative `../../` paths. Check
46
+ `compilerOptions.paths` in the project's `tsconfig.json` for the available aliases (e.g.
47
+ `@components/*`, `@helpers/*`, or `@/*`).
48
+
49
+ ## TypeScript
50
+
51
+ - Declare all types with `type`; do not use `interface`. Export a type when it is shared.
52
+ - Do not use double casts (`as unknown as T`) to silence TypeScript errors; narrow values to the
53
+ required type instead.
54
+ - Constants belong in `src/constants/`, never inline in components. Define sets of options as a
55
+ `SCREAMING_SNAKE_CASE` object with `as const` and derive the type from it:
56
+
57
+ ```ts
58
+ // src/constants/sizes.ts
59
+ export const SIZES = {
60
+ SMALL: 'small',
61
+ MEDIUM: 'medium',
62
+ LARGE: 'large',
63
+ } as const;
64
+
65
+ export type Size = (typeof SIZES)[keyof typeof SIZES];
66
+ ```
67
+
68
+ ## Design tokens
69
+
70
+ - Design tokens are CSS custom properties, defined once in a global stylesheet. Reference them with
71
+ `var()`:
72
+
73
+ ```scss
74
+ .root {
75
+ padding: var(--spacing-md);
76
+ color: var(--color-text-primary);
77
+ border-radius: var(--border-radius-sm);
78
+ }
79
+ ```
80
+
81
+ - Do not use Sass variables (`$color-*`) or a `@use`d tokens module for design tokens.
82
+ - Never hardcode colors or spacing values; always use a design token. If a token is missing, add it
83
+ to the token stylesheet instead of inlining a value.
84
+
85
+ ## Versioning
86
+
87
+ - If the project uses [Changesets](https://github.com/changesets/changesets) (a `.changeset/`
88
+ folder exists), every PR must include a changeset describing the change and its semver bump.
package/nest.md ADDED
@@ -0,0 +1,53 @@
1
+ # NestJS — agent instructions
2
+
3
+ Conventions for NestJS services written in TypeScript. Everything in [`base.md`](./base.md)
4
+ applies as well (its CSS/design-token sections just won't come up in a backend service); read it
5
+ first.
6
+
7
+ ## Project structure
8
+
9
+ - Organize by feature module under `src/<feature>/`, each with its own controller, service,
10
+ module and DTOs — the shape `nest g resource` / `nest g module|controller|service` produces.
11
+ - One class per file, named `<name>.<type>.ts` (`users.controller.ts`, `users.service.ts`,
12
+ `users.module.ts`).
13
+ - DTOs live in a `dto/` folder inside the feature module, one class per file
14
+ (`dto/create-user.dto.ts`).
15
+
16
+ ## Modules & dependency injection
17
+
18
+ - Keep controllers thin: parse input, delegate to a service, shape the response. Business logic
19
+ belongs in services, not controllers.
20
+ - Inject dependencies through constructor parameter properties
21
+ (`constructor(private readonly usersService: UsersService) {}`), not property injection or
22
+ manual `new`.
23
+ - Depend on Nest's DI container for anything registered as a provider; don't import a service and
24
+ instantiate it yourself.
25
+
26
+ ## DTOs & validation
27
+
28
+ - Validate every request body/query/param with a DTO class using `class-validator` decorators
29
+ (`@IsString()`, `@IsOptional()`, etc.), not manual checks in the controller.
30
+ - Enable a global `ValidationPipe` (with `whitelist: true`) in `main.ts` instead of adding it
31
+ per-route.
32
+ - Shape what a controller returns with a response DTO or `class-transformer`'s
33
+ `@Expose()`/`@Exclude()`, instead of returning entity/ORM objects straight to the client.
34
+
35
+ ## Error handling
36
+
37
+ - Throw Nest's built-in HTTP exceptions (`NotFoundException`, `BadRequestException`, etc.) instead
38
+ of returning error objects or throwing a plain `Error`.
39
+ - For error formatting that applies across many routes, use an `ExceptionFilter` instead of
40
+ repeating try/catch in every controller.
41
+
42
+ ## Configuration & logging
43
+
44
+ - Read environment values through `@nestjs/config`'s `ConfigService`, not `process.env` scattered
45
+ through the codebase.
46
+ - Log through Nest's built-in `Logger`, not `console.log`.
47
+
48
+ ## Testing
49
+
50
+ - Build tests with `Test.createTestingModule` and override providers with mocks, rather than
51
+ instantiating classes by hand.
52
+ - Co-locate unit tests with their source as `*.spec.ts`. Keep end-to-end tests that exercise the
53
+ HTTP layer in `test/` as `*.e2e-spec.ts`.
package/package.json CHANGED
@@ -1,6 +1,35 @@
1
1
  {
2
2
  "name": "@mkappelhof/agent-instructions",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.1.0",
4
+ "description": "Shared instructions for AI coding agents working on React/Next.js, Astro and NestJS projects",
5
+ "exports": {
6
+ "./base.md": "./base.md",
7
+ "./react.md": "./react.md",
8
+ "./astro.md": "./astro.md",
9
+ "./nest.md": "./nest.md",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "files": [
13
+ "base.md",
14
+ "react.md",
15
+ "astro.md",
16
+ "nest.md",
17
+ "README.md",
18
+ "CHANGELOG.md"
19
+ ],
20
+ "license": "MIT",
21
+ "repository": "git@github.com:mkappelhof/frontend-tools.git",
22
+ "author": "Maurice Kappelhof <maurice@mauricekappelhof.nl>",
23
+ "scripts": {
24
+ "test": "echo 'no test step'"
25
+ },
26
+ "keywords": [
27
+ "agents",
28
+ "agents.md",
29
+ "ai",
30
+ "react",
31
+ "nextjs",
32
+ "astro",
33
+ "nestjs"
34
+ ]
6
35
  }
package/react.md ADDED
@@ -0,0 +1,131 @@
1
+ # React / Next.js — agent instructions
2
+
3
+ Conventions for React projects (Vite, Next.js or another bundler) written in TypeScript and styled
4
+ with SCSS modules. Everything in [`base.md`](./base.md) applies as well; read it first.
5
+
6
+ ## Project structure
7
+
8
+ - **`src/components/`** — Feature components, each co-located with its `.module.scss`.
9
+ - **`src/helpers/`** — Pure utility functions. Every function lives in its own dedicated helper file.
10
+ - **`src/contexts/`** — React context providers (`*.context.tsx`).
11
+ - **`src/constants/`** — Constants and option sets.
12
+ - **`src/interfaces/`** — Shared TypeScript types.
13
+ - **`src/i18n/`** — Localization: `config.ts` initializes i18next, `locales/<locale>.json` holds
14
+ the nested translation keys.
15
+
16
+ In a Next.js project the routes live in `src/app/`; keep route files thin and put reusable UI in
17
+ `src/components/`.
18
+
19
+ ## Components
20
+
21
+ - Components are named arrow-function exports typed as `FC<Props>`, never `function` declarations.
22
+ - **One component per file.** Subcomponents get their own file.
23
+ - Type DOM-wrapping components with `ComponentPropsWithoutRef<'element'>` and wrappers with
24
+ `PropsWithChildren<Props>`.
25
+ - Destructure props in the parameter list instead of using `props.x`. Use default parameter values,
26
+ not `defaultProps` or `propTypes`.
27
+ - Always render text through the project's `Text` component (e.g. `@components/text/text`); never
28
+ place raw strings in bare DOM elements such as `<span>` or `<p>`.
29
+ - **Composition over configuration**: pass content as `children` rather than through content props
30
+ (`label`, `icon`, `text`).
31
+ - **Compound components**: build multi-part components using composition, not props. Keep
32
+ subcomponents in an `elements/` folder and re-export them from the parent module (no
33
+ `elements/index.ts` barrel). The parent manages state and shares it with its subcomponents
34
+ through a context.
35
+
36
+ ```tsx
37
+ // Usage of src/components/tabs/tabs.tsx
38
+ <Tabs defaultValue="account">
39
+ <Tabs.List>
40
+ <Tabs.Tab value="account">{t('settings.account')}</Tabs.Tab>
41
+ <Tabs.Tab value="billing">{t('settings.billing')}</Tabs.Tab>
42
+ </Tabs.List>
43
+ <Tabs.Panel value="account">...</Tabs.Panel>
44
+ <Tabs.Panel value="billing">...</Tabs.Panel>
45
+ </Tabs>
46
+ ```
47
+
48
+ ### Naming
49
+
50
+ - Boolean props start with `is` or `has`: `isOpen`, `hasError`.
51
+ - `useState` pairs are named `[value, setValue]`.
52
+ - Event handler props are named `onX`, and the handlers you pass are named `handleX`:
53
+ `onClick={handleClick}`.
54
+
55
+ ### JSX
56
+
57
+ - Import `clsx` as `classnames`: `import classnames from 'clsx'`. Compose class names as
58
+ `classnames(css.root, className)`.
59
+ - No useless braces: `variant="primary"`, not `variant={'primary'}`.
60
+ - Self-close elements without children: `<Icon />`, `<div />`.
61
+ - Only use a fragment (`<>…</>`) when you need to wrap several children.
62
+ - Every element in a list needs a stable `key`. Do not use the array index if items can reorder.
63
+ - Keep JSX nesting to 4 levels or fewer. Extract a component when it gets deeper.
64
+
65
+ ## Contexts
66
+
67
+ Create all contexts in `src/contexts/` named `*.context.tsx`. A context file exports the context
68
+ value type, the context, a dedicated provider component, and a `use*Context` consumer hook that
69
+ throws when used outside its provider. Always consume a context through its hook, never with
70
+ `useContext` directly. Memoize the value you pass to a provider with `useMemo`; never pass a new
71
+ object or array literal.
72
+
73
+ ```tsx
74
+ // src/contexts/tabs.context.tsx
75
+ export type TabsContextValue = {
76
+ activeValue: string;
77
+ setActiveValue: (value: string) => void;
78
+ };
79
+
80
+ export const TabsContext = createContext<TabsContextValue | undefined>(undefined);
81
+
82
+ export const TabsProvider: FC<PropsWithChildren<{ value: TabsContextValue }>> = ({ value, children }) => (
83
+ <TabsContext.Provider value={value}>{children}</TabsContext.Provider>
84
+ );
85
+
86
+ export const useTabsContext = (): TabsContextValue => {
87
+ const context = useContext(TabsContext);
88
+
89
+ if (!context) throw new Error('useTabsContext must be used within a TabsProvider');
90
+
91
+ return context;
92
+ };
93
+ ```
94
+
95
+ ## Next.js
96
+
97
+ - Components in `app/` are Server Components by default. Add `'use client'` only to the components
98
+ that need state, effects, browser APIs or context, and keep that boundary as low in the tree as
99
+ possible.
100
+ - Context providers are client components; wrap them in a small `'use client'` providers component
101
+ and render it from the layout.
102
+ - Use `next/link` for internal navigation, not a plain `<a href="/…">`.
103
+ - Use `next/image` instead of `<img>`, and `next/script` instead of a raw `<script>` tag.
104
+ - Load fonts with `next/font`, not `<link>` tags to font CDNs.
105
+ - Set page metadata with the Metadata API (`export const metadata` / `generateMetadata`). Do not
106
+ import `next/head` or `next/document` in `app/`.
107
+
108
+ ## Localization
109
+
110
+ - Never hardcode user-facing text (labels, placeholders, aria-labels, messages). Add a key to the
111
+ matching group in the locale file (e.g. `src/i18n/locales/en-US.json`) and render it with
112
+ `const { t } = useTranslation()` from `react-i18next`.
113
+ - Interpolate values with `t('group.key', { name })`, matching `{{name}}` in the translation. Use
114
+ i18next `_one` / `_other` suffixed keys with `{ count }` for plurals.
115
+ - Non-component code (helpers, constants) returns a `TranslationKey` instead of translated text, so
116
+ the component can translate it.
117
+
118
+ ## Styling
119
+
120
+ - Use SCSS modules (`.module.scss`) co-located with each component.
121
+ - Import the design token stylesheet (see `base.md`) once at the app root, e.g. in `main.tsx` or
122
+ the root `layout.tsx`.
123
+
124
+ ## Testing
125
+
126
+ - Use **Vitest** with the JSDOM environment for unit tests.
127
+ - Co-locate tests with their source as `*.spec.ts` or `*.spec.tsx`.
128
+ - Every helper must have a unit test. Add or update the co-located `*.spec.ts` whenever you add or
129
+ change one.
130
+ - Test pure helpers directly. Mock browser APIs and external dependencies at module boundaries with
131
+ Vitest mocks.