diff --git a/docsite/site/content/_index.md b/docsite/site/content/_index.md
index d574918..b2ef281 100644
--- a/docsite/site/content/_index.md
+++ b/docsite/site/content/_index.md
@@ -85,23 +85,28 @@ tbody td:nth-child(even) {
| UCG | JSonnet | Dhall |
Variables | x | x | x |
-
+
Conditionals | x | x | x |
-
+
Functions | x | x | x |
-
+
Modules/Classes | x | x | x |
-
-Imports | x | x | x |
+Imports | x | x | x |
+
Std Lib | Minimal | x | Prelude |
-Type Safety | Inferred types and schema validation | Unknown | Inferred types |
+
+Type Safety | Inferred types and schema validation | Unknown | Inferred types |
+
+
+Guaranteed to terminate | No | No | Yes |
+
diff --git a/docsite/site/content/reference/_index.md b/docsite/site/content/reference/_index.md
index c2cc31e..01030c3 100644
--- a/docsite/site/content/reference/_index.md
+++ b/docsite/site/content/reference/_index.md
@@ -1,7 +1,7 @@
+++
title = "The UCG Language Reference"
slug = "reference"
-weight = 2
+weight = 3
sort_by = "weight"
in_search_index = true
+++
diff --git a/docsite/site/content/reference/converters.md b/docsite/site/content/reference/converters.md
index c177fdf..ed8f4b2 100644
--- a/docsite/site/content/reference/converters.md
+++ b/docsite/site/content/reference/converters.md
@@ -1,5 +1,5 @@
+++
-title = "UCG Converters"
+title = "Converters"
weight = 5
sort_by = "weight"
in_search_index = true
diff --git a/docsite/site/content/stdlib/_index.md b/docsite/site/content/stdlib/_index.md
index 66b9a19..582663c 100644
--- a/docsite/site/content/stdlib/_index.md
+++ b/docsite/site/content/stdlib/_index.md
@@ -1,7 +1,7 @@
+++
title = "The UCG Standard Library"
slug = "stdlib"
-weight = 3
+weight = 4
sort_by = "weight"
in_search_index = true
+++
diff --git a/docsite/site/content/how-to/_index.md b/docsite/site/content/tutorials/_index.md
similarity index 56%
rename from docsite/site/content/how-to/_index.md
rename to docsite/site/content/tutorials/_index.md
index b840a9b..4c1e556 100644
--- a/docsite/site/content/how-to/_index.md
+++ b/docsite/site/content/tutorials/_index.md
@@ -1,12 +1,13 @@
+++
-title = "HowTo Guides"
-weight = 4
+title = "Tutorials"
+weight = 2
sort_by = "weight"
in_search_index = true
+++
-A collection of useful HowTo Guides
+A collection of useful Tutorials
----------
Some example use cases for UCG.
-* Creating a launch script for a docker container.
\ No newline at end of file
+* Creating a launch script for a docker container
+* Recursive Modules
\ No newline at end of file
diff --git a/docsite/site/content/tutorials/recursive-modules.md b/docsite/site/content/tutorials/recursive-modules.md
new file mode 100644
index 0000000..6566e2d
--- /dev/null
+++ b/docsite/site/content/tutorials/recursive-modules.md
@@ -0,0 +1,159 @@
++++
+title = "Recursive Modules and their Uses"
+slug = "recursive-modules"
+weight = 2
+in_search_index = true
++++
+
+Modules are the only expression in UCG with the capablility to perform
+recursion using self import[^1]. This is safe because statements in a module
+are evaluated at module copy time. This is useful when you need to traverse a
+UCG value deeply. You can see an example of this in the UCG `std/schema.ucg`
+module where we perform a deep type comparison between two UCG values.
+
+As an example we will create a module that can do a dynamic deep index into a
+tuple by using recursion. The module will take in a tuple to traverse and a
+list of field names to descend into.
+
+Create a file called `deep_index.ucg` and put the following into it.
+
+```
+let deep_index = module {
+ tpl = {}, // We expect that tuples here.
+ names = [], // We expect a list of names here.
+} => {
+ // todo
+};
+```
+
+Our `deep_index` module expects a tuple and list of names. We set the defaults
+to an empty tuple and an empty list so anything that isn't either those or NULL
+will be a compile error when we call our module. Next we need to check for the
+existence of the first name in the tuple.
+
+```
+let deep_index = module {
+ tpl = {}, // We expect tuples here.
+ names = [], // We expect a list of names here.
+} => (result) {
+ // Fill in
+
+ let result = select ((mod.names.0) in mod.tpl), NULL, {
+ true = mod.tpl.(mod.names.0),
+ };
+};
+```
+
+There are a few things to note here. We use the out expression `(result)` to
+make this module more ergonomic. We reference our modulr arguments with the
+`mod.` prefix. We also surround part of our selector with parens in
+`(mod.tpl.(mod.names.0))` to force the last selector to pick the field
+dynamically from the result of the grouped expression.
+
+As written this module has a few problems though.
+
+* It is unsafe for inputs where the list of names is empty
+* it is unsafe for inputs where the list of names contains items that are not
+ strings.
+
+## Handling Unsafe inputs.
+
+We want it to be a compile error if anyone calls our module with inputs of the
+wrong shape. We have two possibilities to handle. NULL inputs for either
+argument or an list that contains items that are not strings.
+
+```
+let deep_index = module {
+ tpl = {}, // We expect tuples here.
+ names = [], // We expect a list of names here.
+} => (result) {
+ // import some useful items from the std lib
+ let schema = import "std/schema.ucg";
+ let l = import "std/lists.ucg";
+
+ // Assert some compile time expectations.
+ // First ensure that names is a list of strings.
+ (names != NULL && schema.shaped{val=names, shape=[""]}) ||
+ fail "names must be non NULL and a list of strings";
+ // Now ensure that tpl is not NULL
+ tpl != NULL || fail "tpl must not be NULL";
+
+ let select_field = func(name) select (name in mod.tpl), NULL {
+ true = mod.tpl.(name),
+ };
+
+ let result = select l.len(names) > 0, mod.tpl, {
+ true = select_field(mod.names.0),
+ };
+};
+```
+
+Our module will now throw appropriate compile time errors if we pass in invalid
+input shapes. We also correctly handle the case where we have no more names to
+descend into. We now need to handle calling our module recursively.
+
+## Module Recursion
+
+In order to do recursion we have to import ourself.
+
+```
+let deep_index = module {
+ tpl = {}, // We expect that tuples here.
+ names = [], // We expect a list of names here.
+} => (result) {
+ // import some useful items from the std lib
+ let schema = import "std/schema.ucg";
+ let l = import "std/lists.ucg";
+
+ // import ourself now.
+ let self = import "deep_index.ucg".deep_index;
+
+ // Assert some compile time expectations.
+ // First ensure that names is a list of strings.
+ (names != NULL && schema.shaped{val=names, shape=[""]}) ||
+ fail "names must be non NULL and a list of strings";
+ // Now ensure that tpl is not NULL
+ tpl != NULL || fail "tpl must not be NULL";
+
+ let name = mod.names.0;
+ let fail_msg = "Attempt to descend into a non existent name @" % (name);
+
+ // Field selector function that throws a compile error if the field
+ // doesn't exist.
+ let select_field = func(name) => select (name in mod.tpl), fail fail_message {
+ true = mod.tpl.(name),
+ };
+
+ // calculate our next value.
+ // If there are no more names then something has gone wrong and
+ // we should hard fail.
+ let next = select l.len(names) > 0, mod.tpl, fail "Impossible" {
+ true = select_field(name),
+ };
+
+ // we need to get the tail of our list.
+ let tail = l.tail(names);
+
+ // if the tail is non empty then recurse down.
+ // If the tail is empty then return the current value.
+ let result = select l.len(tail) > 0, next, {
+ // recurse
+ true = self{tpl=result, names=tail},
+ };
+};
+```
+
+Our `deep_index` module can now descend down into a tuple given a list of field
+names. If any of the names does not exist it will be a compile failure.
+
+## Final notes
+
+One consquence of this method of doing recursion is that you can not reference
+the module in the file it is defined in. Doing so would result in a compile
+error as UCG detects an import loop. In practice this does not prove to be a
+problem since nearly all usages of the module will be outside of the file it is
+defined in.
+
+
+
+[^1]: Technnically functions can do recursion if you manually pass in the same function as an argument to itself, but this is unwieldy and error-prone.
\ No newline at end of file
diff --git a/docsite/site/content/how-to/script.md b/docsite/site/content/tutorials/script.md
similarity index 100%
rename from docsite/site/content/how-to/script.md
rename to docsite/site/content/tutorials/script.md