diff --git a/.phive/.gitignore b/.phive/.gitignore
new file mode 100644
index 0000000..71d2e19
--- /dev/null
+++ b/.phive/.gitignore
@@ -0,0 +1,3 @@
+*
+!.gitignore
+!phars.xml
diff --git a/.phive/phars.xml b/.phive/phars.xml
new file mode 100644
index 0000000..13cfd4e
--- /dev/null
+++ b/.phive/phars.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phive xmlns="https://phar.io/phive">
+  <phar name="composer-normalize" version="^2.42.0" installed="2.42.0" location="./.phive/composer-normalize" copy="false"/>
+  <phar name="composer-require-checker" version="^4.10.0" installed="4.10.0" location="./.phive/composer-require-checker" copy="false"/>
+  <phar name="box-project/box" version="^4.6.1" installed="4.6.1" location="./.phive/box" copy="false"/>
+</phive>
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
new file mode 100644
index 0000000..54e8b20
--- /dev/null
+++ b/psalm-baseline.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<files psalm-version="5.25.0@01a8eb06b9e9cc6cfb6a320bf9fb14331919d505">
+  <file src="src/Command/Get.php">
+    <MixedArgument>
+      <code><![CDATA[$binary]]></code>
+    </MixedArgument>
+    <MixedAssignment>
+      <code><![CDATA[$binary]]></code>
+    </MixedAssignment>
+    <MixedOperand>
+      <code><![CDATA[$input->getArgument('binary')]]></code>
+      <code><![CDATA[$input->getOption('path')]]></code>
+    </MixedOperand>
+    <PropertyNotSetInConstructor>
+      <code><![CDATA[$container]]></code>
+      <code><![CDATA[$logger]]></code>
+    </PropertyNotSetInConstructor>
+  </file>
+  <file src="src/DLoad.php">
+    <ArgumentTypeCoercion>
+      <code><![CDATA[$conf->pattern]]></code>
+    </ArgumentTypeCoercion>
+  </file>
+  <file src="src/Module/Archive/ArchiveFactory.php">
+    <MixedPropertyTypeCoercion>
+      <code><![CDATA[$this->matchers]]></code>
+    </MixedPropertyTypeCoercion>
+    <PropertyTypeCoercion>
+      <code><![CDATA[\array_unique(\array_merge($this->extensions, $extensions))]]></code>
+    </PropertyTypeCoercion>
+  </file>
+  <file src="src/Module/Archive/Internal/PharAwareArchive.php">
+    <MoreSpecificReturnType>
+      <code><![CDATA[\Generator]]></code>
+    </MoreSpecificReturnType>
+  </file>
+  <file src="src/Module/Common/Config/Embed/Repository.php">
+    <MissingConstructor>
+      <code><![CDATA[$uri]]></code>
+    </MissingConstructor>
+  </file>
+  <file src="src/Module/Common/Config/Embed/Software.php">
+    <MissingConstructor>
+      <code><![CDATA[$name]]></code>
+    </MissingConstructor>
+  </file>
+  <file src="src/Module/Common/Internal/Container.php">
+    <MixedPropertyTypeCoercion>
+      <code><![CDATA[$this->factory]]></code>
+    </MixedPropertyTypeCoercion>
+    <UndefinedMethod>
+      <code><![CDATA[$id::create(...)]]></code>
+    </UndefinedMethod>
+  </file>
+  <file src="src/Module/Common/Internal/Injection/ConfigLoader.php">
+    <MixedMethodCall>
+      <code><![CDATA[new $attribute->class()]]></code>
+    </MixedMethodCall>
+    <RedundantCondition>
+      <code><![CDATA[\assert($xml instanceof \SimpleXMLElement)]]></code>
+    </RedundantCondition>
+  </file>
+  <file src="src/Module/Common/OperatingSystem.php">
+    <DocblockTypeContradiction>
+      <code><![CDATA['bSD' => self::BSD]]></code>
+    </DocblockTypeContradiction>
+  </file>
+  <file src="src/Module/Downloader/Downloader.php">
+    <ArgumentTypeCoercion>
+      <code><![CDATA[$context->repoConfig->assetPattern]]></code>
+    </ArgumentTypeCoercion>
+    <InternalMethod>
+      <code><![CDATA[toArray]]></code>
+      <code><![CDATA[toArray]]></code>
+    </InternalMethod>
+    <InvalidNullableReturnType>
+      <code><![CDATA[AssetInterface]]></code>
+      <code><![CDATA[ReleaseInterface]]></code>
+    </InvalidNullableReturnType>
+    <MissingClosureReturnType>
+      <code><![CDATA[static fn(int $dlNow, int $dlSize, array $info) => ($context->onProgress)(]]></code>
+    </MissingClosureReturnType>
+    <TooManyArguments>
+      <code><![CDATA[download]]></code>
+    </TooManyArguments>
+  </file>
+  <file src="src/Module/Downloader/Internal/DownloadContext.php">
+    <PropertyNotSetInConstructor>
+      <code><![CDATA[$asset]]></code>
+      <code><![CDATA[$file]]></code>
+      <code><![CDATA[$release]]></code>
+      <code><![CDATA[$repoConfig]]></code>
+    </PropertyNotSetInConstructor>
+  </file>
+  <file src="src/Module/Repository/Collection/ReleasesCollection.php">
+    <LessSpecificReturnStatement>
+      <code><![CDATA[\ltrim(\str_replace(
+            '-' . $stability->value,
+            '.' . $stability->getWeight() . '.',
+            $release->getVersion(),
+        ), 'v')]]></code>
+    </LessSpecificReturnStatement>
+    <MoreSpecificReturnType>
+      <code><![CDATA[non-empty-string]]></code>
+    </MoreSpecificReturnType>
+  </file>
+  <file src="src/Module/Repository/Internal/Collection.php">
+    <MixedArgument>
+      <code><![CDATA[$generator()]]></code>
+    </MixedArgument>
+    <UnsafeGenericInstantiation>
+      <code><![CDATA[new static($items)]]></code>
+      <code><![CDATA[new static(\array_filter($this->items, $callback))]]></code>
+      <code><![CDATA[new static(\array_filter($this->items, $filter))]]></code>
+      <code><![CDATA[new static(\array_map($map, $this->items))]]></code>
+      <code><![CDATA[new static(\iterator_to_array($items))]]></code>
+    </UnsafeGenericInstantiation>
+  </file>
+  <file src="src/Module/Repository/Internal/GitHub/Factory.php">
+    <ArgumentTypeCoercion>
+      <code><![CDATA[$org]]></code>
+      <code><![CDATA[$repo]]></code>
+    </ArgumentTypeCoercion>
+    <InternalClass>
+      <code><![CDATA[new GitHubRepository($org, $repo, $this->createClient())]]></code>
+    </InternalClass>
+    <InternalMethod>
+      <code><![CDATA[new GitHubRepository($org, $repo, $this->createClient())]]></code>
+    </InternalMethod>
+    <PossiblyUndefinedArrayOffset>
+      <code><![CDATA[$org]]></code>
+    </PossiblyUndefinedArrayOffset>
+    <RiskyTruthyFalsyComparison>
+      <code><![CDATA[$this->config->token]]></code>
+    </RiskyTruthyFalsyComparison>
+  </file>
+  <file src="src/Module/Repository/Internal/GitHub/GitHubAsset.php">
+    <InternalClass>
+      <code><![CDATA[new self($client, $release, $data['name'], $data['browser_download_url'])]]></code>
+    </InternalClass>
+    <InternalMethod>
+      <code><![CDATA[new self($client, $release, $data['name'], $data['browser_download_url'])]]></code>
+    </InternalMethod>
+    <LessSpecificImplementedReturnType>
+      <code><![CDATA[\Traversable]]></code>
+    </LessSpecificImplementedReturnType>
+  </file>
+  <file src="src/Module/Repository/Internal/GitHub/GitHubRelease.php">
+    <ArgumentTypeCoercion>
+      <code><![CDATA[$name]]></code>
+    </ArgumentTypeCoercion>
+    <InternalClass>
+      <code><![CDATA[GitHubAsset::fromApiResponse($client, $result, $item)]]></code>
+      <code><![CDATA[new self($client, $repository, $name, $version)]]></code>
+      <code><![CDATA[self::getTagName($data)]]></code>
+    </InternalClass>
+    <InternalMethod>
+      <code><![CDATA[GitHubAsset::fromApiResponse($client, $result, $item)]]></code>
+      <code><![CDATA[new self($client, $repository, $name, $version)]]></code>
+      <code><![CDATA[self::getTagName($data)]]></code>
+    </InternalMethod>
+    <InvalidArgument>
+      <code><![CDATA[$data]]></code>
+    </InvalidArgument>
+    <InvalidArrayOffset>
+      <code><![CDATA[$data['tag_name']]]></code>
+    </InvalidArrayOffset>
+    <LessSpecificReturnStatement>
+      <code><![CDATA[$this->client->request('GET', $config)->getContent()]]></code>
+    </LessSpecificReturnStatement>
+    <MixedArgument>
+      <code><![CDATA[$version]]></code>
+    </MixedArgument>
+    <MixedAssignment>
+      <code><![CDATA[$version]]></code>
+    </MixedAssignment>
+    <MoreSpecificReturnType>
+      <code><![CDATA[non-empty-string]]></code>
+    </MoreSpecificReturnType>
+    <RedundantCondition>
+      <code><![CDATA[$this->assets === null]]></code>
+    </RedundantCondition>
+    <TypeDoesNotContainNull>
+      <code><![CDATA[$this->assets === null]]></code>
+    </TypeDoesNotContainNull>
+  </file>
+  <file src="src/Module/Repository/Internal/GitHub/GitHubRepository.php">
+    <InternalClass>
+      <code><![CDATA[GitHubRelease::fromApiResponse($this, $this->client, $data)]]></code>
+      <code><![CDATA[self::URL_RELEASES]]></code>
+    </InternalClass>
+    <InternalMethod>
+      <code><![CDATA[GitHubRelease::fromApiResponse($this, $this->client, $data)]]></code>
+      <code><![CDATA[getName]]></code>
+      <code><![CDATA[hasNextPage]]></code>
+      <code><![CDATA[releasesRequest]]></code>
+      <code><![CDATA[request]]></code>
+      <code><![CDATA[uri]]></code>
+    </InternalMethod>
+    <InternalProperty>
+      <code><![CDATA[$this->client]]></code>
+      <code><![CDATA[$this->name]]></code>
+      <code><![CDATA[$this->releases]]></code>
+    </InternalProperty>
+    <LessSpecificImplementedReturnType>
+      <code><![CDATA[string]]></code>
+    </LessSpecificImplementedReturnType>
+    <LessSpecificReturnStatement>
+      <code><![CDATA[\sprintf($pattern, $this->getName())]]></code>
+    </LessSpecificReturnStatement>
+    <MoreSpecificReturnType>
+      <code><![CDATA[non-empty-string]]></code>
+    </MoreSpecificReturnType>
+  </file>
+  <file src="src/Module/Repository/Internal/Release.php">
+    <InvalidNullableReturnType>
+      <code><![CDATA[Stability]]></code>
+    </InvalidNullableReturnType>
+    <LessSpecificReturnStatement>
+      <code><![CDATA[isset($parts[1])
+            ? $number . '-' . $parts[1]
+            : $number]]></code>
+    </LessSpecificReturnStatement>
+    <MoreSpecificReturnType>
+      <code><![CDATA[non-empty-string]]></code>
+    </MoreSpecificReturnType>
+    <NullableReturnStatement>
+      <code><![CDATA[Stability::tryFrom(VersionParser::parseStability($version))]]></code>
+    </NullableReturnStatement>
+  </file>
+  <file src="src/Module/Repository/RepositoryProvider.php">
+    <ArgumentTypeCoercion>
+      <code><![CDATA[$config->uri]]></code>
+    </ArgumentTypeCoercion>
+  </file>
+  <file src="src/Service/Factoriable.php">
+    <InvalidDocblock>
+      <code><![CDATA[Factoriable]]></code>
+    </InvalidDocblock>
+  </file>
+  <file src="src/Service/Logger.php">
+    <ArgumentTypeCoercion>
+      <code><![CDATA[$values]]></code>
+      <code><![CDATA[$values]]></code>
+      <code><![CDATA[$values]]></code>
+      <code><![CDATA[$values]]></code>
+    </ArgumentTypeCoercion>
+  </file>
+</files>
diff --git a/src/Module/Archive/ArchiveFactory.php b/src/Module/Archive/ArchiveFactory.php
index e53f3d6..d645b2c 100644
--- a/src/Module/Archive/ArchiveFactory.php
+++ b/src/Module/Archive/ArchiveFactory.php
@@ -14,6 +14,9 @@
  */
 final class ArchiveFactory
 {
+    /** @var list<non-empty-string> */
+    private array $extensions = [];
+
     /**
      * @var array<ArchiveMatcher>
      */
@@ -27,9 +30,13 @@ public function __construct()
         $this->bootDefaultMatchers();
     }
 
-    public function extend(\Closure $matcher): void
+    /**
+     * @param list<non-empty-string> $extensions List of supported extensions
+     */
+    public function extend(\Closure $matcher, array $extensions = []): void
     {
         \array_unshift($this->matchers, $matcher);
+        $this->extensions = \array_unique(\array_merge($this->extensions, $extensions));
     }
 
     public function create(\SplFileInfo $file): Archive
@@ -52,22 +59,30 @@ public function create(\SplFileInfo $file): Archive
         throw new \InvalidArgumentException($error);
     }
 
+    /**
+     * @return list<non-empty-string>
+     */
+    public function getSupportedExtensions(): array
+    {
+        return $this->extensions;
+    }
+
     private function bootDefaultMatchers(): void
     {
         $this->extend($this->matcher(
             'zip',
             static fn(\SplFileInfo $info): Archive => new ZipPharArchive($info),
-        ));
+        ), ['zip']);
 
         $this->extend($this->matcher(
             'tar.gz',
             static fn(\SplFileInfo $info): Archive => new TarPharArchive($info),
-        ));
+        ), ['tar.gz']);
 
         $this->extend($this->matcher(
             'phar',
             static fn(\SplFileInfo $info): Archive => new PharArchive($info),
-        ));
+        ), ['phar']);
     }
 
     /**
diff --git a/src/Module/Downloader/Downloader.php b/src/Module/Downloader/Downloader.php
index 23c3e06..c5e37b4 100644
--- a/src/Module/Downloader/Downloader.php
+++ b/src/Module/Downloader/Downloader.php
@@ -4,6 +4,7 @@
 
 namespace Internal\DLoad\Module\Downloader;
 
+use Internal\DLoad\Module\Archive\ArchiveFactory;
 use Internal\DLoad\Module\Common\Architecture;
 use Internal\DLoad\Module\Common\Config\DownloaderConfig;
 use Internal\DLoad\Module\Common\Config\Embed\Software;
@@ -32,6 +33,7 @@ public function __construct(
         private readonly Architecture $architecture,
         private readonly OperatingSystem $operatingSystem,
         private readonly Stability $stability,
+        private readonly ArchiveFactory $archiveService,
     ) {}
 
     /**
@@ -123,6 +125,7 @@ private function processRelease(DownloadContext $context): \Closure
                 ->whereArchitecture($this->architecture)
                 ->whereOperatingSystem($this->operatingSystem)
                 ->whereNameMatches($context->repoConfig->assetPattern)
+                ->whereFileExtensions($this->archiveService->getSupportedExtensions())
                 ->toArray();
 
             $this->logger->debug('%d assets found.', \count($assets));
diff --git a/src/Module/Repository/Internal/AssetsCollection.php b/src/Module/Repository/Collection/AssetsCollection.php
similarity index 70%
rename from src/Module/Repository/Internal/AssetsCollection.php
rename to src/Module/Repository/Collection/AssetsCollection.php
index 92c10af..eebaf82 100644
--- a/src/Module/Repository/Internal/AssetsCollection.php
+++ b/src/Module/Repository/Collection/AssetsCollection.php
@@ -2,16 +2,17 @@
 
 declare(strict_types=1);
 
-namespace Internal\DLoad\Module\Repository\Internal;
+namespace Internal\DLoad\Module\Repository\Collection;
 
 use Internal\DLoad\Module\Common\Architecture;
 use Internal\DLoad\Module\Common\OperatingSystem;
 use Internal\DLoad\Module\Repository\AssetInterface;
+use Internal\DLoad\Module\Repository\Internal\Collection;
 
 /**
  * @template-extends Collection<AssetInterface>
  * @internal
- * @psalm-internal Internal\DLoad\Module\Repository
+ * @psalm-internal Internal\DLoad\Module
  */
 final class AssetsCollection extends Collection
 {
@@ -37,6 +38,20 @@ public function whereOperatingSystem(OperatingSystem $os): self
         );
     }
 
+    /**
+     * @param list<non-empty-string> $extensions
+     */
+    public function whereFileExtensions(array $extensions): self
+    {
+        return $this->filter(
+            static fn(AssetInterface $asset): bool => \in_array(
+                \pathinfo($asset->getName(), \PATHINFO_EXTENSION),
+                $extensions,
+                true,
+            ),
+        );
+    }
+
     /**
      * Select all the assets with names that match the given pattern.
      *
diff --git a/src/Module/Repository/Internal/ReleasesCollection.php b/src/Module/Repository/Collection/ReleasesCollection.php
similarity index 93%
rename from src/Module/Repository/Internal/ReleasesCollection.php
rename to src/Module/Repository/Collection/ReleasesCollection.php
index 2e399c1..c5814a8 100644
--- a/src/Module/Repository/Internal/ReleasesCollection.php
+++ b/src/Module/Repository/Collection/ReleasesCollection.php
@@ -2,21 +2,21 @@
 
 declare(strict_types=1);
 
-namespace Internal\DLoad\Module\Repository\Internal;
+namespace Internal\DLoad\Module\Repository\Collection;
 
 use Internal\DLoad\Module\Common\Stability;
+use Internal\DLoad\Module\Repository\Internal\Collection;
 use Internal\DLoad\Module\Repository\ReleaseInterface;
 
 /**
  * @template-extends Collection<ReleaseInterface>
- * @psalm-import-type StabilityType from Stability
  * @internal
- * @psalm-internal Internal\DLoad\Module\Repository
+ * @psalm-internal Internal\DLoad\Module
  */
 final class ReleasesCollection extends Collection
 {
     /**
-     * @param string ...$constraints
+     * @param non-empty-string ...$constraints
      * @return $this
      */
     public function satisfies(string ...$constraints): self
diff --git a/src/Module/Repository/Internal/RepositoriesCollection.php b/src/Module/Repository/Collection/RepositoriesCollection.php
similarity index 88%
rename from src/Module/Repository/Internal/RepositoriesCollection.php
rename to src/Module/Repository/Collection/RepositoriesCollection.php
index 602bc40..2bb5c91 100644
--- a/src/Module/Repository/Internal/RepositoriesCollection.php
+++ b/src/Module/Repository/Collection/RepositoriesCollection.php
@@ -2,13 +2,13 @@
 
 declare(strict_types=1);
 
-namespace Internal\DLoad\Module\Repository\Internal;
+namespace Internal\DLoad\Module\Repository\Collection;
 
 use Internal\DLoad\Module\Repository\RepositoryInterface;
 
 /**
  * @internal
- * @psalm-internal Internal\DLoad\Module\Repository
+ * @psalm-internal Internal\DLoad\Module
  */
 class RepositoriesCollection implements RepositoryInterface
 {
diff --git a/src/Module/Repository/Internal/GitHub/GitHubRelease.php b/src/Module/Repository/Internal/GitHub/GitHubRelease.php
index adbf73c..833b5fa 100644
--- a/src/Module/Repository/Internal/GitHub/GitHubRelease.php
+++ b/src/Module/Repository/Internal/GitHub/GitHubRelease.php
@@ -5,7 +5,7 @@
 namespace Internal\DLoad\Module\Repository\Internal\GitHub;
 
 use Composer\Semver\VersionParser;
-use Internal\DLoad\Module\Repository\Internal\AssetsCollection;
+use Internal\DLoad\Module\Repository\Collection\AssetsCollection;
 use Internal\DLoad\Module\Repository\Internal\Release;
 use Internal\DLoad\Service\Destroyable;
 use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
diff --git a/src/Module/Repository/Internal/GitHub/GitHubRepository.php b/src/Module/Repository/Internal/GitHub/GitHubRepository.php
index b66236c..98e296d 100644
--- a/src/Module/Repository/Internal/GitHub/GitHubRepository.php
+++ b/src/Module/Repository/Internal/GitHub/GitHubRepository.php
@@ -4,7 +4,7 @@
 
 namespace Internal\DLoad\Module\Repository\Internal\GitHub;
 
-use Internal\DLoad\Module\Repository\Internal\ReleasesCollection;
+use Internal\DLoad\Module\Repository\Collection\ReleasesCollection;
 use Internal\DLoad\Module\Repository\RepositoryInterface;
 use Internal\DLoad\Service\Destroyable;
 use Symfony\Component\HttpClient\HttpClient;
diff --git a/src/Module/Repository/Internal/Release.php b/src/Module/Repository/Internal/Release.php
index d4f95ad..854cfa0 100644
--- a/src/Module/Repository/Internal/Release.php
+++ b/src/Module/Repository/Internal/Release.php
@@ -4,8 +4,10 @@
 
 namespace Internal\DLoad\Module\Repository\Internal;
 
+use Composer\Semver\Semver;
 use Composer\Semver\VersionParser;
 use Internal\DLoad\Module\Common\Stability;
+use Internal\DLoad\Module\Repository\Collection\AssetsCollection;
 use Internal\DLoad\Module\Repository\ReleaseInterface;
 use Internal\DLoad\Module\Repository\RepositoryInterface;
 
@@ -68,6 +70,11 @@ public function getAssets(): AssetsCollection
         return $this->assets;
     }
 
+    public function satisfies(string $constraint): bool
+    {
+        return Semver::satisfies($this->getName(), $constraint);
+    }
+
     /**
      * @param non-empty-string $version
      */
diff --git a/src/Module/Repository/ReleaseInterface.php b/src/Module/Repository/ReleaseInterface.php
index 2fc31ca..1c29fe8 100644
--- a/src/Module/Repository/ReleaseInterface.php
+++ b/src/Module/Repository/ReleaseInterface.php
@@ -5,7 +5,7 @@
 namespace Internal\DLoad\Module\Repository;
 
 use Internal\DLoad\Module\Common\Stability;
-use Internal\DLoad\Module\Repository\Internal\AssetsCollection;
+use Internal\DLoad\Module\Repository\Collection\AssetsCollection;
 
 interface ReleaseInterface
 {
@@ -30,4 +30,6 @@ public function getVersion(): string;
     public function getStability(): Stability;
 
     public function getAssets(): AssetsCollection;
+
+    public function satisfies(string $constraint): bool;
 }
diff --git a/src/Module/Repository/RepositoryInterface.php b/src/Module/Repository/RepositoryInterface.php
index 00ebc2e..7dc0a98 100644
--- a/src/Module/Repository/RepositoryInterface.php
+++ b/src/Module/Repository/RepositoryInterface.php
@@ -4,7 +4,7 @@
 
 namespace Internal\DLoad\Module\Repository;
 
-use Internal\DLoad\Module\Repository\Internal\ReleasesCollection;
+use Internal\DLoad\Module\Repository\Collection\ReleasesCollection;
 
 interface RepositoryInterface
 {