This file provides guidance to AI coding assistants when working with code in this repository.
# Build the platform toolchain (default target)
make
# Build the platform toolchain + stdlib
make lib
# Build the platform toolchain + stdlib and run tests
make test
# Format code
make format
# Check formatting
make checkformatThe Makefile’s targets build on each other in this order:
yarn-installruns automatically for targets that need JavaScript tooling (lib, playground, tests, formatting, etc.).build(default target) builds the toolchain binaries (all copied intopackages/@rescript/<platform>/bin):compilerbuilds the dune executables (bsc,rescript-*,ounit_tests, etc.).rewatchbuilds the Rust-based ReScript build system and CLI.
libuses those toolchain outputs to build the runtime sources.- Test targets (
make test,make test-syntax, etc.) reuse everything above.
Before changing a subsystem, read its local agent instructions and area guide. For compiler changes, read compiler/AGENTS.md. For build system changes, read rewatch/AGENTS.md. These apply even when the task starts at the repository root. Changes spanning areas need the relevant guidance from each.
compiler/syntax/README.mdfor parsing, printing, and JSX transformationcompiler/ml/README.mdfor the type checker and typed treecompiler/core/README.mdfor Lambda optimization and JavaScript generationanalysis/README.mdfor editor analysisrewatch/README.mdfor the build systemtools/README.mdforrescript-tools
-
Use underscore patterns carefully - Don't use
_patterns as lazy placeholders for new language features that then get forgotten. Only use them when you're certain the value should be ignored for that specific case. Ensure all new language features are handled correctly and completely across all compiler layers -
Avoid
let _ = …for side effects - If you need to call a function only for its side effects, useignore expr(or bind the result and thread state explicitly). Do not writelet _ = expr in (), and do not discard stateful results—plumb them through instead. -
Don't use unit
()with mandatory labeled arguments - When a function has a mandatory labeled argument (like~config), don't add a trailing()parameter. The labeled argument already prevents accidental partial application. Only use()when all parameters are optional and you need to force evaluation. Example:let forceDelayedItems ~config = ...notlet forceDelayedItems ~config () = ... -
Avoid warning suppressions - Never use
[@@warning "..."]to silence warnings. Instead, fix the underlying issue properly -
Skip trailing
; _in record patterns - The warning it targets is disabled in this codebase, so prefer{field = x}over{field = x; _}.
- OCaml code: snake_case (e.g.,
to_string) - ReScript code: camelCase (e.g.,
toString)
- Use DCO sign-off:
Signed-Off-By: Your Name <email> - Include appropriate tests with all changes
- Build must pass before committing
When a PR depends on another unmerged PR, make a native GitHub stack. Keep the
branches linear and in the same repository, then run gh stack link BOTTOM [NEXT...], listing the stack bottom to top. Each argument is a branch name or
a PR number: the command pushes each branch, reuses the PR that already exists
for it, and opens one where there is none, so branches alone are enough. Open
the PRs yourself first if you want to write their titles and descriptions.
Linking sets each PR's base to the branch below it, leaving only the bottom PR
on master. CI runs on every PR in the stack.
- Follow existing patterns in the codebase
- Prefer existing utility functions over reinventing
- Comment complex algorithms and non-obvious logic
- Maintain backward compatibility where possible
Add a CHANGELOG.md entry for any user-facing change (bug fix, feature, or breaking change). Put it under the matching section of the current (Unreleased) version and end the line with the PR link. See CONTRIBUTING.md. PRs are expected to include one.
For compiler or standard-library changes, run make test. For syntax changes,
also run make test-syntax; use make test-syntax-roundtrip when parsing or
printing changes. Other focused suites are make test-gentype,
make test-analysis, make test-tools, and make test-rewatch.
- Always for new language features
- Always for bug fixes
- When modifying analysis passes
- When changing JavaScript generation
- Syntax tests (
tests/syntax_tests/) - Parser validation - Integration tests (
tests/tests/) - End-to-end behavior - Unit tests (
tests/ounit_tests/) - Compiler functions - Build tests (
tests/build_tests/) - Error cases and edge cases - Type tests (
tests/build_tests/super_errors/) - Single-file type checking errors - Multi-file error tests (
tests/build_tests/super_errors_multi/) - Cross-module errors that need separate.res/.resifiles
tests/ERROR_VARIANTS.md is a per-module
catalog of every error and warning variant the compiler can emit, with
each entry mapped to a fixture (or a documented reason it's unreachable).
When adding or removing an error variant, also update the catalog:
- Add (or remove) the row in the relevant module section.
- Set the status (
✓covered /⚠unreachable /☐TODO). - If covered, link the fixture path; if unreachable, note the reason.
When adding or removing a fixture, update the corresponding row's
Fixture and status columns so the catalog stays in sync with the test
suite. The catalog is the primary tool for finding coverage gaps and
dead-code removal candidates; stale entries make both jobs harder.
Run commands from the repository root:
make watch # Watch compiler sources
make artifacts # Build artifacts and update the artifact list
make clean # Clean build outputs
npm run check # Lint with Biome
npm run check:all
npm run typecheck # TypeScript type checkingSee CONTRIBUTING.md for toolchain requirements and setup, and the area guides above for subsystem-specific debugging commands.