diff --git a/content/designs/coding_conventions.md b/content/designs/coding_conventions.md
index 71676714bfd614e43714fee45ec3dff2a5c52e78..cf5a3837012bc29ee8330eaab836873f8c35a125 100644
--- a/content/designs/coding_conventions.md
+++ b/content/designs/coding_conventions.md
@@ -18,34 +18,34 @@ specific to other APIs are covered on their respective pages.
 ## Summary
 
 * Use the GLib coding style, with vim modelines.
-  ([Code formatting](#code-formatting))
+  ([Code formatting]( {{< ref "#code-formatting" >}} ))
 * Consistently namespace files, functions and types.
-  ([Namespacing](#namespacing))
+  ([Namespacing]( {{< ref "#namespacing" >}} ))
 * Always design code to be modular, encapsulated and loosely coupled.
-  ([Modularity](#modularity))
+  ([Modularity]( {{< ref "#modularity" >}} ))
   * Especially by keeping object member variables inside the object’s private
     structure.
 * Code defensively by adding pre- and post-conditions assertions to all public
   functions.
-  ([Pre- and post-condition assertions](#pre-and-postcondition-assertions))
+  ([Pre- and post-condition assertions]( {{< ref "#pre-and-postcondition-assertions" >}} ))
 * Report all user errors (and no programmer errors) using GError.
-  ([GError usage](#gerror-usage))
-* Use appropriate container types for sets of items. ([GList](#glist))
+  ([GError usage]( {{< ref "#gerror-usage" >}} ))
+* Use appropriate container types for sets of items. ([GList]( {{< ref "#glist" >}} ))
 * Document all constant values used in the code.
-  ([Magic values](#magic-values))
+  ([Magic values]( {{< ref "#magic-values" >}} ))
 * Use standard GLib patterns for defining asynchronous methods.
-  ([Asynchronous methods](#asynchronous-methods))
+  ([Asynchronous methods]( {{< ref "#asynchronous-methods" >}} ))
 * Do not call any blocking, synchronous functions.
-  ([Asynchronous methods](#asynchronous-methods))
+  ([Asynchronous methods]( {{< ref "#asynchronous-methods" >}} ))
 * Do not run blocking operations in separate threads; use asynchronous calls
-  instead. ([Asynchronous methods](#asynchronous-methods))
+  instead. ([Asynchronous methods]( {{< ref "#asynchronous-methods" >}} ))
 * Prefer enumerated types over booleans whenever there is the potential for
   ambiguity between true and false.
-  ([Enumerated types and booleans](#enumerated-types-and-booleans))
+  ([Enumerated types and booleans]( {{< ref "#enumerated-types-and-booleans" >}} ))
 * Ensure GObject properties have no side-effects.
-  ([GObject properties](#gobject-properties))
+  ([GObject properties]( {{< ref "#gobject-properties" >}} ))
 * Treat resources as heap-allocated memory and do not leak them.
-  ([Resource leaks](#resource-leaks))
+  ([Resource leaks]( {{< ref "#resource-leaks" >}} ))
 
 ## Code formatting
 
@@ -62,7 +62,7 @@ Each C and H file should have a vim-style modeline, which lets the programmer’
 editor know how code in the file should be formatted. This helps keep the coding
 style consistent as the files evolve. The following modeline should be put as
 the very first line of the file, immediately before the
-[copyright comment](license-applying.md#licensing-of-code):
+[copyright comment]( {{< ref "license-applying.md#licensing-of-code" >}} ):
 
 ```
 /* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
@@ -225,7 +225,7 @@ module. There are two levels of checking:
 * Validation: Check for invalid input and return an error gracefully on failure.
 
 Validation is a complex topic, and is handled using
-[GErrors](#gerror-usage). The remainder of this section discusses pre- and
+[GErrors]( {{< ref "#gerror-usage" >}} ). The remainder of this section discusses pre- and
 post-condition assertions, which are purely for catching programmer errors. A
 programmer error is where a function is called in a way which is documented as
 disallowed. For example, if `NULL` is passed to a parameter which is documented
@@ -266,7 +266,7 @@ thought of as a C implementation of an
 [exception](http://en.wikipedia.org/wiki/Exception_handling exception).
 
 Any kind of runtime failure (anything which is not a
-[programmer error](#pre-and-postcondition-assertions)) must be handled by
+[programmer error]( {{< ref "#pre-and-postcondition-assertions" >}} )) must be handled by
 including a `GError**` parameter in the function, and setting a useful and
 relevant GError describing the failure, before returning from the function.
 Programmer errors must not be handled using GError: use assertions,
diff --git a/content/designs/list.md b/content/designs/list.md
index 206765235368f4eb6f8eed2ac75bf6e65101f248..8f619bf6bbce92c1c500f01bd78c3d0287e53ea5 100644
--- a/content/designs/list.md
+++ b/content/designs/list.md
@@ -789,7 +789,7 @@ by updating the contents of the adapter.
 The list widget will be connected to the adapter, and will update itself
 appropriately when notified of changes.
 
-An example of this is shown in [the next section](#filtering1), the following
+An example of this is shown in [the next section]( {{< ref "#filtering1" >}} ), the following
 diagram illustrates the filtering process.
 
 ![Adapter filtering](/images/list_adapter_filtering.png)
@@ -915,7 +915,7 @@ The roller widget will implement the `MxScrollable` interface, setting
 appropriate increment values on its adjustments, in order to ensure the
 currently-focused row will always be aligned with the middle after scrolling.
 
-As the roller subclass will implement [rollover](#roller-rollover), the
+As the roller subclass will implement [rollover]( {{< ref "#roller-rollover" >}} ), the
 elastic effect when reaching the bottom of the list will not be used.
 
 In addition, it will also, in its `init` method, use a `ClutterEffect` in
diff --git a/content/designs/long-term-reproducibility.md b/content/designs/long-term-reproducibility.md
index 453ba6536bce2ce0d3941795dbc2bcf16c43d7c0..629257ee6112ca45a3c23a37a98d3f55b52ede34 100644
--- a/content/designs/long-term-reproducibility.md
+++ b/content/designs/long-term-reproducibility.md
@@ -141,7 +141,7 @@ and the main build process.
 ## Build recipes
 
 The process to the reference images is described by textual, YAML-based
-[Debos recipes](image-build-infrastructure.md#image-building-process) stored in
+[Debos recipes]( {{< ref "image-build-infrastructure.md#image-building-process" >}} ) stored in
 git repository, with a different branch for each release channel.
 
 The textual, YAML-based GitLab-CI pipeline definitions then control how the
@@ -258,7 +258,7 @@ version shipped in the Apertis repositories.
 
 The purpose of the previously described software items is to generate a set of
 artefacts, such as those described in [the v2019 release artefacts
-document](release-v2019-artifacts.md). With the artefacts themselves a few metadata
+document]( {{< ref "release-v2019-artifacts.md" >}} ). With the artefacts themselves a few metadata
 entries are generated to help tracking what has been used during the build.
 
 In particular, the `pkglist` files capture the full list of packages installed
diff --git a/content/designs/multiuser-transactional-switching.md b/content/designs/multiuser-transactional-switching.md
index 5eac13874882fe09112bc46c9d5b13c3d0e86ecd..4347c5952e1194874a8be71586a2795af629f034 100644
--- a/content/designs/multiuser-transactional-switching.md
+++ b/content/designs/multiuser-transactional-switching.md
@@ -12,7 +12,7 @@ outputs = [ "html", "pdf-in",]
 
 This document describes one particular set of use-cases for how multiple
 users are expected to use the Apertis system, using the [Multiuser Design
-document](multiuser.md)
+document]( {{< ref "multiuser.md" >}} )
 as a base. It starts by describing the use cases that are
 believed to be important in the automotive context, followed by a
 technical analysis and recommendations.
@@ -752,8 +752,8 @@ all.
 
 The actual state transfer would be similar to the state saving mechanism
 that is already needed for save/restore functionality (as discussed in
-the Preferences and [Persistence design document](preferences-and-persistence.md), and more briefly
-in the [Multiuser](multiuser.md) and [Applications](applications.md) design documents), but placing
+the Preferences and [Persistence design document]( {{< ref "preferences-and-persistence.md" >}} ), and more briefly
+in the [Multiuser]( {{< ref "multiuser.md" >}} ) and [Applications]( {{< ref "applications.md" >}} ) design documents), but placing
 state in memory or in an OS-supplied temporary directory instead of in
 the per-(user, app) data directory. We recommend that similar data
 formats and API conventions should be used, so that in trivial cases
@@ -813,7 +813,7 @@ freezing the existing session or not touching it at all.
 By using the traditional “one UNIX uid per user” approach, each user
 will have its own home directory protected by the usual mechanisms, such
 as file ownership, user and group permissions, in addition to the
-AppArmor restrictions described in the [Security Design document](security.md).
+AppArmor restrictions described in the [Security Design document]( {{< ref "security.md" >}} ).
 Note that usage of the UNIX home directory concept, in which a single
 directory has all of a given user's files, is not in the plans for
 Apertis. Instead, each application will store its data in a directory
diff --git a/content/designs/op-tee.md b/content/designs/op-tee.md
index 3fb7735883daedd61d2c3cb34205e40a66cf0e7c..844c3ed1fb13ffefda2be46b18fc7cf179791b32 100644
--- a/content/designs/op-tee.md
+++ b/content/designs/op-tee.md
@@ -35,7 +35,7 @@ When enabled, a "secure monitor" runs in the highest privilege level provided by
 The secure monitor supports switching between the trusted and untrusted environments and enabling messages to be passed from one environment to the other.
 ARM provide a reference secure monitor as part of the [ARM Trusted Firmware](https://github.com/ARM-software/arm-trusted-firmware) (ATF) project.
 The ATF secure monitor provides an API to enable the development of trusted operating systems to run within the trusted environment, one such trusted OS is the open source [OP-TEE](https://www.op-tee.org/).
-OP-TEE provides a trusted environment which can run [Trusted Applications](#trusted-applications) (TAs), which are written against the TEE internal API.
+OP-TEE provides a trusted environment which can run [Trusted Applications]( {{< ref "#trusted-applications" >}} ) (TAs), which are written against the TEE internal API.
 
 As well as starting up a trusted OS in the trusted environment, ATF typically starts a standard OS such as Linux on the untrusted side, known as the rich operating system or "Rich Execution Environment" (REE), by running the firmware normally used for this OS.
 It is necessary for the OS to have drivers capable of interfacing with the secure monitor and that understands how to format messages for the trusted OS used on the trusted side.
@@ -100,11 +100,11 @@ A number of steps need to be taken in order to enable TEE support in Apertis.
 
 Secure boot provides an initial important step in initialisation of the TEE by ensuring that the initialisation process is able to proceed without interference.
 Unfortunately this fundamental step is very platform dependent and can not be solved as a general case.
-Apertis has already taken steps to [document and demonstrate secure boot](secure-boot.md).
+Apertis has already taken steps to [document and demonstrate secure boot]( {{< ref "secure-boot.md" >}} ).
 At the moment, Apertis only ships some support for secure on the SABRE Lite platform. This provides a good reference for the overall process but, unfortunately, the SABRE Lite is not a good choice as a technology demonstrator for TEE due to its age.
 
 We advise the implementation of a TEE demonstrator on a more modern platform to take advantage of the more advanced functionality found in such platforms.
-This will be covered in more detail in our recommendations for the [next steps](#next-steps).
+This will be covered in more detail in our recommendations for the [next steps]( {{< ref "#next-steps" >}} ).
 
 In addition to the board verifying the initial binaries that are executed, it is important that the verification of binaries continues through the boot process in order to build a [chain of trust](https://en.wikipedia.org/wiki/Chain_of_trust) so that later stages can determine whether boot was carried out appropriately.
 
diff --git a/content/designs/release-flow.md b/content/designs/release-flow.md
index a33d2a5fd220ed5d103e502f1dd4914bba836b91..8eede3e6e74a8c86cc8466d0185e1d8b18b881d0 100644
--- a/content/designs/release-flow.md
+++ b/content/designs/release-flow.md
@@ -451,7 +451,7 @@ is, which use-cases it validates and which part of the software stack are
 fully supported for product usage.
 
 For the 2019 product release this document can be found in the
-["Release artifacts for Apertis v2019"](release-v2019-artifacts.md) document.
+["Release artifacts for Apertis v2019"]( {{< ref "release-v2019-artifacts.md" >}} ) document.
 
 ## Apertis release flow conclusions
 
@@ -640,7 +640,7 @@ Ubuntu and Debian cases are released every 2 years, with 5 years of support.
 
 The rationale for switching from Ubuntu as a baseline to Debian has been
 outlined in more detailed in the
-["The case for moving to Debian stretch or Ubuntu 18.04"](case-for-moving-to-debian.md)
+["The case for moving to Debian stretch or Ubuntu 18.04"]( {{< ref "case-for-moving-to-debian.md" >}} )
 concept document.
 
 # Appendix: Distribution "freshness"
diff --git a/content/designs/secure-boot.md b/content/designs/secure-boot.md
index 6139e583b326f847c3c59952fe1084d3d91161a0..be960091441bbaacc4a2e0b72c395fa84fd3e9fe 100644
--- a/content/designs/secure-boot.md
+++ b/content/designs/secure-boot.md
@@ -69,7 +69,7 @@ can directly be Linux, in some cases it will be a bootloader with more
 functionality (as all of main memory is now available) and in some cases it
 will be multiple loader steps. As an example of the last case for devices using
 ARM Trusted Firmware there will typically be follow-on steps to load the secure
-firmware (such as [OP-TEE](op-tee.md)) followed by a non-secure world
+firmware (such as [OP-TEE]( {{< ref "op-tee.md" >}} )) followed by a non-secure world
 bootloader which loads Linux. For those interested the various images used in
 an ATF setup can be found
 [here](https://trustedfirmware-a.readthedocs.io/en/latest/getting_started/image-terminology.html).
@@ -547,7 +547,7 @@ $ cat vmlinuz-pad.itb ivt.bin > vmlinuz-pad-ivt.itb
 ```
 
 We need to prepare the config file for signing the padded FIT image with IVT.
-This step is absolutely the same as for [U-Boot signing](#sign-uboot-bootloader-such-that-the-rom-can-verify).
+This step is absolutely the same as for [U-Boot signing]( {{< ref "#sign-uboot-bootloader-such-that-the-rom-can-verify" >}} ).
 
 Configuration file for FIT image is created from
 template [csf_uboot.txt](https://gitlab.apertis.org/infrastructure/apertis-imx-srk/-/blob/master/csf/csf_uboot.txt),
@@ -634,7 +634,7 @@ The FIT image is more complex. So for Apertis we use 2 scripts:
 - the [`scripts/generate_signed_fit_image.py` script](https://gitlab.apertis.org/infrastructure/apertis-image-recipes/-/blob/apertis/v2021dev1/scripts/generate_signed_fit_image.py)
   is used for generation FIT image, padding, IVT calculation and signing.
   This script can be used standalone to automate all steps described
-  in the section "[Sign kernel images for U-Boot to load](#sign-kernel-images-for-uboot-to-load)"
+  in the section "[Sign kernel images for U-Boot to load]( {{< ref "#sign-kernel-images-for-uboot-to-load" >}} )"
 - the [`scripts/generate_fit_image.sh` script](https://gitlab.apertis.org/infrastructure/apertis-image-recipes/-/blob/apertis/v2021dev1/scripts/generate_fit_image.sh)
   is a wrapper for the former providing it the paths
   for kernel, initramfs and DTB to include them in the signed FIT image.
diff --git a/content/designs/security.md b/content/designs/security.md
index 807d5fd963fff8b7b8fecf4dbfab14961d579fb7..68972d26b5e36c320e914ed17128026af4c0fe9d 100644
--- a/content/designs/security.md
+++ b/content/designs/security.md
@@ -77,7 +77,7 @@ in practice, and not a property of whether the component is
 ***trustworthy***, i.e. safe to rely on. For a system to be secure, it
 is necessary that all of its trusted components be trustworthy.
 
-One subtlety of [Apertis' app-centric design](applications.md) is that there is a
+One subtlety of [Apertis' app-centric design]( {{< ref "applications.md" >}} ) is that there is a
 privilege boundary between *application bundles* even within the context
 of one user. As a result, a multi-user design has two main layers in its
 security model: system-level security that protects users from each
@@ -349,7 +349,7 @@ applications ( [Security between applications]( {{< ref "#security-between-appli
 multi-user support, user IDs are used to provide two separate security
 boundaries – isolating applications from each other, and isolating users
 from each other ( [Security between users]( {{< ref "#security-between-users" >}} )) – with one user ID per (user, app) pair.
-This is discussed in more detail in the [Multiuser design document](multiuser.md).
+This is discussed in more detail in the [Multiuser design document]( {{< ref "multiuser.md" >}} ).
 
 The system's main file system is mounted read-only to protect against
 unauthorized tampering with system files (integrity for platform data,
@@ -379,7 +379,7 @@ The idea of restricting the services an application can use to those specified i
 manifest also exists in Android. Before installation, Android shows a
 list of system services the application intends to access and
 installation only initiates if the user agrees. This differs slightly
-from the [Applications design in Apertis](applications.md), in which some permissions
+from the [Applications design in Apertis]( {{< ref "applications.md" >}} ), in which some permissions
 are subject to prompting similar to Android's, while other permissions
 are checked by the app store curator and unconditionally granted on
 installation.
@@ -1634,11 +1634,11 @@ repositories and signing infrastructure.
 
 ##  Secure Boot
 
-The objective of [secure boot](secure-boot.md) is to ensure that the system is
+The objective of [secure boot]( {{< ref "secure-boot.md" >}} ) is to ensure that the system is
 booted using sanctioned components. The extent to which this is ultimately
 taken will vary between implementations, some may use secure boot avoid system
 kernel replacement, whilst others may also use it to ensure a
-[Trusted Execution Environment](op-tee.md) is loaded without interference.
+[Trusted Execution Environment]( {{< ref "op-tee.md" >}} ) is loaded without interference.
 
 The steps required to implement secure boot are vendor specific and thus the
 full specification for the solution depends on a definition from the
diff --git a/content/designs/sensors-and-actuators.md b/content/designs/sensors-and-actuators.md
index b9fd523b761e6b55ee87859a6bd0512ebded54f5..caf6b8a3f90a8a8801c789f691bc9e2d2e905b10 100644
--- a/content/designs/sensors-and-actuators.md
+++ b/content/designs/sensors-and-actuators.md
@@ -990,7 +990,7 @@ but cannot abstract all the differences between vehicles. (See
 It is expected that the main backend service for a vehicle, provided by
 that vehicle’s OEM, will be access the vehicle-specific network
 implementation running in the automotive domain, and hence will use the
-[inter-domain communications connection](inter-domain-communication.md). In order to avoid
+[inter-domain communications connection]( {{< ref "inter-domain-communication.md" >}} ). In order to avoid
 additional unnecessary inter-process communication (IPC) hops, it is
 suggested that the main backend service acts as *the* proxy for sensor
 data on the inter-domain connection, rather than communicating with a
diff --git a/content/designs/test-data-reporting.md b/content/designs/test-data-reporting.md
index 60806dba4a99ce166e60cbc4dce41beb8c790e72..2c85f0eab6d520a5747c5594f7c4e180de1eee09 100644
--- a/content/designs/test-data-reporting.md
+++ b/content/designs/test-data-reporting.md
@@ -239,7 +239,7 @@ they can just be convenient links to generate test reports for past images
 versions.
 
 The page should also show the relevant options for filtering and searching test
-results as explained in the [web application dashboard section](#web-application-dashboard).
+results as explained in the [web application dashboard section]( {{< ref "#web-application-dashboard" >}} ).
 
 In summary, the minimal required layout of the main page for the web application
 dashboard will be the history view, a list to recent test reports and the searching
diff --git a/content/designs/test-data-storage.md b/content/designs/test-data-storage.md
index 754778b02b7e9569d02f8b3106ef070221bbf495..b39adf41b368c080df9f64ff468d420350429dd6 100644
--- a/content/designs/test-data-storage.md
+++ b/content/designs/test-data-storage.md
@@ -773,7 +773,7 @@ kinds of report.
 
 These applications will need to trigger a GET request to the SQUAD HTTP API to
 fetch the specific tests results (as explained in the
-[Fetching Test Results](#fetching-test-results) section) and generate the
+[Fetching Test Results]( {{< ref "#fetching-test-results" >}} ) section) and generate the
 report pages or documents using that data.
 
 These applications can be developed as command line tools or web applications
diff --git a/content/designs/upstreaming.md b/content/designs/upstreaming.md
index b062732db16b248d8aa45dbb31191b2b044acdb1..d9e571db50f0d4b08b2c4a7e04264d02c90c390c 100644
--- a/content/designs/upstreaming.md
+++ b/content/designs/upstreaming.md
@@ -121,13 +121,13 @@ basis for addition into Apertis.
 
 **Note**: Upstreaming is generally a process best considered from the outset.
 If upstreaming is planned at an early stage consider actively
-[working with the community](contribution-process.md#upstream-early-upstream-often)
+[working with the community]( {{< ref "contribution_process.md#upstream-early-upstream-often" >}} )
 during development, as this may streamline and simplify the development and
 upstreaming process.
 
 Modifications and functionality that are not suitable for upstreaming will be
 considered on a
-[case by case basis](contribution-process.md#adding-components-to-apertis).
+[case by case basis]( {{< ref "contribution_process.md#adding-components-to-apertis" >}} ).
 Whether they will be considered suitable for integration into the main Apertis
 repositories will depend in part on how broad the usefulness of the changes
 will be with the Apertis user base. At a minimum it would be necessary for such