diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..27143cb1220409cd7d7c1649f9c837155bd59f27
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+SHELL = /bin/bash
+.PHONY: run test docs release install
+
+run:
+	# running example simulation
+	if [ -d "example_results" ]; then rm -r example_results; fi
+	./run.jl -o example_results
+	src/analysis/analyse_nature.R example_results
+
+test:
+	# running test suite
+	cd test; julia runtests.jl
+
+commit = $(shell git log --format="%cd (commit %h)" --date=short -1)
+
+docs:
+	# building documentation
+	# include a date stamp with the latest commit
+	sed -i -e "s/\*Last updated:.*/\*Last updated: ${commit}\*/" docs/src/index.md
+	cd docs; julia builddocs.jl
+
+release:
+	echo "Not yet implemented."
+
+install:
+	echo: "Not relevant. Use `julia run.jl` to run Persephone."
diff --git a/README.md b/README.md
index 94f45f52b67afd610289fda433ec2d6cc14150b0..e80ef367b3760ab40de9ded94b62942c0f2eb179 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,8 @@ framework. It is currently in the very early stages of development.
 
 ## Usage
 
+*For the full documentation, open `docs/documentation.html` in a browser.*
+
 ### Installation
 
 Install the latest version of the [Julia](https://julialang.org/downloads/) programming 
@@ -24,10 +26,10 @@ To install package dependencies, open a Julia REPL in this folder and run
 
 ### Running from the commandline
 
-This is the normal mode of operation. Simply execute `run.jl`, typically like so (in Linux):
+This is the normal mode of operation. Simply execute `run.jl` in a terminal, typically like so:
 
 ```
-> ./run.jl -c <config>
+> julia run.jl -c <config>
 ```
 
 where `<config>` specifies the configuration file to use. The recommended workflow is
@@ -52,11 +54,15 @@ optional arguments:
   -h, --help            show this help message and exit
 ```
 
-To run the test suite, do the following:
+To run the test suite, switch to the `test` directory and execute `runtests.jl`.
+
+If you are on Linux or MacOS, you can also use `make`:
 
 ```
-> cd test
-> julia runtests.jl
+> make run       # run a simulation with default values
+> make test      # run the test suite
+> make docs      # build the documentation
+> make release   # create a release
 ```
 
 ### Running from within Julia
diff --git a/docs/src/architecture.md b/docs/src/architecture.md
index 7dccdb98b416343c07f2aac6e3b2ff31d9633cde..7fbbfdec8e866f9bc40c4b6d01c6b610202d457d 100644
--- a/docs/src/architecture.md
+++ b/docs/src/architecture.md
@@ -30,28 +30,34 @@ the `Animal`s in the model landscape.
 
 !["the model object"](assets/model_object.png)
 
-1. **The `model` object:** A cursory reading of the source code will quickly show that
-   most functions take an `AgentBasedModel` object as one of their arguments. This is the
-   key data structure of [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/tutorial/#.-The-model-1),
-   and holds all state that is in any way relevant to a simulation run. (Persephone has
-   a strict "no global state" policy to avoid state-dependent bugs and allow parallelisation.)
-   The model object gives access to all agent instances (via `model[id]`, where `id` is the
-   unique identifier of this agent). It also stores the configuration (`model.settings`),
-   the landscape (`model.landscape`, a matrix of [`Pixel`](@ref) objects that store the local
-   land cover, amongst other things), and the current simulation date (`model.date`).
-   (See [`initmodel`](@ref) for details.)
-
-2. **Model configuration/the [`@param`](@ref) macro:** The model is configured via a 
-   [TOML](https://toml.io/en/) file, the default version of which is at 
-   [`src/parameters.toml`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/parameters.toml).
-   An individual run can be configured using a user-defined configuration file, commandline
-   arguments, or function calls (when Persephone is used as a package rather than an application).
-   During a model run, the `@param(parameter)` macro can be used as a short-hand for
-   `model.settings["parameter"]`. Note that parameter names are prepended with the name
-   of the component they are associated with. For example, the `outdir` parameter belongs
-   to the `[core]` section of the TOML file, and must therefore be referenced as 
-   `@param(core.outdir)`. (See [`src/core/input.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/input.jl) 
-   for details.)
+### The `model` object
+
+A cursory reading of the source code will quickly show that most functions take an 
+`AgentBasedModel` object as one of their arguments. This is the key data structure 
+of [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/tutorial/#.-The-model-1),
+and holds all state that is in any way relevant to a simulation run. (Persephone has
+a strict "no global state" policy to avoid state-dependent bugs and allow parallelisation.)
+The model object gives access to all agent instances (via `model[id]`, where `id` is the
+unique identifier of this agent). It also stores the configuration (`model.settings`),
+the landscape (`model.landscape`, a matrix of [`Pixel`](@ref) objects that store the local
+land cover, amongst other things), and the current simulation date (`model.date`).
+(See [`initmodel`](@ref) for details.)
+
+For more information about working with agent objects, see the 
+[Agents.jl API](https://juliadynamics.github.io/Agents.jl/stable/api/).
+
+### Model configuration/the `@param` macro
+
+The model is configured via a [TOML](https://toml.io/en/) file, the default version of which is at 
+[`src/parameters.toml`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/parameters.toml).
+An individual run can be configured using a user-defined configuration file, commandline
+arguments, or function calls (when Persephone is used as a package rather than an application).
+During a model run, the [`@param`](@ref) macro can be used to access parameter values. 
+Note that parameter names are prepended with the name of the component they are associated 
+with. For example, the `outdir` parameter belongs to the `[core]` section of the TOML file, 
+and must therefore be referenced as  `@param(core.outdir)`. (See 
+[`src/core/input.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/input.jl) 
+for details.)
    
 !!! info "@param and other macros"
 	As `@param(parameter)` expands to `model.settings["parameter"]`, it can obviously
@@ -60,28 +66,33 @@ the `Animal`s in the model landscape.
 	macros depend on specific variables being available where they are called, and can
 	therefore only be used in specific contexts (this is indicated in their documentation).
 
-3. **Output data:** Persephone can output model data into text files with a specified
-   frequency (daily, monthly, yearly, or at the simulation end). Submodels can use
-   [`newdataoutput!`](@ref) to plug into this system. For an example of how to use this,
-   see [`src/nature/ecologicaldata.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/nature/ecologicaldata.jl). 
-   (See [`src/core/output.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/output.jl) for details.)
+### Output data 
 
-4. **Farm events:** The [`FarmEvent`](@ref) struct is used to communicate farming-related
-   events between submodels. An event can be triggered with [`createevent!`](@ref) and affects
-   all pixels within a `FarmPlot`. (See [`src/core/landscape.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/landscape.jl) 
-   for details.)
+Persephone can output model data into text files with a specified
+frequency (daily, monthly, yearly, or at the simulation end). Submodels can use
+[`newdataoutput!`](@ref) to plug into this system. For an example of how to use this, see
+[`src/nature/ecologicaldata.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/nature/ecologicaldata.jl). 
+(See [`src/core/output.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/output.jl) for details.)
+
+### Farm events 
+
+The [`FarmEvent`](@ref) struct is used to communicate farming-related events between 
+submodels. An event can be triggered with [`createevent!`](@ref) and affects all pixels 
+within a [`FarmPlot`](@ref). (See 
+[`src/core/landscape.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/landscape.jl) 
+for details.)
    
-5. **Random numbers and logging:** By default in Julia, the random number generator (RNG)
-   and the system logger are two globally accessible variables. As Persephone needs to avoid
-   all global data (as this would interfere with reproducibility in parallel runs), the `model` 
-   object stores a local logger and a local RNG. The local logger generally does not change the 
-   way the model uses [log statements](https://docs.julialang.org/en/v1/stdlib/Logging/), it is 
-   only relevant for some functions in [`src/core/simulation.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/simulation.jl).
+### Random numbers and logging 
+
+By default in Julia, the [random number generator](https://docs.julialang.org/en/v1/stdlib/Random/)
+(RNG) and the [system logger](https://docs.julialang.org/en/v1/stdlib/Logging/#Logging.global_logger)
+are two globally accessible variables. As Persephone needs to avoid all global data (since
+this would interfere with reproducibility in parallel runs), the `model` object stores a 
+local logger and a local RNG. The local logger generally does not change the way the 
+model uses [log statements](https://docs.julialang.org/en/v1/stdlib/Logging/), it is 
+only relevant for some functions in [`src/core/simulation.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/simulation.jl).
    
 !!! info "Using the model RNG"
 	Whenever you need to use a [random number](https://docs.julialang.org/en/v1/stdlib/Random/#Base.rand), 
 	you must use the `model.rng`. The easiest way to do this is with the [`@rand`](@ref) 
 	and [`@shuffle!`](@ref) macros. (Note that these, too, require access to the `model` object.)
-	
-6. **Working with agents:** For more information about working with agent objects, see the 
-   [Agents.jl API](https://juliadynamics.github.io/Agents.jl/stable/api/).
diff --git a/docs/src/developing.md b/docs/src/developing.md
index 4e42cf72c8776fcdf10b38c13355a10bba434d5d..8451bf76cb54028d1ba77f27ed13b5c0c8a04ad8 100644
--- a/docs/src/developing.md
+++ b/docs/src/developing.md
@@ -2,16 +2,16 @@
 
 ## Workflow
 
-1. Pull the current development version from the master branch on Gitlab: 
+1. Pull the current version from the master branch on Gitlab: 
    [https://git.idiv.de/xo30xoqa/persephone](https://git.idiv.de/xo30xoqa/persephone).
 
 2. If you are working on a new feature, create a new branch to avoid breaking the `master` branch.
-   (The `master` branch should always be in a runnable and (as far as possible) error-free state.)
+   (The `master` branch on Github should always be in a runnable and error-free state.)
 
 3. Implement your changes.
 
-4. Run `example.sh` to make sure the model executes without crashing. Also run the test suite
-   (`cd test; julia runtests.jl`).
+4. Run an example simulation and the test suite to make sure everything works without crashing
+   (`make run` and `make test` on Linux, or execute `run.jl` and `test/runtests.jl` manually.)
 
 5. Commit your work frequently, and try to keep each commit small. Don't forget to add
    relevant tests to the test suite.
@@ -22,11 +22,13 @@
    
 8. Repeat :-)
 
-The Gitlab issue tracker can be used to create, discuss, and assign tasks, as well as to monitor
-progress towards milestones/releases. Once we have a first release, we will start using
-[semantic versioning](https://semver.org/).
+The Gitlab [issue tracker](https://git.idiv.de/xo30xoqa/persephone/-/boards/373) can be used 
+to create, discuss, and assign tasks, as well as to monitor progress towards milestones/releases. 
+Once we have a first release, we will start using [semantic versioning](https://semver.org/).
 
-## Agents.jl
+## Libraries
+
+### Agents.jl
 
 Our model uses [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/) as a framework.
 Their [repository](https://github.com/JuliaDynamics/Agents.jl) can be used to inspect the source
@@ -36,6 +38,29 @@ code or submit bug reports (the authors are quick to respond). Questions can be
 *Tutorial on collaborating on Julia packages: 
 [https://www.matecdev.com/posts/julia-package-collaboration.html](https://www.matecdev.com/posts/julia-package-collaboration.html).*
 
+### Revise.jl
+
+[`Revise.jl`](https://timholy.github.io/Revise.jl/stable/) allows one to reload code
+without restarting the Julia interpreter. Get it with `Pkg.add("Revise")`, then 
+add `using Revise` to `.julia/config/startup.jl` to have it automatically available.
+
+### Test
+
+Persephone uses the inbuilt Julia [testing framework](https://docs.julialang.org/en/v1/stdlib/Test/).
+All new functions should have appropriate tests written for them in the appropriate
+file in the `test` directory. (See [`test/runtests.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/test/runtests.jl)
+for details.) There are three ways to run the test suite: in the terminal, executing
+`make test` or `cd test; julia runtests.jl`; or in the Julia REPL, 
+`Pkg.activate("."); Pkg.test()`.
+
+### Documenter.jl
+
+The HTML documentation is generated using [Documenter.jl](https://documenter.juliadocs.org).
+Therefore, all new functions should have docstrings attached. New files need to be integrated
+into the relevant documentation source files in `docs/src`, and if necessary into
+[`docs/builddocs.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/docs/builddocs.jl).
+To build the documentation, run `make docs`, or `cd docs; julia builddocs.jl`
+(if using the latter, don't forget to update the date and commit in `docs/src/index.md`).
 
 ## Julia editors
 
@@ -68,16 +93,3 @@ See [here](https://www.julia-vscode.org/).
 
 *TODO: add more detail.*
 
-### Other useful stuff
-
-1. [`Revise.jl`](https://timholy.github.io/Revise.jl/stable/) allows one to reload code
-   without restarting the Julia interpreter. Get it with `Pkg.add("Revise")`, then 
-   add `using Revise` to `.julia/config/startup.jl` to have it automatically available.
-
-2. [`git-bug`](https://github.com/MichaelMure/git-bug) is a commandline bug tracker that
-   integrates directly with git. It can also be used as a local interface to Gitlab issues.
-   To install on Linux, download the [binary](https://github.com/MichaelMure/git-bug/releases/tag/v0.8.0),
-   copy it to `/usr/local/bin/git-bug`, and set it as executable with `chmod +x 
-   /usr/local/bin/git-bug`. To set up Gitlab integration, run `git bug bridge configure`
-   from within the relevant repository.
-   
diff --git a/docs/src/index.md b/docs/src/index.md
index 3b5ef53ab6342ef9185bdfe3e786aea95061ebbe..b7c8257194277bf3b2e08bce24863e30442fd907 100644
--- a/docs/src/index.md
+++ b/docs/src/index.md
@@ -13,7 +13,7 @@ an ecological submodels.
 
 ## Running the model
 
-To run a single experiment, execute:
+To run a single experiment, execute `run.jl`:
 
 ```
 julia run.jl -c <CONFIG>
@@ -74,10 +74,10 @@ indoutfreq = "end" # output frequency individual-level data, daily/monthly/yearl
 cropmodel = "linear" # crop growth model to use, "linear" or "aquacrop" (not yet implemented)
 ```
 
-!!! tip "Parameter scanning"
+!!! info "Parameter scanning"
 	You can set any parameter to a list of different values, e.g. `seed = [1,2,3]`.
 	Persephone will then set up and run multiple simulations, one for every possible
 	combination of parameters that you entered (i.e. do a full-factorial simulation
 	experiment).
 
-*Last updated: 2023-02-07 (commit 600bbd3)*  
+*Last updated: 2023-02-07 (commit b402c07)*
diff --git a/src/nature/nature.jl b/src/nature/nature.jl
index 9bdbd347644de485f3e161d6e2f7e39e1b5d69b4..4a2698f09329b37d5f5a9962ff4ab9cf1ac96cb1 100644
--- a/src/nature/nature.jl
+++ b/src/nature/nature.jl
@@ -65,7 +65,7 @@ Update an animal by one day, executing it's currently active phase function.
 """
 function stepagent!(animal::Animal, model::AgentBasedModel)
     animal.age += 1
-    animal.phase(animal,model)
+    animal.traits[animal.phase](animal,model) #FIXME
 end
 
 """