diff --git a/README.md b/README.md
index 2753226..59ba6c8 100644
--- a/README.md
+++ b/README.md
@@ -142,40 +142,9 @@ favorite editor if it is not yet supported.
## Development
-Run all tests and checks below in one command:
+To get started hacking on RCL, see [`docs/development.md`][dev-docs].
- nix flake check
-
-Run golden tests:
-
- cargo build
- golden/run.py
-
-Run unit tests and lints:
-
- cargo test
- cargo clippy
-
-Typecheck Python sources
-
- mypy --strict --exclude pyrcl .
- mypy --strict pyrcl
-
-Check formatting:
-
- cargo fmt
- black .
-
-View coverage of the golden tests:
-
- nix build .#coverage --out-link result
- xdg-open result/index.html
-
-For how to run the fuzzers, see [`docs/testing.md`](docs/testing.md).
-
-## Building WASM
-
-See [the readme in the `wasm` directory](wasm/README.md).
+[dev-docs]: https://docs.ruuda.nl/rcl/development/
## License
diff --git a/docs/building.md b/docs/building.md
index db648eb..335bbf0 100644
--- a/docs/building.md
+++ b/docs/building.md
@@ -48,3 +48,11 @@ fix the discrepancies is welcome:
* aarch64-apple-darwin
[reproducible]: https://reproducible-builds.org/
+
+## Python module
+
+See the readme in the `pyrcl` directory for how to build the Python module.
+
+## Wasm module
+
+See the readme in the `wasm` directory for how to build the Webassembly module.
diff --git a/docs/development.md b/docs/development.md
new file mode 100644
index 0000000..3a9c184
--- /dev/null
+++ b/docs/development.md
@@ -0,0 +1,93 @@
+# Developing RCL
+
+This chapter explains the tools and workflows involved in hacking on RCL.
+To get started, clone the repository from one of the two mirrors:
+
+ git clone https://codeberg.org/ruuda/rcl.git
+ git clone https://github.com/ruuda/rcl.git
+
+## Building
+
+RCL is written in Rust and builds with Cargo:
+
+ cargo build
+ target/debug/rcl --help
+
+See the [building chapter](building.md) for more details and alternative build
+configurations.
+
+## CI and automated tests
+
+Almost all of the checks that are part of the RCL development
+process are automated, and included in [the Nix flake][flake]. These checks are
+verified on CI by [Garnix], but you can run them locally as well:
+
+ nix flake check
+
+This means that you can reproduce and debug any CI run locally.
+
+While it is convenient to be able to run all checks in one command, if you know
+what parts of RCL you changed, you can run just the relevant
+checks. They are listed in [the section below](#individual-checks).
+
+## Development environment
+
+For the tools used for development, the Nix flake includes a devshell with the
+right version of development dependencies (Python, MkDocs, Tree-sitter, ets.)
+that you can enter with:
+
+ nix develop --command $SHELL
+
+Sourcing your tools elsewhere (e.g. your system package manager) will probably
+work, but only the Nix flake is continuously tested on CI.
+
+[flake]: installation.md#as-a-nix-flake
+[Garnix]: https://app.garnix.io/repo/ruuda/rcl
+
+## Individual checks
+
+
+Run the [golden tests](testing.md#golden-tests):
+
+ cargo build
+ golden/run.py
+
+View coverage of the golden tests:
+
+ nix build .#coverage --out-link result
+ xdg-open result/index.html
+
+Run unit tests and lints:
+
+ cargo test --workspace
+ cargo clippy --workspace
+
+Typecheck Python sources:
+
+ mypy --strict --exclude pyrcl .
+ mypy --strict pyrcl
+
+Autoformat Rust, Python, and RCL code:
+
+
+```sh
+cargo fmt
+black .
+fd . --extension .rcl --exclude golden --exec-batch rcl format --in-place
+```
+
+Build and preview the manual:
+
+ mkdocs serve
+
+Build crate documentation and check for issues:
+
+ RUSTFLAGS="--deny warnings" cargo doc --no-deps --workspace
+
+## Fuzz tests
+
+After implementing a feature, run the fuzzers to ensure the code still respects
+all invariants and is free of crashes. See [the fuzzing section in the testing
+chapter][fuzz].
+
+[fuzz]: testing.md#running-the-fuzzers
diff --git a/mkdocs.yml b/mkdocs.yml
index 3552cad..93012f6 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -49,9 +49,10 @@ nav:
- "rcl patch": "rcl_patch.md"
- "rcl query": "rcl_query.md"
- "Development":
- - "About": "about.md"
+ - "Overview": "development.md"
- "Building": "building.md"
- "Testing": "testing.md"
- "Grammars": "grammars.md"
- "Tree-sitter": "tree_sitter.md"
- "Releasing": "releasing.md"
+ - "About": "about.md"