Imported from datisthq/fairspec-application (
AGENTS.md). Install upstream withnpx skills add datisthq/fairspec-application. Copyright stays with the author.
Agents
This file provides guidance to coding agents when working with code in this repository.
General
- Never commit code to git!
- Don't change shadcn code in
elements/ - Prioritize using LSP capabilities if possible
- When resolving a TODO, follow its instructions literally
- Run type checking as part of your tasks
- Run specs as part of your tasks
- Don't run linting as part of your tasks
Skills
Depth lives in skills/ (reached by Claude Code through the .claude/skills symlink), so
this file carries invariants and the skills carry procedure. Reach for one before working in
its area:
| skill | when |
|---|---|
review-changes |
reviewing a pull request — also what the review workflow runs |
Commands
- Run
pnpm lintto lint the code - Run
pnpm formatto auto-fix formatting issues - Run
pnpm typeto check TypeScript types - Run
pnpm testto run the full test suite including linting, type checking, and tests - Run
pnpm unitto run only the Vitest tests - Run
pnpm exec vitest run -t "test name"orpnpm exec vitest run path/to/test.tsto run a single test - Run
pnpm docs:startto serve the landing site andpnpm docs:buildto build it
Structure
- The renderer (React SPA) lives flat at the repository root:
routes/,components/,elements/,hooks/,helpers/,services/,constants/,styles/,locales/ - Electron process code lives under
processes/main/andprocesses/preload/ models/holds the zod schemas shared by the renderer and the engine — the oRPC wire contract- The renderer must never import from
#processes/*,electronornode:*; the only legal crossing is the type-onlyRouterimport inservices/engine.ts(enforced by oxlint) .livemark/is the landing site published at application.fairspec.org, built with livemark and deployed to Cloudflare as static assets. It is independent of the Electron app, is English-only and outside the i18n workflow, and its dependencies must stay indevDependenciesso they never reach the installer
i18n
- Any change that adds or edits a user-facing string must run
pnpm extractand then fillmsgstrfor every new or changed message in all seven non-source catalogues ptis European Portuguese, never Brazilianlingui extractreports a Total count that includes obsolete entries. A#~ msgidwhose string no longer exists still counts, and grepping^msgstr ""will never find it because the line is#~ msgstr "". Parse with@lingui/format-po's ownparse()to see what is genuinely untranslated, or runpnpm extract --cleanto drop obsolete entries- Long msgids wrap across lines in the PO, so naive text replacement silently misses them. Fill
those through the same parser and
serialize()rather than string surgery
Formats
- Use 2-space indentation, UTF-8 encoding, and LF line endings
- Use PascalCase for classes and interfaces, and camelCase for methods and variables
- Place high-level public items first in a file and low-level private items last
- Use ES modules with full import paths including the ".ts(x)" file extension
Types
- Use strict TypeScript with null checks but don't add explicit return types to functions
- Never use TypeScript
any, type castingas, or!without permission
Specs
- Place unit tests in
<module>.unit.tsfiles and don't add useless comments like "Arrange", "Act", "Assert"
Docs
- Add Typedoc comments only for public APIs and don't add them for files or use @params directives
- Don't write
//comments in the code