diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
index a29ac18..c2fd5ee 100644
--- a/.github/workflows/phpunit.yml
+++ b/.github/workflows/phpunit.yml
@@ -3,6 +3,8 @@ on: push
 jobs:
   phpunit:
     runs-on: ubuntu-latest
+    env:
+      IS_CI_TEST: true
     steps:
       - uses: actions/checkout@v1
       - uses: shivammathur/setup-php@v2
diff --git a/.gitignore b/.gitignore
index 4da6094..99cb968 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 vendor
 var
+!var/tests/repo
 !var/**/.gitkeep
 .phpunit.result.cache
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..95cd4ff
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+# PHPCS Documentation Generator
+
+Note: this currently works only with the PHPCompatibility standard.
+
+## Usage
+
+Copy the `generator.xml.dist` template to `generator.xml` and add your sources and standards.
+
+```sh
+bin/phpcsdocs generate
+```
diff --git a/composer.json b/composer.json
index 1242441..c381f2c 100644
--- a/composer.json
+++ b/composer.json
@@ -6,9 +6,12 @@
         "danielstjules/stringy": "^3.1",
         "roave/better-reflection": "^4.12",
         "phpdocumentor/reflection-docblock": "^5.2",
-        "ext-simplexml": "*",
         "symfony/filesystem": "^5.2",
-        "symfony/process": "^5.2"
+        "symfony/process": "^5.2",
+        "nikic/php-parser": "4.6.*",
+        "ext-simplexml": "*",
+        "ext-dom": "*",
+        "ext-libxml": "*"
     },
     "autoload": {
         "psr-4": {
@@ -17,6 +20,6 @@
         }
     },
     "require-dev": {
-        "phpunit/phpunit": "^9.5"
+        "phpunit/phpunit": "^9.0"
     }
 }
diff --git a/composer.lock b/composer.lock
index 89eee70..fad8cb9 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "d1e357dd79e21303096f74a1a97631ed",
+    "content-hash": "27502a4c19ce2892bc1f63c5028e2b76",
     "packages": [
         {
             "name": "beberlei/assert",
@@ -180,16 +180,16 @@
         },
         {
             "name": "nikic/php-parser",
-            "version": "v4.10.4",
+            "version": "v4.6.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e"
+                "reference": "c346bbfafe2ff60680258b631afb730d186ed864"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e",
-                "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864",
+                "reference": "c346bbfafe2ff60680258b631afb730d186ed864",
                 "shasum": ""
             },
             "require": {
@@ -197,8 +197,8 @@
                 "php": ">=7.0"
             },
             "require-dev": {
-                "ircmaxell/php-yacc": "^0.0.7",
-                "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+                "ircmaxell/php-yacc": "0.0.5",
+                "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0"
             },
             "bin": [
                 "bin/php-parse"
@@ -206,7 +206,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.9-dev"
+                    "dev-master": "4.3-dev"
                 }
             },
             "autoload": {
@@ -230,9 +230,9 @@
             ],
             "support": {
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
-                "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4"
+                "source": "https://github.com/nikic/PHP-Parser/tree/v4.6.0"
             },
-            "time": "2020-12-20T10:01:03+00:00"
+            "time": "2020-07-02T17:12:47+00:00"
         },
         {
             "name": "opis/closure",
@@ -763,26 +763,26 @@
         },
         {
             "name": "roave/signature",
-            "version": "1.3.0",
+            "version": "1.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Roave/Signature.git",
-                "reference": "bbbcc317dfe3a750e27231c5d2130153aa4c41b3"
+                "reference": "5b5bb9499cfbcc78d9f472e03af1e97e4341ec7c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Roave/Signature/zipball/bbbcc317dfe3a750e27231c5d2130153aa4c41b3",
-                "reference": "bbbcc317dfe3a750e27231c5d2130153aa4c41b3",
+                "url": "https://api.github.com/repos/Roave/Signature/zipball/5b5bb9499cfbcc78d9f472e03af1e97e4341ec7c",
+                "reference": "5b5bb9499cfbcc78d9f472e03af1e97e4341ec7c",
                 "shasum": ""
             },
             "require": {
-                "php": "7.4.*"
+                "php": "7.4.*|8.0.*"
             },
             "require-dev": {
-                "doctrine/coding-standard": "^8.1",
-                "infection/infection": "^0.17.5",
-                "phpunit/phpunit": "^9.3",
-                "vimeo/psalm": "^3.16"
+                "doctrine/coding-standard": "^8.2",
+                "infection/infection": "^0.20.2",
+                "phpunit/phpunit": "^9.5.1",
+                "vimeo/psalm": "^4.4"
             },
             "type": "library",
             "autoload": {
@@ -797,22 +797,22 @@
             "description": "Sign and verify stuff",
             "support": {
                 "issues": "https://github.com/Roave/Signature/issues",
-                "source": "https://github.com/Roave/Signature/tree/1.3.0"
+                "source": "https://github.com/Roave/Signature/tree/1.4.0"
             },
-            "time": "2020-10-01T08:35:57+00:00"
+            "time": "2021-01-25T09:39:37+00:00"
         },
         {
             "name": "symfony/console",
-            "version": "v5.2.1",
+            "version": "v5.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "47c02526c532fb381374dab26df05e7313978976"
+                "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/47c02526c532fb381374dab26df05e7313978976",
-                "reference": "47c02526c532fb381374dab26df05e7313978976",
+                "url": "https://api.github.com/repos/symfony/console/zipball/d62ec79478b55036f65e2602e282822b8eaaff0a",
+                "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a",
                 "shasum": ""
             },
             "require": {
@@ -871,7 +871,7 @@
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony Console Component",
+            "description": "Eases the creation of beautiful and testable command line interfaces",
             "homepage": "https://symfony.com",
             "keywords": [
                 "cli",
@@ -880,7 +880,7 @@
                 "terminal"
             ],
             "support": {
-                "source": "https://github.com/symfony/console/tree/v5.2.1"
+                "source": "https://github.com/symfony/console/tree/v5.2.2"
             },
             "funding": [
                 {
@@ -896,20 +896,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-12-18T08:03:05+00:00"
+            "time": "2021-01-27T10:15:41+00:00"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v5.2.1",
+            "version": "v5.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d"
+                "reference": "262d033b57c73e8b59cd6e68a45c528318b15038"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d",
-                "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038",
+                "reference": "262d033b57c73e8b59cd6e68a45c528318b15038",
                 "shasum": ""
             },
             "require": {
@@ -939,10 +939,10 @@
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony Filesystem Component",
+            "description": "Provides basic utilities for the filesystem",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/filesystem/tree/v5.2.1"
+                "source": "https://github.com/symfony/filesystem/tree/v5.2.2"
             },
             "funding": [
                 {
@@ -958,7 +958,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-11-30T17:05:38+00:00"
+            "time": "2021-01-27T10:01:46+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
@@ -1448,16 +1448,16 @@
         },
         {
             "name": "symfony/process",
-            "version": "v5.2.1",
+            "version": "v5.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd"
+                "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/bd8815b8b6705298beaa384f04fabd459c10bedd",
-                "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd",
+                "url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
+                "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
                 "shasum": ""
             },
             "require": {
@@ -1487,10 +1487,10 @@
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony Process Component",
+            "description": "Executes commands in sub-processes",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/process/tree/v5.2.1"
+                "source": "https://github.com/symfony/process/tree/v5.2.2"
             },
             "funding": [
                 {
@@ -1506,7 +1506,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-12-08T17:03:37+00:00"
+            "time": "2021-01-27T10:15:41+00:00"
         },
         {
             "name": "symfony/service-contracts",
@@ -1589,16 +1589,16 @@
         },
         {
             "name": "symfony/string",
-            "version": "v5.2.1",
+            "version": "v5.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/string.git",
-                "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed"
+                "reference": "c95468897f408dd0aca2ff582074423dd0455122"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/string/zipball/5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed",
-                "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed",
+                "url": "https://api.github.com/repos/symfony/string/zipball/c95468897f408dd0aca2ff582074423dd0455122",
+                "reference": "c95468897f408dd0aca2ff582074423dd0455122",
                 "shasum": ""
             },
             "require": {
@@ -1641,7 +1641,7 @@
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony String component",
+            "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
             "homepage": "https://symfony.com",
             "keywords": [
                 "grapheme",
@@ -1652,7 +1652,7 @@
                 "utf8"
             ],
             "support": {
-                "source": "https://github.com/symfony/string/tree/v5.2.1"
+                "source": "https://github.com/symfony/string/tree/v5.2.2"
             },
             "funding": [
                 {
@@ -1668,7 +1668,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-12-05T07:33:16+00:00"
+            "time": "2021-01-25T15:14:59+00:00"
         },
         {
             "name": "webmozart/assert",
@@ -1854,29 +1854,28 @@
         },
         {
             "name": "phar-io/manifest",
-            "version": "2.0.1",
+            "version": "1.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phar-io/manifest.git",
-                "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133"
+                "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
-                "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
+                "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+                "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-phar": "*",
-                "ext-xmlwriter": "*",
-                "phar-io/version": "^3.0.1",
-                "php": "^7.2 || ^8.0"
+                "phar-io/version": "^2.0",
+                "php": "^5.6 || ^7.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0.x-dev"
+                    "dev-master": "1.0.x-dev"
                 }
             },
             "autoload": {
@@ -1910,24 +1909,24 @@
                 "issues": "https://github.com/phar-io/manifest/issues",
                 "source": "https://github.com/phar-io/manifest/tree/master"
             },
-            "time": "2020-06-27T14:33:11+00:00"
+            "time": "2018-07-08T19:23:20+00:00"
         },
         {
             "name": "phar-io/version",
-            "version": "3.0.4",
+            "version": "2.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phar-io/version.git",
-                "reference": "e4782611070e50613683d2b9a57730e9a3ba5451"
+                "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451",
-                "reference": "e4782611070e50613683d2b9a57730e9a3ba5451",
+                "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+                "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
                 "shasum": ""
             },
             "require": {
-                "php": "^7.2 || ^8.0"
+                "php": "^5.6 || ^7.0"
             },
             "type": "library",
             "autoload": {
@@ -1959,9 +1958,9 @@
             "description": "Library for handling version information and constraints",
             "support": {
                 "issues": "https://github.com/phar-io/version/issues",
-                "source": "https://github.com/phar-io/version/tree/3.0.4"
+                "source": "https://github.com/phar-io/version/tree/master"
             },
-            "time": "2020-12-13T23:18:30+00:00"
+            "time": "2018-07-08T19:19:57+00:00"
         },
         {
             "name": "phpspec/prophecy",
@@ -2032,35 +2031,32 @@
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "9.2.5",
+            "version": "8.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1"
+                "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1",
-                "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc",
+                "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
-                "ext-libxml": "*",
                 "ext-xmlwriter": "*",
-                "nikic/php-parser": "^4.10.2",
-                "php": ">=7.3",
-                "phpunit/php-file-iterator": "^3.0.3",
-                "phpunit/php-text-template": "^2.0.2",
-                "sebastian/code-unit-reverse-lookup": "^2.0.2",
-                "sebastian/complexity": "^2.0",
-                "sebastian/environment": "^5.1.2",
-                "sebastian/lines-of-code": "^1.0.3",
-                "sebastian/version": "^3.0.1",
-                "theseer/tokenizer": "^1.2.0"
+                "php": "^7.3",
+                "phpunit/php-file-iterator": "^3.0",
+                "phpunit/php-text-template": "^2.0",
+                "phpunit/php-token-stream": "^4.0",
+                "sebastian/code-unit-reverse-lookup": "^2.0",
+                "sebastian/environment": "^5.0",
+                "sebastian/version": "^3.0",
+                "theseer/tokenizer": "^1.1.3"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^9.0"
             },
             "suggest": {
                 "ext-pcov": "*",
@@ -2069,7 +2065,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.2-dev"
+                    "dev-master": "8.0-dev"
                 }
             },
             "autoload": {
@@ -2097,7 +2093,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
-                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.5"
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/8.0.2"
             },
             "funding": [
                 {
@@ -2105,7 +2101,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-11-28T06:44:49+00:00"
+            "time": "2020-05-23T08:02:54+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -2349,72 +2345,35 @@
             "time": "2020-10-26T13:16:10+00:00"
         },
         {
-            "name": "phpunit/phpunit",
-            "version": "9.5.1",
+            "name": "phpunit/php-token-stream",
+            "version": "4.0.4",
             "source": {
                 "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360"
+                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+                "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7bdf4085de85a825f4424eae52c99a1cec2f360",
-                "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3",
+                "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3",
                 "shasum": ""
             },
             "require": {
-                "doctrine/instantiator": "^1.3.1",
-                "ext-dom": "*",
-                "ext-json": "*",
-                "ext-libxml": "*",
-                "ext-mbstring": "*",
-                "ext-xml": "*",
-                "ext-xmlwriter": "*",
-                "myclabs/deep-copy": "^1.10.1",
-                "phar-io/manifest": "^2.0.1",
-                "phar-io/version": "^3.0.2",
-                "php": ">=7.3",
-                "phpspec/prophecy": "^1.12.1",
-                "phpunit/php-code-coverage": "^9.2.3",
-                "phpunit/php-file-iterator": "^3.0.5",
-                "phpunit/php-invoker": "^3.1.1",
-                "phpunit/php-text-template": "^2.0.3",
-                "phpunit/php-timer": "^5.0.2",
-                "sebastian/cli-parser": "^1.0.1",
-                "sebastian/code-unit": "^1.0.6",
-                "sebastian/comparator": "^4.0.5",
-                "sebastian/diff": "^4.0.3",
-                "sebastian/environment": "^5.1.3",
-                "sebastian/exporter": "^4.0.3",
-                "sebastian/global-state": "^5.0.1",
-                "sebastian/object-enumerator": "^4.0.3",
-                "sebastian/resource-operations": "^3.0.3",
-                "sebastian/type": "^2.3",
-                "sebastian/version": "^3.0.2"
+                "ext-tokenizer": "*",
+                "php": "^7.3 || ^8.0"
             },
             "require-dev": {
-                "ext-pdo": "*",
-                "phpspec/prophecy-phpunit": "^2.0.1"
-            },
-            "suggest": {
-                "ext-soap": "*",
-                "ext-xdebug": "*"
+                "phpunit/phpunit": "^9.0"
             },
-            "bin": [
-                "phpunit"
-            ],
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.5-dev"
+                    "dev-master": "4.0-dev"
                 }
             },
             "autoload": {
                 "classmap": [
                     "src/"
-                ],
-                "files": [
-                    "src/Framework/Assert/Functions.php"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -2424,62 +2383,93 @@
             "authors": [
                 {
                     "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
+                    "email": "sebastian@phpunit.de"
                 }
             ],
-            "description": "The PHP Unit Testing framework.",
-            "homepage": "https://phpunit.de/",
+            "description": "Wrapper around PHP's tokenizer extension.",
+            "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
             "keywords": [
-                "phpunit",
-                "testing",
-                "xunit"
+                "tokenizer"
             ],
             "support": {
-                "issues": "https://github.com/sebastianbergmann/phpunit/issues",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.1"
+                "issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
+                "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
             },
             "funding": [
-                {
-                    "url": "https://phpunit.de/donate.html",
-                    "type": "custom"
-                },
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
                 }
             ],
-            "time": "2021-01-17T07:42:25+00:00"
+            "abandoned": true,
+            "time": "2020-08-04T08:28:15+00:00"
         },
         {
-            "name": "sebastian/cli-parser",
-            "version": "1.0.1",
+            "name": "phpunit/phpunit",
+            "version": "9.2.6",
             "source": {
                 "type": "git",
-                "url": "https://github.com/sebastianbergmann/cli-parser.git",
-                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
+                "url": "https://github.com/sebastianbergmann/phpunit.git",
+                "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
-                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6",
+                "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "doctrine/instantiator": "^1.3.1",
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "ext-xmlwriter": "*",
+                "myclabs/deep-copy": "^1.9.5",
+                "phar-io/manifest": "^1.0.3",
+                "phar-io/version": "^2.0.1",
+                "php": "^7.3",
+                "phpspec/prophecy": "^1.10.3",
+                "phpunit/php-code-coverage": "^8.0.2",
+                "phpunit/php-file-iterator": "^3.0.3",
+                "phpunit/php-invoker": "^3.0.2",
+                "phpunit/php-text-template": "^2.0.2",
+                "phpunit/php-timer": "^5.0.1",
+                "sebastian/code-unit": "^1.0.5",
+                "sebastian/comparator": "^4.0.3",
+                "sebastian/diff": "^4.0.1",
+                "sebastian/environment": "^5.1.2",
+                "sebastian/exporter": "^4.0.2",
+                "sebastian/global-state": "^4.0",
+                "sebastian/object-enumerator": "^4.0.2",
+                "sebastian/resource-operations": "^3.0.2",
+                "sebastian/type": "^2.1.1",
+                "sebastian/version": "^3.0.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "ext-pdo": "*",
+                "phpspec/prophecy-phpunit": "^2.0"
+            },
+            "suggest": {
+                "ext-soap": "*",
+                "ext-xdebug": "*"
             },
+            "bin": [
+                "phpunit"
+            ],
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-master": "9.2-dev"
                 }
             },
             "autoload": {
                 "classmap": [
                     "src/"
+                ],
+                "files": [
+                    "src/Framework/Assert/Functions.php"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -2493,19 +2483,28 @@
                     "role": "lead"
                 }
             ],
-            "description": "Library for parsing CLI options",
-            "homepage": "https://github.com/sebastianbergmann/cli-parser",
+            "description": "The PHP Unit Testing framework.",
+            "homepage": "https://phpunit.de/",
+            "keywords": [
+                "phpunit",
+                "testing",
+                "xunit"
+            ],
             "support": {
-                "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
-                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
+                "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.2.6"
             },
             "funding": [
+                {
+                    "url": "https://phpunit.de/donate.html",
+                    "type": "custom"
+                },
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T06:08:49+00:00"
+            "time": "2020-07-13T17:55:55+00:00"
         },
         {
             "name": "sebastian/code-unit",
@@ -2692,63 +2691,6 @@
             ],
             "time": "2020-10-26T15:49:45+00:00"
         },
-        {
-            "name": "sebastian/complexity",
-            "version": "2.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/complexity.git",
-                "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
-                "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
-                "shasum": ""
-            },
-            "require": {
-                "nikic/php-parser": "^4.7",
-                "php": ">=7.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^9.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library for calculating the complexity of PHP code units",
-            "homepage": "https://github.com/sebastianbergmann/complexity",
-            "support": {
-                "issues": "https://github.com/sebastianbergmann/complexity/issues",
-                "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
-            },
-            "funding": [
-                {
-                    "url": "https://github.com/sebastianbergmann",
-                    "type": "github"
-                }
-            ],
-            "time": "2020-10-26T15:52:27+00:00"
-        },
         {
             "name": "sebastian/diff",
             "version": "4.0.4",
@@ -2957,26 +2899,26 @@
         },
         {
             "name": "sebastian/global-state",
-            "version": "5.0.2",
+            "version": "4.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "a90ccbddffa067b51f574dea6eb25d5680839455"
+                "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455",
-                "reference": "a90ccbddffa067b51f574dea6eb25d5680839455",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
+                "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
+                "php": "^7.3",
                 "sebastian/object-reflector": "^2.0",
                 "sebastian/recursion-context": "^4.0"
             },
             "require-dev": {
                 "ext-dom": "*",
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^9.0"
             },
             "suggest": {
                 "ext-uopz": "*"
@@ -2984,7 +2926,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.0-dev"
+                    "dev-master": "4.0-dev"
                 }
             },
             "autoload": {
@@ -3009,72 +2951,9 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
-                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2"
-            },
-            "funding": [
-                {
-                    "url": "https://github.com/sebastianbergmann",
-                    "type": "github"
-                }
-            ],
-            "time": "2020-10-26T15:55:19+00:00"
-        },
-        {
-            "name": "sebastian/lines-of-code",
-            "version": "1.0.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/lines-of-code.git",
-                "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
-                "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
-                "shasum": ""
-            },
-            "require": {
-                "nikic/php-parser": "^4.6",
-                "php": ">=7.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^9.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0-dev"
-                }
+                "source": "https://github.com/sebastianbergmann/global-state/tree/master"
             },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library for counting the lines of code in PHP source code",
-            "homepage": "https://github.com/sebastianbergmann/lines-of-code",
-            "support": {
-                "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
-                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
-            },
-            "funding": [
-                {
-                    "url": "https://github.com/sebastianbergmann",
-                    "type": "github"
-                }
-            ],
-            "time": "2020-11-28T06:42:11+00:00"
+            "time": "2020-02-07T06:11:37+00:00"
         },
         {
             "name": "sebastian/object-enumerator",
@@ -3472,7 +3351,9 @@
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
-        "ext-simplexml": "*"
+        "ext-simplexml": "*",
+        "ext-dom": "*",
+        "ext-libxml": "*"
     },
     "platform-dev": [],
     "plugin-api-version": "2.0.0"
diff --git a/config/di.php b/config/di.php
index 85b2b4e..b51af2d 100644
--- a/config/di.php
+++ b/config/di.php
@@ -1,15 +1,18 @@
 <?php
 declare(strict_types=1);
 
-use App\CodeRepository\CodeRepository;
-use App\CodeRepository\GithubCodeRepository;
+use App\Configuration\ConfigurationRepository;
+use App\Configuration\XmlConfigurationRepository;
 use App\Generator\Generator as DocGenerator;
 use App\Generator\MarkdownGenerator;
 use App\SniffFinder\FilesystemSniffFinder;
 use App\SniffFinder\SniffFinder;
+use App\Value\Folder;
 
 return [
-    CodeRepository::class => DI\autowire(GithubCodeRepository::class),
     DocGenerator::class => DI\autowire(MarkdownGenerator::class),
     SniffFinder::class => DI\autowire(FilesystemSniffFinder::class),
+    ConfigurationRepository::class => DI\factory(function () {
+        return new XmlConfigurationRepository(new Folder(__DIR__ . '/../'));
+    })
 ];
diff --git a/generator.xml.dist b/generator.xml.dist
new file mode 100644
index 0000000..647bea3
--- /dev/null
+++ b/generator.xml.dist
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<generator format="markdown">
+    <source path="git@github.com:PHPCompatibility/PHPCompatibility.git">
+        <standard path="PHPCompatibility" />
+    </source>
+</generator>
diff --git a/src/CodeRepository/CodeRepository.php b/src/CodeRepository/CodeRepository.php
index d132f32..1ff2784 100644
--- a/src/CodeRepository/CodeRepository.php
+++ b/src/CodeRepository/CodeRepository.php
@@ -3,11 +3,12 @@
 
 namespace App\CodeRepository;
 
+use App\Configuration\Value\Source;
 use App\Value\Folder;
 
 interface CodeRepository
 {
     public const CODE_DOWNLOAD_PATH = 'var/repos/';
 
-    public function downloadCode(string $repoName): Folder;
+    public function getFolder(Source $source): Folder;
 }
diff --git a/src/CodeRepository/CodeRepositoryFactory.php b/src/CodeRepository/CodeRepositoryFactory.php
new file mode 100644
index 0000000..26f6ab9
--- /dev/null
+++ b/src/CodeRepository/CodeRepositoryFactory.php
@@ -0,0 +1,22 @@
+<?php
+declare(strict_types=1);
+
+namespace App\CodeRepository;
+
+use App\Configuration\Value\Source;
+use InvalidArgumentException;
+
+class CodeRepositoryFactory
+{
+    public function fromType(string $type): CodeRepository
+    {
+        switch ($type) {
+            case Source::TYPE_GIT:
+                return new GitCodeRepository();
+            case Source::TYPE_LOCAL:
+                return new LocalCodeRepository();
+            default:
+                throw new InvalidArgumentException('Invalid type: ' . $type);
+        }
+    }
+}
diff --git a/src/CodeRepository/GithubCodeRepository.php b/src/CodeRepository/GitCodeRepository.php
similarity index 60%
rename from src/CodeRepository/GithubCodeRepository.php
rename to src/CodeRepository/GitCodeRepository.php
index 3f16837..4cb4dbf 100644
--- a/src/CodeRepository/GithubCodeRepository.php
+++ b/src/CodeRepository/GitCodeRepository.php
@@ -3,20 +3,19 @@
 
 namespace App\CodeRepository;
 
+use App\Configuration\Value\Source;
 use App\Value\Folder;
 use Symfony\Component\Process\Exception\ProcessFailedException;
 use Symfony\Component\Process\Process;
 
-class GithubCodeRepository implements CodeRepository
+class GitCodeRepository implements CodeRepository
 {
-    public function downloadCode(string $repoName): Folder
+    public function getFolder(Source $source): Folder
     {
-        $repoPath = new Folder(self::CODE_DOWNLOAD_PATH . $repoName . '/');
+        $this->runProcess($this->getCloneOrPullProcess($source->getLocalFolder(), $source->getPath()));
+        $this->runProcess($this->getComposerInstallProcess($source->getLocalFolder()));
 
-        $this->runProcess($this->getCloneOrPullProcess($repoPath, $repoName));
-        $this->runProcess($this->getComposerInstallProcess($repoPath));
-
-        return $repoPath;
+        return $source->getLocalFolder();
     }
 
     private function runProcess(Process $process): void
@@ -28,21 +27,21 @@ private function runProcess(Process $process): void
         }
     }
 
-    private function getCloneOrPullProcess(Folder $repoPath, string $repoName): Process
+    private function getCloneOrPullProcess(Folder $localPath, string $sourcePath): Process
     {
-        if (!is_dir((string)$repoPath)) {
+        if (!is_dir((string)$localPath)) {
             return new Process([
                 'git',
                 'clone',
-                'git@github.com:' . $repoName,
-                $repoPath
+                $sourcePath,
+                (string)$localPath
             ]);
         }
 
         return new Process([
             'git',
             '-C',
-            $repoPath,
+            (string)$localPath,
             'pull'
         ]);
     }
diff --git a/src/CodeRepository/LocalCodeRepository.php b/src/CodeRepository/LocalCodeRepository.php
new file mode 100644
index 0000000..62594fa
--- /dev/null
+++ b/src/CodeRepository/LocalCodeRepository.php
@@ -0,0 +1,38 @@
+<?php
+declare(strict_types=1);
+
+namespace App\CodeRepository;
+
+use App\Configuration\Value\Source;
+use App\Value\Folder;
+use Symfony\Component\Process\Exception\ProcessFailedException;
+use Symfony\Component\Process\Process;
+
+class LocalCodeRepository implements CodeRepository
+{
+    public function getFolder(Source $source): Folder
+    {
+        $this->runProcess($this->getComposerInstallProcess($source->getLocalFolder()));
+
+        return $source->getLocalFolder();
+    }
+
+    private function runProcess(Process $process): void
+    {
+        $process->run();
+
+        if (!$process->isSuccessful()) {
+            throw new ProcessFailedException($process);
+        }
+    }
+
+    private function getComposerInstallProcess(Folder $repoPath): Process
+    {
+        return new Process([
+            'composer',
+            'install',
+            '-d',
+            $repoPath
+        ]);
+    }
+}
diff --git a/src/Configuration/ConfigurationRepository.php b/src/Configuration/ConfigurationRepository.php
new file mode 100644
index 0000000..959ff32
--- /dev/null
+++ b/src/Configuration/ConfigurationRepository.php
@@ -0,0 +1,11 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Configuration;
+
+use App\Configuration\Value\Configuration;
+
+interface ConfigurationRepository
+{
+    public function getConfig(): Configuration;
+}
diff --git a/src/Configuration/Value/Configuration.php b/src/Configuration/Value/Configuration.php
new file mode 100644
index 0000000..bddd2aa
--- /dev/null
+++ b/src/Configuration/Value/Configuration.php
@@ -0,0 +1,43 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Configuration\Value;
+
+use Assert\Assert;
+
+final class Configuration
+{
+    private string $format;
+    /**
+     * @var Source[]
+     */
+    private array $sources;
+
+    /**
+     * @param Source[] $sources
+     */
+    public function __construct(string $format, array $sources)
+    {
+        Assert::that($format)
+            ->inArray(['markdown'], sprintf('Invalid generator format "%s"', $format));
+
+        Assert::thatAll($sources)
+            ->isInstanceOf(Source::class);
+
+        $this->format = $format;
+        $this->sources = $sources;
+    }
+
+    public function getFormat(): string
+    {
+        return $this->format;
+    }
+
+    /**
+     * @return Source[]
+     */
+    public function getSources(): array
+    {
+        return $this->sources;
+    }
+}
diff --git a/src/Configuration/Value/Source.php b/src/Configuration/Value/Source.php
new file mode 100644
index 0000000..c7fa46b
--- /dev/null
+++ b/src/Configuration/Value/Source.php
@@ -0,0 +1,68 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Configuration\Value;
+
+use App\CodeRepository\CodeRepository;
+use App\Value\Folder;
+use function Stringy\create as s;
+
+final class Source
+{
+    public const TYPE_GIT = 'git';
+    public const TYPE_LOCAL = 'local';
+
+    private string $path;
+    /**
+     * @var Standard[]
+     */
+    private array $standards;
+    private Folder $localFolder;
+    private string $type = self::TYPE_LOCAL;
+
+    /**
+     * @param Standard[] $standards
+     */
+    public function __construct(string $path, array $standards)
+    {
+        $this->path = $path;
+        $this->standards = $standards;
+
+        if (preg_match('/([^.\/]+)\.git$/', $path, $matches)) {
+            $this->localFolder = $this->createLocalFolder(CodeRepository::CODE_DOWNLOAD_PATH . $matches[1]);
+            $this->type = self::TYPE_GIT;
+            return;
+        }
+
+        $this->localFolder = $this->createLocalFolder($path);
+    }
+
+    private function createLocalFolder(string $path): Folder
+    {
+        $path = s($path)->ensureRight('/');
+        return new Folder((string)$path);
+    }
+
+    public function getPath(): string
+    {
+        return $this->path;
+    }
+
+    public function getLocalFolder(): Folder
+    {
+        return $this->localFolder;
+    }
+
+    /**
+     * @return Standard[]
+     */
+    public function getStandards(): array
+    {
+        return $this->standards;
+    }
+
+    public function getType(): string
+    {
+        return $this->type;
+    }
+}
diff --git a/src/Configuration/Value/Standard.php b/src/Configuration/Value/Standard.php
new file mode 100644
index 0000000..af4c35d
--- /dev/null
+++ b/src/Configuration/Value/Standard.php
@@ -0,0 +1,24 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Configuration\Value;
+
+use Assert\Assert;
+
+final class Standard
+{
+    private string $path;
+
+    public function __construct(string $path)
+    {
+        Assert::that($path)
+            ->notBlank();
+
+        $this->path = $path;
+    }
+
+    public function getPath(): string
+    {
+        return $this->path;
+    }
+}
diff --git a/src/Configuration/XmlConfigurationRepository.php b/src/Configuration/XmlConfigurationRepository.php
new file mode 100644
index 0000000..7b52817
--- /dev/null
+++ b/src/Configuration/XmlConfigurationRepository.php
@@ -0,0 +1,82 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Configuration;
+
+use App\Configuration\Value\Configuration;
+use App\Configuration\Value\Source;
+use App\Configuration\Value\Standard;
+use App\Value\Folder;
+use DOMDocument;
+use RuntimeException;
+use SimpleXMLElement;
+
+class XmlConfigurationRepository implements ConfigurationRepository
+{
+    private Folder $root;
+
+    public function __construct(Folder $root)
+    {
+        $this->root = $root;
+    }
+
+    public function getConfig(): Configuration
+    {
+        $paths = [$this->root . 'generator.xml', $this->root . 'generator.xml.dist'];
+        foreach ($paths as $path) {
+            if (file_exists($path)) {
+                return $this->parse($path);
+            }
+        }
+
+        throw new RuntimeException(
+            sprintf('Could not find a configuration file in any of these paths: %s', implode(',', $paths))
+        );
+    }
+
+    private function parse(string $path): Configuration
+    {
+        $dom = new DOMDocument;
+        $dom->load($path);
+
+        set_error_handler(function (int $number, string $error) use ($path) {
+            throw new RuntimeException(
+                sprintf("The configuration file %s is invalid.\n%s", $path, $error)
+            );
+        });
+        $dom->schemaValidate(__DIR__ . '/generator.xsd');
+        restore_error_handler();
+
+        $xml = new SimpleXMLElement(file_get_contents($path));
+
+        return new Configuration(
+            (string)$xml['format'],
+            $this->getSources($xml),
+        );
+    }
+
+    /**
+     * @return Source[]
+     */
+    private function getSources(SimpleXMLElement $xml): array
+    {
+        return array_map(function (SimpleXMLElement $source): Source {
+            return new Source(
+                (string)$source['path'],
+                $this->getStandards($source)
+            );
+        }, $xml->xpath('source'));
+    }
+
+    /**
+     * @return Standard[]
+     */
+    private function getStandards(SimpleXMLElement $xml): array
+    {
+        return array_map(function (SimpleXMLElement $standard): Standard {
+            return new Standard(
+                (string)$standard['path']
+            );
+        }, $xml->xpath('standard'));
+    }
+}
diff --git a/src/Configuration/generator.xsd b/src/Configuration/generator.xsd
new file mode 100644
index 0000000..fe6c4af
--- /dev/null
+++ b/src/Configuration/generator.xsd
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+    <xs:element name="generator">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="source" maxOccurs="unbounded">
+                    <xs:complexType>
+                        <xs:sequence>
+                            <xs:element name="standard" maxOccurs="unbounded">
+                                <xs:complexType>
+                                    <xs:attribute name="path" type="xs:string" use="required"/>
+                                </xs:complexType>
+                            </xs:element>
+                        </xs:sequence>
+                        <xs:attribute name="path" type="xs:string" use="required"/>
+                    </xs:complexType>
+                </xs:element>
+            </xs:sequence>
+            <xs:attribute name="format" type="xs:string" use="required"/>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>
diff --git a/src/Generator/MarkdownGenerator.php b/src/Generator/MarkdownGenerator.php
index b329433..2baaa73 100644
--- a/src/Generator/MarkdownGenerator.php
+++ b/src/Generator/MarkdownGenerator.php
@@ -27,8 +27,8 @@ public function createSniffDoc(Sniff $sniff): string
         {$this->getViolations($sniff->getViolations())}
         MD;
 
-        $sniffDoc = preg_replace('/\n{3,}/', "\n\n",$sniffDoc);
-        return preg_replace('/\n{2,}$/', "\n",$sniffDoc);
+        $sniffDoc = preg_replace('/\n{3,}/', "\n\n", $sniffDoc);
+        return preg_replace('/\n{2,}$/', "\n", $sniffDoc);
     }
 
     private function getDescription(Sniff $sniff): string
diff --git a/src/Handler/GenerateHandler.php b/src/Handler/GenerateHandler.php
index 8ebedf8..2aa7e83 100644
--- a/src/Handler/GenerateHandler.php
+++ b/src/Handler/GenerateHandler.php
@@ -3,7 +3,8 @@
 
 namespace App\Handler;
 
-use App\CodeRepository\CodeRepository;
+use App\CodeRepository\CodeRepositoryFactory;
+use App\Configuration\ConfigurationRepository;
 use App\Generator\Generator;
 use App\SniffFinder\SniffFinder;
 use App\Value\Folder;
@@ -11,15 +12,22 @@
 
 class GenerateHandler
 {
-    private CodeRepository $codeRepository;
+    private CodeRepositoryFactory $codeRepositoryFactory;
     private Generator $generator;
     private SniffFinder $sniffFinder;
+    private ConfigurationRepository $configRepo;
 
-    public function __construct(CodeRepository $codeRepository, Generator $generator, SniffFinder $sniffFinder)
+    public function __construct(
+        CodeRepositoryFactory $codeRepositoryFactory,
+        Generator $generator,
+        SniffFinder $sniffFinder,
+        ConfigurationRepository $configRepo
+    )
     {
-        $this->codeRepository = $codeRepository;
+        $this->codeRepositoryFactory = $codeRepositoryFactory;
         $this->generator = $generator;
         $this->sniffFinder = $sniffFinder;
+        $this->configRepo = $configRepo;
     }
 
     /**
@@ -27,27 +35,32 @@ public function __construct(CodeRepository $codeRepository, Generator $generator
      */
     public function handle(string $sniffPath = null): iterable
     {
-        $repoName = 'PHPCompatibility/PHPCompatibility';
-        $repoPath = $this->codeRepository->downloadCode($repoName);
+        $config = $this->configRepo->getConfig();
         $filesystem = new Filesystem();
 
-        $standardPath = new Folder($repoPath . 'PHPCompatibility/');
-        yield "Searching for sniffs...";
+        foreach ($config->getSources() as $source) {
+            $codeRepository = $this->codeRepositoryFactory->fromType($source->getType());
+            $sourceFolder = $codeRepository->getFolder($source);
+            foreach ($source->getStandards() as $standard) {
+                $standardFolder = new Folder($sourceFolder . $standard->getPath() . '/');
+                yield "Searching for sniffs in {$standardFolder}...";
 
-        if ($sniffPath !== null) {
-            $sniffs = [$this->sniffFinder->getSniff($standardPath, $sniffPath)];
-        } else {
-            $sniffs = $this->sniffFinder->getSniffs($standardPath);
-        }
+                if ($sniffPath !== null) {
+                    $sniffs = [$this->sniffFinder->getSniff($standardFolder, $sourceFolder, $sniffPath)];
+                } else {
+                    $sniffs = $this->sniffFinder->getSniffs($standardFolder, $sourceFolder);
+                }
 
-        foreach ($sniffs as $sniff) {
-            $markdownPath = $this->sniffCodeToMarkdownPath($sniff->getCode());
-            $filesystem->dumpFile(
-            // TODO: perhaps we can move this logic to the the sniff class
-                $markdownPath,
-                $this->generator->createSniffDoc($sniff)
-            );
-            yield "Created file: {$markdownPath}";
+                foreach ($sniffs as $sniff) {
+                    $markdownPath = $this->sniffCodeToMarkdownPath($sniff->getCode());
+                    $filesystem->dumpFile(
+                    // TODO: perhaps we can move this logic to the the sniff class
+                        $markdownPath,
+                        $this->generator->createSniffDoc($sniff)
+                    );
+                    yield "Created file: {$markdownPath}";
+                }
+            }
         }
     }
 
diff --git a/src/Parser/SniffParser.php b/src/Parser/SniffParser.php
index d8e4565..11973b6 100644
--- a/src/Parser/SniffParser.php
+++ b/src/Parser/SniffParser.php
@@ -206,7 +206,8 @@ private function getUrls(ReflectionClass $classInfo, array $xmlUrls): UrlList
             ->getTagsByName('link');
 
         $urls = array_map(function (string $url) {
-            return new Url($url);
+            preg_match('/(http[^ ]+)/', $url, $matches);
+            return new Url($matches[0]);
         }, $links);
 
         return new UrlList(array_merge($urls, $xmlUrls));
diff --git a/src/SniffFinder/FilesystemSniffFinder.php b/src/SniffFinder/FilesystemSniffFinder.php
index 58f744f..ee4bddf 100644
--- a/src/SniffFinder/FilesystemSniffFinder.php
+++ b/src/SniffFinder/FilesystemSniffFinder.php
@@ -18,21 +18,18 @@
 
 class FilesystemSniffFinder implements SniffFinder
 {
-    public function getSniff(Folder $folder, string $sniffPath): Sniff
+    public function getSniff(Folder $standardFolder, Folder $sourceFolder, string $sniffPath): Sniff
     {
         $parser = new SniffParser();
-        $projectSourceLocator = $this->createProjectSourceLocator($folder);
+        $projectSourceLocator = $this->createProjectSourceLocator($sourceFolder);
         return $parser->parse($sniffPath, $projectSourceLocator);
     }
 
-    public function getSniffs(Folder $folder): iterable
+    private function createProjectSourceLocator(Folder $folder): SourceLocator
     {
-        $parser = new SniffParser();
-        $globSniffs = new GlobIterator($folder->getPath() . 'Sniffs/*/*Sniff.php');
-        $projectSourceLocator = $this->createProjectSourceLocator($folder);
-        foreach ($globSniffs as $fileInfo) {
-            yield $parser->parse($fileInfo->getPathname(), $projectSourceLocator);
-        }
+        $astLocator = (new BetterReflection())->astLocator();
+        $fileInfoIterator = $this->recursiveSearch($folder);
+        return new FileIteratorSourceLocator($fileInfoIterator, $astLocator);
     }
 
     /**
@@ -47,10 +44,13 @@ private function recursiveSearch(Folder $folder): Iterator
         });
     }
 
-    private function createProjectSourceLocator(Folder $folder): SourceLocator
+    public function getSniffs(Folder $standardFolder, Folder $sourceFolder): iterable
     {
-        $astLocator = (new BetterReflection())->astLocator();
-        $fileInfoIterator = $this->recursiveSearch($folder);
-        return new FileIteratorSourceLocator($fileInfoIterator, $astLocator);
+        $parser = new SniffParser();
+        $globSniffs = new GlobIterator($standardFolder->getPath() . 'Sniffs/*/*Sniff.php');
+        $projectSourceLocator = $this->createProjectSourceLocator($sourceFolder);
+        foreach ($globSniffs as $fileInfo) {
+            yield $parser->parse($fileInfo->getPathname(), $projectSourceLocator);
+        }
     }
 }
diff --git a/src/SniffFinder/SniffFinder.php b/src/SniffFinder/SniffFinder.php
index c512125..e19088b 100644
--- a/src/SniffFinder/SniffFinder.php
+++ b/src/SniffFinder/SniffFinder.php
@@ -8,10 +8,10 @@
 
 interface SniffFinder
 {
-    public function getSniff(Folder $folder, string $sniffPath): Sniff;
+    public function getSniff(Folder $standardFolder, Folder $sourceFolder, string $sniffPath): Sniff;
 
     /**
      * @return iterable<Sniff>
      */
-    public function getSniffs(Folder $folder): iterable;
+    public function getSniffs(Folder $standardFolder, Folder $sourceFolder): iterable;
 }
diff --git a/src/Value/Diff.php b/src/Value/Diff.php
index 03e1f53..b991ae9 100644
--- a/src/Value/Diff.php
+++ b/src/Value/Diff.php
@@ -5,7 +5,7 @@
 
 use Assert\Assert;
 
-class Diff
+final class Diff
 {
     private string $before;
     private string $after;
diff --git a/src/Value/Folder.php b/src/Value/Folder.php
index 76fdb84..e14fd2d 100644
--- a/src/Value/Folder.php
+++ b/src/Value/Folder.php
@@ -5,7 +5,7 @@
 
 use Assert\Assert;
 
-class Folder
+final class Folder
 {
     private string $path;
 
@@ -17,7 +17,7 @@ public function __construct(string $path)
         $this->path = $path;
     }
 
-    public function __toString()
+    public function __toString(): string
     {
         return $this->getPath();
     }
diff --git a/src/Value/Property.php b/src/Value/Property.php
index 80856dc..1c017c4 100644
--- a/src/Value/Property.php
+++ b/src/Value/Property.php
@@ -5,7 +5,7 @@
 
 use Assert\Assert;
 
-class Property
+final class Property
 {
     private string $name;
     private string $type;
diff --git a/src/Value/Sniff.php b/src/Value/Sniff.php
index deb666d..c277762 100644
--- a/src/Value/Sniff.php
+++ b/src/Value/Sniff.php
@@ -5,7 +5,7 @@
 
 use Assert\Assert;
 
-class Sniff
+final class Sniff
 {
     private string $code;
     private string $docblock;
diff --git a/src/Value/Url.php b/src/Value/Url.php
index 92ed716..bbe8ebb 100644
--- a/src/Value/Url.php
+++ b/src/Value/Url.php
@@ -5,19 +5,19 @@
 
 use Assert\Assert;
 
-class Url
+final class Url
 {
     private string $url;
 
     public function __construct(string $url)
     {
         Assert::that($url)
-            ->url();
+            ->url('Not a valid URL: ' . $url);
 
         $this->url = $url;
     }
 
-    public function __toString()
+    public function __toString(): string
     {
         return $this->getUrl();
     }
diff --git a/src/Value/UrlList.php b/src/Value/UrlList.php
index c852847..1fbd5e2 100644
--- a/src/Value/UrlList.php
+++ b/src/Value/UrlList.php
@@ -6,7 +6,7 @@
 /**
  * Collection of unique URLs.
  */
-class UrlList
+final class UrlList
 {
     /**
      * @var Url[]
diff --git a/src/Value/Violation.php b/src/Value/Violation.php
index 91ca7e5..29e4912 100644
--- a/src/Value/Violation.php
+++ b/src/Value/Violation.php
@@ -5,7 +5,7 @@
 
 use Assert\Assert;
 
-class Violation
+final class Violation
 {
     private string $code;
     private string $description;
diff --git a/tests/CodeRepository/CodeRepositoryFactoryTest.php b/tests/CodeRepository/CodeRepositoryFactoryTest.php
new file mode 100644
index 0000000..932af42
--- /dev/null
+++ b/tests/CodeRepository/CodeRepositoryFactoryTest.php
@@ -0,0 +1,40 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Tests\CodeRepository;
+
+use App\CodeRepository\CodeRepositoryFactory;
+use App\CodeRepository\GitCodeRepository;
+use App\CodeRepository\LocalCodeRepository;
+use App\Configuration\Value\Source;
+use InvalidArgumentException;
+use PHPUnit\Framework\TestCase;
+
+/** @covers \App\CodeRepository\CodeRepositoryFactory */
+class CodeRepositoryFactoryTest extends TestCase
+{
+    /** @test */
+    public function fromType_WithInvalid_ThrowException()
+    {
+        $this->expectException(InvalidArgumentException::class);
+        (new CodeRepositoryFactory)->fromType('INVALID');
+    }
+
+    /** @test */
+    public function fromType_WithGit_ReturnGitImplementation()
+    {
+        self::assertInstanceOf(
+            GitCodeRepository::class,
+            (new CodeRepositoryFactory)->fromType(Source::TYPE_GIT)
+        );
+    }
+
+    /** @test */
+    public function fromType_WithLocal_ReturnLocalImplementation()
+    {
+        self::assertInstanceOf(
+            LocalCodeRepository::class,
+            (new CodeRepositoryFactory)->fromType(Source::TYPE_LOCAL)
+        );
+    }
+}
diff --git a/tests/CodeRepository/GitCodeRepositoryTest.php b/tests/CodeRepository/GitCodeRepositoryTest.php
new file mode 100644
index 0000000..4798400
--- /dev/null
+++ b/tests/CodeRepository/GitCodeRepositoryTest.php
@@ -0,0 +1,62 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Tests\CodeRepository;
+
+use App\CodeRepository\GitCodeRepository;
+use App\Configuration\Value\Source;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Filesystem\Filesystem;
+use Symfony\Component\Process\Exception\RuntimeException;
+
+/** @covers \App\CodeRepository\GitCodeRepository */
+class GitCodeRepositoryTest extends TestCase
+{
+    private const LOCAL_GIT_PATH = 'var/tests/repo/Standard.git';
+    private GitCodeRepository $codeRepo;
+
+    /** @test */
+    public function getFolder_WithMissingPath_ThrowException()
+    {
+        $this->expectException(RuntimeException::class);
+        $sourcePath = 'var/repos/MISSING.git';
+        $this->codeRepo->getFolder(new Source($sourcePath, []));
+    }
+
+    /** @test */
+    public function getFolder_WithGitPath_InstallComposer()
+    {
+        $this->createGitRepo();
+        (new Filesystem())->remove('var/repos/Standard'); // force fresh clone
+
+        $this->codeRepo->getFolder(new Source(self::LOCAL_GIT_PATH, []));
+        self::assertFileExists('var/repos/Standard/composer.lock');
+    }
+
+    private function createGitRepo(): void
+    {
+        $fs = new Filesystem;
+        $gitPath = self::LOCAL_GIT_PATH;
+        $fs->mkdir($gitPath);
+        $fs->dumpFile($gitPath . '/composer.json', '{}');
+        if (getenv('IS_CI_TEST')) {
+            `git config --global user.email "you@example.com"`;
+            `git config --global user.name "Your Name"`;
+        }
+        `cd {$gitPath} && git init && git add composer.json && git commit -m "Init"`;
+    }
+
+    /** @test */
+    public function getFolder_WithExistingGitClone_InstallComposer()
+    {
+        $this->createGitRepo();
+
+        $this->codeRepo->getFolder(new Source(self::LOCAL_GIT_PATH, []));
+        self::assertFileExists('var/repos/Standard/composer.lock');
+    }
+
+    protected function setUp(): void
+    {
+        $this->codeRepo = new GitCodeRepository();
+    }
+}
diff --git a/tests/CodeRepository/LocalCodeRepositoryTest.php b/tests/CodeRepository/LocalCodeRepositoryTest.php
new file mode 100644
index 0000000..6071176
--- /dev/null
+++ b/tests/CodeRepository/LocalCodeRepositoryTest.php
@@ -0,0 +1,43 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Tests\CodeRepository;
+
+use App\CodeRepository\LocalCodeRepository;
+use App\Configuration\Value\Source;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Filesystem\Filesystem;
+use Symfony\Component\Process\Exception\RuntimeException;
+
+/** @covers \App\CodeRepository\LocalCodeRepository */
+class LocalCodeRepositoryTest extends TestCase
+{
+    private const LOCAL_PATH = 'var/repos/Standard';
+    private LocalCodeRepository $codeRepo;
+
+    /** @test */
+    public function getFolder_WithMissingPath_ThrowException()
+    {
+        $this->expectException(RuntimeException::class);
+        $sourcePath = 'var/repos/MISSING';
+        $this->codeRepo->getFolder(new Source($sourcePath, []));
+    }
+
+    /** @test */
+    public function getFolder_WithExistingPath_InstallComposer()
+    {
+        $fs = new Filesystem;
+        $sourcePath = self::LOCAL_PATH;
+        $fs->remove($sourcePath);
+        $fs->mkdir($sourcePath);
+        $fs->dumpFile($sourcePath . '/composer.json', '{}');
+
+        $this->codeRepo->getFolder(new Source($sourcePath, []));
+        self::assertFileExists('var/repos/Standard/composer.lock');
+    }
+
+    protected function setUp(): void
+    {
+        $this->codeRepo = new LocalCodeRepository();
+    }
+}
diff --git a/tests/Configuration/Value/ConfigurationTest.php b/tests/Configuration/Value/ConfigurationTest.php
new file mode 100644
index 0000000..bb8b7b1
--- /dev/null
+++ b/tests/Configuration/Value/ConfigurationTest.php
@@ -0,0 +1,51 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Tests\Configuration\Value;
+
+use App\Configuration\Value\Configuration;
+use App\Configuration\Value\Source;
+use PHPUnit\Framework\TestCase;
+
+/** @covers \App\Configuration\Value\Configuration */
+class ConfigurationTest extends TestCase
+{
+    private const FORMAT = 'markdown';
+    /**
+     * @var Source[]
+     */
+    private static array $SOURCES;
+
+    public static function setUpBeforeClass(): void
+    {
+        self::$SOURCES = [
+            new Source('path/to/source', [])
+        ];
+    }
+
+    /** @test */
+    public function getSources()
+    {
+        self::assertEquals(
+            self::$SOURCES,
+            $this->createValidVO()->getSources(),
+        );
+    }
+
+    private function createValidVO(): Configuration
+    {
+        return new Configuration(
+            self::FORMAT,
+            self::$SOURCES
+        );
+    }
+
+    /** @test */
+    public function getFormat()
+    {
+        self::assertEquals(
+            self::FORMAT,
+            $this->createValidVO()->getFormat(),
+        );
+    }
+}
diff --git a/tests/Configuration/Value/SourceTest.php b/tests/Configuration/Value/SourceTest.php
new file mode 100644
index 0000000..e35bd13
--- /dev/null
+++ b/tests/Configuration/Value/SourceTest.php
@@ -0,0 +1,56 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Tests\Configuration\Value;
+
+use App\Configuration\Value\Source;
+use App\Configuration\Value\Standard;
+use App\Value\Folder;
+use PHPUnit\Framework\TestCase;
+
+/** @covers \App\Configuration\Value\Source */
+class SourceTest extends TestCase
+{
+    private const SOURCE_PATH = 'path/to/source';
+    private const STANDARD_PATH = 'path/to/standard';
+
+    /** @test */
+    public function getStandards()
+    {
+        self::assertEquals(
+            [
+                new Standard(self::STANDARD_PATH)
+            ],
+            (new Source(self::SOURCE_PATH, [
+                new Standard(self::STANDARD_PATH)
+            ]))->getStandards()
+        );
+    }
+
+    /** @test */
+    public function getLocalFolder_WithGit_PrependDownloadPath()
+    {
+        self::assertEquals(
+            new Folder('var/repos/repo/'),
+            (new Source('path/to/repo.git', []))->getLocalFolder()
+        );
+    }
+
+    /** @test */
+    public function getType_WithGit_ReturnGit()
+    {
+        self::assertEquals(
+            Source::TYPE_GIT,
+            (new Source('path/to/repo.git', []))->getType()
+        );
+    }
+
+    /** @test */
+    public function getPath()
+    {
+        self::assertEquals(
+            self::SOURCE_PATH,
+            (new Source(self::SOURCE_PATH, []))->getPath()
+        );
+    }
+}
diff --git a/tests/Configuration/Value/StandardTest.php b/tests/Configuration/Value/StandardTest.php
new file mode 100644
index 0000000..23e3bb9
--- /dev/null
+++ b/tests/Configuration/Value/StandardTest.php
@@ -0,0 +1,30 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Tests\Configuration\Value;
+
+use App\Configuration\Value\Standard;
+use InvalidArgumentException;
+use PHPUnit\Framework\TestCase;
+
+/** @covers \App\Configuration\Value\Standard */
+class StandardTest extends TestCase
+{
+    private const STANDARD_PATH = 'path/to/standard';
+
+    /** @test */
+    public function construct_WithBlankPath_ThrowException()
+    {
+        $this->expectException(InvalidArgumentException::class);
+        new Standard('');
+    }
+
+    /** @test */
+    public function getPath()
+    {
+        self::assertEquals(
+            self::STANDARD_PATH,
+            (new Standard(self::STANDARD_PATH))->getPath()
+        );
+    }
+}
diff --git a/tests/Configuration/XmlConfigurationRepositoryTest.php b/tests/Configuration/XmlConfigurationRepositoryTest.php
new file mode 100644
index 0000000..a452182
--- /dev/null
+++ b/tests/Configuration/XmlConfigurationRepositoryTest.php
@@ -0,0 +1,106 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Tests\Configuration;
+
+use App\Configuration\Value\Configuration;
+use App\Configuration\Value\Source;
+use App\Configuration\Value\Standard;
+use App\Configuration\XmlConfigurationRepository;
+use App\Value\Folder;
+use PHPUnit\Framework\TestCase;
+use RuntimeException;
+use Symfony\Component\Filesystem\Filesystem;
+
+/** @covers \App\Configuration\XmlConfigurationRepository */
+class XmlConfigurationRepositoryTest extends TestCase
+{
+    const XML_FILE_PATH = 'var/tests/generator.xml';
+    const XML_DIST_FILE_PATH = 'var/tests/generator.xml.dist';
+    private XmlConfigurationRepository $repo;
+
+    /** @test */
+    public function getConfig_WithMissingFile_ThrowException()
+    {
+        $this->expectException(RuntimeException::class);
+        $this->repo->getConfig();
+    }
+
+    /** @test */
+    public function getConfig_WithInvalidSchema_ThrowException()
+    {
+        $this->expectException(RuntimeException::class);
+
+        $xmlContent =
+            '<?xml version="1.0" encoding="UTF-8"?>
+        <generator>
+        </generator>';
+
+        (new Filesystem)->dumpFile(self::XML_FILE_PATH, $xmlContent);
+
+        $this->repo->getConfig();
+    }
+
+    /** @test */
+    public function getConfig_WithBothFiles_PickNonDist()
+    {
+        $xmlContent =
+            '<?xml version="1.0" encoding="UTF-8"?>
+        <generator format="markdown">
+            <source path="../">
+                <standard path="Xml" />
+            </source>
+        </generator>';
+
+        (new Filesystem)->dumpFile(self::XML_FILE_PATH, $xmlContent);
+
+        $xmlDistContent =
+            '<generator format="markdown">
+            <source path="../">
+                <standard path="Dist" />
+            </source>
+        </generator>';
+
+        (new Filesystem)->dumpFile(self::XML_DIST_FILE_PATH, $xmlDistContent);
+
+        $config = $this->repo->getConfig();
+        self::assertEquals(
+            'Xml',
+            $config->getSources()[0]->getStandards()[0]->getPath()
+        );
+    }
+
+    /** @test */
+    public function getConfig_WithValidFile_ReturnConfiguration()
+    {
+        $xmlContent =
+            '<?xml version="1.0" encoding="UTF-8"?>
+        <generator format="markdown">
+            <source path="path/to/code">
+                <standard path="Standard" />
+            </source>
+        </generator>';
+
+        (new Filesystem)->dumpFile(self::XML_FILE_PATH, $xmlContent);
+
+        self::assertEquals(
+            new Configuration(
+                'markdown',
+                [
+                    new Source('path/to/code', [
+                        new Standard('Standard')
+                    ]),
+                ]
+            ),
+            $this->repo->getConfig()
+        );
+    }
+
+    protected function setUp(): void
+    {
+        $fs = new Filesystem;
+        $fs->remove(self::XML_DIST_FILE_PATH);
+        $fs->remove(self::XML_FILE_PATH);
+        $this->repo = new XmlConfigurationRepository(new Folder('var/tests/'));
+    }
+}
diff --git a/tests/Handler/GenerateHandlerTest.php b/tests/Handler/GenerateHandlerTest.php
index eb92c2a..9f46cb8 100644
--- a/tests/Handler/GenerateHandlerTest.php
+++ b/tests/Handler/GenerateHandlerTest.php
@@ -4,6 +4,11 @@
 namespace App\Tests\Handler;
 
 use App\CodeRepository\CodeRepository;
+use App\CodeRepository\CodeRepositoryFactory;
+use App\Configuration\ConfigurationRepository;
+use App\Configuration\Value\Configuration;
+use App\Configuration\Value\Source;
+use App\Configuration\Value\Standard;
 use App\Generator\Generator;
 use App\Handler\GenerateHandler;
 use App\SniffFinder\SniffFinder;
@@ -23,9 +28,9 @@ class GenerateHandlerTest extends TestCase
      */
     private GenerateHandler $handler;
     /**
-     * @var CodeRepository|MockObject
+     * @var CodeRepositoryFactory|MockObject
      */
-    private $codeRepository;
+    private $codeRepositoryFactory;
     /**
      * @var Generator|MockObject
      */
@@ -34,11 +39,18 @@ class GenerateHandlerTest extends TestCase
      * @var SniffFinder|MockObject
      */
     private $sniffFinder;
+    /**
+     * @var ConfigurationRepository|MockObject
+     */
+    private $configRepo;
 
     /** @test */
     public function handle_WithoutArguments_CreatesFile()
     {
-        $this->codeRepository->method('downloadCode')->willReturn(new Folder('var/tests/'));
+        $codeRepository = $this->createMock(CodeRepository::class);
+        $codeRepository->method('getFolder')->willReturn(new Folder('var/tests/'));
+        $this->codeRepositoryFactory->method('fromType')->willReturn($codeRepository);
+
         $sniffs = $this->createSniffs(['First', 'Second']);
         $this->sniffFinder->method('getSniffs')->willReturn($sniffs);
         $this->generator->method('createSniffDoc')->withConsecutive([$sniffs[0]], [$sniffs[1]]);
@@ -48,7 +60,7 @@ public function handle_WithoutArguments_CreatesFile()
 
         self::assertEquals(
             [
-                'Searching for sniffs...',
+                'Searching for sniffs in var/tests/Standard/...',
                 'Created file: var/markdown/Standard/Category/First.md',
                 'Created file: var/markdown/Standard/Category/Second.md'
             ],
@@ -89,7 +101,9 @@ private function createSniff(string $name): Sniff
     /** @test */
     public function handle_WithSniffPath_CreatesSingleFile()
     {
-        $this->codeRepository->method('downloadCode')->willReturn(new Folder('var/tests/'));
+        $codeRepository = $this->createMock(CodeRepository::class);
+        $codeRepository->method('getFolder')->willReturn(new Folder('var/tests/'));
+        $this->codeRepositoryFactory->method('fromType')->willReturn($codeRepository);
         $this->sniffFinder->method('getSniff')->willReturn($this->createSniff('First'));
 
         /** @var \Generator $messages */
@@ -97,7 +111,7 @@ public function handle_WithSniffPath_CreatesSingleFile()
 
         self::assertEquals(
             [
-                'Searching for sniffs...',
+                'Searching for sniffs in var/tests/Standard/...',
                 'Created file: var/markdown/Standard/Category/First.md',
             ],
             iterator_to_array($messages)
@@ -108,14 +122,25 @@ protected function setUp(): void
     {
         (new Filesystem())->remove('var/markdown/Standard');
 
-        $this->codeRepository = $this->createMock(CodeRepository::class);
+        $this->codeRepositoryFactory = $this->createMock(CodeRepositoryFactory::class);
         $this->generator = $this->createMock(Generator::class);
         $this->sniffFinder = $this->createMock(SniffFinder::class);
+        $this->configRepo = $this->createMock(ConfigurationRepository::class);
+
+        $this->configRepo->method('getConfig')->willReturn(new Configuration(
+            'markdown',
+            [
+                new Source('../Standard', [
+                    new Standard('Standard')
+                ])
+            ]
+        ));
 
         $this->handler = new GenerateHandler(
-            $this->codeRepository,
+            $this->codeRepositoryFactory,
             $this->generator,
-            $this->sniffFinder
+            $this->sniffFinder,
+            $this->configRepo
         );
     }
 }
diff --git a/tests/SniffFinder/FilesystemSniffFinderTest.php b/tests/SniffFinder/FilesystemSniffFinderTest.php
index e161aff..457f88d 100644
--- a/tests/SniffFinder/FilesystemSniffFinderTest.php
+++ b/tests/SniffFinder/FilesystemSniffFinderTest.php
@@ -32,6 +32,9 @@ public function getSniffs()
         $sniffs = $this->finder->getSniffs(
             new Folder(
                 'var/tests/src/Standard/'
+            ),
+            new Folder(
+                'var/tests/'
             )
         );
         self::assertEquals(
@@ -114,6 +117,9 @@ public function getSniff()
                 new Folder(
                     'var/tests/src/Standard/'
                 ),
+                new Folder(
+                    'var/tests/'
+                ),
                 self::PHP_SNIFF_PATH
             )
         );
diff --git a/var/repos/.gitkeep b/var/repos/.gitkeep
deleted file mode 100644
index e69de29..0000000