diff --git a/.gitignore b/.gitignore
index 567609b1234a9b8806c5a05da6c866e480aa148d..6f31401f787928dc3bb3e2622578f889336d1d92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 build/
+.vscode/
diff --git a/.gitlab-ci.common.yml b/.gitlab-ci.common.yml
index 37762af3eaddbf028efd735f6c452e97f345a41c..82494622e8305a7bedd95cd7a8292b0d20d823c7 100644
--- a/.gitlab-ci.common.yml
+++ b/.gitlab-ci.common.yml
@@ -40,13 +40,11 @@ build-docker-ubuntu-22.04:
   stage: prepare
   needs: ["versioning"]
   image: docker:latest
+  before_script:
+    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
   script:
     - |
       if ! docker manifest inspect $BASE_IMAGE > /dev/null || [ "$BUILD_DOCKER_IMAGE" = "1" ]; then
         docker build --tag $BASE_IMAGE -f ci/ubuntu_22_04-base .
         docker push $BASE_IMAGE
       fi
-  before_script:
-    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
-
-
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4b85ed69b43fa4d319bbe640f46543265f422c40..c5d463511c1815a8828422442a50d36c3637b9fa 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,7 @@
 
 include: .gitlab-ci.common.yml
 
-lint:
+format:
   stage: linting
   needs: ["versioning", "build-docker-ubuntu-22.04"]
   image: $BASE_IMAGE
@@ -13,13 +13,20 @@ lint:
     - git diff > format.patch
     # Fail when the patch is not empy (note ! can't be used directly.)
     - (! grep -q '^--- a'  format.patch)
+  artifacts:
+    when: on_failure
+    paths:
+      - format.patch
+
+tidy:
+  stage: linting
+  needs: ["versioning", "build-docker-ubuntu-22.04"]
+  image: $BASE_IMAGE
+  script:
     - mkdir build
     - cd build
     - cmake -DCMAKE_CXX_CLANG_TIDY=clang-tidy -G Ninja ..
     - ninja
-  artifacts:
-    paths:
-      - format.patch
 
 test:
   stage: test
@@ -28,7 +35,7 @@ test:
   script:
     - mkdir build
     - cd build
-    - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTINDBUILD_TESTSG=ON -DCMAKE_CXX_FLAGS="-coverage" -DCMAKE_EXE_LINKER_FLAGS="-coverage" -G Ninja ..
+    - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DCMAKE_CXX_FLAGS="-coverage" -DCMAKE_EXE_LINKER_FLAGS="-coverage" -G Ninja ..
     - ninja
     - ctest --output-on-failure |& tee ctest.out
     - mkdir coverage
@@ -57,10 +64,13 @@ build:
 
 pages:
   stage: pages
-  needs: ["versioning", "build-docker-ubuntu-22.04"]
+  needs: ["versioning", "test"]
   image: $BASE_IMAGE
   script:
-    - mkdir build
+    # Generate documentation.
     - cd build
     - cmake -DBUILD_DOCUMENTATION=ON -G Ninja ..
     - ninja sphinx
+    # Extract HTML coverage report.
+    - tar xfz coverage.tar.gz
+    # TODO: Add an index page with links to the documentation and coverage.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b03a8115f8c1a9f4f0988bf58b89b325541c043a..9ad0c6ea481c2a2c685be7b4cc29930ec7613514 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,7 +13,10 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
 option(BUILD_TESTING "Build the test suite" OFF)
 option(BUILD_DOCUMENTATION "Build the documentation" OFF)
 
+install(DIRECTORY include DESTINATION .)
+
 add_subdirectory(src)
+
 if(BUILD_TESTING)
   include(CTest)
   add_subdirectory(test)
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 12d1fe1693104f52b16701c900a6dd9043b1928b..533dc1c97474fceaa4d4efafed29bdaeb8aac6c7 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -4,3 +4,5 @@
 add_library(hello SHARED hello.cpp)
 
 target_include_directories(hello PUBLIC "${CMAKE_SOURCE_DIR}/include")
+
+install(TARGETS hello)
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 9496c79dd1d77f979b06c662ea2b0caf9a517ed0..ed4b94d92b9af2a63ff1762cea94addb201f405f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -6,11 +6,8 @@ find_package(
   COMPONENTS unit_test_framework
   REQUIRED)
 
-add_executable(unittests main.cpp hello.cpp)
+add_executable(unittests main.cpp thello.cpp)
 
 target_link_libraries(unittests PRIVATE hello Boost::unit_test_framework)
 
-add_test(
-  NAME unittests
-  COMMAND unittests -f JUNIT -k unittests.xml
-  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIRECTORY}")
+add_test(NAME unittests COMMAND unittests -f JUNIT -k unittests.xml)
diff --git a/test/hello.cpp b/test/thello.cpp
similarity index 100%
rename from test/hello.cpp
rename to test/thello.cpp