diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for keid-core
 
+## 0.1.7.1
+
+- SPIR-V reflection loader changed to `spirv-reflect-ffi`.
+
 ## 0.1.7.0
 
 - Graphics pipelines extracted to `Engine.Vulkan.Pipeline.Graphics`.
diff --git a/keid-core.cabal b/keid-core.cabal
--- a/keid-core.cabal
+++ b/keid-core.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           keid-core
-version:        0.1.7.0
+version:        0.1.7.1
 synopsis:       Core parts of Keid engine.
 category:       Game Engine
 homepage:       https://keid.haskell-game.dev
@@ -175,8 +175,8 @@
     , rio >=0.1.12.0
     , rio-app
     , serialise
-    , spirv-reflect-types
-    , spirv-reflect-yaml
+    , spirv-reflect-ffi >=0.2
+    , spirv-reflect-types >=0.2
     , tagged
     , template-haskell
     , text
diff --git a/src/Engine/SpirV/Reflect.hs b/src/Engine/SpirV/Reflect.hs
--- a/src/Engine/SpirV/Reflect.hs
+++ b/src/Engine/SpirV/Reflect.hs
@@ -10,38 +10,25 @@
 import Data.SpirV.Reflect.DescriptorBinding qualified as DescriptorBinding
 import Data.SpirV.Reflect.DescriptorSet qualified as DescriptorSet
 import Data.SpirV.Reflect.Enums qualified as Enums
+import Data.SpirV.Reflect.FFI qualified as Reflect
 import Data.SpirV.Reflect.InterfaceVariable (InterfaceVariable)
 import Data.SpirV.Reflect.InterfaceVariable qualified as InterfaceVariable
 import Data.SpirV.Reflect.Module (Module)
 import Data.SpirV.Reflect.Module qualified as Module
 import Data.SpirV.Reflect.Traits qualified as Traits
 import Data.SpirV.Reflect.TypeDescription qualified as TypeDescription
-import Data.SpirV.Reflect.Yaml qualified as ReflectYaml
 import Data.Tree (Tree(..))
 import Engine.Vulkan.Pipeline.Stages (StageInfo(..), withLabels)
-import RIO.Process (HasProcessContext, proc, readProcess_)
 import RIO.Text qualified as Text
+import RIO.ByteString (readFile)
 import Vulkan.Core10.Enums.Format qualified as VkFormat
 
 invoke
-  :: ( HasProcessContext env
-     , HasLogFunc env
-     , MonadReader env m
-     , MonadIO m
-     )
+  :: MonadIO m
   => FilePath
   -> m Module
-invoke file = do
-  (out, _err) <- proc
-    "spirv-reflect"
-    [ "-v"
-    , "1"
-    , "--yaml"
-    , file
-    ]
-    readProcess_
-
-  ReflectYaml.loadBytes ("spirv-reflect < " <> file) out
+invoke file =
+  readFile file >>= Reflect.loadBytes
 
 data Reflect stages = Reflect
   { bindMap    :: BindMap BlockBinding
@@ -67,7 +54,7 @@
 type BlockBinding =
   ( Text
   , Enums.DescriptorType
-  , Tree ([Maybe Text], BlockSignature)
+  , Maybe (Tree ([Maybe Text], BlockSignature))
   )
 
 data BlockSignature = BlockSignature
@@ -118,20 +105,25 @@
     unionDS =
       bindMapUnionWith \(_, adt, asig) (_, bdt, bsig) ->
         adt == bdt &&
-        fmap snd asig == fmap snd bsig
+        fmap (fmap snd) asig == fmap (fmap snd) bsig
 
     displayDS (name, dt, sigs) = mconcat
       [ display name
       , " :: "
       , maybe (displayShow dt) display $
           Enums.descriptorTypeName @Text dt
-      , " -- "
-      , displayShow . toList $
-          sigs <&> \(path, BlockSignature{..}) ->
-            ( Text.intercalate "|" (catMaybes path)
-            , (size, offset, Enums.typeFlagsNames @Text flags)
-            , scalar
-            )
+      , maybe
+          mempty
+          ( \sigs' ->
+              mappend " -- " $
+                displayShow . toList $
+                  sigs' <&> \(path, BlockSignature{..}) ->
+                    ( Text.intercalate "|" (catMaybes path)
+                    , (size, offset, Enums.typeFlagsNames @Text flags)
+                    , scalar
+                    )
+          )
+          sigs
       ]
 
 moduleBindMap :: Module -> BindMap BlockBinding
@@ -148,7 +140,7 @@
           ( fromIntegral binding
           , ( name
             , descriptor_type
-            , blockTree [] block
+            , fmap (blockTree []) block
             )
           )
     )
diff --git a/src/Engine/Vulkan/Pipeline/External.hs b/src/Engine/Vulkan/Pipeline/External.hs
--- a/src/Engine/Vulkan/Pipeline/External.hs
+++ b/src/Engine/Vulkan/Pipeline/External.hs
@@ -34,7 +34,6 @@
 import RIO.ByteString qualified as ByteString
 import RIO.Directory (createDirectoryIfMissing, getModificationTime, doesFileExist)
 import RIO.Map qualified as Map
-import RIO.Process (HasProcessContext)
 import RIO.Text qualified as Text
 import RIO.Time (UTCTime, getCurrentTime)
 import RIO.FilePath ((</>), (<.>))
@@ -99,7 +98,6 @@
   :: ( MonadUnliftIO m
      , MonadReader env m
      , HasLogFunc env
-     , HasProcessContext env
      , StageInfo stages
      )
   => Text
@@ -139,7 +137,6 @@
      , MonadIO io
      , MonadReader env io
      , HasLogFunc env
-     , HasProcessContext env
      )
   => stages (Maybe FilePath)
   -> io (stages (Maybe ByteString), Reflect.Reflect stages)
@@ -158,12 +155,12 @@
       logDebug $ displayShow ok
     Left (inputStage, outputStage, location, err) -> do
       let
-        between = "Between " <> inputStage <> " and " <> outputStage
+        between = "Between " <> outputStage <> " and " <> inputStage
         locInfo = "(location=" <> show location <> ")"
       case err of
         Nothing ->
           throwString $
-            unwords [ between, locInfo <> ":", "missing output" ]
+            unwords [ between, "missing output ", locInfo ]
         Just (sigRequested, sigProvided) ->
           throwString $ unlines
             [ unwords [ between, locInfo <> ":", "incompatible signatures" ]
