@activatus/code-standards 0.0.0-stage → 3.0.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.
Files changed (180) hide show
  1. package/README.md +199 -2
  2. package/docs/Guides/_category_.json +4 -0
  3. package/docs/Guides/component-library-workflow.md +182 -0
  4. package/docs/Guides/migrating.md +161 -0
  5. package/docs/Guides/setup.md +158 -0
  6. package/docs/Standards/_category_.json +4 -0
  7. package/docs/Standards/agent-skills.md +125 -0
  8. package/docs/Standards/agent-specs.md +74 -0
  9. package/docs/Standards/direnv.mdx +249 -0
  10. package/docs/Standards/documentation.md +314 -0
  11. package/docs/Standards/editorconfig.md +74 -0
  12. package/docs/Standards/eslint.md +900 -0
  13. package/docs/Standards/human-readable-names.md +274 -0
  14. package/docs/Standards/lint-errors.md +171 -0
  15. package/docs/Standards/prettier.md +106 -0
  16. package/docs/Standards/readable-code.md +570 -0
  17. package/docs/Standards/stylelint.md +193 -0
  18. package/docs/Standards/styling.md +290 -0
  19. package/docs/Standards/tech-stack.md +158 -0
  20. package/docs/Structure/_category_.json +4 -0
  21. package/docs/Structure/api-routes.md +118 -0
  22. package/docs/Structure/component-organization.md +526 -0
  23. package/docs/Structure/folder-structure.md +366 -0
  24. package/docs/Structure/import-organization.md +158 -0
  25. package/docs/Structure/naming-conventions.md +334 -0
  26. package/docs/design-system-components.md +117 -0
  27. package/docs/intro.md +44 -0
  28. package/docs/ontology.md +127 -0
  29. package/docs/templates.mdx +396 -0
  30. package/docs/version-history.md +338 -0
  31. package/package.json +60 -3
  32. package/scripts/renameSymbol.mjs +188 -0
  33. package/static/templates/.editorconfig +25 -0
  34. package/static/templates/.envrc +25 -0
  35. package/static/templates/.nvmrc +1 -0
  36. package/static/templates/AGENTS.md +163 -0
  37. package/static/templates/decision-doc.md +19 -0
  38. package/static/templates/docs/ai/agent-harness.md +17 -0
  39. package/static/templates/docs/ai/agents.md +17 -0
  40. package/static/templates/docs/ai/architecture.md +17 -0
  41. package/static/templates/docs/ai/context.md +17 -0
  42. package/static/templates/docs/ai/model-routing.md +17 -0
  43. package/static/templates/docs/ai/models.md +17 -0
  44. package/static/templates/docs/ai/retrieval.md +17 -0
  45. package/static/templates/docs/ai/tools.md +17 -0
  46. package/static/templates/docs/architecture/authentication.md +17 -0
  47. package/static/templates/docs/architecture/backend.md +17 -0
  48. package/static/templates/docs/architecture/background-jobs.md +17 -0
  49. package/static/templates/docs/architecture/backups.md +17 -0
  50. package/static/templates/docs/architecture/caching.md +17 -0
  51. package/static/templates/docs/architecture/ci-cd.md +17 -0
  52. package/static/templates/docs/architecture/disaster-recovery.md +17 -0
  53. package/static/templates/docs/architecture/environments.md +17 -0
  54. package/static/templates/docs/architecture/frontend.md +17 -0
  55. package/static/templates/docs/architecture/hosting.md +17 -0
  56. package/static/templates/docs/architecture/observability.md +17 -0
  57. package/static/templates/docs/architecture/realtime.md +17 -0
  58. package/static/templates/docs/architecture/search.md +17 -0
  59. package/static/templates/docs/architecture/services.md +17 -0
  60. package/static/templates/docs/architecture/state-management.md +17 -0
  61. package/static/templates/docs/architecture/storage.md +17 -0
  62. package/static/templates/docs/architecture/system.md +17 -0
  63. package/static/templates/docs/business/buying-trigger.md +17 -0
  64. package/static/templates/docs/business/customer-value.md +17 -0
  65. package/static/templates/docs/business/customer.md +17 -0
  66. package/static/templates/docs/business/defensibility.md +17 -0
  67. package/static/templates/docs/business/growth.md +17 -0
  68. package/static/templates/docs/business/pricing.md +17 -0
  69. package/static/templates/docs/business/revenue-model.md +17 -0
  70. package/static/templates/docs/business/unit-economics.md +17 -0
  71. package/static/templates/docs/data/analytics.md +17 -0
  72. package/static/templates/docs/data/audit.md +17 -0
  73. package/static/templates/docs/data/database.md +17 -0
  74. package/static/templates/docs/data/indexing.md +17 -0
  75. package/static/templates/docs/data/migrations.md +17 -0
  76. package/static/templates/docs/data/model.md +17 -0
  77. package/static/templates/docs/data/retention.md +17 -0
  78. package/static/templates/docs/data/schema.md +17 -0
  79. package/static/templates/docs/deployment/approval.md +17 -0
  80. package/static/templates/docs/deployment/live-verification.md +17 -0
  81. package/static/templates/docs/deployment/process.md +17 -0
  82. package/static/templates/docs/deployment/rollback.md +17 -0
  83. package/static/templates/docs/design/design-system.md +17 -0
  84. package/static/templates/docs/design/errors.md +17 -0
  85. package/static/templates/docs/design/feedback.md +17 -0
  86. package/static/templates/docs/design/interactions.md +17 -0
  87. package/static/templates/docs/design/layout.md +17 -0
  88. package/static/templates/docs/design/navigation.md +17 -0
  89. package/static/templates/docs/design/principles.md +17 -0
  90. package/static/templates/docs/design/responsive.md +17 -0
  91. package/static/templates/docs/development/branching.md +17 -0
  92. package/static/templates/docs/development/code-quality.md +17 -0
  93. package/static/templates/docs/development/coding-standards.md +21 -0
  94. package/static/templates/docs/development/commits.md +17 -0
  95. package/static/templates/docs/development/merge-strategy.md +17 -0
  96. package/static/templates/docs/development/process.md +17 -0
  97. package/static/templates/docs/development/pull-requests.md +17 -0
  98. package/static/templates/docs/experience/accessibility.md +17 -0
  99. package/static/templates/docs/experience/aha-moment.md +17 -0
  100. package/static/templates/docs/experience/anti-experience.md +17 -0
  101. package/static/templates/docs/experience/friction.md +17 -0
  102. package/static/templates/docs/experience/outcomes.md +17 -0
  103. package/static/templates/docs/experience/principles.md +17 -0
  104. package/static/templates/docs/experience/retention.md +17 -0
  105. package/static/templates/docs/experience/sharing.md +17 -0
  106. package/static/templates/docs/overview/how-it-works.md +17 -0
  107. package/static/templates/docs/overview/what-is-it.md +17 -0
  108. package/static/templates/docs/overview/writing-docs.md +16 -0
  109. package/static/templates/docs/pitch/alternatives.md +17 -0
  110. package/static/templates/docs/pitch/assumptions.md +17 -0
  111. package/static/templates/docs/pitch/audience.md +17 -0
  112. package/static/templates/docs/pitch/concept.md +17 -0
  113. package/static/templates/docs/pitch/differentiators.md +17 -0
  114. package/static/templates/docs/pitch/outcomes.md +17 -0
  115. package/static/templates/docs/pitch/problem.md +17 -0
  116. package/static/templates/docs/pitch/product-market-fit.md +17 -0
  117. package/static/templates/docs/pitch/success-criteria.md +17 -0
  118. package/static/templates/docs/pitch/validation.md +17 -0
  119. package/static/templates/docs/pitch/value-proposition.md +17 -0
  120. package/static/templates/docs/pitch/vision.md +17 -0
  121. package/static/templates/docs/scope/core.md +17 -0
  122. package/static/templates/docs/scope/exclusions.md +17 -0
  123. package/static/templates/docs/scope/future.md +17 -0
  124. package/static/templates/docs/scope/launch.md +17 -0
  125. package/static/templates/docs/scope/post-launch.md +17 -0
  126. package/static/templates/docs/scope/priorities.md +17 -0
  127. package/static/templates/docs/scope/quality-bar.md +17 -0
  128. package/static/templates/docs/security/audit.md +17 -0
  129. package/static/templates/docs/security/data-access.md +17 -0
  130. package/static/templates/docs/security/logging.md +17 -0
  131. package/static/templates/docs/security/privacy.md +17 -0
  132. package/static/templates/docs/security/secrets.md +17 -0
  133. package/static/templates/docs/security/threat-model.md +17 -0
  134. package/static/templates/docs/testing/end-to-end.md +17 -0
  135. package/static/templates/docs/testing/integration.md +17 -0
  136. package/static/templates/docs/testing/regression.md +17 -0
  137. package/static/templates/docs/testing/security.md +17 -0
  138. package/static/templates/docs/testing/strategy.md +17 -0
  139. package/static/templates/docs/testing/test-data.md +17 -0
  140. package/static/templates/docs/testing/unit.md +17 -0
  141. package/static/templates/docs/uat/checks.md +17 -0
  142. package/static/templates/docs/uat/strategy.md +17 -0
  143. package/static/templates/docs/users/permissions.md +17 -0
  144. package/static/templates/docs/users/roles.md +17 -0
  145. package/static/templates/docs/users/user-types.md +17 -0
  146. package/static/templates/docs/workflows/assignment.md +17 -0
  147. package/static/templates/docs/workflows/bugfix.md +17 -0
  148. package/static/templates/docs/workflows/dependencies.md +17 -0
  149. package/static/templates/docs/workflows/deployment.md +17 -0
  150. package/static/templates/docs/workflows/development.md +17 -0
  151. package/static/templates/docs/workflows/planning.md +17 -0
  152. package/static/templates/docs/workflows/review.md +17 -0
  153. package/static/templates/docs/workflows/uat.md +17 -0
  154. package/static/templates/docsSite/docusaurus.config.mjs +144 -0
  155. package/static/templates/docsSite/gitignore.txt +3 -0
  156. package/static/templates/docsSite/package.json.txt +42 -0
  157. package/static/templates/docsSite/pnpm-workspace.yaml +2 -0
  158. package/static/templates/docsSite/sidebars.mjs +7 -0
  159. package/static/templates/docsSite/src/css/custom.css +7 -0
  160. package/static/templates/docsSite/src/pages/index.tsx +9 -0
  161. package/static/templates/docsSite/static/images/logo.svg +4 -0
  162. package/static/templates/docsSite/tsconfig.json +7 -0
  163. package/static/templates/eslint/base/eslint.config.mjs +104 -0
  164. package/static/templates/eslint/nextjs/eslint.config.mjs +181 -0
  165. package/static/templates/eslint/react/eslint.config.mjs +173 -0
  166. package/static/templates/eslint/typescript/eslint.config.mjs +154 -0
  167. package/static/templates/globals.css +16 -0
  168. package/static/templates/husky/pre-commit +1 -0
  169. package/static/templates/next.config.mjs +21 -0
  170. package/static/templates/prettier.config.mjs +26 -0
  171. package/static/templates/skills/codeReview.md +31 -0
  172. package/static/templates/skills/format.md +18 -0
  173. package/static/templates/skills/lint.md +21 -0
  174. package/static/templates/skills/lintFix.md +24 -0
  175. package/static/templates/skills/securityAudit.md +28 -0
  176. package/static/templates/skills/test.md +24 -0
  177. package/static/templates/skills/typescript.md +28 -0
  178. package/static/templates/skills/updateLayout.md +20 -0
  179. package/static/templates/stylelint/css/stylelint.config.mjs +40 -0
  180. package/static/templates/stylelint/scss/stylelint.config.mjs +13 -0
@@ -0,0 +1,338 @@
1
+ ---
2
+ sidebar_position: 1.6
3
+ sidebar_label: "Version History"
4
+ ---
5
+
6
+ # Version History
7
+
8
+ > What changed in each version of the standards, and exactly what a project has to do about it. Written for the AI agent doing the update.
9
+
10
+ **Every change to the standards gets a new version number.** Each project records the version it follows in its `AGENTS.md`, under "Code standards":
11
+
12
+ ```md
13
+ **Code standards version:** 2
14
+ ```
15
+
16
+ ## Updating a project to a new version
17
+
18
+ **Read only the versions newer than the project's.** A project on version 1 that is updating to version 3 reads version 2 and version 3 on this page, and nothing else. Do not re-read every standard or check the whole codebase: each version lists every change that matters, and how to find the code it affects.
19
+
20
+ 1. **Find the project's version** in its `AGENTS.md`. If there is none, the project has never followed the standards: follow [Setup](/Guides/setup) instead.
21
+ 2. **Update the package:** `pnpm update @activatus/code-standards --latest`. Then read this page from `node_modules/@activatus/code-standards/docs/version-history.md`.
22
+ 3. **Read each version newer than the project's**, oldest first. Skip any change to a standard the project opted out of: they are listed in `docs/development/coding-standards.md`.
23
+ 4. **For each change, do the "What to do" steps**, then run the "How to check" searches. A search that still finds something means the change is not finished.
24
+ 5. **One pull request per kind of change** (for example, all the folder renames together), so each one stays easy to review. Follow the project's commit rule in `AGENTS.md`.
25
+ 6. **Run `pnpm lint`, `pnpm test` and the build** after each change.
26
+ 7. **Update the version number** in `AGENTS.md` once every change is done.
27
+
28
+ **When a change does not fit the project**, for example it renames a folder the project does not have, skip it. If you are not sure, ask; do not guess.
29
+
30
+ ## Adding a version
31
+
32
+ Anyone changing the standards adds a version, in the same pull request as the change:
33
+
34
+ - **One version per release**, numbered one higher than the last. Whole numbers only. A version can collect several changes before it is released.
35
+ - **Bump the package's major version to match** in `package.json`: version 3 is `3.0.0`. Then publish it to npm (npmjs.com) with `pnpm publish`. pnpm is the tool; npm is where the package lives, and projects install it from there with `pnpm add`.
36
+ - **For every change, write:** what changed, why, what to do in a project, and how to check it is done. Write it for an agent that has not read the rest of the standards.
37
+ - **If a project has nothing to do, say so.**
38
+ - **Newest version at the top.**
39
+ - **Work in progress goes under `## Version N — not released yet`**, with a line saying projects should not apply it yet. Changes can be added to it over several Pull Requests. To release it: drop "not released yet", add the **Released** date and **Updates from** line, set `package.json` to `N.0.0`, then publish.
40
+
41
+ ---
42
+
43
+ ## Version 3
44
+
45
+ **Released:** 2026-10-17 · **Updates from:** version 2
46
+
47
+ Install it with `pnpm add -D @activatus/code-standards@3.0.0`. Do change 1 first: it says which parts of the project's `AGENTS.md` are now the project's own to write.
48
+
49
+ ### 1. Project workflow is no longer part of the standards
50
+
51
+ **Why:** The standards are a base for code. How a project runs its work — branch names, commit messages, Pull Requests, merging, releases, and whether AI agents may commit — is each project's own decision, and every project makes it differently.
52
+
53
+ **What to do:**
54
+
55
+ - The Branch Naming and Commit Messages standards are gone, along with standards 19, 20 and 22 from the setup list. Keep whatever the project already does, and make sure it is written up in the project's own docs, usually `docs/development/`.
56
+ - In `AGENTS.md`, replace the "Development workflow" section with a **Project workflow** section, copied from the [template](/templates#agents). Fill it in with the project's own rules: who commits, branches, commit messages, Pull Requests, merging and releases. Put the most important rule for agents — whether they may commit — in the line at the very top.
57
+ - Remove the "Never commit code" and "Do not create, switch or delete branches" lines from "Out of scope for AI agents", unless they are the project's own rule. If they are, they belong in Project workflow.
58
+ - Commitlint and the `.husky/commit-msg` hook are no longer templates. Keep them if the project wants its commit messages checked; they are now the project's choice.
59
+ - **Keep `.husky/pre-commit`.** Running `pnpm lint` before every commit is still a standard. See [Lint before every commit](/Standards/lint-errors#lint-before-every-commit).
60
+
61
+ **How to check:** `AGENTS.md` has a Project workflow section, and every rule in it is written up in the project's docs.
62
+
63
+ ### 2. `lib`, `ref` and `repo` are dictionary words, and `library/` is `lib/`
64
+
65
+ **Why:** They are the words developers use. `lib/` is the name Next.js and shadcn/ui use too.
66
+
67
+ **What to do:**
68
+
69
+ - Rename the `library/` folder to `lib/` with `git mv`, and fix the imports: `@/library/` → `@/lib/`.
70
+ - Rename names ending in `Reference` that hold a React ref back to `Ref`: `inputReference` → `inputRef`. Rename `repository` back to `repo` where it is short for a Git repository, such as `repositoryName` → `repoName`. Use the editor's Rename Symbol (F2), or the [rename script](/Guides/migrating#renaming-from-the-command-line).
71
+ - Copy the new [ESLint config](/Standards/eslint). The naming rule now has `replacements: { docs: false, lib: false, props: false, ref: false, repo: false, utils: false }` and `allowList: { params: true, searchParams: true }`.
72
+ - Update the "Dictionary words stay short" line in `AGENTS.md` from the [template](/templates#agents), and remove `lib/` → `library/` and `repo` → `repository` from its Never / Always table.
73
+
74
+ **How to check:** There is no `library/` folder, `grep -rn "@/library" --exclude-dir=node_modules .` finds nothing, and `pnpm lint` passes.
75
+
76
+ ### 3. utils, services and lib are defined
77
+
78
+ **Why:** It wasn't clear which functions go in `utils/`, `services/` or `lib/`. See [utils, services and lib](/Structure/folder-structure#utils-services-and-lib).
79
+
80
+ **What to do:** Check each function in those three folders against the definitions, and move any that are in the wrong one. The common one: a function in `utils/` that calls a database or an API belongs in `services/` or `lib/`. Shared constants and types live in `lib/constants/` and `lib/types/`; a component's own types stay in its `types.ts`. Move any root-level `constants/` or `types/` folder into `lib/`.
81
+
82
+ **How to check:** Nothing in `utils/` imports from `services/`, `lib/integrations/` or a database client, and there is no root-level `constants/` or `types/` folder.
83
+
84
+ ### 4. The Ontology only holds code words
85
+
86
+ **Why:** Project-management words mean different things in different projects. Launchpad's "project" is a product made of several MVPs, and its Pull Requests go through `feature → dev → uat → main`.
87
+
88
+ **What to do:** The code [Ontology](/ontology) no longer defines `project`, `repository`, `branch`, `commit`, `pull_request`, `pull_request_review` or `production`, and `human`, `developer` and `agent` no longer say who may commit. If the project uses those words, define them in its own `docs/product/ontology.md`, the way the project actually works.
89
+
90
+ **How to check:** The project's ontology defines every project-management word it uses.
91
+
92
+ ### 5. Every config file is `.mjs`
93
+
94
+ **Why:** `.mjs` works in TypeScript and JavaScript projects alike, so every project looks the same.
95
+
96
+ **What to do:**
97
+
98
+ - Rename each config file that is `.js`, `.ts` or `.mts` to `.mjs`, even in a TypeScript project, wherever the tool can read `.mjs`: `prettier.config.mjs`, `next.config.mjs`, `eslint.config.mjs`, `docsSite/docusaurus.config.mjs`, `docsSite/sidebars.mjs` and so on. Use `git mv`. Never convert a config to `.ts` or `.mts`.
99
+ - Remove any TypeScript-only syntax as you go. A type annotation becomes a JSDoc comment: `const config: NextConfig = {` becomes `/** @type {import("next").NextConfig} */ const config = {`. Copy the [`docsSite/` templates](/templates#docs-site), which are already `.mjs`.
100
+ - Update anything that names the old file, such as `sidebarPath: './sidebars.mjs'` in the docs site config.
101
+
102
+ **How to check:** `ls *.config.* docsSite/*.config.* docsSite/sidebars.*` shows only `.mjs` files, and `pnpm lint`, `pnpm format:check`, the build and `pnpm docs:build` still run.
103
+
104
+ ### 6. Prettier: 70-character lines and tabs
105
+
106
+ **Why:** A lot of code is read and reviewed on a phone, where short lines fit the screen. Tabs let each person see the indent at the width they like.
107
+
108
+ **What to do:**
109
+
110
+ - Copy the new [`prettier.config.mjs`](/templates#prettier) and [`.editorconfig`](/templates#editorconfig). Prettier now has `printWidth: 70` and `useTabs: true`, and keeps spaces for Markdown and YAML. EditorConfig indents with tabs, except Markdown, YAML and Python.
111
+ - Run `pnpm format` once, on its own, in a Pull Request with nothing else in it. It touches nearly every file, so keep it apart from real changes.
112
+ - If the project shows code on a web page, such as its docs site, add `pre, code { tab-size: 2; }` to its CSS, so tabs are not shown 8 characters wide. The [`docsSite/` template](/templates#docs-site) already has it.
113
+
114
+ **How to check:** `pnpm format:check` passes.
115
+
116
+ ### 7. When a name clashes, rename our own thing first
117
+
118
+ **Why:** A third-party name is the name everyone knows it by, and a clash usually means our own name is too vague. Renaming an import for taste makes the code harder to search and to match against the package's docs.
119
+
120
+ **What to do:** Search for renamed imports: `grep -rn "import {[^}]* as " --include=*.ts --include=*.tsx --exclude-dir=node_modules .`. For each one:
121
+
122
+ - **If nothing in the file clashes with the original name**, undo the rename and use the original name.
123
+ - **If our own thing clashes**, rename ours to a more specific full-word name, with the editor's Rename Symbol or the [rename script](/Guides/migrating#renaming-from-the-command-line). Then undo the import rename. For example, our `createClient` becomes `createProjectDatabaseClient`, and Supabase's `createClient` keeps its name.
124
+ - **If both names are third-party, or ours is fixed by a framework** (such as a Next.js route's `GET`), keep the import renamed, as the owner plus the original name, never shortened: `Link as LucideLinkIcon`.
125
+
126
+ See [When a name clashes](/Standards/human-readable-names#when-a-name-clashes).
127
+
128
+ **How to check:** Every renamed import that is left clashes with another third-party name or a framework-fixed name, and starts with its owner's name.
129
+
130
+ ### 8. Name a type after what it is, not the job it does
131
+
132
+ **Why:** A type named after its role in one function, such as `StartAgentRunDependenciesType`, is a second name for what is really part of that function's props.
133
+
134
+ **What to do:** Find types used for only one field of one `Props` type. Move each one inside that `Props` and delete the separate type. Where the object is built somewhere else, remove its type annotation: TypeScript checks it against the `Props` when it is passed in. See [Name a type after what it is](/Standards/readable-code#name-a-type-after-what-it-is-not-the-job-it-does).
135
+
136
+ **How to check:** No type is used only as the type of one field of one `Props`.
137
+
138
+ ### 9. "go" means carry on
139
+
140
+ **Why:** People often send just "go" to nudge an agent along, for example when their connection drops and the agent looks stuck. An agent must never read it as permission to commit.
141
+
142
+ **What to do:** Copy the line that starts **"go" means carry on** from the top of the [`AGENTS.md` template](/templates#agents) into the top of the project's `AGENTS.md`.
143
+
144
+ **How to check:** The project's `AGENTS.md` has the line near the top.
145
+
146
+ ### 10. Unfinished changes are recorded, not hidden
147
+
148
+ **Why:** A big change, such as switching on the standard ESLint config, may be done later in its own Pull Request. The version number has to stay honest about that.
149
+
150
+ **What to do:** Add an "Unfinished changes" section to `docs/development/coding-standards.md`, from the [template](/templates#document-templates). List any change from any version that is not done yet, with what is left and where it is being done, or write "None". See [Finishing a change later](/Guides/setup#finishing-a-change-later).
151
+
152
+ **How to check:** `docs/development/coding-standards.md` has an "Unfinished changes" section.
153
+
154
+ ### No action needed
155
+
156
+ - The [Ontology](/ontology) defines `dependency`: something the code relies on but does not define itself. Ticket relationships are not dependencies; each project names those itself.
157
+ - The package now ships a rename script for agents working from the command line, using TypeScript's own rename: `node node_modules/@activatus/code-standards/scripts/renameSymbol.mjs <file> <currentName> <newName>`. See [Renaming from the command line](/Guides/migrating#renaming-from-the-command-line).
158
+ - The [Setup](/Guides/setup) guide says the standards are a base for code only, and explains how to get past pnpm's `minimumReleaseAge` when a new version is too fresh to install.
159
+ - [Folder Structure](/Structure/folder-structure) explains each `lib/` folder in one line.
160
+ - The [ESLint page](/Standards/eslint#installation) says the config needs ESLint 10.4 or later, and the React configs explain why they set `settings.react.version`.
161
+ - "Lint before every commit" moved to [Lint Errors](/Standards/lint-errors#lint-before-every-commit).
162
+
163
+ ---
164
+
165
+ ## Version 2
166
+
167
+ **Released:** 2026-10-15 · **Updates from:** version 1
168
+
169
+ ### 1. The standards are an npm package — do this first
170
+
171
+ **Why:** A project installs the standards, so an agent reads the exact version the project uses, straight from `node_modules`. The package version is the standards version: `2.0.0` is version 2.
172
+
173
+ **What to do:**
174
+
175
+ - `pnpm add -D @activatus/code-standards`
176
+ - Read the rest of this update from `node_modules/@activatus/code-standards/docs/version-history.md`. The templates to copy are in `node_modules/@activatus/code-standards/static/templates/`.
177
+ - In `AGENTS.md`, under "Code standards", say the standards are installed as `@activatus/code-standards`, and that agents read them from `node_modules/@activatus/code-standards/docs/`. Copy the wording from the [`AGENTS.md` template](/templates#agents).
178
+
179
+ **How to check:** `@activatus/code-standards` is in the project's `devDependencies`.
180
+
181
+ ### 2. The person agrees which standards apply — do this second
182
+
183
+ **Why:** Not every standard suits every project. The person now picks, from a numbered list, and the choices are written down so every agent follows the same ones.
184
+
185
+ **What to do:**
186
+
187
+ - Print the numbered list in [Setup, step 3](/Guides/setup#3-agree-the-standards) to the person, exactly as written, and record their answer in `docs/development/coding-standards.md`.
188
+ - For the rest of this update, **skip any change to a standard the person opted out of.**
189
+
190
+ **How to check:** `docs/development/coding-standards.md` lists the opted-out standards by number, or says "No differences".
191
+
192
+ ### 3. `docs` is a dictionary word: the docs folder is `docs/` again
193
+
194
+ **Why:** `docs` is a word, not an abbreviation, and `documentation` is long and hard to read in names.
195
+
196
+ **What to do:**
197
+
198
+ - Rename the folders with `git mv`: `documentation/` → `docs/`, `documentationSite/` → `docsSite/`.
199
+ - **If both `docsSite/` and `documentationSite/` exist**, merge them into `docsSite/`: move each tracked file from `documentationSite/` with `git mv`, keeping whichever copy is newer, then delete `documentationSite/`. Ask the person before deleting a file that exists in only one of them.
200
+ - Rename `docs/overview/writing-documentation.md` → `docs/overview/writing-docs.md`, and fix every link to it.
201
+ - Rename the environment variable `DOCUMENTATION_URL` → `DOCS_URL` in `next.config.mjs`, `.env.local`, `.env.example` and the hosting provider's settings.
202
+ - Rename the route `/documentation` → `/docs`. Copy the new rewrite from the [`next.config.mjs` template](/templates#docs-route).
203
+ - **Re-copy `docsSite/docusaurus.config.ts`** from the [`docsSite/` template](/templates#docs-site), keeping the project's name and theme. Version 2 changed it: `baseUrl: '/docs/'`, `path: '../docs'`, full-word variable names (`rest` → `remainingArguments`, `doc` → `page`), and `static/img` → `static/images`. Rename the project's `docsSite/static/img/` to `static/images/` to match.
204
+ - Rename the scripts in `package.json`: `documentation:install` → `docs:install`, `documentation:dev` → `docs:dev`, `documentation:build` → `docs:build`.
205
+ - If the docs site's generated folders were ever committed, stop tracking them: `git rm -r --cached docsSite/.docusaurus docsSite/build`. They are in the [`docsSite/` template's](/templates#docs-site) `.gitignore`.
206
+ - Update every mention in `AGENTS.md`, `README.md` and the docs themselves.
207
+ - **Update every ignore list** that names the old folders: ESLint, Prettier, `tsconfig.json`, Vitest or Jest, and `.gitignore`. A leftover docs site with its own `node_modules` makes test runners and linters run its files too.
208
+
209
+ **How to check:** `grep -rn "documentation/\|'../documentation'\|documentationSite\|DOCUMENTATION_URL\|documentation:" --exclude-dir=node_modules .` finds nothing. Normal sentences that say "documentation" are fine.
210
+
211
+ ### 4. `props` is a dictionary word: prop types end in `Props`
212
+
213
+ **Why:** `props` is the word every React developer uses. `properties` is harder to read.
214
+
215
+ **What to do:**
216
+
217
+ - Rename every type ending in `Properties` to end in `Props`: `ButtonProperties` → `ButtonProps`. Never use find-and-replace. Use the editor's Rename Symbol (F2) or, for an agent working from the command line, the rename script in version 3 and later of the package: `node node_modules/@activatus/code-standards/scripts/renameSymbol.mjs <file> <currentName> <newName>`. Both use TypeScript's own rename, so they change every use and nothing else.
218
+ - Rename variables and parameters called `properties` to `props`, including spreads: `...buttonProperties` → `...buttonProps`.
219
+ - **If the project already uses the standard ESLint config**, copy the new [ESLint config](/Standards/eslint). It needs ESLint 10.4 or later. Two things changed in it:
220
+ - The type-name rule is now `(Props|Type)$`.
221
+ - `unicorn/name-replacements` now has `replacements: { docs: false, props: false, utils: false }`.
222
+ - **If the project never had the standard ESLint config**, do only the renames in this change. Switching the config on can find hundreds of problems, so do it separately with [Migrating an Existing Project](/Guides/migrating), one stage per Pull Request, and record it as unfinished: see [Finishing a change later](/Guides/setup#finishing-a-change-later).
223
+
224
+ **How to check:** `grep -rn "Properties\b" --include=*.ts --include=*.tsx --exclude-dir=node_modules .` finds nothing of ours, and `pnpm lint` passes.
225
+
226
+ ### 5. `utils` is a dictionary word: reusable functions live in `utils/`
227
+
228
+ **Why:** `utils` is the word developers use. `utilities` and `helpers` are not.
229
+
230
+ **What to do:**
231
+
232
+ - Rename every `utilities/` folder to `utils/` with `git mv`, at every level: global, section and component.
233
+ - Rename any `helpers/` folder to `utils/`. Split a `helpers.ts` grab-bag file into one folder per function.
234
+ - Fix the imports: `@/utilities` → `@/utils`, `./utilities` → `./utils`.
235
+
236
+ **How to check:** `find . -type d \( -name utilities -o -name helpers \) -not -path "*/node_modules/*"` finds nothing, and `grep -rn "utilities\"" --exclude-dir=node_modules .` finds no imports.
237
+
238
+ ### 6. Components live where they are used: no feature folders
239
+
240
+ **Why:** Grouping by feature and grouping by page meant two places for the same component. Now there is one rule. See [Where components live](/Structure/folder-structure#-where-components-live).
241
+
242
+ | Used by | Lives in |
243
+ | -------------------------------------------------------- | --------------------------- |
244
+ | Every project the same way: the Design System Components | `components/ui/` |
245
+ | More than one page of this project | `components/shared/` |
246
+ | A few pages in one section | `app/(section)/components/` |
247
+ | One page only | `app/page-name/components/` |
248
+
249
+ **What to do:**
250
+
251
+ - For each component in `components/features/` or `components/layout/`, find where it is imported (`grep -rn "ComponentName"`).
252
+ - Imported by one page → move it to that page's `components/` folder.
253
+ - Imported by pages in one section → move it to that section's route group: `app/(section)/components/`.
254
+ - Imported by pages in more than one section → move it to `components/shared/`.
255
+ - Move a feature's `utils/` folder the same way, to wherever its functions are used.
256
+ - Delete the empty `components/features/` and `components/layout/` folders.
257
+ - Leave `components/ui/` as it is.
258
+
259
+ **How to check:** `components/features/` and `components/layout/` do not exist, and the build passes.
260
+
261
+ ### 7. The Component Reference is now Design System Components
262
+
263
+ **Why:** It is the list of standard components every project builds the same way, and "design system components" is what people call that.
264
+
265
+ **What to do:** In `AGENTS.md` and the project's docs, change "Component Reference" to "Design System Components", and change links from `/template-components` to `/design-system-components`.
266
+
267
+ **How to check:** `grep -rn "Component Reference\|template-components" --exclude-dir=node_modules .` finds nothing.
268
+
269
+ ### 8. The Dictionary: short names that are words
270
+
271
+ **Why:** Some short names are words, not abbreviations. The [Dictionary](/Standards/human-readable-names#dictionary) is the one list of them, so nobody has to guess.
272
+
273
+ **What to do:**
274
+
275
+ - The Dictionary has: `id`, `docs`, `props`, `utils`, `app`, `url`, `api`, `uat`, `pdf`, `html`, `css`, `json`, `readme`.
276
+ - Any other short name in the project's own code is written out in full. If one seems like a word, ask for it to be added to the Dictionary; do not just use it.
277
+ - Copy the new "Dictionary words stay short" bullet into `AGENTS.md` from the [template](/templates#agents).
278
+
279
+ **How to check:** `pnpm lint` passes with the new ESLint config.
280
+
281
+ ### 9. Third-party names are used as they are
282
+
283
+ **Why:** The naming rule is only for names we write. Names from someone else's code keep their own names: everyone knows them by those names, and renaming them breaks the code.
284
+
285
+ **What to do:**
286
+
287
+ - Undo any rename of a third-party name. The common one is shadcn/ui's `cn` function: it stays `cn`.
288
+ - In our own code, give the value a full-word name as soon as it arrives: `const workingDirectory = process.cwd();`, then `{ cwd: workingDirectory }`.
289
+
290
+ **How to check:** Nothing to search for. Review any renamed import from a package.
291
+
292
+ ### 10. The ontology only holds code words
293
+
294
+ **Why:** The code standards define words about writing code. Each project defines the words for what it builds.
295
+
296
+ **What to do:**
297
+
298
+ - Keep the project's product words in `docs/product/ontology.md`.
299
+ - Check every word in it against the [Ontology](/ontology). If the project gives a code word a different meaning, remove that entry and use the code standards' meaning. Tell a person what changed.
300
+ - Make the project's ontology say that it adds to the code standards' ontology.
301
+ - Update the "Ontology" section of `AGENTS.md` from the [template](/templates#agents). It now points to both ontologies.
302
+
303
+ **How to check:** No term in `docs/product/ontology.md` is also defined in the code standards' [Ontology](/ontology).
304
+
305
+ ### 11. Whether agents may commit is the project's choice
306
+
307
+ **Why:** Strict no commit is right for most projects, but a tool built to ship code with AI, such as Launchpad, needs agents to commit.
308
+
309
+ **What to do:** This is standard 22 in the list from change 2. If the person kept it, keep the template's "NEVER COMMIT CODE" lines for strict no commit. Otherwise, replace them with the project's own rule, saying exactly which agents may commit, push and open Pull Requests, and when. See [A project can choose otherwise](/Standards/agent-specs#project-workflow).
310
+
311
+ **How to check:** The top of `AGENTS.md` states the project's commit rule.
312
+
313
+ ### 12. The live standards site
314
+
315
+ **Why:** The standards now have a real address: https://activatus-code-standards.vercel.app
316
+
317
+ **What to do:** Replace `[code standards site URL]` in `AGENTS.md` and `docs/development/coding-standards.md` with https://activatus-code-standards.vercel.app
318
+
319
+ **How to check:** `grep -rn "code standards site URL" .` finds nothing.
320
+
321
+ ### 13. This Version History
322
+
323
+ **What to do:** Add `**Code standards version:** 2` to `AGENTS.md`, under "Code standards".
324
+
325
+ ### No action needed
326
+
327
+ - The [Setup](/Guides/setup) guide is written for the agent: install the package, check the version, agree the standards, apply them. It never asks which framework the project uses, and never creates the app: the person does that.
328
+ - The [migration guide](/Guides/migrating#stage-4--names) has a Names stage.
329
+
330
+ ---
331
+
332
+ ## Version 1
333
+
334
+ **Released:** 2026-10-15
335
+
336
+ The first numbered version: everything in the standards on this date. It included `documentation/` for the docs folder, `Properties` at the end of prop types, `utilities/` for reusable functions, `components/features/`, and the Component Reference. Version 2 replaced all five.
337
+
338
+ **What to do in a project:** follow the [migration guide](/Guides/migrating) for everything.
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
2
  "name": "@activatus/code-standards",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "3.0.0",
4
+ "description": "The Activatus code standards: the rules as Markdown, and the config files to copy. Install it so an AI agent can read the standards from node_modules.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/activatus-life/code-standards.git"
8
+ },
9
+ "homepage": "https://activatus-code-standards.vercel.app",
10
+ "files": [
11
+ "docs",
12
+ "scripts",
13
+ "static/templates",
14
+ "README.md"
15
+ ],
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "devDependencies": {
20
+ "@docusaurus/core": "3.10.2",
21
+ "@docusaurus/module-type-aliases": "3.10.2",
22
+ "@docusaurus/preset-classic": "3.10.2",
23
+ "@docusaurus/theme-mermaid": "3.10.2",
24
+ "@docusaurus/tsconfig": "3.10.2",
25
+ "@docusaurus/types": "3.10.2",
26
+ "@getcanary/docusaurus-theme-search-pagefind": "1.0.2",
27
+ "@getcanary/web": "^1.0.0",
28
+ "@mdx-js/react": "^3.0.0",
29
+ "clsx": "^2.0.0",
30
+ "pagefind": "^1.3.0",
31
+ "prettier": "^3.9.10",
32
+ "prism-react-renderer": "^2.3.0",
33
+ "raw-loader": "^4.0.2",
34
+ "react": "^18.3.1",
35
+ "react-dom": "^18.3.1",
36
+ "typescript": "~5.6.2"
37
+ },
38
+ "browserslist": {
39
+ "production": [
40
+ ">0.5%",
41
+ "not dead",
42
+ "not op_mini all"
43
+ ],
44
+ "development": [
45
+ "last 3 chrome version",
46
+ "last 3 firefox version",
47
+ "last 5 safari version"
48
+ ]
49
+ },
50
+ "engines": {
51
+ "node": ">=20.0"
52
+ },
53
+ "scripts": {
54
+ "docusaurus": "docusaurus",
55
+ "start": "docusaurus start",
56
+ "build": "docusaurus build",
57
+ "serve": "docusaurus serve",
58
+ "clear": "docusaurus clear",
59
+ "typecheck": "tsc",
60
+ "format": "prettier --write .",
61
+ "format:check": "prettier --check ."
62
+ }
6
63
  }
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env node
2
+ // Renames a TypeScript symbol everywhere it is used, with TypeScript's own rename: the same engine as an
3
+ // editor's Rename Symbol (F2). For agents working from the command line. Never use find-and-replace.
4
+ //
5
+ // Run it from the project root, with the file where the symbol is declared:
6
+ // node node_modules/@activatus/code-standards/scripts/renameSymbol.mjs <file> <currentName> <newName>
7
+ // For example:
8
+ // node node_modules/@activatus/code-standards/scripts/renameSymbol.mjs components/ui/button/types.ts ButtonProperties ButtonProps
9
+ import { readFileSync, writeFileSync } from "node:fs";
10
+ import { createRequire } from "node:module";
11
+ import path from "node:path";
12
+
13
+ // process.argv starts with the node binary and this script's path.
14
+ const FIRST_ARGUMENT_INDEX = 2;
15
+ const USAGE =
16
+ "Usage: node renameSymbol.mjs <file> <currentName> <newName>";
17
+
18
+ // Uses the project's own TypeScript, so the rename matches the project's compiler exactly.
19
+ const requireFromProject = createRequire(
20
+ path.join(process.cwd(), "package.json"),
21
+ );
22
+ const typescript = requireFromProject("typescript");
23
+
24
+ const readProjectSettings = () => {
25
+ const configPath = typescript.findConfigFile(
26
+ process.cwd(),
27
+ typescript.sys.fileExists,
28
+ "tsconfig.json",
29
+ );
30
+
31
+ if (!configPath) {
32
+ throw new Error(
33
+ "No tsconfig.json found. Run this from the project root.",
34
+ );
35
+ }
36
+
37
+ const configFile = typescript.readConfigFile(
38
+ configPath,
39
+ typescript.sys.readFile,
40
+ );
41
+
42
+ return typescript.parseJsonConfigFileContent(
43
+ configFile.config,
44
+ typescript.sys,
45
+ path.dirname(configPath),
46
+ );
47
+ };
48
+
49
+ const createLanguageService = ({ projectSettings }) => {
50
+ const host = {
51
+ getScriptFileNames: () => projectSettings.fileNames,
52
+ getScriptVersion: () => "0",
53
+ getScriptSnapshot: (fileName) =>
54
+ typescript.sys.fileExists(fileName)
55
+ ? typescript.ScriptSnapshot.fromString(
56
+ typescript.sys.readFile(fileName),
57
+ )
58
+ : undefined,
59
+ getCurrentDirectory: () => process.cwd(),
60
+ getCompilationSettings: () => projectSettings.options,
61
+ getDefaultLibFileName: (options) =>
62
+ typescript.getDefaultLibFilePath(options),
63
+ fileExists: typescript.sys.fileExists,
64
+ readFile: typescript.sys.readFile,
65
+ readDirectory: typescript.sys.readDirectory,
66
+ directoryExists: typescript.sys.directoryExists,
67
+ getDirectories: typescript.sys.getDirectories,
68
+ };
69
+
70
+ return typescript.createLanguageService(
71
+ host,
72
+ typescript.createDocumentRegistry(),
73
+ );
74
+ };
75
+
76
+ // The first place the name appears as a declaration in the file: an interface, type, function, variable or parameter.
77
+ const findDeclarationPosition = ({ sourceFile, currentName }) => {
78
+ const visit = (node) => {
79
+ const isDeclarationName =
80
+ typescript.isIdentifier(node) &&
81
+ node.text === currentName &&
82
+ node.parent?.name === node;
83
+
84
+ return isDeclarationName
85
+ ? node.getStart(sourceFile)
86
+ : typescript.forEachChild(node, visit);
87
+ };
88
+
89
+ return visit(sourceFile);
90
+ };
91
+
92
+ const endOf = (location) =>
93
+ location.textSpan.start + location.textSpan.length;
94
+
95
+ const applyEdits = ({ renameLocations, newName }) => {
96
+ const locationsByFile = Map.groupBy(
97
+ renameLocations,
98
+ (location) => location.fileName,
99
+ );
100
+
101
+ for (const [fileName, locations] of locationsByFile) {
102
+ const originalText = readFileSync(fileName, "utf8");
103
+ const sortedFromStart = locations.toSorted(
104
+ (first, second) => first.textSpan.start - second.textSpan.start,
105
+ );
106
+ const pieces = sortedFromStart.flatMap((location, index) => {
107
+ const previousEnd =
108
+ index === 0 ? 0 : endOf(sortedFromStart[index - 1]);
109
+ const replacement = `${location.prefixText ?? ""}${newName}${location.suffixText ?? ""}`;
110
+
111
+ return [
112
+ originalText.slice(previousEnd, location.textSpan.start),
113
+ replacement,
114
+ ];
115
+ });
116
+ const lastLocation = sortedFromStart.at(-1);
117
+
118
+ writeFileSync(
119
+ fileName,
120
+ pieces.join("") + originalText.slice(endOf(lastLocation)),
121
+ );
122
+ }
123
+
124
+ return locationsByFile.size;
125
+ };
126
+
127
+ const renameSymbol = ({ filePath, currentName, newName }) => {
128
+ const projectSettings = readProjectSettings();
129
+ const languageService = createLanguageService({ projectSettings });
130
+ const fileName = path.resolve(filePath);
131
+ const sourceFile = languageService
132
+ .getProgram()
133
+ ?.getSourceFile(fileName);
134
+
135
+ if (!sourceFile) {
136
+ throw new Error(
137
+ `${filePath} is not part of the TypeScript project in tsconfig.json.`,
138
+ );
139
+ }
140
+
141
+ const position = findDeclarationPosition({
142
+ sourceFile,
143
+ currentName,
144
+ });
145
+
146
+ if (position === undefined) {
147
+ throw new Error(`${currentName} is not declared in ${filePath}.`);
148
+ }
149
+
150
+ const renameInfo = languageService.getRenameInfo(
151
+ fileName,
152
+ position,
153
+ {
154
+ allowRenameOfImportPath: false,
155
+ },
156
+ );
157
+
158
+ if (!renameInfo.canRename) {
159
+ throw new Error(
160
+ `TypeScript cannot rename ${currentName}: ${renameInfo.localizedErrorMessage}`,
161
+ );
162
+ }
163
+
164
+ const renameLocations = languageService.findRenameLocations(
165
+ fileName,
166
+ position,
167
+ false,
168
+ false,
169
+ {
170
+ providePrefixAndSuffixTextForRename: true,
171
+ },
172
+ );
173
+ const fileCount = applyEdits({ renameLocations, newName });
174
+ const fileWord = fileCount === 1 ? "file" : "files";
175
+
176
+ return `Renamed ${currentName} to ${newName}: ${renameLocations.length} places in ${fileCount} ${fileWord}.`;
177
+ };
178
+
179
+ const [filePath, currentName, newName] = process.argv.slice(
180
+ FIRST_ARGUMENT_INDEX,
181
+ );
182
+
183
+ if (filePath && currentName && newName) {
184
+ console.log(renameSymbol({ filePath, currentName, newName }));
185
+ } else {
186
+ console.error(USAGE);
187
+ process.exitCode = 1;
188
+ }
@@ -0,0 +1,25 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ indent_size = 2
7
+ indent_style = tab
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
10
+
11
+ # Markdown reads a tab as four spaces, so it uses spaces.
12
+ [*.{md,mdx}]
13
+ indent_style = space
14
+ trim_trailing_whitespace = false
15
+ max_line_length = off
16
+
17
+ # YAML does not allow tabs.
18
+ [*.{yml,yaml}]
19
+ indent_style = space
20
+ indent_size = 2
21
+
22
+ # Python's own style guide uses 4 spaces.
23
+ [*.py]
24
+ indent_style = space
25
+ indent_size = 4
@@ -0,0 +1,25 @@
1
+ export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
2
+
3
+ # Source the nvm shell function.
4
+ # Handles: manual install ($HOME/.nvm), Homebrew on macOS, and WSL.
5
+ # On Windows with nvm-windows, nvm is already an executable in PATH — no sourcing needed.
6
+ if [ -s "$NVM_DIR/nvm.sh" ]; then
7
+ . "$NVM_DIR/nvm.sh"
8
+ elif [ "$(uname -s 2>/dev/null)" = "Darwin" ] && command -v brew &>/dev/null; then
9
+ _nvm_sh="$(brew --prefix nvm 2>/dev/null)/nvm.sh"
10
+ [ -s "$_nvm_sh" ] && . "$_nvm_sh"
11
+ unset _nvm_sh
12
+ fi
13
+
14
+ if [ -f ".nvmrc" ]; then
15
+ _node_version="$(tr -d '[:space:]' < .nvmrc)"
16
+ nvm install "$_node_version"
17
+ nvm use "$_node_version"
18
+ unset _node_version
19
+ fi
20
+
21
+ # Ensure the pnpm shim declared in package.json#packageManager is active via Corepack.
22
+ # `corepack enable` is idempotent — safe to run on every cd.
23
+ if command -v corepack &>/dev/null; then
24
+ corepack enable pnpm
25
+ fi
@@ -0,0 +1 @@
1
+ 20