diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2026 Simon Hengel <sol@typeful.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/driver/Main.hs b/driver/Main.hs
new file mode 100644
--- /dev/null
+++ b/driver/Main.hs
@@ -0,0 +1,9 @@
+module Main (main) where
+
+import Prelude
+import System.Environment
+
+import qualified Run
+
+main :: IO ()
+main = getArgs >>= Run.main
diff --git a/ghc-bench.cabal b/ghc-bench.cabal
new file mode 100644
--- /dev/null
+++ b/ghc-bench.cabal
@@ -0,0 +1,101 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.39.1.
+--
+-- see: https://github.com/sol/hpack
+
+name:           ghc-bench
+version:        0.1.0
+synopsis:       Benchmark a Haskell development system
+description:    See README at <https://github.com/sol/ghc-bench#readme>
+category:       Development
+homepage:       https://github.com/sol/ghc-bench#readme
+bug-reports:    https://github.com/sol/ghc-bench/issues
+author:         Simon Hengel <sol@typeful.net>
+maintainer:     Simon Hengel <sol@typeful.net>
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+
+source-repository head
+  type: git
+  location: https://github.com/sol/ghc-bench
+
+executable ghc-bench
+  main-is: Main.hs
+  other-modules:
+      Asset
+      Command
+      Imports
+      Result
+      Run
+      SystemInfo
+  hs-source-dirs:
+      src
+      driver
+  default-extensions:
+      NoImplicitPrelude
+      OverloadedStrings
+      RecordWildCards
+      ViewPatterns
+      BlockArguments
+      LambdaCase
+      NoFieldSelectors
+      DuplicateRecordFields
+      OverloadedRecordDot
+  ghc-options: -Wall
+  build-depends:
+      base ==4.*
+    , bytestring
+    , directory
+    , filepath
+    , http-types
+    , process
+    , temporary
+    , text
+  default-language: GHC2024
+
+test-suite spec
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Asset
+      Command
+      Imports
+      Result
+      Run
+      SystemInfo
+      CommandSpec
+      Fixtures.System
+      Helper
+      ResultSpec
+      SystemInfoSpec
+  hs-source-dirs:
+      src
+      test
+  default-extensions:
+      NoImplicitPrelude
+      OverloadedStrings
+      RecordWildCards
+      ViewPatterns
+      BlockArguments
+      LambdaCase
+      NoFieldSelectors
+      DuplicateRecordFields
+      OverloadedRecordDot
+  ghc-options: -Wall
+  cpp-options: -DTEST
+  build-tool-depends:
+      hspec-discover:hspec-discover
+  build-depends:
+      base ==4.*
+    , bytestring
+    , directory
+    , filepath
+    , hspec ==2.*
+    , http-types
+    , process
+    , silently
+    , temporary
+    , text
+  default-language: GHC2024
diff --git a/src/Asset.hs b/src/Asset.hs
new file mode 100644
--- /dev/null
+++ b/src/Asset.hs
@@ -0,0 +1,36 @@
+module Asset (
+  download
+, Asset(..)
+) where
+
+import Imports
+
+import System.Directory (doesFileExist, renameFile)
+
+import Command (curl, sha256sum)
+
+data Asset = Asset {
+  url :: FilePath
+, path :: FilePath
+, hash :: Text
+} deriving (Eq, Show)
+
+download :: Asset -> IO ()
+download asset = do
+  ensure asset.url asset.path
+  verify asset.path asset.hash
+
+ensure :: FilePath -> FilePath -> IO ()
+ensure url path = unless -< doesFileExist path $ do
+  let tmp = path <> ".tmp"
+  curl ["-L", url, "-o", tmp]
+  renameFile tmp path
+
+verify :: FilePath -> Text -> IO ()
+verify path expected = do
+  actual <- sha256sum path
+  when (actual /= expected) . error $ unlines [
+      "SHA256 mismatch!"
+    , "Expected: " <> expected
+    , "Actual:   " <> actual
+    ]
diff --git a/src/Command.hs b/src/Command.hs
new file mode 100644
--- /dev/null
+++ b/src/Command.hs
@@ -0,0 +1,90 @@
+module Command (
+  requireAll
+, require
+, resolve
+
+, eval
+, sh
+
+, awk
+, uname
+, free
+, lscpu
+, sha256sum
+, nproc
+
+, curl
+, tar
+) where
+
+import Imports hiding (strip)
+
+import Data.Char (isSpace)
+import Data.Text qualified as T
+
+import System.Process (readProcessWithExitCode, rawSystem, callProcess)
+import System.Process qualified as Process
+
+eval :: String -> IO Text
+eval command = run "bash" ["-c", command]
+
+sh :: FilePath -> String -> IO ()
+sh dir command = rawSystem "bash" ["-c", "cd " <> dir <> " && " <> command] >>= \ case
+  ExitSuccess -> pass
+  ExitFailure _ -> error $ "Running `" <> pack command <> "` failed!"
+
+awk :: Text -> Text -> IO Text
+awk command = readProcess "awk" [unpack command]
+
+uname :: [String] -> IO Text
+uname args = run "uname" args <&> T.strip
+
+free :: [String] -> IO Text
+free = run "free"
+
+lscpu :: [String] -> IO Text
+lscpu = run "lscpu"
+
+sha256sum :: String -> IO Text
+sha256sum file = T.take 64 <$> run "sha256sum" [file]
+
+nproc :: IO Int
+nproc = read <$> Process.readProcess "nproc" [] ""
+
+curl :: [String] -> IO ()
+curl = callProcess "curl"
+
+tar :: [String] -> IO ()
+tar = callProcess "tar"
+
+requireAll :: IO ()
+requireAll = do
+  require "bash"
+  require "awk"
+  require "uname"
+  require "free"
+  require "lscpu"
+  require "sha256sum"
+  require "nproc"
+  require "curl"
+  require "tar"
+
+require :: String -> IO ()
+require = void . resolve
+
+resolve :: FilePath -> IO FilePath
+resolve name = readProcessWithExitCode "which" [name] "" >>= \ case
+  (ExitFailure _, _, _) -> error message
+  (ExitSuccess, path, _) -> return $ strip path
+  where
+    message :: Text
+    message = mconcat ["`", pack name, "` is required, but couldn't be found on the search PATH."]
+
+    strip :: String -> String
+    strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace
+
+run :: String -> [String] -> IO Text
+run command args = readProcess command args ""
+
+readProcess :: FilePath -> [FilePath] -> Text -> IO Text
+readProcess name args input = pack <$> Process.readProcess name args (unpack input)
diff --git a/src/Imports.hs b/src/Imports.hs
new file mode 100644
--- /dev/null
+++ b/src/Imports.hs
@@ -0,0 +1,45 @@
+module Imports (module Imports) where
+
+import Prelude as Imports hiding (show, lines, unlines, words, unwords, error, putStrLn)
+
+import Data.Maybe as Imports
+
+import Data.Functor as Imports (void, (<&>))
+import Control.Arrow as Imports ((>>>))
+import Control.Monad as Imports (when, unless)
+
+import Data.Text as Imports (Text, show, lines, unlines, words, unwords, pack, unpack, strip)
+import Data.Text.Encoding as Imports (encodeUtf8)
+
+import System.Exit as Imports (ExitCode(..))
+import System.FilePath as Imports ((</>))
+
+import System.Exit (die)
+import System.Directory (removePathForcibly)
+import System.IO.Temp (createTempDirectory)
+import Control.Exception (bracket)
+
+withTempDirectory :: FilePath -> FilePath -> (FilePath -> IO a) -> IO a
+withTempDirectory dir name = bracket (createTempDirectory dir name) removePathForcibly
+
+error :: Text -> IO a
+error message = die $ "ghc-bench: " <> unpack message
+
+class Bind m r where
+  bind :: (a -> r) -> m a -> r
+
+instance Monad m => Bind m (m b) where
+  bind :: (a -> m b) -> m a -> m b
+  bind = (=<<)
+
+instance Bind m r => Bind m (b -> r) where
+  bind :: (a -> b -> r) -> m a -> b -> r
+  bind f ma b = bind (flip f b) ma
+
+infixl 1 -<
+
+(-<) :: Bind m r => (a -> r) -> m a -> r
+(-<) = bind
+
+pass :: Applicative m => m ()
+pass = pure ()
diff --git a/src/Result.hs b/src/Result.hs
new file mode 100644
--- /dev/null
+++ b/src/Result.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE CPP #-}
+module Result (
+  submit
+, Result(..)
+#ifdef TEST
+, issueTitle
+#endif
+) where
+
+import Imports
+
+import Data.Text qualified as T
+import Data.ByteString.Char8 (ByteString, putStrLn)
+import Network.HTTP.Types.URI (renderSimpleQuery)
+
+import SystemInfo
+
+base :: ByteString
+base = "https://github.com/sol/ghc-bench/issues/new"
+
+data Result = Result {
+  time :: Int
+, concurrency :: Int
+} deriving (Eq, Show)
+
+submit :: Result -> SystemInfo -> IO ()
+submit result system = do
+  putStrLn "Open this URL to submit your result:"
+  putStrLn $ issueUrl result system
+
+issueUrl :: Result -> SystemInfo -> ByteString
+issueUrl result system = base <> renderQuery [
+    ("template", "benchmark-result.yml")
+  , ("title", issueTitle result.time system)
+
+  , ("time", show result.time)
+  , ("concurrency", show result.concurrency)
+
+  , ("os", system.os)
+  , ("arch", system.arch)
+
+  , ("system_vendor", system.vendor)
+
+  , ("product_category", system.product.category)
+  , ("product_chassis_type", system.product.chassis_type)
+  , ("product_family", system.product.family)
+  , ("product_name", system.product.name)
+  , ("product_version", system.product.version)
+
+  , ("board", unwords [system.board.vendor, system.board.name])
+
+  , ("cpu_name", system.cpu.name)
+  , ("cpu_cores", show system.cpu.cores)
+  , ("cpu_threads", show system.cpu.threads)
+
+  , ("cpuid", cpuid)
+
+  , ("ram", system.ram)
+  ]
+  where
+    cpuid :: Text
+    cpuid = T.intercalate " / " [
+        fromMaybe "unknown" system.cpu.vendor
+      , fromMaybe "unknown" system.cpu.family
+      , fromMaybe "unknown" system.cpu.model
+      , fromMaybe "unknown" system.cpu.stepping
+      ]
+
+issueTitle :: Int -> SystemInfo -> Text
+issueTitle seconds system = unwords ["[result]", show seconds <> "s", "-", description, "-", cpu]
+  where
+    description :: Text
+    description = unwords case (system.vendor, system.product.name) of
+      ("LENOVO", _) -> [system.vendor, system.product.version]
+      (unknown -> True, _) -> [system.product.category, "computer"]
+      (vendor, unknown -> True) -> [vendor, system.product.category]
+      (vendor, name) -> [vendor, name]
+
+    unknown :: Text -> Bool
+    unknown = (== "To Be Filled By O.E.M.")
+
+    cpu :: Text
+    cpu = case system.cpu.vendor of
+      Just "GenuineIntel" -> case T.breakOn " @ " system.cpu.name of
+        (name, _) -> T.replace "(TM)" "" $ T.replace "(R)" "" name
+      _ -> system.cpu.name
+
+renderQuery :: [(ByteString, Text)] -> ByteString
+renderQuery = renderSimpleQuery True . map (fmap encodeUtf8)
diff --git a/src/Run.hs b/src/Run.hs
new file mode 100644
--- /dev/null
+++ b/src/Run.hs
@@ -0,0 +1,80 @@
+module Run (main) where
+
+import Imports
+import Prelude qualified
+
+import Data.Text.IO (putStrLn)
+
+import GHC.Clock (getMonotonicTimeNSec)
+import System.Directory (createDirectoryIfMissing)
+import System.Environment.Blank (setEnv)
+import System.Exit (die)
+
+import Command (tar, nproc, sh)
+import Command qualified
+
+import SystemInfo qualified
+
+import Asset (Asset(..))
+import Asset qualified
+
+import Result (Result(..))
+import Result qualified
+
+version :: FilePath
+version = "9.12.4"
+
+bootGhc :: FilePath
+bootGhc = "ghc-" <> version
+
+baseDir :: FilePath
+baseDir = "/tmp/ghc-bench"
+
+sourceTarball :: Asset
+sourceTarball = Asset {
+    url = "https://downloads.haskell.org/~ghc/" <> version <> "/ghc-" <> version <> "-src.tar.gz"
+  , path = baseDir </> "ghc-" <> version <> "-src.tar.gz"
+  , hash = "df71d96169056d3a6d7ec17498864cbdd5511bda196440dc38a692133833dfa4"
+  }
+
+main :: [String] -> IO ()
+main args = do
+  Command.requireAll
+  Command.require "cabal"
+  ghc <- Command.resolve bootGhc
+  createDirectoryIfMissing False baseDir
+  info <- SystemInfo.collect
+  result <- case args of
+    [] -> run ghc sourceTarball
+    ["info"] -> return Result {time = 0, concurrency = 0}
+    _ -> die "usage: ghc-bench [info]"
+  putStrLn $ "Build time: " <> show result.time <> "s"
+  putStrLn ""
+  Result.submit result info
+
+run :: FilePath -> Asset -> IO Result
+run ghc source = withTempDirectory baseDir "run" \ sandbox -> do
+  Asset.download source
+  tar ["-xf", source.path, "-C", sandbox]
+  build (sandbox </> "ghc-" <> version) ghc
+
+build :: FilePath -> FilePath -> IO Result
+build dir ghc = do
+  setEnv "GHC" ghc True
+  sh dir "./configure"
+
+  -- this makes sure that building hadrian dependencies is not measured
+  sh dir "hadrian/build --help"
+
+  concurrency <- nproc
+  time <- measure do
+    sh dir $ "hadrian/build -j" <> Prelude.show concurrency <> " --flavour=quickest"
+  return Result{..}
+
+measure :: IO () -> IO Int
+measure action = do
+  start <- getMonotonicTimeNSec
+  action
+  end <- getMonotonicTimeNSec
+  let dtSeconds = fromIntegral (end - start) / 1e9 :: Double
+  pure (round dtSeconds)
diff --git a/src/SystemInfo.hs b/src/SystemInfo.hs
new file mode 100644
--- /dev/null
+++ b/src/SystemInfo.hs
@@ -0,0 +1,127 @@
+module SystemInfo (
+  collect
+, SystemInfo(..)
+, Product(..)
+, Board(..)
+, Cpu(..)
+) where
+
+import Imports hiding (product)
+
+import Data.List (nub)
+import Control.Exception
+
+import Data.Text qualified as T
+import Data.Text.IO.Utf8 qualified as Utf8
+
+import Command (eval, uname, lscpu, free, awk)
+
+data SystemInfo = SystemInfo {
+  os :: Text
+, arch :: Text
+, vendor :: Text
+, product :: Product
+, board :: Board
+, cpu :: Cpu
+, ram :: Text
+} deriving (Eq, Show)
+
+collect :: IO SystemInfo
+collect = do
+  os <- eval ". /etc/os-release && echo $NAME || uname" <&> strip
+  arch <- uname ["--machine"]
+  vendor <- fromFile "/sys/class/dmi/id/sys_vendor"
+  product <- getProductInfo
+  board <- getBoardInfo
+  cpu <- getCpuInfo
+  ram <- free ["-b"] >>= awk "/Mem:/ {print $2}" <&> strip
+  return SystemInfo {..}
+
+data Product = Product {
+  category :: Text
+, chassis_type :: Text
+, family :: Text
+, name :: Text
+, version :: Text
+} deriving (Eq, Show)
+
+getProductInfo :: IO Product
+getProductInfo = do
+  chassis_type <- fromFile "/sys/class/dmi/id/chassis_type"
+  family <- fromFile "/sys/class/dmi/id/product_family"
+  name <- fromFile "/sys/class/dmi/id/product_name"
+  version <- fromFile "/sys/class/dmi/id/product_version"
+  return Product {
+      category = interpretChassisType chassis_type
+    , ..
+    }
+
+interpretChassisType :: Text -> Text
+interpretChassisType = \ case
+  "3" -> "desktop"
+  "4" -> "desktop"
+  "8" -> "laptop"
+  "9" -> "laptop"
+  "10" -> "laptop"
+  "14" -> "laptop"
+  _ -> "unknown"
+
+data Board = Board {
+  vendor :: Text
+, name :: Text
+} deriving (Eq, Show)
+
+getBoardInfo :: IO Board
+getBoardInfo = do
+  vendor <- fromFile "/sys/class/dmi/id/board_vendor"
+  name <- fromFile "/sys/class/dmi/id/board_name"
+  return Board {..}
+
+data Cpu = Cpu {
+  name :: Text
+, cores :: Int
+, threads :: Int
+, vendor :: Maybe Text
+, family :: Maybe Text
+, model :: Maybe Text
+, stepping :: Maybe Text
+} deriving (Eq, Show)
+
+getCpuInfo :: IO Cpu
+getCpuInfo = do
+  threads <- lscpu ["-p=SOCKET,CORE,CPU,MODELNAME"] <&> parse
+  let
+    cpus  = nub [(socket, name) | (socket, _, _, name) <- threads]
+    cores = nub [(socket, core) | (socket, core, _, _) <- threads]
+  fields <- lscpu [] <&> parseFields
+  return Cpu {
+      name = T.intercalate " / " $ map snd cpus
+    , cores = length cores
+    , threads = length threads
+    , vendor = lookup "Vendor ID" fields
+    , family = lookup "CPU family" fields
+    , model = lookup "Model" fields
+    , stepping = lookup "Stepping" fields
+    }
+  where
+    parse :: Text -> [(Text, Text, Text, Text)]
+    parse = mapMaybe parseLine . removeComments . lines
+
+    parseLine :: Text -> Maybe (Text, Text, Text, Text)
+    parseLine = T.splitOn "," >>> \ case
+      socket : core : thread : name -> Just (socket, core, thread, T.intercalate "," name)
+      _ -> Nothing
+
+    removeComments :: [Text] -> [Text]
+    removeComments = filter (not . T.isPrefixOf "#")
+
+    parseFields :: Text -> [(Text, Text)]
+    parseFields = map parseField . lines
+
+    parseField :: Text -> (Text, Text)
+    parseField = fmap (strip . T.drop 1) . T.breakOn ": "
+
+fromFile :: FilePath -> IO Text
+fromFile p = try @IOException (Utf8.readFile p) <&> \ case
+  Left _ -> "unknown"
+  Right c -> strip c
diff --git a/test/CommandSpec.hs b/test/CommandSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/CommandSpec.hs
@@ -0,0 +1,22 @@
+module CommandSpec (spec) where
+
+import Helper
+
+import System.IO
+import System.IO.Silently
+import Control.Exception
+
+import Command
+
+spec :: Spec
+spec = do
+  describe "resolve" do
+    it "returns the absolute path to an executable" do
+      resolve "cp" `shouldReturn` "/usr/bin/cp"
+
+    context "when executable does not exist" do
+      it "terminates" do
+        hCapture [stderr] (try $ resolve "d3b07384") `shouldReturn` (
+            "ghc-bench: `d3b07384` is required, but couldn't be found on the search PATH.\n"
+          , Left $ ExitFailure 1
+          )
diff --git a/test/Fixtures/System.hs b/test/Fixtures/System.hs
new file mode 100644
--- /dev/null
+++ b/test/Fixtures/System.hs
@@ -0,0 +1,61 @@
+module Fixtures.System where
+
+import Imports
+
+import SystemInfo
+
+i10900K_desktop :: SystemInfo
+i10900K_desktop = SystemInfo {
+    os = "Arch Linux"
+  , arch = "x86_64"
+  , vendor = "To Be Filled By O.E.M."
+  , product = Product {
+      category = "desktop"
+    , chassis_type = "3"
+    , family = "To Be Filled By O.E.M."
+    , name = "To Be Filled By O.E.M."
+    , version = "To Be Filled By O.E.M."
+    }
+  , board = Board {
+      vendor = "ASRock"
+    , name = "Z490M-ITX/ac"
+    }
+  , cpu = Cpu {
+      name = "Intel(R) Core(TM) i9-10900K CPU @ 3.70GHz"
+    , cores = 10
+    , threads = 20
+    , vendor = Just "GenuineIntel"
+    , family = Just "6"
+    , model = Just "165"
+    , stepping = Just "5"
+    }
+  , ram = "33273524224"
+  }
+
+t60_ThinkPad :: SystemInfo
+t60_ThinkPad = SystemInfo {
+    os = "Arch Linux"
+  , arch = "x86_64"
+  , vendor = "LENOVO"
+  , product = Product {
+      category = "laptop"
+    , chassis_type = "10"
+    , family = "ThinkPad T60"
+    , name = "1952W5R"
+    , version = "ThinkPad T60"
+    }
+  , board = Board {
+      vendor = "LENOVO"
+    , name = "1952W5R"
+    }
+  , cpu = Cpu {
+      name = "Intel(R) Core(TM) 2 Duo Processor T7200 @ 2.00GHz"
+    , cores = 2
+    , threads = 2
+    , vendor = Just "GenuineIntel"
+    , family = Just "6"
+    , model = Just "15"
+    , stepping = Just "6"
+    }
+  , ram = "0"
+  }
diff --git a/test/Helper.hs b/test/Helper.hs
new file mode 100644
--- /dev/null
+++ b/test/Helper.hs
@@ -0,0 +1,5 @@
+module Helper (module Imports) where
+
+import Imports
+import Test.Hspec as Imports
+import Run ()
diff --git a/test/ResultSpec.hs b/test/ResultSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/ResultSpec.hs
@@ -0,0 +1,18 @@
+module ResultSpec (spec) where
+
+import Helper
+
+import Fixtures.System qualified as System
+
+import Result
+
+spec :: Spec
+spec = do
+  describe "issueTitle" do
+    context "with a desktop system" do
+      it "creates a descriptive issue title" do
+        issueTitle 0 System.i10900K_desktop `shouldBe` "[result] 0s - desktop computer - Intel Core i9-10900K CPU"
+
+    context "with a laptop system" do
+      it "creates a descriptive issue title" do
+        issueTitle 0 System.t60_ThinkPad `shouldBe` "[result] 0s - LENOVO ThinkPad T60 - Intel Core 2 Duo Processor T7200"
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/test/SystemInfoSpec.hs b/test/SystemInfoSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/SystemInfoSpec.hs
@@ -0,0 +1,16 @@
+module SystemInfoSpec (spec) where
+
+import Helper
+
+import Command qualified as Command
+import Fixtures.System qualified as System
+
+import SystemInfo
+
+spec :: Spec
+spec = do
+  describe "collect" do
+    it "collects system information" do
+      Command.eval "whoami" <&> strip >>= \ case
+        "sol" -> SystemInfo.collect `shouldReturn` System.i10900K_desktop
+        _ -> pendingWith "add your system info to run this test"
