diff --git a/.changeset/funny-lamps-relax.md b/.changeset/funny-lamps-relax.md
new file mode 100644
index 0000000..c19a1bb
--- /dev/null
+++ b/.changeset/funny-lamps-relax.md
@@ -0,0 +1,5 @@
+---
+"create-solana-program": patch
+---
+
+Write generated READMEs
diff --git a/template/base/README.md.njk b/template/base/README.md.njk
index 242396d..5b26467 100644
--- a/template/base/README.md.njk
+++ b/template/base/README.md.njk
@@ -1,6 +1,34 @@
# {{ programName | titleCase }}
-TODO
+{# TODO: Uncomment when CI is generated. #}
+{# #}
+
+{% if clients.includes('js') %}
+
+{% endif %}
+{% if clients.includes('rust') %}
+
+{% else %}
+
+{% endif %}
+
+This template should help get you started developing Solana programs. Let's walk through this generated program repository and see what's included.
+
+## Project setup
+
+The first thing you'll want to do is install NPM dependencies which will allow you to access all the scripts and tools provided by this template.
+
+```sh
+{{ getNpmCommand("install") }}
+```
+
+## Managing programs
+
+You'll notice a `program` folder in the root of this repository. This is where your generated Solana program is located.
+
+Whilst only one program gets generated, not that you can have as many programs as you like in this repository.
+Whenever you add a new program folder to this repository, remember to add it to the `members` array of your root `Cargo.toml` file.
+That way, your programs will be recognized by the following scripts that allow you to build, test, format and lint your programs respectively.
```sh
{{ getNpmCommand("programs:build") }}
@@ -9,4 +37,81 @@ TODO
{{ getNpmCommand("programs:lint") }}
```
-TODO
+## Generating IDLs
+
+You may use the following command to generate the IDLs for your programs.
+
+```sh
+{{ getNpmCommand("generate:idls") }}
+```
+
+Depending on your program's framework, this will either use Shank or Anchor to generate the IDLs.
+Note that, to ensure IDLs are generated using the correct framework version, the specific version used by the program will be downloaded and used locally.
+
+{% if clients.length > 0 %}
+## Generating clients
+
+Once your programs' IDLs have been generated, you can generate clients for them using the following command.
+
+```sh
+{{ getNpmCommand("generate:clients") }}
+```
+
+Alternatively, you can use the `generate` script to generate both the IDLs and the clients at once.
+
+```sh
+{{ getNpmCommand("generate") }}
+```
+
+## Managing clients
+
+The following clients are available for your programs. You may use the following links to learn more about each client.
+
+{% for client in clients %}
+{% if ['js'].includes(client) %}
+- [{{ client | upper }} client](./clients/{{ client }})
+{% else %}
+- [{{ client | titleCase }} client](./clients/{{ client }})
+{% endif %}
+{% endfor %}
+
+## Starting and stopping the local validator
+
+The following script is available to start your local validator.
+
+```sh
+{{ getNpmCommand("validator") }}
+```
+
+By default, if a local validator is already running, the script will be skipped. You may use the `--restart` flag to force the validator to restart.
+
+```sh
+{{ getNpmCommand("validator", "--restart") }}
+```
+
+Finally, you may stop the local validator using the following command.
+
+```sh
+{{ getNpmCommand("validator:stop") }}
+```
+
+## Using external programs in your validator
+
+If your program requires any external programs to be running, you'll want to in your local validator.
+
+You can do this by adding their program addresses to the `program-dependencies` array in the `Cargo.toml` of your program.
+
+```toml
+program-dependencies = [
+ "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
+ "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV",
+]
+```
+
+Next time you build your program and run your validator, these external programs will automatically be fetched from mainnet and used in your local validator.
+
+```sh
+{{ getNpmCommand("programs:build") }}
+{{ getNpmCommand("validator", "--restart") }}
+```
+{% endif %}
diff --git a/template/clients/js/clients/js/README.md b/template/clients/js/clients/js/README.md
deleted file mode 100644
index 92c0fea..0000000
--- a/template/clients/js/clients/js/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# JavaScript client
-
-A generated JavaScript library for the Counter program.
diff --git a/template/clients/js/clients/js/README.md.njk b/template/clients/js/clients/js/README.md.njk
new file mode 100644
index 0000000..acfe980
--- /dev/null
+++ b/template/clients/js/clients/js/README.md.njk
@@ -0,0 +1,38 @@
+# JavaScript client
+
+A generated JavaScript library for the {{ programName | titleCase }} program.
+
+## Getting started
+
+To build and test your JavaScript client from the root of the repository, you may use the following command.
+
+```sh
+{{ getNpmCommand("clients:js:test") }}
+```
+
+This will start a new local validator, if one is not already running, and run the tests for your JavaScript client.
+
+## Available client scripts.
+
+Alternatively, you can go into the client directory and run the tests directly.
+
+```sh
+# Build your programs and start the validator.
+{{ getNpmCommand("programs:build") }}
+{{ getNpmCommand("validator") }}
+
+# Go into the client directory and run the tests.
+cd clients/js
+{{ getNpmCommand("install") }}
+{{ getNpmCommand("build") }}
+{{ getNpmCommand("test") }}
+```
+
+You may also use the following scripts to lint and/or format your JavaScript client.
+
+```sh
+{{ getNpmCommand("lint") }}
+{{ getNpmCommand("lint:fix") }}
+{{ getNpmCommand("format") }}
+{{ getNpmCommand("format:fix") }}
+```
diff --git a/template/clients/rust/clients/rust/README.md b/template/clients/rust/clients/rust/README.md
deleted file mode 100644
index 288bfca..0000000
--- a/template/clients/rust/clients/rust/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Rust client
-
-A generated Rust library for the Counter program.
diff --git a/template/clients/rust/clients/rust/README.md.njk b/template/clients/rust/clients/rust/README.md.njk
new file mode 100644
index 0000000..0484a99
--- /dev/null
+++ b/template/clients/rust/clients/rust/README.md.njk
@@ -0,0 +1,13 @@
+# Rust client
+
+A generated Rust library for the {{ programName | titleCase }} program.
+
+## Getting started
+
+To build and test your Rust client from the root of the repository, you may use the following command.
+
+```sh
+{{ getNpmCommand("clients:js:test") }}
+```
+
+This will start a new local validator, if one is not already running, and run the tests for your Rust client.
diff --git a/template/programs/counter-shank/program/README.md b/template/programs/counter-shank/program/README.md
deleted file mode 100644
index 5b58fb4..0000000
--- a/template/programs/counter-shank/program/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Counter program
-
-Simple counter program as an example.
diff --git a/template/programs/counter-shank/program/README.md.njk b/template/programs/counter-shank/program/README.md.njk
new file mode 100644
index 0000000..32c4679
--- /dev/null
+++ b/template/programs/counter-shank/program/README.md.njk
@@ -0,0 +1,3 @@
+# {{ programName | titleCase }}
+
+Your generated Solana program. Have fun!