diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2023-2025, Ian Duncan & Mercury Technologies
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,177 @@
+import Control.Monad
+import Data.Char (toLower)
+import Data.Functor (($>))
+import Data.Maybe (fromMaybe)
+import Distribution.PackageDescription
+import Distribution.Simple
+import Distribution.Simple.LocalBuildInfo (
+  InstallDirs (..),
+  LocalBuildInfo (..),
+  absoluteInstallDirs,
+  buildDir,
+  localPkgDescr,
+ )
+import Distribution.Simple.Program.Find (
+  defaultProgramSearchPath,
+  findProgramOnSearchPath,
+ )
+import Distribution.Simple.Setup
+import Distribution.Simple.Utils (
+  IODataMode (IODataModeBinary),
+  installExecutableFile,
+  maybeExit,
+  rawSystemStdInOut,
+ )
+import Distribution.System
+import Distribution.Verbosity (Verbosity)
+import qualified Distribution.Verbosity as Verbosity
+import System.Directory (
+  getCurrentDirectory,
+ )
+import System.Environment (getEnv)
+import System.FilePath ((</>))
+import System.Posix.Files (createSymbolicLink)
+
+
+main :: IO ()
+main = defaultMainWithHooks hooks
+  where
+    hooks =
+      simpleUserHooks
+        { preConf = \_ flags -> do
+            unlessFlagM externalLibFlag flags $ rsMake (fromFlag $ configVerbosity flags)
+            pure emptyHookedBuildInfo
+        , confHook = \a flags -> do
+            lbi <- confHook simpleUserHooks a flags >>= rsAddLibraryInfo flags
+            unless (cabalFlag externalLibFlag flags) $ do
+              copyTemporalBridge lbi (buildDir lbi)
+            pure lbi
+        , postClean = \_ flags _ _ ->
+            rsClean (fromFlag $ cleanVerbosity flags)
+        , postCopy =
+            installTemporalBridge
+        }
+
+
+rsFolder :: FilePath
+rsFolder = "rust"
+
+
+externalLibFlagStr :: String
+externalLibFlagStr = "external_lib"
+
+
+externalLibFlag :: FlagName
+externalLibFlag = mkFlagName externalLibFlagStr
+
+
+execCargo :: Verbosity -> String -> [String] -> IO ()
+execCargo verbosity command args = do
+  cargoPath <- findProgramOnSearchPath Verbosity.silent defaultProgramSearchPath "cargo"
+  dir <- getCurrentDirectory
+  let cargoExec = case cargoPath of
+        Just (p, _) -> p
+        Nothing -> "cargo"
+      cargoArgs = command : args
+      workingDir = Just (dir </> rsFolder)
+      thirdComponent (_, _, c) = c
+  maybeExit . fmap thirdComponent $ rawSystemStdInOut verbosity cargoExec cargoArgs workingDir Nothing Nothing IODataModeBinary
+
+
+rsMake :: Verbosity -> IO ()
+rsMake verbosity = execCargo verbosity "build" ["--release", "--lib"]
+
+
+rsAddLibraryInfo :: ConfigFlags -> LocalBuildInfo -> IO LocalBuildInfo
+rsAddLibraryInfo fl lbi' = do
+  dir <- getCurrentDirectory
+  let external = getCabalFlag externalLibFlagStr fl
+  let updateLbi lbi =
+        lbi
+          { localPkgDescr = updatePkgDescr (localPkgDescr lbi)
+          }
+      updatePkgDescr pkgDescr =
+        pkgDescr
+          { library = updateLib <$> library pkgDescr
+          }
+      updateLib lib =
+        lib
+          { libBuildInfo = updateLibBi (libBuildInfo lib)
+          }
+      updateLibBi libBuild =
+        libBuild
+          { extraLibDirs =
+              if external
+                then extraLibDirs libBuild
+                else (dir </> buildDir lbi') : extraLibDirs libBuild
+          }
+  pure $ updateLbi lbi'
+
+
+rsClean :: Verbosity -> IO ()
+rsClean verbosity = execCargo verbosity "clean" []
+
+
+cabalFlag :: FlagName -> ConfigFlags -> Bool
+cabalFlag name = fromMaybe False . lookupFlagAssignment name . configConfigurationsFlags
+
+
+unlessFlagM :: FlagName -> ConfigFlags -> IO () -> IO ()
+unlessFlagM name flags action
+  | cabalFlag name flags = do
+      putStrLn "Skipping cargo action because external_lib flag is set"
+      pure ()
+  | otherwise = do
+      putStrLn ("Running cargo action because we don't have the flag: " ++ show name)
+      action
+
+
+copyLib :: ConfigFlags -> FilePath -> Bool -> IO ()
+copyLib fl libPref shared = do
+  libraryPath <- getLibraryPath
+  installExecutableFile
+    verb
+    libraryPath
+    (libPref ++ "/libtemporal_bridge." ++ ext)
+  where
+    verb = fromFlag $ configVerbosity fl
+    external = getCabalFlag externalLibFlagStr fl
+    ext =
+      if shared
+        then case buildOS of
+          Windows -> "dll"
+          OSX -> "dylib"
+          _ -> "so"
+        else "a"
+    getLibraryPath =
+      pure ("rust/target/release/libtemporal_bridge." ++ ext)
+
+
+copyTemporalBridge :: LocalBuildInfo -> FilePath -> IO ()
+copyTemporalBridge lbi fp = do
+  copyLib config fp False
+  where
+    config = configFlags lbi
+
+
+installTemporalBridge :: Args -> CopyFlags -> PackageDescription -> LocalBuildInfo -> IO ()
+installTemporalBridge _ flags pkg_descr lbi = do
+  let
+    libPref =
+      libdir
+        . absoluteInstallDirs pkg_descr lbi
+        . fromFlag
+        . copyDest
+        $ flags
+    config = configFlags lbi
+
+  unless (cabalFlag externalLibFlag $ configFlags lbi) $ do
+    copyLib config libPref True
+    copyLib config libPref False
+
+
+getCabalFlag :: String -> ConfigFlags -> Bool
+getCabalFlag name flags = fromMaybe False (lookupFlagAssignment (mkFlagName name') allFlags)
+  where
+    allFlags = configConfigurationsFlags flags
+    name' = map toLower name
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
new file mode 100644
--- /dev/null
+++ b/rust/Cargo.lock
@@ -0,0 +1,3701 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "arbitrary"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
+dependencies = [
+ "derive_arbitrary",
+]
+
+[[package]]
+name = "async-stream"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.88"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "axum"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
+dependencies = [
+ "async-trait",
+ "axum-core",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustversion",
+ "serde",
+ "sync_wrapper",
+ "tower 0.5.2",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "axum-core"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "mime",
+ "pin-project-lite",
+ "rustversion",
+ "sync_wrapper",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "backoff"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1"
+dependencies = [
+ "getrandom 0.2.16",
+ "instant",
+ "rand 0.8.5",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[package]]
+name = "bzip2"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
+dependencies = [
+ "bzip2-sys",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.13+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
+dependencies = [
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "chrono"
+version = "0.4.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+dependencies = [
+ "num-traits",
+ "serde",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
+
+[[package]]
+name = "core-foundation"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "dashmap"
+version = "6.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "deflate64"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
+
+[[package]]
+name = "deranged"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "derive_arbitrary"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "derive_builder"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
+dependencies = [
+ "derive_builder_macro",
+]
+
+[[package]]
+name = "derive_builder_core"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "derive_builder_macro"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
+dependencies = [
+ "derive_builder_core",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "derive_more"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+ "unicode-xid",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "downcast"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "enum-iterator"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c280b9e6b3ae19e152d8e31cf47f18389781e119d4013a2a2bb0180e5facc635"
+dependencies = [
+ "enum-iterator-derive",
+]
+
+[[package]]
+name = "enum-iterator-derive"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "enum_dispatch"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd"
+dependencies = [
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "erased-serde"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7"
+dependencies = [
+ "serde",
+ "typeid",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "ffi-convert"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88d96fa39640e119d4bc9898672ab63d9c575810dbad8806683a993fa8de0a8b"
+dependencies = [
+ "ffi-convert-derive",
+ "libc",
+ "thiserror 2.0.12",
+]
+
+[[package]]
+name = "ffi-convert-derive"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "480d55e4c9442832b168701bcc7f2e3282608f841791224ea1ed6ae35d450175"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "filetime"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "fixedbitset"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+
+[[package]]
+name = "flate2"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fragile"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619"
+
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "futures-retry"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fde5a672a61f96552aa5ed9fd9c81c3fbdae4be9b1e205d6eaf17c83705adc0f"
+dependencies = [
+ "futures",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-timer"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "glob"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
+
+[[package]]
+name = "governor"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb"
+dependencies = [
+ "cfg-if",
+ "dashmap",
+ "futures-sink",
+ "futures-timer",
+ "futures-util",
+ "getrandom 0.3.2",
+ "no-std-compat",
+ "nonzero_ext",
+ "parking_lot",
+ "portable-atomic",
+ "quanta",
+ "rand 0.9.1",
+ "smallvec",
+ "spinning_top",
+ "web-time",
+]
+
+[[package]]
+name = "h2"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap 2.9.0",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "http"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hyper"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-timeout"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
+dependencies = [
+ "hyper",
+ "hyper-util",
+ "pin-project-lite",
+ "tokio",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "libc",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.2",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "inventory"
+version = "0.3.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab08d7cd2c5897f2c949e5383ea7c7db03fb19130ffcfbf7eda795137ae3cb83"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "jobserver"
+version = "0.1.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
+dependencies = [
+ "getrandom 0.3.2",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.172"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags",
+ "libc",
+ "redox_syscall",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
+
+[[package]]
+name = "litemap"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[package]]
+name = "lru"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465"
+dependencies = [
+ "hashbrown 0.15.2",
+]
+
+[[package]]
+name = "lzma-rs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
+dependencies = [
+ "byteorder",
+ "crc",
+]
+
+[[package]]
+name = "lzma-sys"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata 0.1.10",
+]
+
+[[package]]
+name = "matchit"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+dependencies = [
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "mockall"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2"
+dependencies = [
+ "cfg-if",
+ "downcast",
+ "fragile",
+ "mockall_derive",
+ "predicates",
+ "predicates-tree",
+]
+
+[[package]]
+name = "mockall_derive"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898"
+dependencies = [
+ "cfg-if",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "multimap"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
+
+[[package]]
+name = "no-std-compat"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
+
+[[package]]
+name = "nonzero_ext"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
+
+[[package]]
+name = "ntapi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "object"
+version = "0.36.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+
+[[package]]
+name = "opentelemetry"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "570074cc999d1a58184080966e5bd3bf3a9a4af650c3b05047c2621e7405cd17"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "js-sys",
+ "once_cell",
+ "pin-project-lite",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "opentelemetry-http"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6351496aeaa49d7c267fb480678d85d1cd30c5edb20b497c48c56f62a8c14b99"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "http",
+ "opentelemetry",
+ "reqwest",
+]
+
+[[package]]
+name = "opentelemetry-otlp"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29e1f9c8b032d4f635c730c0efcf731d5e2530ea13fa8bef7939ddc8420696bd"
+dependencies = [
+ "async-trait",
+ "futures-core",
+ "http",
+ "opentelemetry",
+ "opentelemetry-http",
+ "opentelemetry-proto",
+ "opentelemetry_sdk",
+ "prost",
+ "reqwest",
+ "thiserror 1.0.69",
+ "tokio",
+ "tonic",
+]
+
+[[package]]
+name = "opentelemetry-prometheus"
+version = "0.17.0"
+source = "git+https://github.com/open-telemetry/opentelemetry-rust.git?rev=e911383#e91138351a689cd21923c15eb48f5fbc95ded807"
+dependencies = [
+ "once_cell",
+ "opentelemetry",
+ "opentelemetry_sdk",
+ "prometheus",
+ "protobuf",
+]
+
+[[package]]
+name = "opentelemetry-proto"
+version = "0.26.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9d3968ce3aefdcca5c27e3c4ea4391b37547726a70893aab52d3de95d5f8b34"
+dependencies = [
+ "opentelemetry",
+ "opentelemetry_sdk",
+ "prost",
+ "tonic",
+]
+
+[[package]]
+name = "opentelemetry_sdk"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2c627d9f4c9cdc1f21a29ee4bfbd6028fcb8bcf2a857b43f3abdf72c9c862f3"
+dependencies = [
+ "async-trait",
+ "futures-channel",
+ "futures-executor",
+ "futures-util",
+ "glob",
+ "once_cell",
+ "opentelemetry",
+ "percent-encoding",
+ "rand 0.8.5",
+ "serde_json",
+ "thiserror 1.0.69",
+ "tokio",
+ "tokio-stream",
+]
+
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "petgraph"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
+dependencies = [
+ "fixedbitset",
+ "indexmap 2.9.0",
+]
+
+[[package]]
+name = "pid"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c931ef9756cd5e3fa3d395bfe09df4dfa6f0612c6ca8f6b12927d17ca34e36"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "portable-atomic"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "predicates"
+version = "3.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573"
+dependencies = [
+ "anstyle",
+ "predicates-core",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c"
+dependencies = [
+ "predicates-core",
+ "termtree",
+]
+
+[[package]]
+name = "prettyplease"
+version = "0.2.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "prometheus"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1"
+dependencies = [
+ "cfg-if",
+ "fnv",
+ "lazy_static",
+ "memchr",
+ "parking_lot",
+ "protobuf",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "prost"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
+dependencies = [
+ "bytes",
+ "prost-derive",
+]
+
+[[package]]
+name = "prost-build"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
+dependencies = [
+ "heck",
+ "itertools",
+ "log",
+ "multimap",
+ "once_cell",
+ "petgraph",
+ "prettyplease",
+ "prost",
+ "prost-types",
+ "regex",
+ "syn 2.0.100",
+ "tempfile",
+]
+
+[[package]]
+name = "prost-derive"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
+dependencies = [
+ "anyhow",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "prost-types"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16"
+dependencies = [
+ "prost",
+]
+
+[[package]]
+name = "prost-wkt"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8d84e2bee181b04c2bac339f2bfe818c46a99750488cc6728ce4181d5aa8299"
+dependencies = [
+ "chrono",
+ "inventory",
+ "prost",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "typetag",
+]
+
+[[package]]
+name = "prost-wkt-build"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a669d5acbe719010c6f62a64e6d7d88fdedc1fe46e419747949ecb6312e9b14"
+dependencies = [
+ "heck",
+ "prost",
+ "prost-build",
+ "prost-types",
+ "quote",
+]
+
+[[package]]
+name = "prost-wkt-types"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01ef068e9b82e654614b22e6b13699bd545b6c0e2e721736008b00b38aeb4f64"
+dependencies = [
+ "chrono",
+ "prost",
+ "prost-build",
+ "prost-types",
+ "prost-wkt",
+ "prost-wkt-build",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
+[[package]]
+name = "protobuf"
+version = "2.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
+
+[[package]]
+name = "quanta"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e"
+dependencies = [
+ "crossbeam-utils",
+ "libc",
+ "once_cell",
+ "raw-cpuid",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "web-sys",
+ "winapi",
+]
+
+[[package]]
+name = "quinn"
+version = "0.11.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls",
+ "socket2",
+ "thiserror 2.0.12",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b"
+dependencies = [
+ "bytes",
+ "getrandom 0.3.2",
+ "rand 0.9.1",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.12",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.3",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.3",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.16",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom 0.3.2",
+]
+
+[[package]]
+name = "raw-cpuid"
+version = "11.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata 0.4.9",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax 0.6.29",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "reqwest"
+version = "0.12.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tokio-util",
+ "tower 0.5.2",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+ "windows-registry",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.16",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ringbuf"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe47b720588c8702e34b5979cb3271a8b1842c7cb6f57408efa70c779363488c"
+dependencies = [
+ "crossbeam-utils",
+ "portable-atomic",
+ "portable-atomic-util",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
+name = "rustfsm"
+version = "0.1.0"
+source = "git+https://github.com/temporalio/sdk-core?rev=97093c5ea4b0d933513f4c8999f7960f0c16f05f#97093c5ea4b0d933513f4c8999f7960f0c16f05f"
+dependencies = [
+ "rustfsm_procmacro",
+ "rustfsm_trait",
+]
+
+[[package]]
+name = "rustfsm_procmacro"
+version = "0.1.0"
+source = "git+https://github.com/temporalio/sdk-core?rev=97093c5ea4b0d933513f4c8999f7960f0c16f05f#97093c5ea4b0d933513f4c8999f7960f0c16f05f"
+dependencies = [
+ "derive_more",
+ "proc-macro2",
+ "quote",
+ "rustfsm_trait",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "rustfsm_trait"
+version = "0.1.0"
+source = "git+https://github.com/temporalio/sdk-core?rev=97093c5ea4b0d933513f4c8999f7960f0c16f05f#97093c5ea4b0d933513f4c8999f7960f0c16f05f"
+
+[[package]]
+name = "rustix"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
+dependencies = [
+ "log",
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
+dependencies = [
+ "web-time",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "schannel"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "security-framework"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
+[[package]]
+name = "siphasher"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "slotmap"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+
+[[package]]
+name = "socket2"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "spinning_top"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "sysinfo"
+version = "0.33.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+ "memchr",
+ "ntapi",
+ "windows",
+]
+
+[[package]]
+name = "tar"
+version = "0.4.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
+dependencies = [
+ "filetime",
+ "libc",
+ "xattr",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
+dependencies = [
+ "fastrand",
+ "getrandom 0.3.2",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "temporal-client"
+version = "0.1.0"
+source = "git+https://github.com/temporalio/sdk-core?rev=97093c5ea4b0d933513f4c8999f7960f0c16f05f#97093c5ea4b0d933513f4c8999f7960f0c16f05f"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "backoff",
+ "base64",
+ "derive_builder",
+ "derive_more",
+ "futures-retry",
+ "futures-util",
+ "http",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "parking_lot",
+ "slotmap",
+ "temporal-sdk-core-api",
+ "temporal-sdk-core-protos",
+ "thiserror 2.0.12",
+ "tokio",
+ "tonic",
+ "tower 0.5.2",
+ "tracing",
+ "url",
+ "uuid",
+]
+
+[[package]]
+name = "temporal-sdk-core"
+version = "0.1.0"
+source = "git+https://github.com/temporalio/sdk-core?rev=97093c5ea4b0d933513f4c8999f7960f0c16f05f#97093c5ea4b0d933513f4c8999f7960f0c16f05f"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "crossbeam-channel",
+ "crossbeam-queue",
+ "crossbeam-utils",
+ "dashmap",
+ "derive_builder",
+ "derive_more",
+ "enum-iterator",
+ "enum_dispatch",
+ "flate2",
+ "futures-channel",
+ "futures-util",
+ "governor",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "itertools",
+ "lru",
+ "mockall",
+ "opentelemetry",
+ "opentelemetry-otlp",
+ "opentelemetry-prometheus",
+ "opentelemetry_sdk",
+ "parking_lot",
+ "pid",
+ "pin-project",
+ "prometheus",
+ "prost",
+ "prost-wkt-types",
+ "rand 0.9.1",
+ "reqwest",
+ "ringbuf",
+ "rustfsm",
+ "serde",
+ "serde_json",
+ "siphasher",
+ "slotmap",
+ "sysinfo",
+ "tar",
+ "temporal-client",
+ "temporal-sdk-core-api",
+ "temporal-sdk-core-protos",
+ "thiserror 2.0.12",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tonic",
+ "tracing",
+ "tracing-subscriber",
+ "url",
+ "uuid",
+ "zip",
+]
+
+[[package]]
+name = "temporal-sdk-core-api"
+version = "0.1.0"
+source = "git+https://github.com/temporalio/sdk-core?rev=97093c5ea4b0d933513f4c8999f7960f0c16f05f#97093c5ea4b0d933513f4c8999f7960f0c16f05f"
+dependencies = [
+ "async-trait",
+ "derive_builder",
+ "derive_more",
+ "opentelemetry",
+ "prost",
+ "serde_json",
+ "temporal-sdk-core-protos",
+ "thiserror 2.0.12",
+ "tonic",
+ "tracing-core",
+ "url",
+]
+
+[[package]]
+name = "temporal-sdk-core-protos"
+version = "0.1.0"
+source = "git+https://github.com/temporalio/sdk-core?rev=97093c5ea4b0d933513f4c8999f7960f0c16f05f#97093c5ea4b0d933513f4c8999f7960f0c16f05f"
+dependencies = [
+ "anyhow",
+ "base64",
+ "derive_more",
+ "prost",
+ "prost-build",
+ "prost-wkt",
+ "prost-wkt-build",
+ "prost-wkt-types",
+ "rand 0.9.1",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.12",
+ "tonic",
+ "tonic-build",
+ "uuid",
+]
+
+[[package]]
+name = "temporal_bridge"
+version = "0.1.0"
+dependencies = [
+ "ffi-convert",
+ "libc",
+ "prost",
+ "prost-types",
+ "rustfsm",
+ "serde",
+ "serde_json",
+ "temporal-client",
+ "temporal-sdk-core",
+ "temporal-sdk-core-api",
+ "temporal-sdk-core-protos",
+ "tokio",
+ "tokio-stream",
+ "tonic",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "termtree"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl 2.0.12",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "time"
+version = "0.3.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
+dependencies = [
+ "deranged",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
+
+[[package]]
+name = "tinystr"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.44.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tonic"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
+dependencies = [
+ "async-stream",
+ "async-trait",
+ "axum",
+ "base64",
+ "bytes",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-timeout",
+ "hyper-util",
+ "percent-encoding",
+ "pin-project",
+ "prost",
+ "rustls-native-certs",
+ "rustls-pemfile",
+ "socket2",
+ "tokio",
+ "tokio-rustls",
+ "tokio-stream",
+ "tower 0.4.13",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tonic-build"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11"
+dependencies = [
+ "prettyplease",
+ "proc-macro2",
+ "prost-build",
+ "prost-types",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "tower"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "indexmap 1.9.3",
+ "pin-project",
+ "pin-project-lite",
+ "rand 0.8.5",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tower"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "parking_lot",
+ "regex",
+ "sharded-slab",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "typeid"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
+
+[[package]]
+name = "typenum"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
+
+[[package]]
+name = "typetag"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f22b40dd7bfe8c14230cf9702081366421890435b2d625fa92b4acc4c3de6f"
+dependencies = [
+ "erased-serde",
+ "inventory",
+ "once_cell",
+ "serde",
+ "typetag-impl",
+]
+
+[[package]]
+name = "typetag-impl"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35f5380909ffc31b4de4f4bdf96b877175a016aa2ca98cee39fcfd8c4d53d952"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "uuid"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+dependencies = [
+ "getrandom 0.3.2",
+]
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-streams"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
+dependencies = [
+ "windows-core",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-result 0.1.2",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+
+[[package]]
+name = "windows-registry"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
+dependencies = [
+ "windows-result 0.3.2",
+ "windows-strings",
+ "windows-targets 0.53.0",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
+dependencies = [
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
+[[package]]
+name = "xattr"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
+dependencies = [
+ "libc",
+ "rustix",
+]
+
+[[package]]
+name = "xz2"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
+dependencies = [
+ "lzma-sys",
+]
+
+[[package]]
+name = "yoke"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "zip"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744"
+dependencies = [
+ "aes",
+ "arbitrary",
+ "bzip2",
+ "constant_time_eq",
+ "crc32fast",
+ "crossbeam-utils",
+ "deflate64",
+ "flate2",
+ "getrandom 0.3.2",
+ "hmac",
+ "indexmap 2.9.0",
+ "lzma-rs",
+ "memchr",
+ "pbkdf2",
+ "sha1",
+ "time",
+ "xz2",
+ "zeroize",
+ "zopfli",
+ "zstd",
+]
+
+[[package]]
+name = "zopfli"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
+dependencies = [
+ "bumpalo",
+ "crc32fast",
+ "log",
+ "simd-adler32",
+]
+
+[[package]]
+name = "zstd"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "7.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
+dependencies = [
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.15+zstd.1.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
new file mode 100644
--- /dev/null
+++ b/rust/Cargo.toml
@@ -0,0 +1,33 @@
+[package]
+name = "temporal_bridge"
+version = "0.1.0"
+edition = "2024"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[lib]
+crate-type = ["cdylib", "staticlib"]
+
+[dependencies]
+temporal-client = { git = "https://github.com/temporalio/sdk-core", rev = "97093c5ea4b0d933513f4c8999f7960f0c16f05f" }
+temporal-sdk-core = { git = "https://github.com/temporalio/sdk-core", rev = "97093c5ea4b0d933513f4c8999f7960f0c16f05f", features = ["ephemeral-server"] }
+temporal-sdk-core-api = { git = "https://github.com/temporalio/sdk-core", rev = "97093c5ea4b0d933513f4c8999f7960f0c16f05f" }
+temporal-sdk-core-protos = { git = "https://github.com/temporalio/sdk-core", rev = "97093c5ea4b0d933513f4c8999f7960f0c16f05f" }
+rustfsm = { git = "https://github.com/temporalio/sdk-core", rev = "97093c5ea4b0d933513f4c8999f7960f0c16f05f" }
+tokio = "~1.44"
+tokio-stream = "~0.1"
+tonic = "~0.12"
+tracing = "~0.1"
+url = "~2.5"
+ffi-convert = "~0.6"
+serde = { version = "~1.0", features = ["derive"] }
+serde_json = "~1.0"
+prost = "~0.13"
+prost-types = "~0.13"
+libc = "0.2.172"
+
+[profile.release]
+opt-level = 3
+debug = false
+lto = true
+incremental = true
diff --git a/rust/src/client.rs b/rust/src/client.rs
new file mode 100644
--- /dev/null
+++ b/rust/src/client.rs
@@ -0,0 +1,334 @@
+use crate::runtime::{self, Capability, HsCallback, MVar};
+use ffi_convert::*;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::ffi::CStr;
+use std::str::{from_utf8_unchecked, FromStr};
+use std::time::Duration;
+use temporal_client::{
+    ClientOptions, ClientOptionsBuilder, ClientOptionsBuilderError, ConfiguredClient, RetryClient,
+    RetryConfig, TemporalServiceClientWithMetrics, TlsConfig,
+};
+use tonic::metadata::{errors::InvalidMetadataValue, MetadataKey};
+use url::Url;
+
+type Client = RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>;
+
+#[derive(Serialize, Deserialize)]
+pub struct ClientConfig {
+    target_url: String,
+    client_name: String,
+    client_version: String,
+    metadata: HashMap<String, String>,
+    identity: String,
+    tls_config: Option<ClientTlsConfig>,
+    retry_config: Option<ClientRetryConfig>,
+    api_key: Option<String>,
+}
+
+#[derive(Serialize, Deserialize)]
+struct ClientTlsConfig {
+    server_root_ca_cert: Option<Vec<u8>>,
+    domain: Option<String>,
+    client_cert: Option<Vec<u8>>,
+    client_private_key: Option<Vec<u8>>,
+}
+
+#[derive(Serialize, Deserialize)]
+struct ClientRetryConfig {
+    pub initial_interval_millis: u64,
+    pub randomization_factor: f64,
+    pub multiplier: f64,
+    pub max_interval_millis: u64,
+    pub max_elapsed_time_millis: Option<u64>,
+    pub max_retries: usize,
+}
+
+fn client_config_to_options(
+    client_config: ClientConfig,
+) -> Result<ClientOptions, ClientOptionsBuilderError> {
+    let mut defaults = ClientOptionsBuilder::default();
+    let mut options_builder = defaults
+        .target_url(Url::parse(&client_config.target_url).unwrap())
+        .client_name(client_config.client_name)
+        .client_version(client_config.client_version)
+        .identity(client_config.identity);
+
+    if let Some(tls_config) = client_config.tls_config {
+        let tls_config = TlsConfig {
+            server_root_ca_cert: tls_config.server_root_ca_cert,
+            domain: tls_config.domain,
+            client_tls_config: match (tls_config.client_cert, tls_config.client_private_key) {
+                (Some(client_cert), Some(client_private_key)) => {
+                    Some(temporal_client::ClientTlsConfig {
+                        client_cert,
+                        client_private_key,
+                    })
+                }
+                _ => None,
+            },
+        };
+        options_builder = options_builder.tls_cfg(tls_config);
+    }
+
+    if let Some(retry_config) = client_config.retry_config {
+        options_builder = options_builder.retry_config(RetryConfig {
+            initial_interval: Duration::from_millis(retry_config.initial_interval_millis),
+            randomization_factor: retry_config.randomization_factor,
+            multiplier: retry_config.multiplier,
+            max_interval: Duration::from_millis(retry_config.max_interval_millis),
+            max_elapsed_time: retry_config
+                .max_elapsed_time_millis
+                .map(Duration::from_millis),
+            max_retries: retry_config.max_retries,
+        });
+    }
+
+    if client_config.api_key.is_some() {
+        options_builder = options_builder.api_key(client_config.api_key)
+    }
+
+    options_builder.build()
+}
+
+#[repr(C)]
+pub struct HaskellHashMapEntries {
+    key: *const u8,
+    key_len: usize,
+    value: *const u8,
+    value_len: usize,
+    next: *const HaskellHashMapEntries,
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+pub unsafe fn convert_hashmap(hashmap: *const HaskellHashMapEntries) -> HashMap<String, String> {
+    let mut map = HashMap::new();
+    if hashmap.is_null() {
+        return map;
+    }
+
+    let mut hashmap_ptr = hashmap;
+    while !hashmap_ptr.is_null() {
+        let hashmap_val = unsafe { &*hashmap_ptr };
+        let key = unsafe {
+            from_utf8_unchecked(std::slice::from_raw_parts(
+                hashmap_val.key,
+                hashmap_val.key_len,
+            ))
+        };
+        let value = unsafe {
+            from_utf8_unchecked(std::slice::from_raw_parts(
+                hashmap_val.value,
+                hashmap_val.value_len,
+            ))
+        };
+        map.insert(key.to_string(), value.to_string());
+        hashmap_ptr = unsafe { (*hashmap).next };
+    }
+
+    map
+}
+#[repr(C)]
+pub struct RpcCall {
+    req: *const CArray<u8>,
+    retry: bool,
+    metadata: *const HaskellHashMapEntries,
+    // nullable
+    timeout_millis: *const u64,
+}
+
+pub(crate) struct TemporalCall {
+    pub(crate) req: Vec<u8>,
+    pub(crate) retry: bool,
+    pub(crate) metadata: HashMap<String, String>,
+    pub(crate) timeout_millis: Option<u64>,
+}
+
+impl From<&RpcCall> for TemporalCall {
+    fn from(rpc_call: &RpcCall) -> Self {
+        TemporalCall {
+            req: unsafe {
+                let req_array = rpc_call.req;
+                let rust_vec = (*req_array).as_rust();
+                rust_vec.unwrap().clone()
+            },
+            retry: rpc_call.retry,
+            metadata: unsafe { convert_hashmap(rpc_call.metadata) },
+            timeout_millis: if rpc_call.timeout_millis.is_null() {
+                None
+            } else {
+                Some(unsafe { *rpc_call.timeout_millis })
+            },
+        }
+    }
+}
+
+pub struct ClientRef {
+    pub(crate) retry_client: Client,
+    pub(crate) runtime: runtime::Runtime,
+}
+
+impl RawPointerConverter<ClientRef> for ClientRef {
+    fn into_raw_pointer(self) -> *const ClientRef {
+        convert_into_raw_pointer(self)
+    }
+
+    fn into_raw_pointer_mut(self) -> *mut ClientRef {
+        convert_into_raw_pointer_mut(self)
+    }
+
+    unsafe fn from_raw_pointer(ptr: *const ClientRef) -> Result<Self, UnexpectedNullPointerError> {
+        unsafe { take_back_from_raw_pointer(ptr) }
+    }
+
+    unsafe fn from_raw_pointer_mut(
+        ptr: *mut ClientRef,
+    ) -> Result<Self, UnexpectedNullPointerError> {
+        unsafe { take_back_from_raw_pointer_mut(ptr) }
+    }
+}
+
+pub fn connect_client(
+    runtime_ref: &runtime::RuntimeRef,
+    config: ClientConfig,
+    hs_callback: HsCallback<ClientRef, CArray<u8>>,
+) {
+    let opts: ClientOptions = client_config_to_options(config).unwrap();
+    let runtime = runtime_ref.runtime.clone();
+    runtime_ref
+        .runtime
+        .future_result_into_hs(hs_callback, async move {
+            let retry_client_result = opts
+                .connect_no_namespace(runtime.core.as_ref().telemetry().get_metric_meter())
+                .await;
+
+            match retry_client_result {
+                Ok(retry_client) => Ok(ClientRef {
+                    retry_client,
+                    runtime,
+                }),
+                Err(e) => {
+                    let err_message = e.to_string().into_bytes();
+                    Err(CArray::c_repr_of(err_message).unwrap())
+                }
+            }
+        })
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_connect_client(
+    runtime_ref: *const runtime::RuntimeRef,
+    config_json: *const libc::c_char,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CArray<u8>,
+    result_slot: *mut *mut ClientRef,
+) {
+    let runtime_ref = unsafe { &*runtime_ref };
+    let config_json = unsafe { CStr::from_ptr(config_json) };
+    let config: ClientConfig = serde_json::from_slice(config_json.to_bytes()).unwrap();
+    let hs_callback = runtime::HsCallback {
+        cap,
+        mvar,
+        error_slot,
+        result_slot,
+    };
+    connect_client(runtime_ref, config, hs_callback);
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_drop_client(client: *mut ClientRef) {
+    unsafe {
+        drop(Box::from_raw(client));
+    }
+}
+
+pub(crate) fn rpc_req<P: prost::Message + Default>(
+    call: TemporalCall,
+) -> Result<tonic::Request<P>, String> {
+    let buf = call.req.as_slice();
+    let proto = P::decode(buf).map_err(|err| err.to_string())?;
+    let mut req = tonic::Request::new(proto);
+    let metadata = &call.metadata;
+    for (k, v) in metadata {
+        req.metadata_mut().insert(
+            MetadataKey::from_str(k.as_str()).map_err(|err| err.to_string())?,
+            v.parse()
+                .map_err(|err: InvalidMetadataValue| err.to_string())?,
+        );
+    }
+    if let Some(timeout_millis) = call.timeout_millis {
+        req.set_timeout(Duration::from_millis(timeout_millis));
+    }
+    Ok(req)
+}
+
+#[derive(Debug)]
+pub struct RPCError {
+    pub code: u32,
+    pub message: String,
+    pub details: Vec<u8>,
+}
+
+#[repr(C)]
+#[derive(CReprOf, AsRust, CDrop, RawPointerConverter)]
+#[target_type(RPCError)]
+pub struct CRPCError {
+    code: u32,
+    message: *const libc::c_char,
+    details: *const CArray<u8>,
+}
+
+impl From<String> for CRPCError {
+    fn from(err: String) -> Self {
+        CRPCError::c_repr_of(RPCError {
+            code: 0,
+            message: err,
+            details: vec![],
+        })
+        .unwrap()
+    }
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_drop_rpc_error(error: *mut CRPCError) {
+    unsafe {
+        CRPCError::drop_raw_pointer(error).unwrap();
+    }
+}
+
+pub(crate) fn rpc_resp<P>(
+    res: Result<tonic::Response<P>, tonic::Status>,
+) -> Result<Vec<u8>, CRPCError>
+where
+    P: prost::Message,
+    P: Default,
+{
+    match res {
+        Ok(resp) => Ok(resp.get_ref().encode_to_vec()),
+        Err(err) => {
+            eprintln!("Error: {:?}", err);
+            Err(CRPCError::c_repr_of(RPCError {
+                code: err.code() as u32,
+                message: err.message().to_owned(),
+                details: err.details().into(),
+            })
+            .unwrap())
+        }
+    }
+}
diff --git a/rust/src/ephemeral_server.rs b/rust/src/ephemeral_server.rs
new file mode 100644
--- /dev/null
+++ b/rust/src/ephemeral_server.rs
@@ -0,0 +1,216 @@
+use crate::runtime::{Capability, HsCallback, MVar, Runtime, RuntimeRef};
+use crate::worker::{CUnit, Unit};
+use ffi_convert::*;
+use serde::Deserialize;
+use std::ffi::{c_char, CStr};
+use std::time::Duration;
+use temporal_sdk_core::ephemeral_server::*;
+
+pub struct EphemeralServerRef {
+    pub(crate) server: EphemeralServer,
+    runtime: Runtime,
+}
+
+impl RawPointerConverter<EphemeralServerRef> for EphemeralServerRef {
+    fn into_raw_pointer(self) -> *const EphemeralServerRef {
+        convert_into_raw_pointer(self)
+    }
+
+    fn into_raw_pointer_mut(self) -> *mut EphemeralServerRef {
+        convert_into_raw_pointer_mut(self)
+    }
+
+    unsafe fn from_raw_pointer(
+        ptr: *const EphemeralServerRef,
+    ) -> Result<Self, UnexpectedNullPointerError> {
+        unsafe { take_back_from_raw_pointer(ptr) }
+    }
+
+    unsafe fn from_raw_pointer_mut(
+        ptr: *mut EphemeralServerRef,
+    ) -> Result<Self, UnexpectedNullPointerError> {
+        unsafe { take_back_from_raw_pointer_mut(ptr) }
+    }
+}
+
+/// Where to find an executable. Can be a path or download.
+#[derive(Deserialize)]
+#[serde(tag = "type", content = "contents", remote = "EphemeralExe")]
+pub enum EphemeralExeDef {
+    /// Existing path on the filesystem for the executable.
+    ExistingPath(String),
+    /// Download the executable if not already there.
+    CachedDownload {
+        /// Which version to download.
+        #[serde(with = "EphemeralExeVersionDef")]
+        version: EphemeralExeVersion,
+        /// Destination directory or the user temp directory if none set.
+        dest_dir: Option<String>,
+        ttl: Option<Duration>
+    },
+}
+
+/// Which version of the exe to download.
+#[derive(Deserialize)]
+#[serde(tag = "type", content = "contents", remote = "EphemeralExeVersion")]
+pub enum EphemeralExeVersionDef {
+    /// Use a default version for the given SDK name and version.
+    SDKDefault {
+        /// Name of the SDK to get the default for.
+        sdk_name: String,
+        /// Version of the SDK to get the default for.
+        sdk_version: String,
+    },
+    /// Specific version.
+    Fixed(String),
+}
+
+#[derive(Deserialize)]
+#[serde(remote = "TemporalDevServerConfig")]
+pub struct TemporalDevServerConfigDef {
+    /// Required path to executable or download info.
+    #[serde(with = "EphemeralExeDef")]
+    pub exe: EphemeralExe,
+    /// Namespace to use.
+    pub namespace: String,
+    /// IP to bind to.
+    pub ip: String,
+    /// Port to use or obtains a free one if none given.
+    pub port: Option<u16>,
+    /// Sqlite DB filename if persisting or non-persistent if none.
+    pub db_filename: Option<String>,
+    /// Whether to enable the UI.
+    pub ui: bool,
+    /// What port to run the UI on.
+    pub ui_port: Option<u16>,
+    /// Log format and level
+    pub log: (String, String),
+    /// Additional arguments to Temporalite.
+    pub extra_args: Vec<String>,
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_start_dev_server(
+    runtime: *mut RuntimeRef,
+    json_string: *const c_char,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CArray<u8>,
+    result_slot: *mut *mut EphemeralServerRef,
+) {
+    let runtime_ref = unsafe { runtime.as_ref().unwrap() };
+    let runtime = &runtime_ref.runtime;
+    let mut de = serde_json::Deserializer::from_str(unsafe {
+        std::str::from_utf8_unchecked(CStr::from_ptr(json_string).to_bytes())
+    });
+    let conf =
+        TemporalDevServerConfigDef::deserialize(&mut de).expect("Failed to deserialize config");
+    let hs: HsCallback<EphemeralServerRef, CArray<u8>> = HsCallback {
+        cap,
+        mvar,
+        error_slot,
+        result_slot,
+    };
+    runtime.future_result_into_hs(hs, async move {
+        let result = conf.start_server().await;
+        match result {
+            Ok(server) => Ok(EphemeralServerRef {
+                server,
+                runtime: runtime.clone(),
+            }),
+            Err(e) => Err(
+                CArray::c_repr_of(format!("Failed to start server: {}", e).into_bytes())
+                    .expect("Failed to convert error to CArray"),
+            ),
+        }
+    })
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_shutdown_ephemeral_server(
+    server: *mut EphemeralServerRef,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CArray<u8>,
+    result_slot: *mut *mut CUnit,
+) {
+    let server_ref = unsafe { Box::from_raw(server) };
+    let mut server = server_ref.server;
+    let hs: HsCallback<CUnit, CArray<u8>> = HsCallback {
+        cap,
+        mvar,
+        error_slot,
+        result_slot,
+    };
+    server_ref.runtime.future_result_into_hs(hs, async move {
+        let result = server.shutdown().await;
+        match result {
+            Ok(()) => Ok(CUnit::c_repr_of(Unit {}).unwrap()),
+            Err(e) => Err(CArray::c_repr_of(
+                format!("Failed to shutdown server: {}", e).into_bytes(),
+            )
+            .expect("Failed to convert error to CArray")),
+        }
+    })
+}
+
+/// Configuration for the test server.
+#[derive(Deserialize)]
+#[serde(remote = "TestServerConfig")]
+pub struct TestServerConfigDef {
+    /// Required path to executable or download info.
+    #[serde(with = "EphemeralExeDef")]
+    pub exe: EphemeralExe,
+    /// Port to use or obtains a free one if none given.
+    pub port: Option<u16>,
+    /// Additional arguments to the test server.
+    pub extra_args: Vec<String>,
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_start_test_server(
+    runtime: *mut RuntimeRef,
+    json_string: *const c_char,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CArray<u8>,
+    result_slot: *mut *mut EphemeralServerRef,
+) {
+    let runtime_ref = unsafe { runtime.as_ref().unwrap() };
+    let runtime = &runtime_ref.runtime;
+    let mut de = serde_json::Deserializer::from_str(unsafe {
+        std::str::from_utf8_unchecked(CStr::from_ptr(json_string).to_bytes())
+    });
+    let conf = TestServerConfigDef::deserialize(&mut de).expect("Failed to deserialize config");
+    let hs: HsCallback<EphemeralServerRef, CArray<u8>> = HsCallback {
+        cap,
+        mvar,
+        error_slot,
+        result_slot,
+    };
+    runtime.future_result_into_hs(hs, async move {
+        let result = conf.start_server().await;
+        match result {
+            Ok(server) => Ok(EphemeralServerRef {
+                server,
+                runtime: runtime.clone(),
+            }),
+            Err(e) => Err(
+                CArray::c_repr_of(format!("Failed to start server: {}", e).into_bytes())
+                    .expect("Failed to convert error to CArray"),
+            ),
+        }
+    })
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
new file mode 100644
--- /dev/null
+++ b/rust/src/lib.rs
@@ -0,0 +1,5 @@
+pub mod client;
+pub mod ephemeral_server;
+pub mod rpc;
+pub mod runtime;
+pub mod worker;
diff --git a/rust/src/rpc.rs b/rust/src/rpc.rs
new file mode 100644
--- /dev/null
+++ b/rust/src/rpc.rs
@@ -0,0 +1,2017 @@
+use crate::client::{rpc_req, rpc_resp, CRPCError, ClientRef, RPCError, RpcCall, TemporalCall};
+use crate::runtime::{Capability, HsCallback, MVar};
+use ffi_convert::{CArray, CReprOf};
+use temporal_client::OperatorService;
+use temporal_client::TestService;
+use temporal_client::WorkflowService;
+
+macro_rules! rpc_call {
+    ($retry_client:ident, $call:ident, $call_name:ident) => {{
+        if $call.retry {
+            let req = rpc_req($call).map_err(|err| {
+                CRPCError::c_repr_of(RPCError {
+                    code: 0,
+                    message: err,
+                    details: vec![],
+                })
+                .unwrap()
+            })?;
+            rpc_resp($retry_client.$call_name(req).await)
+        } else {
+            let req = rpc_req($call).map_err(|err| {
+                CRPCError::c_repr_of(RPCError {
+                    code: 0,
+                    message: err,
+                    details: vec![],
+                })
+                .unwrap()
+            })?;
+            rpc_resp($retry_client.into_inner().$call_name(req).await)
+        }
+    }};
+}
+
+// TODO, these are all quite repetitive, can we generate them?
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_count_workflow_executions(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, count_workflow_executions) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_create_schedule(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, create_schedule) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_delete_schedule(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, delete_schedule) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_deprecate_namespace(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, deprecate_namespace) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_describe_namespace(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, describe_namespace) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_describe_schedule(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, describe_schedule) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_describe_task_queue(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, describe_task_queue) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_describe_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, describe_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_get_cluster_info(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, get_cluster_info) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_get_search_attributes(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, get_search_attributes) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_get_system_info(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, get_system_info) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_get_worker_build_id_compatibility(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, get_worker_build_id_compatibility) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_get_workflow_execution_history(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, get_workflow_execution_history) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_get_workflow_execution_history_reverse(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, get_workflow_execution_history_reverse) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_archived_workflow_executions(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_archived_workflow_executions) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_closed_workflow_executions(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_closed_workflow_executions) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_namespaces(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_namespaces) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_open_workflow_executions(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_open_workflow_executions) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_schedule_matching_times(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_schedule_matching_times) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_schedules(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_schedules) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_task_queue_partitions(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_task_queue_partitions) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_workflow_executions(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_workflow_executions) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_patch_schedule(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, patch_schedule) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_poll_activity_task_queue(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, poll_activity_task_queue) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_poll_workflow_execution_update(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, poll_workflow_execution_update) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_poll_workflow_task_queue(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, poll_workflow_task_queue) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_query_workflow(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, query_workflow) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_record_activity_task_heartbeat(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, record_activity_task_heartbeat) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_record_activity_task_heartbeat_by_id(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, record_activity_task_heartbeat_by_id) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_register_namespace(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, register_namespace) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_request_cancel_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, request_cancel_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_reset_sticky_task_queue(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, reset_sticky_task_queue) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_reset_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, reset_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_activity_task_canceled(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_activity_task_canceled) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_activity_task_canceled_by_id(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_activity_task_canceled_by_id) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_activity_task_completed(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_activity_task_completed) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_activity_task_completed_by_id(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_activity_task_completed_by_id) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_activity_task_failed(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_activity_task_failed) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_activity_task_failed_by_id(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_activity_task_failed_by_id) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_query_task_completed(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_query_task_completed) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_workflow_task_completed(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_workflow_task_completed) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_respond_workflow_task_failed(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, respond_workflow_task_failed) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_scan_workflow_executions(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, scan_workflow_executions) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_signal_with_start_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, signal_with_start_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_signal_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, signal_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_start_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, start_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_terminate_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, terminate_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_update_namespace(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, update_namespace) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_update_schedule(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, update_schedule) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_update_workflow_execution(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, update_workflow_execution) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_update_worker_build_id_compatibility(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, update_worker_build_id_compatibility) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_get_current_time(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, get_current_time) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_lock_time_skipping(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, lock_time_skipping) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_sleep_until(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, sleep_until) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_sleep(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, sleep) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_unlock_time_skipping_with_sleep(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, unlock_time_skipping_with_sleep) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_unlock_time_skipping(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, unlock_time_skipping) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_add_or_update_remote_cluster(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, add_or_update_remote_cluster) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_add_search_attributes(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, add_search_attributes) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_delete_namespace(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, delete_namespace) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_clusters(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_clusters) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_list_search_attributes(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, list_search_attributes) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_remove_remote_cluster(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, remove_remote_cluster) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_remove_search_attributes(
+    client: *mut ClientRef,
+    c_call: *const RpcCall,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CRPCError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let client = unsafe { &mut *client };
+    let mut retry_client = client.retry_client.clone();
+    let call: TemporalCall = unsafe { (&*c_call).into() };
+
+    let callback: HsCallback<CArray<u8>, CRPCError> = HsCallback {
+        cap,
+        mvar,
+        result_slot,
+        error_slot,
+    };
+    client.runtime.future_result_into_hs(callback, async move {
+        match rpc_call!(retry_client, call, remove_search_attributes) {
+            Ok(resp) => Ok(CArray::c_repr_of(resp).unwrap()),
+            Err(err) => Err(err),
+        }
+    });
+}
diff --git a/rust/src/runtime.rs b/rust/src/runtime.rs
new file mode 100644
--- /dev/null
+++ b/rust/src/runtime.rs
@@ -0,0 +1,277 @@
+use ffi_convert::*;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::future::Future;
+use std::net::SocketAddr;
+use std::os::raw::c_int;
+use std::sync::Arc;
+use std::time::{Duration, SystemTime};
+use temporal_sdk_core::telemetry::{
+    build_otlp_metric_exporter, construct_filter_string, start_prometheus_metric_exporter,
+};
+use temporal_sdk_core::{CoreRuntime, TokioRuntimeBuilder};
+use temporal_sdk_core_api::telemetry::metrics::{CoreMeter, NoOpCoreMeter};
+use temporal_sdk_core_api::telemetry::{
+    CoreTelemetry, Logger, OtelCollectorOptionsBuilder, PrometheusExporterOptionsBuilder,
+    TelemetryOptions, TelemetryOptionsBuilder,
+};
+use tracing::Level;
+
+pub struct RuntimeRef {
+    pub(crate) runtime: Runtime,
+}
+
+#[derive(Clone)]
+pub(crate) struct Runtime {
+    pub(crate) core: Arc<CoreRuntime>,
+    pub(crate) try_put_mvar: extern "C" fn(capability: Capability, mvar: *mut MVar) -> (),
+}
+
+fn init_runtime(
+    telemetry_config: TelemetryOptions,
+    late_telemetry_options: HsTelemetryOptions,
+    try_put_mvar: extern "C" fn(capability: Capability, mvar: *mut MVar) -> (),
+) -> Box<RuntimeRef> {
+    let mut runtime = CoreRuntime::new(telemetry_config, TokioRuntimeBuilder::default()).unwrap();
+
+    let _guard = runtime.tokio_handle().enter();
+    let core_meter: Arc<dyn CoreMeter> = match late_telemetry_options {
+        HsTelemetryOptions::NoTelemetry => Arc::new(NoOpCoreMeter) as Arc<dyn CoreMeter>,
+        HsTelemetryOptions::OtelTelemetryOptions {
+            url,
+            headers,
+            metric_periodicity,
+            global_tags,
+        } => Arc::new(
+            build_otlp_metric_exporter(
+                OtelCollectorOptionsBuilder::default()
+                    .url(url.parse().expect("Invalid URL"))
+                    .metric_periodicity(metric_periodicity.unwrap_or_else(|| Duration::new(1, 0)))
+                    .headers(headers)
+                    .global_tags(global_tags)
+                    .build()
+                    .expect("Invalid OTEl configuration"),
+            )
+            .expect("Otel Metric exporter"),
+        ) as Arc<dyn CoreMeter>,
+        HsTelemetryOptions::PrometheusTelemetryOptions {
+            socket_addr,
+            global_tags,
+            counters_total_suffix,
+            unit_suffix,
+        } => {
+            let srv = start_prometheus_metric_exporter(
+                PrometheusExporterOptionsBuilder::default()
+                    .socket_addr(socket_addr)
+                    .unit_suffix(unit_suffix)
+                    .global_tags(global_tags)
+                    .counters_total_suffix(counters_total_suffix)
+                    .build()
+                    .expect("Invalid Prometheus configuration"),
+            )
+            .expect("Failed to start prometheus exporter");
+            srv.meter as Arc<dyn CoreMeter>
+        }
+    };
+    runtime.telemetry_mut().attach_late_init_metrics(core_meter);
+
+    // TODO need to figure out how to handle errors here
+    Box::new(RuntimeRef {
+        runtime: Runtime {
+            core: Arc::new(runtime),
+            try_put_mvar,
+        },
+    })
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(tag = "tag")]
+pub enum HsTelemetryOptions {
+    OtelTelemetryOptions {
+        url: String,
+        headers: HashMap<String, String>,
+        metric_periodicity: Option<Duration>,
+        global_tags: HashMap<String, String>,
+    },
+    PrometheusTelemetryOptions {
+        socket_addr: SocketAddr,
+        global_tags: HashMap<String, String>,
+        counters_total_suffix: bool,
+        unit_suffix: bool,
+    },
+    NoTelemetry,
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_init_runtime(
+    telemetry_opts: *const CArray<u8>,
+    try_put_mvar: extern "C" fn(Capability, *mut MVar) -> (),
+) -> *mut RuntimeRef {
+    let telemetry_opts = unsafe {
+        CArray::raw_borrow(telemetry_opts)
+            .unwrap()
+            .as_rust()
+            .unwrap()
+            .clone()
+    };
+    let telemetry_opts: HsTelemetryOptions =
+        serde_json::from_slice(telemetry_opts.as_slice()).expect("Failed to parse");
+
+    let early_options = TelemetryOptionsBuilder::default()
+        .logging(Logger::Forward {
+            filter: construct_filter_string(Level::INFO, Level::ERROR),
+        })
+        .attach_service_name(true)
+        // .metrics(core_meter)
+        .build()
+        .expect("Invalid TelemetryOptions");
+    let rt = init_runtime(early_options, telemetry_opts, try_put_mvar);
+    Box::into_raw(rt)
+}
+
+fn safe_drop_runtime(runtime: Box<RuntimeRef>) {
+    drop(runtime)
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_free_runtime(runtime: *mut RuntimeRef) {
+    unsafe { safe_drop_runtime(Box::from_raw(runtime)) };
+}
+
+#[repr(C)]
+pub struct MVar {
+    _data: [u8; 0],
+    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
+}
+
+#[repr(C)]
+pub struct Capability {
+    pub cap_num: c_int,
+}
+
+pub struct HsCallback<A, E> {
+    pub cap: Capability,
+    pub mvar: *mut MVar,
+    pub result_slot: *mut *mut A,
+    pub error_slot: *mut *mut E,
+}
+
+impl<A, E> HsCallback<A, E> {
+    pub(crate) fn put_success(self, runtime: &Runtime, result: A)
+    where
+        A: RawPointerConverter<A>,
+    {
+        unsafe {
+            *self.result_slot = result.into_raw_pointer_mut();
+            *self.error_slot = std::ptr::null_mut();
+            runtime.put_mvar(self.cap, self.mvar);
+        }
+    }
+
+    pub(crate) fn put_failure(self, runtime: &Runtime, error: E)
+    where
+        E: RawPointerConverter<E>,
+    {
+        unsafe {
+            *self.error_slot = error.into_raw_pointer_mut();
+            *self.result_slot = std::ptr::null_mut();
+            runtime.put_mvar(self.cap, self.mvar);
+        }
+    }
+
+    pub(crate) fn put_result(self, runtime: &Runtime, result: Result<A, E>)
+    where
+        A: RawPointerConverter<A>,
+        E: RawPointerConverter<E>,
+    {
+        match result {
+            Ok(result) => self.put_success(runtime, result),
+            Err(error) => self.put_failure(runtime, error),
+        }
+    }
+}
+
+impl Runtime {
+    pub fn future_result_into_hs<F, T, E>(&self, callback: HsCallback<T, E>, fut: F)
+    where
+        F: Future<Output = Result<T, E>> + Send + 'static,
+        T: RawPointerConverter<T>,
+        E: RawPointerConverter<E>,
+    {
+        let handle = self.core.tokio_handle();
+        let _guard = handle.enter();
+        let result = handle.block_on(fut);
+        callback.put_result(self, result);
+    }
+
+    pub fn put_mvar(&self, capability: Capability, mvar: *mut MVar) {
+        (self.try_put_mvar)(capability, mvar);
+    }
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_drop_byte_array(str: *const CArray<u8>) {
+    unsafe {
+        drop(CArray::from_raw_pointer(str));
+    }
+}
+
+#[derive(Serialize)]
+pub struct CoreLogDef {
+    pub target: String,
+    pub message: String,
+    pub timestamp: SystemTime,
+    pub level: String,
+    pub fields: HashMap<String, serde_json::Value>,
+    pub span_contexts: Vec<String>,
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_runtime_fetch_logs(
+    runtime: *mut RuntimeRef,
+) -> *const CArray<CArray<u8>> {
+    let runtime = unsafe { &*runtime };
+    let logs = runtime.runtime.core.telemetry().fetch_buffered_logs();
+    let hs_logs: Vec<Vec<u8>> = logs
+        .iter()
+        .map(|log| {
+            let log = CoreLogDef {
+                target: log.target.clone(),
+                message: log.message.clone(),
+                timestamp: log.timestamp,
+                level: String::from(log.level.as_str()),
+                fields: log.fields.clone(),
+                span_contexts: log.span_contexts.clone(),
+            };
+            serde_json::to_vec(&log).expect("Failed to serialize log line")
+        })
+        .collect();
+    CArray::c_repr_of(hs_logs).unwrap().into_raw_pointer()
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_runtime_free_logs(logs: *const CArray<CArray<u8>>) {
+    unsafe {
+        drop(CArray::from_raw_pointer(logs));
+    }
+}
diff --git a/rust/src/worker.rs b/rust/src/worker.rs
new file mode 100644
--- /dev/null
+++ b/rust/src/worker.rs
@@ -0,0 +1,823 @@
+use ffi_convert::{AsRust, CArray, CDrop, CDropError, CReprOf, RawBorrow, RawPointerConverter};
+use libc::c_char;
+use prost::Message;
+use std::collections::{HashMap, HashSet};
+use std::str;
+use std::sync::Arc;
+use std::time::Duration;
+use temporal_sdk_core::replay::{HistoryForReplay, ReplayWorkerInput};
+use temporal_sdk_core_api::errors::{PollError, WorkflowErrorType};
+use temporal_sdk_core_api::Worker;
+use temporal_sdk_core_protos::coresdk::workflow_completion::WorkflowActivationCompletion;
+use temporal_sdk_core_protos::coresdk::{ActivityHeartbeat, ActivityTaskCompletion};
+use temporal_sdk_core_protos::temporal::api::history::v1::History;
+use tokio::sync::mpsc::{channel, Sender};
+use tokio_stream::wrappers::ReceiverStream;
+
+use crate::client;
+use crate::runtime::{self, Capability, HsCallback, MVar};
+use serde::{Deserialize, Serialize};
+
+pub struct WorkerRef {
+    worker: Option<Arc<temporal_sdk_core::Worker>>,
+    runtime: runtime::Runtime,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct WorkerConfig {
+    namespace: String,
+    task_queue: String,
+    build_id: String,
+    identity_override: Option<String>,
+    max_cached_workflows: usize,
+    max_outstanding_workflow_tasks: usize,
+    max_outstanding_activities: usize,
+    max_outstanding_local_activities: usize,
+    max_concurrent_workflow_task_polls: usize,
+    nonsticky_to_sticky_poll_ratio: f32,
+    max_concurrent_activity_task_polls: usize,
+    no_remote_activities: bool,
+    sticky_queue_schedule_to_start_timeout_millis: u64,
+    max_heartbeat_throttle_interval_millis: u64,
+    default_heartbeat_throttle_interval_millis: u64,
+    max_activities_per_second: Option<f64>,
+    max_task_queue_activities_per_second: Option<f64>,
+    graceful_shutdown_period_millis: u64,
+    nondeterminism_as_workflow_fail: bool,
+    nondeterminism_as_workflow_fail_for_types: Vec<String>,
+}
+
+impl TryFrom<WorkerConfig> for temporal_sdk_core::WorkerConfig {
+    type Error = WorkerError;
+
+    fn try_from(conf: WorkerConfig) -> Result<Self, WorkerError> {
+        temporal_sdk_core::WorkerConfigBuilder::default()
+            .namespace(conf.namespace)
+            .task_queue(conf.task_queue)
+            .worker_build_id(conf.build_id)
+            .client_identity_override(conf.identity_override)
+            .max_cached_workflows(conf.max_cached_workflows)
+            .max_outstanding_workflow_tasks(conf.max_outstanding_workflow_tasks)
+            .max_outstanding_activities(conf.max_outstanding_activities)
+            .max_outstanding_local_activities(conf.max_outstanding_local_activities)
+            .max_concurrent_wft_polls(conf.max_concurrent_workflow_task_polls)
+            .nonsticky_to_sticky_poll_ratio(conf.nonsticky_to_sticky_poll_ratio)
+            .max_concurrent_at_polls(conf.max_concurrent_activity_task_polls)
+            .no_remote_activities(conf.no_remote_activities)
+            .sticky_queue_schedule_to_start_timeout(Duration::from_millis(
+                conf.sticky_queue_schedule_to_start_timeout_millis,
+            ))
+            .max_heartbeat_throttle_interval(Duration::from_millis(
+                conf.max_heartbeat_throttle_interval_millis,
+            ))
+            .default_heartbeat_throttle_interval(Duration::from_millis(
+                conf.default_heartbeat_throttle_interval_millis,
+            ))
+            .max_worker_activities_per_second(conf.max_activities_per_second)
+            .max_task_queue_activities_per_second(conf.max_task_queue_activities_per_second)
+            // Even though grace period is optional, if it is not set then the
+            // auto-cancel-activity behavior of shutdown will not occur, so we
+            // always set it even if 0.
+            .graceful_shutdown_period(Duration::from_millis(conf.graceful_shutdown_period_millis))
+            .workflow_failure_errors(if conf.nondeterminism_as_workflow_fail {
+                HashSet::from([WorkflowErrorType::Nondeterminism])
+            } else {
+                HashSet::new()
+            })
+            .workflow_types_to_failure_errors(
+                conf.nondeterminism_as_workflow_fail_for_types
+                    .iter()
+                    .map(|s| {
+                        (
+                            s.to_owned(),
+                            HashSet::from([WorkflowErrorType::Nondeterminism]),
+                        )
+                    })
+                    .collect::<HashMap<String, HashSet<WorkflowErrorType>>>(),
+            )
+            .build()
+            .map_err(|err| WorkerError {
+                code: WorkerErrorCode::InvalidWorkerConfig,
+                message: format!("{}", err),
+            })
+    }
+}
+
+macro_rules! enter_sync {
+    ($runtime:expr) => {
+        if let Some(subscriber) = $runtime.core.telemetry().trace_subscriber() {
+            temporal_sdk_core::telemetry::set_trace_subscriber_for_current_thread(subscriber);
+        }
+        let _guard = $runtime.core.tokio_handle().enter();
+    };
+}
+
+#[repr(u8)]
+#[derive(Copy, Clone, Debug)]
+pub enum WorkerErrorCode {
+    SDKError = 1,
+    InitWorkerFailed = 2,
+    InitReplayWorkerFailed = 3,
+    InvalidProto = 4,
+    ReplayWorkerClosed = 5,
+    PollShutdownError = 6,
+    PollFailure = 7,
+    CompletionFailure = 8,
+    InvalidWorkerConfig = 9,
+}
+
+impl AsRust<WorkerErrorCode> for WorkerErrorCode {
+    fn as_rust(&self) -> Result<WorkerErrorCode, ffi_convert::AsRustError> {
+        Ok(*self)
+    }
+}
+
+impl CDrop for WorkerErrorCode {
+    fn do_drop(&mut self) -> Result<(), CDropError> {
+        Ok(())
+    }
+}
+
+impl CReprOf<WorkerErrorCode> for WorkerErrorCode {
+    fn c_repr_of(input: WorkerErrorCode) -> Result<WorkerErrorCode, ffi_convert::CReprOfError> {
+        Ok(input)
+    }
+}
+
+#[derive(Debug)]
+pub struct WorkerError {
+    code: WorkerErrorCode,
+    message: String,
+}
+
+#[repr(C)]
+#[derive(CReprOf, AsRust, RawPointerConverter, CDrop)]
+#[target_type(WorkerError)]
+pub struct CWorkerError {
+    code: WorkerErrorCode,
+    message: *const c_char,
+}
+
+struct FormattedError {
+    message: String,
+}
+
+#[repr(C)]
+#[derive(CReprOf, AsRust, RawPointerConverter, CDrop)]
+#[target_type(FormattedError)]
+pub struct CWorkerValidationError {
+    message: *const c_char,
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_drop_worker_validation_error(
+    err: *mut CWorkerValidationError,
+) {
+    unsafe { drop(CWorkerValidationError::from_raw_pointer_mut(err)) }
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_drop_worker_error(err: *mut CWorkerError) {
+    unsafe { drop(CWorkerError::from_raw_pointer_mut(err)) }
+}
+
+pub struct Unit {}
+#[repr(C)]
+#[derive(CReprOf, AsRust, RawPointerConverter, CDrop)]
+#[target_type(Unit)]
+pub struct CUnit {}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_drop_unit(unit: *mut CUnit) {
+    unsafe { drop(CUnit::from_raw_pointer_mut(unit)) }
+}
+
+fn new_worker(client: &client::ClientRef, config: WorkerConfig) -> Result<WorkerRef, WorkerError> {
+    enter_sync!(&client.runtime);
+    let config: temporal_sdk_core::WorkerConfig = config.try_into()?;
+    let worker = temporal_sdk_core::init_worker(
+        &client.runtime.core,
+        config,
+        client.retry_client.clone().into_inner(),
+    )
+    .map_err(|err| WorkerError {
+        code: WorkerErrorCode::InitWorkerFailed,
+        message: format!("Failed creating worker: {}", err),
+    })?;
+    Ok(WorkerRef {
+        worker: Some(Arc::new(worker)),
+        runtime: client.runtime.clone(),
+    })
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_drop_worker(worker: *mut WorkerRef) {
+    unsafe { drop(Box::from_raw(worker)) }
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_new_worker(
+    client: *mut client::ClientRef,
+    config: *const CArray<u8>,
+    result_slot: *mut *mut WorkerRef,
+    error_slot: *mut *mut CWorkerError,
+) {
+    let client_ref = unsafe { client.as_ref() }.expect("client is null");
+    let config_json = unsafe { CArray::raw_borrow(config).unwrap() };
+    let config = serde_json::from_slice(&config_json.as_rust().unwrap().clone()).map_err(|err| {
+        WorkerError {
+            code: WorkerErrorCode::InvalidWorkerConfig,
+            message: format!("{}", err),
+        }
+    });
+
+    match config {
+        Ok(config) => {
+            let result = new_worker(client_ref, config);
+            match result {
+                Ok(worker_ref) => {
+                    unsafe { *result_slot = Box::into_raw(Box::new(worker_ref)) };
+                }
+                Err(worker_error) => {
+                    eprintln!("Error: {:?}", worker_error);
+                    unsafe {
+                        *error_slot = CWorkerError::c_repr_of(worker_error)
+                            .unwrap()
+                            .into_raw_pointer_mut()
+                    };
+                }
+            }
+        }
+        Err(worker_error) => {
+            eprintln!("Error: {:?}", worker_error);
+            unsafe {
+                *error_slot = CWorkerError::c_repr_of(worker_error)
+                    .unwrap()
+                    .into_raw_pointer_mut()
+            };
+        }
+    }
+}
+
+fn new_replay_worker(
+    runtime_ref: &runtime::RuntimeRef,
+    config: WorkerConfig,
+) -> Result<(WorkerRef, HistoryPusher), WorkerError> {
+    enter_sync!(runtime_ref.runtime);
+    let config: temporal_sdk_core::WorkerConfig = config.try_into()?;
+    let (history_pusher, stream) = HistoryPusher::new(runtime_ref.runtime.clone());
+    let worker = WorkerRef {
+        worker: Some(Arc::new(
+            temporal_sdk_core::init_replay_worker(ReplayWorkerInput::new(config, stream)).map_err(
+                |err| WorkerError {
+                    code: WorkerErrorCode::InitReplayWorkerFailed,
+                    message: format!("Failed creating replay worker: {}", err),
+                },
+            )?,
+        )),
+        runtime: runtime_ref.runtime.clone(),
+    };
+
+    Ok((worker, history_pusher))
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_new_replay_worker(
+    runtime: *mut runtime::RuntimeRef,
+    config: *const CArray<u8>,
+    worker_slot: *mut *mut WorkerRef,
+    history_slot: *mut *mut HistoryPusher,
+    error_slot: *mut *mut CWorkerError,
+) {
+    let runtime_ref = unsafe { runtime.as_ref() }.expect("client is null");
+    let config_json = unsafe { CArray::raw_borrow(config).unwrap() };
+    let config =
+        serde_json::from_slice(&config_json.as_rust().unwrap()).map_err(|err| WorkerError {
+            code: WorkerErrorCode::InvalidWorkerConfig,
+            message: format!("{}", err),
+        });
+
+    match config {
+        Ok(config) => {
+            let result = new_replay_worker(runtime_ref, config);
+            match result {
+                Ok((worker_ref, history_pusher)) => unsafe {
+                    *worker_slot = Box::into_raw(Box::new(worker_ref));
+                    *history_slot = Box::into_raw(Box::new(history_pusher));
+                },
+                Err(worker_error) => {
+                    unsafe {
+                        *error_slot = CWorkerError::c_repr_of(worker_error)
+                            .unwrap()
+                            .into_raw_pointer_mut()
+                    };
+                }
+            }
+        }
+        Err(worker_error) => {
+            unsafe {
+                *error_slot = CWorkerError::c_repr_of(worker_error)
+                    .unwrap()
+                    .into_raw_pointer_mut()
+            };
+        }
+    }
+}
+
+impl WorkerRef {
+    fn poll_workflow_activation(&self, hs: HsCallback<CArray<u8>, CWorkerError>) {
+        let worker = self.worker.as_ref().unwrap().clone();
+        self.runtime.future_result_into_hs(hs, async move {
+            let bytes = match worker.poll_workflow_activation().await {
+                Ok(act) => Ok(act.encode_to_vec()),
+                Err(PollError::ShutDown) => Err(WorkerError {
+                    code: WorkerErrorCode::PollShutdownError,
+                    message: "Poll shutdown error".to_string(),
+                }),
+                Err(err) => Err(WorkerError {
+                    code: WorkerErrorCode::PollFailure,
+                    message: format!("{}", err),
+                }),
+            };
+            Ok(
+                CArray::c_repr_of(bytes.map_err(|err| CWorkerError::c_repr_of(err).unwrap())?)
+                    .unwrap(),
+            )
+        })
+    }
+
+    fn poll_activity_task(&self, hs: HsCallback<CArray<u8>, CWorkerError>) {
+        let worker = self.worker.as_ref().unwrap().clone();
+        self.runtime.future_result_into_hs(hs, async move {
+            let bytes = (match worker.poll_activity_task().await {
+                Ok(task) => Ok(task.encode_to_vec()),
+                Err(PollError::ShutDown) => Err(WorkerError {
+                    code: WorkerErrorCode::PollShutdownError,
+                    message: "Poll shutdown error".to_string(),
+                }),
+                Err(err) => Err(WorkerError {
+                    code: WorkerErrorCode::PollFailure,
+                    message: format!("Poll failure: {}", err),
+                }),
+            })
+            .map_err(|err| CWorkerError::c_repr_of(err).unwrap());
+            Ok(CArray::c_repr_of(bytes?).unwrap())
+        })
+    }
+
+    fn complete_workflow_activation(
+        &self,
+        hs: HsCallback<CUnit, CWorkerError>,
+        proto: &[u8],
+    ) {
+        let worker = self.worker.as_ref().unwrap().clone();
+        let completion = WorkflowActivationCompletion::decode(proto);
+        self.runtime.future_result_into_hs(hs, async move {
+            let completion = completion.map_err(|err| {
+                CWorkerError::c_repr_of(WorkerError {
+                    code: WorkerErrorCode::InvalidProto,
+                    message: format!("Invalid proto: {}", err),
+                })
+                .unwrap()
+            })?;
+            worker
+                .complete_workflow_activation(completion)
+                .await
+                .map_err(|err| {
+                    CWorkerError::c_repr_of(WorkerError {
+                        code: WorkerErrorCode::CompletionFailure,
+                        message: format!("{}", err),
+                    })
+                    .unwrap()
+                })?;
+            Ok(CUnit {})
+        })
+    }
+
+    fn complete_activity_task(&self, hs: HsCallback<CUnit, CWorkerError>, proto: &[u8]) {
+        let worker = self.worker.as_ref().unwrap().clone();
+        let completion = ActivityTaskCompletion::decode(proto);
+        self.runtime.future_result_into_hs(hs, async move {
+            let completion = completion.map_err(|err| {
+                CWorkerError::c_repr_of(WorkerError {
+                    code: WorkerErrorCode::InvalidProto,
+                    message: format!("{}", err),
+                })
+                .unwrap()
+            })?;
+            worker
+                .complete_activity_task(completion)
+                .await
+                .map_err(|err| {
+                    CWorkerError::c_repr_of(WorkerError {
+                        code: WorkerErrorCode::CompletionFailure,
+                        message: format!("{}", err),
+                    })
+                    .unwrap()
+                })?;
+            Ok(CUnit {})
+        })
+    }
+
+    fn record_activity_heartbeat(&self, proto: &[u8]) -> Result<(), WorkerError> {
+        enter_sync!(self.runtime);
+        let heartbeat = ActivityHeartbeat::decode(proto).map_err(|err| WorkerError {
+            code: WorkerErrorCode::InvalidProto,
+            message: format!("{}", err),
+        });
+
+        match self.worker.as_ref() {
+            None => Ok(()),
+            Some(worker) => {
+                worker.record_activity_heartbeat(heartbeat?);
+                // TODO return error
+                Ok(())
+            }
+        }
+    }
+
+    fn request_workflow_eviction(&self, run_id: &str) {
+        enter_sync!(self.runtime);
+        self.worker
+            .as_ref()
+            .unwrap()
+            .request_workflow_eviction(run_id);
+    }
+
+    fn initiate_shutdown(&self) {
+        let worker = self.worker.as_ref().unwrap().clone();
+        worker.initiate_shutdown();
+    }
+
+    fn finalize_shutdown(&mut self, hs: HsCallback<CUnit, CWorkerError>) {
+        // Take the worker out of the option and leave None. This should be the
+        // only reference remaining to the worker so try_unwrap will work.
+        let core_worker = match Arc::try_unwrap(self.worker.take().unwrap()) {
+            Ok(core_worker) => Ok(core_worker),
+            Err(arc) => Err(WorkerError {
+                code: WorkerErrorCode::SDKError,
+                message: format!(
+                    "Cannot finalize, expected 1 reference, got {}",
+                    Arc::strong_count(&arc)
+                ),
+            }),
+        };
+        self.runtime.clone().future_result_into_hs(hs, async move {
+            match core_worker {
+                Ok(worker) => {
+                    worker.finalize_shutdown().await;
+                    Ok(CUnit {})
+                }
+                Err(err) => Err(CWorkerError::c_repr_of(err).unwrap()),
+            }
+        })
+    }
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_validate_worker(
+    worker: *mut WorkerRef,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CWorkerValidationError,
+    result_slot: *mut *mut CUnit,
+) {
+    let worker = unsafe { &mut *worker };
+    let hs = HsCallback {
+        mvar,
+        cap,
+        error_slot,
+        result_slot,
+    };
+
+    let w = worker.worker.as_ref().unwrap().clone();
+    worker.runtime.future_result_into_hs(hs, async move {
+        let result = w.validate().await;
+        match result {
+            Ok(()) => Ok(CUnit {}),
+            Err(err) => Err(CWorkerValidationError::c_repr_of(FormattedError {
+                message: format!("{}", err),
+            })
+            .unwrap()),
+        }
+    })
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_poll_workflow_activation(
+    worker: *mut WorkerRef,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CWorkerError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let worker = unsafe { &*worker };
+    let hs = HsCallback {
+        mvar,
+        cap,
+        error_slot,
+        result_slot,
+    };
+    worker.poll_workflow_activation(hs)
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_poll_activity_task(
+    worker: *mut WorkerRef,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CWorkerError,
+    result_slot: *mut *mut CArray<u8>,
+) {
+    let worker = unsafe { &*worker };
+    let hs = HsCallback {
+        mvar,
+        cap,
+        error_slot,
+        result_slot,
+    };
+    worker.poll_activity_task(hs)
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_complete_workflow_activation(
+    worker: *mut WorkerRef,
+    proto: *const CArray<u8>,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CWorkerError,
+    result_slot: *mut *mut CUnit,
+) {
+    let worker = unsafe { &*worker };
+    let proto: &CArray<u8> = unsafe { CArray::raw_borrow(proto).unwrap() };
+    let proto: &[u8] = &proto.as_rust().unwrap().clone();
+    let hs = HsCallback {
+        mvar,
+        cap,
+        error_slot,
+        result_slot,
+    };
+    worker.complete_workflow_activation(hs, proto)
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_complete_activity_task(
+    worker: *mut WorkerRef,
+    proto: *const CArray<u8>,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CWorkerError,
+    result_slot: *mut *mut CUnit,
+) {
+    let worker = unsafe { &*worker };
+    let proto: &CArray<u8> = unsafe { CArray::raw_borrow(proto).unwrap() };
+    let proto: &[u8] = &proto.as_rust().unwrap().clone();
+    let hs = HsCallback {
+        mvar,
+        cap,
+        error_slot,
+        result_slot,
+    };
+    worker.complete_activity_task(hs, proto)
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_record_activity_heartbeat(
+    worker: *mut WorkerRef,
+    proto: *const CArray<u8>,
+    error_slot: *mut *mut CWorkerError,
+    result_slot: *mut *mut CUnit,
+) {
+    let worker = unsafe { &*worker };
+    let proto: &CArray<u8> = unsafe { CArray::raw_borrow(proto).unwrap() };
+    let proto: &[u8] = &proto.as_rust().unwrap().clone();
+    let result = worker.record_activity_heartbeat(proto);
+    match result {
+        Ok(_) => unsafe {
+            *error_slot = std::ptr::null_mut();
+            *result_slot = std::ptr::null_mut();
+        },
+        Err(err) => {
+            let err = CWorkerError::c_repr_of(err).unwrap();
+            unsafe {
+                *error_slot = err.into_raw_pointer_mut();
+                *result_slot = std::ptr::null_mut();
+            }
+        }
+    }
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_request_workflow_eviction(
+    worker: *mut WorkerRef,
+    run_id: *const CArray<u8>,
+) {
+    let worker = unsafe { &*worker };
+    let run_id: &CArray<u8> = unsafe { CArray::raw_borrow(run_id).unwrap() };
+    let run_id: &[u8] = &run_id.as_rust().unwrap().clone();
+    let run_id: &str = unsafe { str::from_utf8_unchecked(run_id) };
+    worker.request_workflow_eviction(run_id)
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_initiate_shutdown(worker: *mut WorkerRef) {
+    let worker = unsafe { &*worker };
+    worker.initiate_shutdown()
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_worker_finalize_shutdown(
+    worker: *mut WorkerRef,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CWorkerError,
+    result_slot: *mut *mut CUnit,
+) {
+    let worker = unsafe { &mut *worker };
+    let hs = HsCallback {
+        mvar,
+        cap,
+        error_slot,
+        result_slot,
+    };
+    worker.finalize_shutdown(hs)
+}
+
+pub struct HistoryPusher {
+    tx: Option<Sender<HistoryForReplay>>,
+    runtime: runtime::Runtime,
+}
+
+impl HistoryPusher {
+    fn new(runtime: runtime::Runtime) -> (Self, ReceiverStream<HistoryForReplay>) {
+        let (tx, rx) = channel(1);
+        (
+            Self {
+                tx: Some(tx),
+                runtime,
+            },
+            ReceiverStream::new(rx),
+        )
+    }
+}
+
+impl HistoryPusher {
+    fn push_history(
+        &self,
+        workflow_id: &str,
+        history_proto: &[u8],
+        hs: HsCallback<CUnit, CWorkerError>,
+    ) {
+        let history = History::decode(history_proto).map_err(|err| WorkerError {
+            code: WorkerErrorCode::InvalidProto,
+            message: format!("Invalid proto: {}", err),
+        });
+        let wfid = workflow_id.to_string();
+        let tx = if let Some(tx) = self.tx.as_ref() {
+            Ok(tx.clone())
+        } else {
+            Err(WorkerError {
+                code: WorkerErrorCode::ReplayWorkerClosed,
+                message: "Replay worker is no longer accepting new histories".to_string(),
+            })
+        };
+        // We accept this doesn't have logging/tracing
+        self.runtime.future_result_into_hs(hs, async move {
+            let history = history.map_err(|err| CWorkerError::c_repr_of(err).unwrap())?;
+            let tx = tx.map_err(|err| CWorkerError::c_repr_of(err).unwrap())?;
+
+            tx.send(HistoryForReplay::new(history, wfid))
+                .await
+                .map_err(|_| {
+                    CWorkerError::c_repr_of(WorkerError {
+                        code: WorkerErrorCode::SDKError,
+                        message: "Channel for history replay was dropped, this is an SDK bug.".to_string(),
+                    })
+                    .unwrap()
+                })?;
+            Ok(CUnit {})
+        })
+    }
+
+    fn close(&mut self) {
+        self.tx.take();
+    }
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell <-> Tokio FFI bridge invariants.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_history_pusher_push_history(
+    history_pusher: *mut HistoryPusher,
+    workflow_id: *const CArray<u8>,
+    history_proto: *const CArray<u8>,
+    mvar: *mut MVar,
+    cap: Capability,
+    error_slot: *mut *mut CWorkerError,
+    result_slot: *mut *mut CUnit,
+) {
+    let history_pusher = unsafe { &mut *history_pusher };
+    let workflow_id: &CArray<u8> = unsafe { CArray::raw_borrow(workflow_id).unwrap() };
+    let workflow_id = workflow_id.as_rust().unwrap().clone();
+    let workflow_id: &str = unsafe { str::from_utf8_unchecked(&workflow_id) };
+    let history_proto: &CArray<u8> = unsafe { CArray::raw_borrow(history_proto).unwrap() };
+    let history_proto: &[u8] = &history_proto.as_rust().unwrap().clone();
+    history_pusher.push_history(
+        workflow_id,
+        history_proto,
+        HsCallback {
+            mvar,
+            cap,
+            error_slot,
+            result_slot,
+        },
+    )
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+///
+/// The caller must ensure that the argument is a live pointer to a [`HistoryPusher`], typically from across the FFI
+/// boundary after having been constructed by [`hs_temporal_new_replay_worker`].
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_history_pusher_close(history_pusher: *mut HistoryPusher) {
+    let history_pusher = unsafe { &mut *history_pusher };
+    history_pusher.close()
+}
+
+// TODO: [publish-crate]
+/// # Safety
+///
+/// Haskell FFI bridge invariants.
+///
+/// The caller must ensure that the argument is a live pointer to a [`HistoryPusher`], typically from across the FFI
+/// boundary after having been constructed by [`hs_temporal_new_replay_worker`].
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn hs_temporal_history_pusher_drop(history_pusher: *mut HistoryPusher) {
+    let history_pusher = unsafe { Box::from_raw(history_pusher) };
+    drop(history_pusher)
+}
diff --git a/rust/temporal_bridge.h b/rust/temporal_bridge.h
new file mode 100644
--- /dev/null
+++ b/rust/temporal_bridge.h
@@ -0,0 +1,706 @@
+/* Generated with cbindgen:0.27.0 */
+
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+enum WorkerErrorCode {
+  SDKError = 1,
+  InitWorkerFailed = 2,
+  InitReplayWorkerFailed = 3,
+  InvalidProto = 4,
+  ReplayWorkerClosed = 5,
+  PollShutdownError = 6,
+  PollFailure = 7,
+  CompletionFailure = 8,
+  InvalidWorkerConfig = 9,
+};
+typedef uint8_t WorkerErrorCode;
+
+typedef struct ClientRef ClientRef;
+
+typedef struct EphemeralServerRef EphemeralServerRef;
+
+typedef struct HistoryPusher HistoryPusher;
+
+typedef struct RuntimeRef RuntimeRef;
+
+typedef struct WorkerRef WorkerRef;
+
+/**
+ * A utility type to represent arrays of the parametrized type.
+ * Note that the parametrized type should have a C-compatible representation.
+ *
+ * # Example
+ *
+ * ```
+ * use ffi_convert::{CReprOf, AsRust, CDrop, CArray};
+ * use libc::c_char;
+ *
+ * pub struct PizzaTopping {
+ *     pub ingredient: String,
+ * }
+ *
+ * #[derive(CDrop, CReprOf, AsRust)]
+ * #[target_type(PizzaTopping)]
+ * pub struct CPizzaTopping {
+ *     pub ingredient: *const c_char
+ * }
+ *
+ * let toppings = vec![
+ *         PizzaTopping { ingredient: "Cheese".to_string() },
+ *         PizzaTopping { ingredient: "Ham".to_string() } ];
+ *
+ * let ctoppings = CArray::<CPizzaTopping>::c_repr_of(toppings);
+ *
+ * ```
+ */
+typedef struct CArray_u8 {
+  const uint8_t *data_ptr;
+  uintptr_t size;
+} CArray_u8;
+
+typedef struct Capability {
+  int cap_num;
+} Capability;
+
+typedef struct MVar {
+  uint8_t _data[0];
+} MVar;
+
+/**
+ * A utility type to represent arrays of the parametrized type.
+ * Note that the parametrized type should have a C-compatible representation.
+ *
+ * # Example
+ *
+ * ```
+ * use ffi_convert::{CReprOf, AsRust, CDrop, CArray};
+ * use libc::c_char;
+ *
+ * pub struct PizzaTopping {
+ *     pub ingredient: String,
+ * }
+ *
+ * #[derive(CDrop, CReprOf, AsRust)]
+ * #[target_type(PizzaTopping)]
+ * pub struct CPizzaTopping {
+ *     pub ingredient: *const c_char
+ * }
+ *
+ * let toppings = vec![
+ *         PizzaTopping { ingredient: "Cheese".to_string() },
+ *         PizzaTopping { ingredient: "Ham".to_string() } ];
+ *
+ * let ctoppings = CArray::<CPizzaTopping>::c_repr_of(toppings);
+ *
+ * ```
+ */
+typedef struct CArray_CArray_u8 {
+  const struct CArray_u8 *data_ptr;
+  uintptr_t size;
+} CArray_CArray_u8;
+
+typedef struct CRPCError {
+  uint32_t code;
+  const char *message;
+  const struct CArray_u8 *details;
+} CRPCError;
+
+typedef struct HaskellHashMapEntries {
+  const uint8_t *key;
+  uintptr_t key_len;
+  const uint8_t *value;
+  uintptr_t value_len;
+  const struct HaskellHashMapEntries *next;
+} HaskellHashMapEntries;
+
+typedef struct RpcCall {
+  const struct CArray_u8 *req;
+  bool retry;
+  const struct HaskellHashMapEntries *metadata;
+  const uint64_t *timeout_millis;
+} RpcCall;
+
+typedef struct CWorkerError {
+  WorkerErrorCode code;
+  const char *message;
+} CWorkerError;
+
+typedef struct CUnit {
+
+} CUnit;
+
+typedef struct CWorkerValidationError {
+  const char *message;
+} CWorkerValidationError;
+
+struct RuntimeRef *hs_temporal_init_runtime(const struct CArray_u8 *telemetry_opts,
+                                            void (*try_put_mvar)(struct Capability, struct MVar*));
+
+void hs_temporal_free_runtime(struct RuntimeRef *runtime);
+
+void hs_temporal_drop_byte_array(const struct CArray_u8 *str);
+
+const struct CArray_CArray_u8 *hs_temporal_runtime_fetch_logs(struct RuntimeRef *runtime);
+
+void hs_temporal_runtime_free_logs(const struct CArray_CArray_u8 *logs);
+
+void hs_temporal_connect_client(const struct RuntimeRef *runtime_ref,
+                                const char *config_json,
+                                struct MVar *mvar,
+                                struct Capability cap,
+                                struct CArray_u8 **error_slot,
+                                struct ClientRef **result_slot);
+
+void hs_temporal_drop_client(struct ClientRef *client);
+
+void hs_temporal_drop_rpc_error(struct CRPCError *error);
+
+void hs_count_workflow_executions(struct ClientRef *client,
+                                  const struct RpcCall *c_call,
+                                  struct MVar *mvar,
+                                  struct Capability cap,
+                                  struct CRPCError **error_slot,
+                                  struct CArray_u8 **result_slot);
+
+void hs_create_schedule(struct ClientRef *client,
+                        const struct RpcCall *c_call,
+                        struct MVar *mvar,
+                        struct Capability cap,
+                        struct CRPCError **error_slot,
+                        struct CArray_u8 **result_slot);
+
+void hs_delete_schedule(struct ClientRef *client,
+                        const struct RpcCall *c_call,
+                        struct MVar *mvar,
+                        struct Capability cap,
+                        struct CRPCError **error_slot,
+                        struct CArray_u8 **result_slot);
+
+void hs_deprecate_namespace(struct ClientRef *client,
+                            const struct RpcCall *c_call,
+                            struct MVar *mvar,
+                            struct Capability cap,
+                            struct CRPCError **error_slot,
+                            struct CArray_u8 **result_slot);
+
+void hs_describe_namespace(struct ClientRef *client,
+                           const struct RpcCall *c_call,
+                           struct MVar *mvar,
+                           struct Capability cap,
+                           struct CRPCError **error_slot,
+                           struct CArray_u8 **result_slot);
+
+void hs_describe_schedule(struct ClientRef *client,
+                          const struct RpcCall *c_call,
+                          struct MVar *mvar,
+                          struct Capability cap,
+                          struct CRPCError **error_slot,
+                          struct CArray_u8 **result_slot);
+
+void hs_describe_task_queue(struct ClientRef *client,
+                            const struct RpcCall *c_call,
+                            struct MVar *mvar,
+                            struct Capability cap,
+                            struct CRPCError **error_slot,
+                            struct CArray_u8 **result_slot);
+
+void hs_describe_workflow_execution(struct ClientRef *client,
+                                    const struct RpcCall *c_call,
+                                    struct MVar *mvar,
+                                    struct Capability cap,
+                                    struct CRPCError **error_slot,
+                                    struct CArray_u8 **result_slot);
+
+void hs_get_cluster_info(struct ClientRef *client,
+                         const struct RpcCall *c_call,
+                         struct MVar *mvar,
+                         struct Capability cap,
+                         struct CRPCError **error_slot,
+                         struct CArray_u8 **result_slot);
+
+void hs_get_search_attributes(struct ClientRef *client,
+                              const struct RpcCall *c_call,
+                              struct MVar *mvar,
+                              struct Capability cap,
+                              struct CRPCError **error_slot,
+                              struct CArray_u8 **result_slot);
+
+void hs_get_system_info(struct ClientRef *client,
+                        const struct RpcCall *c_call,
+                        struct MVar *mvar,
+                        struct Capability cap,
+                        struct CRPCError **error_slot,
+                        struct CArray_u8 **result_slot);
+
+void hs_get_worker_build_id_compatibility(struct ClientRef *client,
+                                          const struct RpcCall *c_call,
+                                          struct MVar *mvar,
+                                          struct Capability cap,
+                                          struct CRPCError **error_slot,
+                                          struct CArray_u8 **result_slot);
+
+void hs_get_workflow_execution_history(struct ClientRef *client,
+                                       const struct RpcCall *c_call,
+                                       struct MVar *mvar,
+                                       struct Capability cap,
+                                       struct CRPCError **error_slot,
+                                       struct CArray_u8 **result_slot);
+
+void hs_get_workflow_execution_history_reverse(struct ClientRef *client,
+                                               const struct RpcCall *c_call,
+                                               struct MVar *mvar,
+                                               struct Capability cap,
+                                               struct CRPCError **error_slot,
+                                               struct CArray_u8 **result_slot);
+
+void hs_list_archived_workflow_executions(struct ClientRef *client,
+                                          const struct RpcCall *c_call,
+                                          struct MVar *mvar,
+                                          struct Capability cap,
+                                          struct CRPCError **error_slot,
+                                          struct CArray_u8 **result_slot);
+
+void hs_list_closed_workflow_executions(struct ClientRef *client,
+                                        const struct RpcCall *c_call,
+                                        struct MVar *mvar,
+                                        struct Capability cap,
+                                        struct CRPCError **error_slot,
+                                        struct CArray_u8 **result_slot);
+
+void hs_list_namespaces(struct ClientRef *client,
+                        const struct RpcCall *c_call,
+                        struct MVar *mvar,
+                        struct Capability cap,
+                        struct CRPCError **error_slot,
+                        struct CArray_u8 **result_slot);
+
+void hs_list_open_workflow_executions(struct ClientRef *client,
+                                      const struct RpcCall *c_call,
+                                      struct MVar *mvar,
+                                      struct Capability cap,
+                                      struct CRPCError **error_slot,
+                                      struct CArray_u8 **result_slot);
+
+void hs_list_schedule_matching_times(struct ClientRef *client,
+                                     const struct RpcCall *c_call,
+                                     struct MVar *mvar,
+                                     struct Capability cap,
+                                     struct CRPCError **error_slot,
+                                     struct CArray_u8 **result_slot);
+
+void hs_list_schedules(struct ClientRef *client,
+                       const struct RpcCall *c_call,
+                       struct MVar *mvar,
+                       struct Capability cap,
+                       struct CRPCError **error_slot,
+                       struct CArray_u8 **result_slot);
+
+void hs_list_task_queue_partitions(struct ClientRef *client,
+                                   const struct RpcCall *c_call,
+                                   struct MVar *mvar,
+                                   struct Capability cap,
+                                   struct CRPCError **error_slot,
+                                   struct CArray_u8 **result_slot);
+
+void hs_list_workflow_executions(struct ClientRef *client,
+                                 const struct RpcCall *c_call,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CRPCError **error_slot,
+                                 struct CArray_u8 **result_slot);
+
+void hs_patch_schedule(struct ClientRef *client,
+                       const struct RpcCall *c_call,
+                       struct MVar *mvar,
+                       struct Capability cap,
+                       struct CRPCError **error_slot,
+                       struct CArray_u8 **result_slot);
+
+void hs_poll_activity_task_queue(struct ClientRef *client,
+                                 const struct RpcCall *c_call,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CRPCError **error_slot,
+                                 struct CArray_u8 **result_slot);
+
+void hs_poll_workflow_execution_update(struct ClientRef *client,
+                                       const struct RpcCall *c_call,
+                                       struct MVar *mvar,
+                                       struct Capability cap,
+                                       struct CRPCError **error_slot,
+                                       struct CArray_u8 **result_slot);
+
+void hs_poll_workflow_task_queue(struct ClientRef *client,
+                                 const struct RpcCall *c_call,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CRPCError **error_slot,
+                                 struct CArray_u8 **result_slot);
+
+void hs_query_workflow(struct ClientRef *client,
+                       const struct RpcCall *c_call,
+                       struct MVar *mvar,
+                       struct Capability cap,
+                       struct CRPCError **error_slot,
+                       struct CArray_u8 **result_slot);
+
+void hs_record_activity_task_heartbeat(struct ClientRef *client,
+                                       const struct RpcCall *c_call,
+                                       struct MVar *mvar,
+                                       struct Capability cap,
+                                       struct CRPCError **error_slot,
+                                       struct CArray_u8 **result_slot);
+
+void hs_record_activity_task_heartbeat_by_id(struct ClientRef *client,
+                                             const struct RpcCall *c_call,
+                                             struct MVar *mvar,
+                                             struct Capability cap,
+                                             struct CRPCError **error_slot,
+                                             struct CArray_u8 **result_slot);
+
+void hs_register_namespace(struct ClientRef *client,
+                           const struct RpcCall *c_call,
+                           struct MVar *mvar,
+                           struct Capability cap,
+                           struct CRPCError **error_slot,
+                           struct CArray_u8 **result_slot);
+
+void hs_request_cancel_workflow_execution(struct ClientRef *client,
+                                          const struct RpcCall *c_call,
+                                          struct MVar *mvar,
+                                          struct Capability cap,
+                                          struct CRPCError **error_slot,
+                                          struct CArray_u8 **result_slot);
+
+void hs_reset_sticky_task_queue(struct ClientRef *client,
+                                const struct RpcCall *c_call,
+                                struct MVar *mvar,
+                                struct Capability cap,
+                                struct CRPCError **error_slot,
+                                struct CArray_u8 **result_slot);
+
+void hs_reset_workflow_execution(struct ClientRef *client,
+                                 const struct RpcCall *c_call,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CRPCError **error_slot,
+                                 struct CArray_u8 **result_slot);
+
+void hs_respond_activity_task_canceled(struct ClientRef *client,
+                                       const struct RpcCall *c_call,
+                                       struct MVar *mvar,
+                                       struct Capability cap,
+                                       struct CRPCError **error_slot,
+                                       struct CArray_u8 **result_slot);
+
+void hs_respond_activity_task_canceled_by_id(struct ClientRef *client,
+                                             const struct RpcCall *c_call,
+                                             struct MVar *mvar,
+                                             struct Capability cap,
+                                             struct CRPCError **error_slot,
+                                             struct CArray_u8 **result_slot);
+
+void hs_respond_activity_task_completed(struct ClientRef *client,
+                                        const struct RpcCall *c_call,
+                                        struct MVar *mvar,
+                                        struct Capability cap,
+                                        struct CRPCError **error_slot,
+                                        struct CArray_u8 **result_slot);
+
+void hs_respond_activity_task_completed_by_id(struct ClientRef *client,
+                                              const struct RpcCall *c_call,
+                                              struct MVar *mvar,
+                                              struct Capability cap,
+                                              struct CRPCError **error_slot,
+                                              struct CArray_u8 **result_slot);
+
+void hs_respond_activity_task_failed(struct ClientRef *client,
+                                     const struct RpcCall *c_call,
+                                     struct MVar *mvar,
+                                     struct Capability cap,
+                                     struct CRPCError **error_slot,
+                                     struct CArray_u8 **result_slot);
+
+void hs_respond_activity_task_failed_by_id(struct ClientRef *client,
+                                           const struct RpcCall *c_call,
+                                           struct MVar *mvar,
+                                           struct Capability cap,
+                                           struct CRPCError **error_slot,
+                                           struct CArray_u8 **result_slot);
+
+void hs_respond_query_task_completed(struct ClientRef *client,
+                                     const struct RpcCall *c_call,
+                                     struct MVar *mvar,
+                                     struct Capability cap,
+                                     struct CRPCError **error_slot,
+                                     struct CArray_u8 **result_slot);
+
+void hs_respond_workflow_task_completed(struct ClientRef *client,
+                                        const struct RpcCall *c_call,
+                                        struct MVar *mvar,
+                                        struct Capability cap,
+                                        struct CRPCError **error_slot,
+                                        struct CArray_u8 **result_slot);
+
+void hs_respond_workflow_task_failed(struct ClientRef *client,
+                                     const struct RpcCall *c_call,
+                                     struct MVar *mvar,
+                                     struct Capability cap,
+                                     struct CRPCError **error_slot,
+                                     struct CArray_u8 **result_slot);
+
+void hs_scan_workflow_executions(struct ClientRef *client,
+                                 const struct RpcCall *c_call,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CRPCError **error_slot,
+                                 struct CArray_u8 **result_slot);
+
+void hs_signal_with_start_workflow_execution(struct ClientRef *client,
+                                             const struct RpcCall *c_call,
+                                             struct MVar *mvar,
+                                             struct Capability cap,
+                                             struct CRPCError **error_slot,
+                                             struct CArray_u8 **result_slot);
+
+void hs_signal_workflow_execution(struct ClientRef *client,
+                                  const struct RpcCall *c_call,
+                                  struct MVar *mvar,
+                                  struct Capability cap,
+                                  struct CRPCError **error_slot,
+                                  struct CArray_u8 **result_slot);
+
+void hs_start_workflow_execution(struct ClientRef *client,
+                                 const struct RpcCall *c_call,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CRPCError **error_slot,
+                                 struct CArray_u8 **result_slot);
+
+void hs_terminate_workflow_execution(struct ClientRef *client,
+                                     const struct RpcCall *c_call,
+                                     struct MVar *mvar,
+                                     struct Capability cap,
+                                     struct CRPCError **error_slot,
+                                     struct CArray_u8 **result_slot);
+
+void hs_update_namespace(struct ClientRef *client,
+                         const struct RpcCall *c_call,
+                         struct MVar *mvar,
+                         struct Capability cap,
+                         struct CRPCError **error_slot,
+                         struct CArray_u8 **result_slot);
+
+void hs_update_schedule(struct ClientRef *client,
+                        const struct RpcCall *c_call,
+                        struct MVar *mvar,
+                        struct Capability cap,
+                        struct CRPCError **error_slot,
+                        struct CArray_u8 **result_slot);
+
+void hs_update_workflow_execution(struct ClientRef *client,
+                                  const struct RpcCall *c_call,
+                                  struct MVar *mvar,
+                                  struct Capability cap,
+                                  struct CRPCError **error_slot,
+                                  struct CArray_u8 **result_slot);
+
+void hs_update_worker_build_id_compatibility(struct ClientRef *client,
+                                             const struct RpcCall *c_call,
+                                             struct MVar *mvar,
+                                             struct Capability cap,
+                                             struct CRPCError **error_slot,
+                                             struct CArray_u8 **result_slot);
+
+void hs_get_current_time(struct ClientRef *client,
+                         const struct RpcCall *c_call,
+                         struct MVar *mvar,
+                         struct Capability cap,
+                         struct CRPCError **error_slot,
+                         struct CArray_u8 **result_slot);
+
+void hs_lock_time_skipping(struct ClientRef *client,
+                           const struct RpcCall *c_call,
+                           struct MVar *mvar,
+                           struct Capability cap,
+                           struct CRPCError **error_slot,
+                           struct CArray_u8 **result_slot);
+
+void hs_sleep_until(struct ClientRef *client,
+                    const struct RpcCall *c_call,
+                    struct MVar *mvar,
+                    struct Capability cap,
+                    struct CRPCError **error_slot,
+                    struct CArray_u8 **result_slot);
+
+void hs_sleep(struct ClientRef *client,
+              const struct RpcCall *c_call,
+              struct MVar *mvar,
+              struct Capability cap,
+              struct CRPCError **error_slot,
+              struct CArray_u8 **result_slot);
+
+void hs_unlock_time_skipping_with_sleep(struct ClientRef *client,
+                                        const struct RpcCall *c_call,
+                                        struct MVar *mvar,
+                                        struct Capability cap,
+                                        struct CRPCError **error_slot,
+                                        struct CArray_u8 **result_slot);
+
+void hs_unlock_time_skipping(struct ClientRef *client,
+                             const struct RpcCall *c_call,
+                             struct MVar *mvar,
+                             struct Capability cap,
+                             struct CRPCError **error_slot,
+                             struct CArray_u8 **result_slot);
+
+void hs_add_or_update_remote_cluster(struct ClientRef *client,
+                                     const struct RpcCall *c_call,
+                                     struct MVar *mvar,
+                                     struct Capability cap,
+                                     struct CRPCError **error_slot,
+                                     struct CArray_u8 **result_slot);
+
+void hs_add_search_attributes(struct ClientRef *client,
+                              const struct RpcCall *c_call,
+                              struct MVar *mvar,
+                              struct Capability cap,
+                              struct CRPCError **error_slot,
+                              struct CArray_u8 **result_slot);
+
+void hs_delete_namespace(struct ClientRef *client,
+                         const struct RpcCall *c_call,
+                         struct MVar *mvar,
+                         struct Capability cap,
+                         struct CRPCError **error_slot,
+                         struct CArray_u8 **result_slot);
+
+void hs_list_clusters(struct ClientRef *client,
+                      const struct RpcCall *c_call,
+                      struct MVar *mvar,
+                      struct Capability cap,
+                      struct CRPCError **error_slot,
+                      struct CArray_u8 **result_slot);
+
+void hs_list_search_attributes(struct ClientRef *client,
+                               const struct RpcCall *c_call,
+                               struct MVar *mvar,
+                               struct Capability cap,
+                               struct CRPCError **error_slot,
+                               struct CArray_u8 **result_slot);
+
+void hs_remove_remote_cluster(struct ClientRef *client,
+                              const struct RpcCall *c_call,
+                              struct MVar *mvar,
+                              struct Capability cap,
+                              struct CRPCError **error_slot,
+                              struct CArray_u8 **result_slot);
+
+void hs_remove_search_attributes(struct ClientRef *client,
+                                 const struct RpcCall *c_call,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CRPCError **error_slot,
+                                 struct CArray_u8 **result_slot);
+
+void hs_temporal_drop_worker_error(struct CWorkerError *err);
+
+void hs_temporal_drop_unit(struct CUnit *unit);
+
+void hs_temporal_drop_worker(struct WorkerRef *worker);
+
+void hs_temporal_new_worker(struct ClientRef *client,
+                            const struct CArray_u8 *config,
+                            struct WorkerRef **result_slot,
+                            struct CWorkerError **error_slot);
+
+void hs_temporal_new_replay_worker(struct RuntimeRef *runtime,
+                                   const struct CArray_u8 *config,
+                                   struct WorkerRef **worker_slot,
+                                   struct HistoryPusher **history_slot,
+                                   struct CWorkerError **error_slot);
+
+void hs_temporal_validate_worker(struct WorkerRef *worker,
+                                 struct MVar *mvar,
+                                 struct Capability cap,
+                                 struct CWorkerValidationError **error_slot,
+                                 struct CUnit **result_slot);
+
+void hs_temporal_worker_poll_workflow_activation(struct WorkerRef *worker,
+                                                 struct MVar *mvar,
+                                                 struct Capability cap,
+                                                 struct CWorkerError **error_slot,
+                                                 struct CArray_u8 **result_slot);
+
+void hs_temporal_worker_poll_activity_task(struct WorkerRef *worker,
+                                           struct MVar *mvar,
+                                           struct Capability cap,
+                                           struct CWorkerError **error_slot,
+                                           struct CArray_u8 **result_slot);
+
+void hs_temporal_worker_complete_workflow_activation(struct WorkerRef *worker,
+                                                     const struct CArray_u8 *proto,
+                                                     struct MVar *mvar,
+                                                     struct Capability cap,
+                                                     struct CWorkerError **error_slot,
+                                                     struct CUnit **result_slot);
+
+void hs_temporal_worker_complete_activity_task(struct WorkerRef *worker,
+                                               const struct CArray_u8 *proto,
+                                               struct MVar *mvar,
+                                               struct Capability cap,
+                                               struct CWorkerError **error_slot,
+                                               struct CUnit **result_slot);
+
+void hs_temporal_worker_record_activity_heartbeat(struct WorkerRef *worker,
+                                                  const struct CArray_u8 *proto,
+                                                  struct CWorkerError **error_slot,
+                                                  struct CUnit **result_slot);
+
+void hs_temporal_worker_request_workflow_eviction(struct WorkerRef *worker,
+                                                  const struct CArray_u8 *run_id);
+
+void hs_temporal_worker_initiate_shutdown(struct WorkerRef *worker);
+
+void hs_temporal_worker_finalize_shutdown(struct WorkerRef *worker,
+                                          struct MVar *mvar,
+                                          struct Capability cap,
+                                          struct CWorkerError **error_slot,
+                                          struct CUnit **result_slot);
+
+void hs_temporal_history_pusher_push_history(struct HistoryPusher *history_pusher,
+                                             const struct CArray_u8 *workflow_id,
+                                             const struct CArray_u8 *history_proto,
+                                             struct MVar *mvar,
+                                             struct Capability cap,
+                                             struct CWorkerError **error_slot,
+                                             struct CUnit **result_slot);
+
+void hs_temporal_history_pusher_close(struct HistoryPusher *history_pusher);
+
+void hs_temporal_history_pusher_drop(struct HistoryPusher *history_pusher);
+
+void hs_temporal_start_dev_server(struct RuntimeRef *runtime,
+                                  const char *json_string,
+                                  struct MVar *mvar,
+                                  struct Capability cap,
+                                  struct CArray_u8 **error_slot,
+                                  struct EphemeralServerRef **result_slot);
+
+void hs_temporal_shutdown_ephemeral_server(struct EphemeralServerRef *server,
+                                           struct MVar *mvar,
+                                           struct Capability cap,
+                                           struct CArray_u8 **error_slot,
+                                           struct CUnit **result_slot);
+
+void hs_temporal_start_test_server(struct RuntimeRef *runtime,
+                                   const char *json_string,
+                                   struct MVar *mvar,
+                                   struct Capability cap,
+                                   struct CArray_u8 **error_slot,
+                                   struct EphemeralServerRef **result_slot);
diff --git a/src/Temporal/Core/CTypes.hsc b/src/Temporal/Core/CTypes.hsc
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/CTypes.hsc
@@ -0,0 +1,329 @@
+#include "temporal_bridge.h"
+
+{-# LANGUAGE OverloadedRecordDot #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+module Temporal.Core.CTypes where
+import Control.Exception
+import Control.Concurrent.MVar (MVar)
+import Data.Aeson
+import Data.Aeson.TH
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as BS
+import Data.Map.Strict (Map)
+import qualified Data.Vector as V
+import Data.Text (Text)
+import Data.Text.Foreign
+import Data.Word
+import Foreign.C.String
+import Foreign.C.Types
+import Foreign.ForeignPtr
+import Foreign.Ptr
+import Foreign.Storable
+
+data CArray a = CArray
+  { dataPtr :: !(Ptr a)
+  , size :: !(#{type uintptr_t})
+  }
+  deriving (Show)
+
+cArrayToByteString :: CArray Word8 -> IO ByteString
+cArrayToByteString CArray{..} = BS.packCStringLen (castPtr dataPtr, fromIntegral size)
+
+cArrayToVector :: Storable a => (a -> IO b) -> CArray a -> IO (V.Vector b)
+cArrayToVector f CArray{..} = do
+  let len = fromIntegral size
+  V.generateM len $ \i -> do
+    x <- peekElemOff dataPtr i
+    f x
+
+cArrayToText :: CArray Word8 -> IO Text
+cArrayToText CArray{..} = do
+  let len = fromIntegral size
+  fromPtr dataPtr len
+
+instance Storable a => Storable (CArray a) where
+  sizeOf _ = #{size CArray_u8}
+  alignment _ = #{alignment CArray_u8}
+  peek ptr = do
+    dataPtr <- #{peek CArray_u8, data_ptr} ptr
+    size <- #{peek CArray_u8, size} ptr
+    pure CArray {..}
+  poke ptr CArray {..} = do
+    #{poke CArray_u8, data_ptr} ptr dataPtr
+    #{poke CArray_u8, size} ptr size
+
+foreign import ccall "&hs_temporal_drop_byte_array" rust_dropByteArray :: FinalizerPtr (CArray Word8)
+
+type TryPutMVarFFI = FunPtr (Ptr CInt -> Ptr (MVar ()) -> IO ())
+foreign import ccall "&hs_try_putmvar" tryPutMVarPtr :: TryPutMVarFFI
+
+-- | A handle to the Rust Tokio runtime and thread-pool.
+--
+-- You almost always should use the 'globalRuntime' value, which is initialized
+-- once for the entire process.
+newtype Runtime = Runtime (ForeignPtr Runtime)
+
+data Periodicity
+  = Periodicity
+    { seconds :: Word64
+    , nanoseconds :: Word32
+    }
+
+instance ToJSON Periodicity where
+  toJSON Periodicity{..} = object
+    [ "secs" .= seconds
+    , "nanos" .= nanoseconds
+    ]
+
+data TelemetryOptions
+  = OtelTelemetryOptions
+    { url :: Text
+    , headers :: Map Text Text
+    , metricPeriodicity :: Maybe Periodicity
+    , globalTags :: Map Text Text
+    }
+  | PrometheusTelemetryOptions
+    { socketAddr :: Text
+    , globalTags :: Map Text Text
+    , countersTotalSuffix :: Bool
+    , unitSuffix :: Bool
+    }
+  | NoTelemetry
+
+deriveToJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''TelemetryOptions
+
+foreign import ccall "hs_temporal_init_runtime" initRuntime :: Ptr (CArray Word8) -> TryPutMVarFFI -> IO (Ptr Runtime)
+foreign import ccall "&hs_temporal_free_runtime" freeRuntime :: FinalizerPtr Runtime
+
+data LogLevel
+  = Trace
+  | Debug
+  | Info
+  | Warn
+  | Error
+  deriving (Show)
+
+instance ToJSON LogLevel where
+  toJSON = \case
+    Trace -> "TRACE"
+    Debug -> "DEBUG"
+    Info -> "INFO"
+    Warn -> "WARN"
+    Temporal.Core.CTypes.Error -> "ERROR"
+
+instance FromJSON LogLevel where
+  parseJSON = withText "LogLevel" $ \case
+    "TRACE" -> pure Trace
+    "DEBUG" -> pure Debug
+    "INFO" -> pure Info
+    "WARN" -> pure Warn
+    "ERROR" -> pure Temporal.Core.CTypes.Error
+    other -> fail $ "Invalid log level: " <> show other
+
+data CoreLog = CoreLog
+  { target :: Text
+  , message :: Text
+  , timestamp :: Value
+  , level :: LogLevel
+  , fields :: Object
+  , spanContexts :: [Text]
+  } deriving (Show)
+
+deriveJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''CoreLog
+
+foreign import ccall "hs_temporal_runtime_fetch_logs" raw_fetchLogs :: Ptr Runtime -> IO (Ptr (CArray (CArray Word8)))
+foreign import ccall "hs_temporal_runtime_free_logs" raw_freeLogs :: Ptr (CArray (CArray Word8)) -> IO ()
+
+data RpcError = RpcError
+  { code :: Word32
+  , message :: Text
+  , details :: ByteString
+  }
+  deriving (Show)
+
+data CRPCError = CRPCError
+  { code :: Word32
+  , message :: CString
+  , details :: Ptr (CArray Word8)
+  }
+
+instance Storable CRPCError where
+  sizeOf _ = #{size CRPCError}
+  alignment _ = #{alignment CRPCError}
+  peek ptr = do
+    code <- #{peek CRPCError, code} ptr
+    message <- #{peek CRPCError, message} ptr
+    details <- #{peek CRPCError, details} ptr
+    pure CRPCError {..}
+  poke ptr CRPCError {..} = do
+    #{poke CRPCError, code} ptr code
+    #{poke CRPCError, message} ptr message
+    #{poke CRPCError, details} ptr details
+
+foreign import ccall "&hs_temporal_drop_rpc_error" rust_drop_rpc_error :: FinalizerPtr CRPCError
+
+peekCRPCError :: CRPCError -> IO RpcError
+peekCRPCError CRPCError{..} = do
+  message <- fromPtr0 $ castPtr message
+  details <- cArrayToByteString =<< peek details
+  pure RpcError{..}
+
+newtype CoreClient = CoreClient
+  { coreClientPtr :: ForeignPtr CoreClient
+  }
+
+-- TODO, this would be better as a pair of vectors instead of a linked list
+data HashMapEntries = HashMapEntries
+  { key :: CString
+  , keyLen :: CSize
+  , value :: CString
+  , valueLen :: CSize
+  , next :: Ptr HashMapEntries
+  }
+
+instance Storable HashMapEntries where
+  sizeOf _ = #{size HaskellHashMapEntries}
+  alignment _ = #{alignment HaskellHashMapEntries}
+  peek ptr = do
+    key <- #{peek HaskellHashMapEntries, key} ptr
+    keyLen <- #{peek HaskellHashMapEntries, key_len} ptr
+    value <- #{peek HaskellHashMapEntries, value} ptr
+    valueLen <- #{peek HaskellHashMapEntries, value_len} ptr
+    next <- #{peek HaskellHashMapEntries, next} ptr
+    pure HashMapEntries {..}
+  poke ptr HashMapEntries{..} = do
+    #{poke HaskellHashMapEntries, key} ptr key
+    #{poke HaskellHashMapEntries, key_len} ptr keyLen
+    #{poke HaskellHashMapEntries, value} ptr value
+    #{poke HaskellHashMapEntries, value_len} ptr valueLen
+    #{poke HaskellHashMapEntries, next} ptr next
+
+data CRpcCall = CRpcCall
+  { rpcCallReq :: Ptr (CArray Word8)
+  , rpcCallRetry :: Word8
+  , rpcCallMetadata :: Ptr HashMapEntries
+  , rpcCallTimeoutMillis :: Ptr Word64
+  }
+
+instance Storable CRpcCall where
+  sizeOf _ = #{size RpcCall}
+  alignment _ = #{alignment RpcCall}
+  peek ptr = do
+    rpcCallReq <- #{peek RpcCall, req} ptr
+    rpcCallRetry <- #{peek RpcCall, retry} ptr
+    rpcCallMetadata <- #{peek RpcCall, metadata} ptr
+    rpcCallTimeoutMillis <- #{peek RpcCall, timeout_millis} ptr
+    pure CRpcCall {..}
+  poke ptr CRpcCall {..} = do
+    #{poke RpcCall, req} ptr rpcCallReq
+    #{poke RpcCall, retry} ptr rpcCallRetry
+    #{poke RpcCall, metadata} ptr rpcCallMetadata
+    #{poke RpcCall, timeout_millis} ptr rpcCallTimeoutMillis
+
+
+data WorkerErrorCode
+  = SDKError
+  | InitWorkerFailed
+  | InitReplayWorkerFailed
+  | InvalidProto
+  | ReplayWorkerClosed
+  | PollShutdown
+  | PollFailure
+  | CompletionFailure
+  | InvalidWorkerConfig
+  | UnknownError Word8
+  deriving (Show, Eq)
+
+instance Storable WorkerErrorCode where
+  sizeOf _ = #{size WorkerErrorCode}
+  alignment _ = #{alignment WorkerErrorCode}
+  peek ptr = do
+    code <- peek (castPtr ptr :: Ptr #{type WorkerErrorCode})
+    case code of
+      #{const SDKError} -> pure SDKError
+      #{const InitWorkerFailed} -> pure InitWorkerFailed
+      #{const InitReplayWorkerFailed} -> pure InitReplayWorkerFailed
+      #{const InvalidProto} -> pure InvalidProto
+      #{const ReplayWorkerClosed} -> pure ReplayWorkerClosed
+      #{const PollShutdownError} -> pure PollShutdown
+      #{const PollFailure} -> pure PollFailure
+      #{const CompletionFailure} -> pure CompletionFailure
+      #{const InvalidWorkerConfig} -> pure InvalidWorkerConfig
+      _ -> pure $ UnknownError code
+  poke ptr_ code = case code of
+    SDKError -> poke ptr #{const SDKError}
+    InitWorkerFailed -> poke ptr #{const InitWorkerFailed}
+    InitReplayWorkerFailed -> poke ptr #{const InitReplayWorkerFailed}
+    InvalidProto -> poke ptr #{const InvalidProto}
+    ReplayWorkerClosed -> poke ptr #{const ReplayWorkerClosed}
+    PollShutdown -> poke ptr #{const PollShutdownError}
+    PollFailure -> poke ptr #{const PollFailure}
+    CompletionFailure -> poke ptr #{const CompletionFailure}
+    InvalidWorkerConfig -> poke ptr #{const InvalidWorkerConfig}
+    (UnknownError code) -> poke ptr code
+    where
+      ptr = (castPtr ptr_ :: Ptr #{type WorkerErrorCode})
+
+data CWorkerError = CWorkerError
+  { code :: WorkerErrorCode
+  , message :: CString
+  }
+
+instance Storable CWorkerError where
+  sizeOf _ = #{size CWorkerError}
+  alignment _ = #{alignment CWorkerError}
+  peek ptr = do
+    code <- #{peek CWorkerError, code} ptr
+    message <- #{peek CWorkerError, message} ptr
+    pure CWorkerError {..}
+  poke ptr CWorkerError {..} = do
+    #{poke CWorkerError, code} ptr code
+    #{poke CWorkerError, message} ptr message
+
+data WorkerError = WorkerError
+  { code :: WorkerErrorCode
+  , message :: Text
+  } deriving (Show, Eq)
+
+instance Exception WorkerError
+
+peekWorkerError :: CWorkerError -> IO WorkerError
+peekWorkerError CWorkerError{..} = do
+  message <- fromPtr0 $ castPtr message
+  pure WorkerError{..}
+
+data CWorkerValidationError = CWorkerValidationError
+  { message :: CString
+  }
+
+instance Storable CWorkerValidationError where
+  sizeOf _ = #{size CWorkerValidationError}
+  alignment _ = #{alignment CWorkerValidationError}
+  peek ptr = do
+    message <- #{peek CWorkerValidationError, message} ptr
+    pure CWorkerValidationError {..}
+
+data WorkerValidationError = WorkerValidationError
+  { message :: Text
+  } deriving (Show, Eq)
+
+instance Exception WorkerValidationError
+
+peekWorkerValidationError :: CWorkerValidationError -> IO WorkerValidationError
+peekWorkerValidationError CWorkerValidationError{..} = do
+  message <- fromPtr0 $ castPtr message
+  pure WorkerValidationError{..}
+
+foreign import ccall "hs_temporal_drop_worker_validation_error" rust_dropWorkerValidationError :: FinalizerPtr CWorkerValidationError
+
+foreign import ccall "&hs_temporal_drop_worker_error" rust_dropWorkerError :: FinalizerPtr CWorkerError
+
+data CUnit = CUnit
+
+foreign import ccall "hs_temporal_drop_unit" rust_dropUnitNow :: Ptr CUnit -> IO ()
+foreign import ccall "&hs_temporal_drop_unit" rust_dropUnit :: FinalizerPtr CUnit
diff --git a/src/Temporal/Core/Client.hs b/src/Temporal/Core/Client.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/Client.hs
@@ -0,0 +1,323 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Temporal.Core.Client (
+  -- * Connecting to the server
+  Client,
+  clientConfig,
+  connectClient,
+  defaultClientConfig,
+  closeClient,
+  clientRuntime,
+  touchClient,
+  CoreClient,
+  ClientConfig (..),
+  ClientTlsConfig (..),
+  ByteVector (..),
+  ClientRetryConfig (..),
+  APIKey (..),
+
+  -- * Making calls to the server
+
+  --
+  -- Generally you should not need to use 'call' directly, but instead should
+  -- use the supplied functions in 'Temporal.Core.Client.WorkflowService' and
+  -- other service modules.
+  --
+  -- For higher-level access, see the@@temporal-sdk@ package for a more
+  -- idiomatic Haskell API.
+  call,
+  RpcCall (..),
+  RpcError (..),
+  ClientError (..),
+
+  -- * Primitive access
+  CRpcCall,
+  TokioCall,
+  TokioResult,
+  PrimRpcCall,
+  -- | Use the underlying Rust client pointer
+  withClient,
+) where
+
+import Control.Concurrent
+import Control.Exception
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Monad.Logger
+import Data.Aeson
+import Data.Aeson.TH
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as BL
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Internal as BS
+import Data.HashMap.Strict (HashMap)
+import Data.ProtoLens.Encoding
+import Data.ProtoLens.Service.Types
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Vector.Storable as V
+import Data.Word
+import Foreign.C.String
+import Foreign.ForeignPtr
+import Foreign.Marshal
+import Foreign.Ptr
+import Foreign.Storable
+import Network.BSD
+import System.Posix.Process
+import Temporal.Core.CTypes
+import Temporal.Internal.FFI
+import Temporal.Runtime
+import UnliftIO (MonadUnliftIO, withRunInIO)
+import qualified UnliftIO
+
+
+foreign import ccall "hs_temporal_connect_client" raw_connectClient :: Ptr Runtime -> CString -> TokioCall (CArray Word8) CoreClient
+
+
+foreign import ccall "&hs_temporal_drop_client" raw_freeClient :: FinalizerPtr CoreClient
+
+
+data ClientConfig = ClientConfig
+  { targetUrl :: Text
+  , clientName :: Text
+  , clientVersion :: Text
+  , metadata :: HashMap Text Text
+  , identity :: Text
+  , tlsConfig :: Maybe ClientTlsConfig
+  , retryConfig :: Maybe ClientRetryConfig
+  , apiKey :: Maybe APIKey
+  }
+
+
+data ClientTlsConfig = ClientTlsConfig
+  { serverRootCaCert :: Maybe ByteVector
+  , domain :: Maybe Text
+  , clientCert :: Maybe ByteVector
+  , clientPrivateKey :: Maybe ByteVector
+  }
+
+
+data ClientRetryConfig = ClientRetryConfig
+  { initialIntervalMillis :: Word64
+  , randomizationFactor :: Double
+  , multiplier :: Double
+  , maxIntervalMillis :: Word64
+  , maxElapsedTimeMillis :: Maybe Word64
+  , maxRetries :: Word64
+  }
+
+
+newtype APIKey = APIKey {unAPIKey :: Text}
+
+
+instance ToJSON APIKey where
+  toJSON (APIKey text) = toJSON text
+
+
+instance FromJSON APIKey where
+  parseJSON = fmap APIKey . parseJSON
+
+
+{- | A client connection to the Temporal server.
+
+The client is thread-safe and can be shared across threads.
+
+Clients are expensive to create, so you should generally create one per
+process and share it across your application..
+
+The client doesn't have an explicit close method, but will be cleaned up
+when it is garbage collected.
+-}
+data Client = Client
+  { client :: MVar CoreClient
+  , runtime :: Runtime
+  , config :: ClientConfig
+  }
+
+
+clientConfig :: Client -> ClientConfig
+clientConfig = config
+
+
+clientRuntime :: Client -> Runtime
+clientRuntime = runtime
+
+
+withClient :: Client -> (Ptr CoreClient -> IO a) -> IO a
+withClient (Client cc r _) f =
+  withMVar cc $ \(CoreClient c) ->
+    withRuntime r $ \_ ->
+      withForeignPtr c f
+
+
+touchClient :: Client -> IO ()
+touchClient (Client cc _ _) = do
+  mcc <- tryReadMVar cc
+  case mcc of
+    Nothing -> return ()
+    Just (CoreClient c) -> touchForeignPtr c
+
+
+newtype ByteVector = ByteVector {byteVector :: ByteString}
+
+
+byteStringToVector :: BS.ByteString -> V.Vector Word8
+byteStringToVector bs = vec
+  where
+    vec = V.unsafeFromForeignPtr (castForeignPtr fptr) off len
+    (fptr, off, len) = BS.toForeignPtr bs
+
+
+vectorToByteString :: V.Vector Word8 -> BS.ByteString
+vectorToByteString vec = BS.fromForeignPtr (castForeignPtr fptr) off len
+  where
+    (fptr, off, len) = V.unsafeToForeignPtr vec
+
+
+instance ToJSON ByteVector where
+  toJSON = toJSON . byteStringToVector . byteVector
+
+
+instance FromJSON ByteVector where
+  parseJSON = fmap (ByteVector . vectorToByteString) . parseJSON
+
+
+deriveJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''ClientTlsConfig
+
+
+deriveJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''ClientRetryConfig
+
+
+deriveJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''ClientConfig
+
+
+data RpcCall a = RpcCall
+  { req :: a
+  , retry :: Bool
+  , metadata :: HashMap Text Text
+  , timeoutMillis :: Maybe Word64
+  }
+
+
+data ClientError
+  = ClientConnectionError Text
+  | ClientClosedError
+  deriving (Show)
+
+
+instance Exception ClientError
+
+
+defaultClientConfig :: ClientConfig
+defaultClientConfig =
+  ClientConfig
+    { targetUrl = "http://localhost:7233"
+    , clientName = "temporal-haskell"
+    , clientVersion = "0.0.1"
+    , metadata = mempty
+    , identity = ""
+    , tlsConfig = Nothing
+    , retryConfig = Nothing
+    , apiKey = Nothing
+    }
+
+
+defaultClientIdentity :: IO Text
+defaultClientIdentity = do
+  pid <- getProcessID
+  host <- getHostName
+  pure (T.pack $ show pid <> "@" <> host)
+
+
+{- | Connect to the Temporal server using a given runtime.
+
+Throws 'ClientConnectionError' if the connection fails.
+-}
+connectClient :: (MonadIO m, MonadLogger m, MonadUnliftIO m) => Runtime -> ClientConfig -> m Client
+connectClient rt conf = do
+  conf' <-
+    if identity conf == ""
+      then do
+        ident <- liftIO defaultClientIdentity
+        pure $ conf {identity = ident}
+      else pure conf
+
+  clientPtrSlot <- liftIO newEmptyMVar
+  withRunInIO $ \runInIO -> do
+    forkIO $ runInIO $ do
+      liftIO $ withRuntime rt $ \rtPtr -> BS.useAsCString (BL.toStrict $ encode conf') $ \confPtr -> do
+        let tryConnect =
+              makeTokioAsyncCall
+                (raw_connectClient rtPtr confPtr)
+                (Just rust_dropByteArray)
+                (Just raw_freeClient)
+            go attempt = do
+              result <- tryConnect
+              case result of
+                Left errFP -> do
+                  err <- withForeignPtr errFP $ peek >=> cArrayToText
+                  let err' = "Error connecting to Temporal server: " <> err
+                  runInIO $ $(logWarn) err'
+                  case retryConfig conf of
+                    Nothing -> liftIO $ putMVar clientPtrSlot (throw $ ClientConnectionError err')
+                    Just retryConf -> do
+                      let delayMillis = fromIntegral (initialIntervalMillis retryConf) * multiplier retryConf ^ attempt
+                          delayMicros = delayMillis * 1000
+                      if (fmap fromIntegral (maxElapsedTimeMillis retryConf) < Just delayMillis) || (maxRetries retryConf <= attempt)
+                        then liftIO $ putMVar clientPtrSlot (throw $ ClientConnectionError err')
+                        else do
+                          liftIO $ threadDelay $ round delayMicros
+                          go (attempt + 1)
+                Right client_ -> liftIO $ putMVar clientPtrSlot (CoreClient client_)
+        go 1
+  pure $ Client clientPtrSlot rt conf'
+
+
+reconnectClient :: (MonadIO m, MonadLogger m, MonadUnliftIO m) => Client -> m ()
+reconnectClient (Client clientPtrSlot rt conf) = UnliftIO.mask $ \restore -> do
+  (CoreClient clientPtr) <- liftIO $ takeMVar clientPtrSlot
+  (Client newClientPtr _ _) <- restore (connectClient rt conf) `UnliftIO.catch` (\c -> liftIO $ putMVar clientPtrSlot (throw (c :: ClientError)) >> throwIO c)
+  liftIO $ takeMVar newClientPtr >>= putMVar clientPtrSlot
+
+
+closeClient :: MonadIO m => Client -> m ()
+closeClient (Client clientPtrSlot _ _) = liftIO $ mask_ $ do
+  (CoreClient clientPtr) <- takeMVar clientPtrSlot
+  finalizeForeignPtr clientPtr
+  putMVar clientPtrSlot (throw ClientClosedError)
+
+
+type PrimRpcCall = Ptr CoreClient -> Ptr CRpcCall -> TokioCall CRPCError (CArray Word8)
+
+
+-- TODO how should we use mask here?
+call :: forall svc t. (HasMethodImpl svc t) => PrimRpcCall -> Client -> MethodInput svc t -> IO (Either RpcError (MethodOutput svc t))
+call f c req_ = withClient c $ \cPtr -> do
+  let msgBytes = encodeMessage req_
+  BS.useAsCStringLen msgBytes $ \(msgPtr, msgLen) -> do
+    alloca $ \cArrayPtr -> do
+      poke cArrayPtr (CArray msgPtr (fromIntegral msgLen))
+      let rpcCall =
+            CRpcCall
+              { rpcCallReq = castPtr cArrayPtr
+              , rpcCallRetry = if False then 0 else 1
+              , rpcCallMetadata = nullPtr
+              , rpcCallTimeoutMillis = nullPtr
+              }
+      alloca $ \rpcCallPtr -> do
+        poke rpcCallPtr rpcCall
+        result <-
+          makeTokioAsyncCall
+            (f cPtr rpcCallPtr)
+            (Just rust_drop_rpc_error)
+            (Just rust_dropByteArray)
+        case result of
+          Left err -> Left <$> withForeignPtr err (peek >=> peekCRPCError)
+          Right r -> Right . decodeMessageOrDie <$> withForeignPtr r (peek >=> cArrayToByteString)
diff --git a/src/Temporal/Core/Client/HealthService.hs b/src/Temporal/Core/Client/HealthService.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/Client/HealthService.hs
@@ -0,0 +1,9 @@
+module Temporal.Core.Client.HealthService where
+
+import Proto.Health.V1.Health
+import Temporal.Core.Client
+
+
+-- foreign import ccall "hs_health_check" hs_health_check :: PrimRpcCall
+-- -- healthCheck :: Client -> HealthCheckRequest -> IO (Either RpcError HealthCheckResponse)
+-- -- healthCheck = call @HealthService @"healthCheck" hs_health_check
diff --git a/src/Temporal/Core/Client/OperatorService.hs b/src/Temporal/Core/Client/OperatorService.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/Client/OperatorService.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeApplications #-}
+
+module Temporal.Core.Client.OperatorService where
+
+import Proto.Temporal.Api.Operatorservice.V1.RequestResponse
+import Proto.Temporal.Api.Operatorservice.V1.Service
+import Temporal.Core.Client
+import Temporal.Internal.FFI
+
+
+foreign import ccall "hs_add_or_update_remote_cluster" hs_add_or_update_remote_cluster :: PrimRpcCall
+
+
+addOrUpdateRemoteCluster :: Client -> AddOrUpdateRemoteClusterRequest -> IO (Either RpcError AddOrUpdateRemoteClusterResponse)
+addOrUpdateRemoteCluster = call @OperatorService @"addOrUpdateRemoteCluster" hs_add_or_update_remote_cluster
+
+
+foreign import ccall "hs_add_search_attributes" hs_add_search_attributes :: PrimRpcCall
+
+
+addSearchAttributes :: Client -> AddSearchAttributesRequest -> IO (Either RpcError AddSearchAttributesResponse)
+addSearchAttributes = call @OperatorService @"addSearchAttributes" hs_add_search_attributes
+
+
+foreign import ccall "hs_delete_namespace" hs_delete_namespace :: PrimRpcCall
+
+
+deleteNamespace :: Client -> DeleteNamespaceRequest -> IO (Either RpcError DeleteNamespaceResponse)
+deleteNamespace = call @OperatorService @"deleteNamespace" hs_delete_namespace
+
+
+foreign import ccall "hs_list_clusters" hs_list_clusters :: PrimRpcCall
+
+
+listClusters :: Client -> ListClustersRequest -> IO (Either RpcError ListClustersResponse)
+listClusters = call @OperatorService @"listClusters" hs_list_clusters
+
+
+foreign import ccall "hs_list_search_attributes" hs_list_search_attributes :: PrimRpcCall
+
+
+listSearchAttributes :: Client -> ListSearchAttributesRequest -> IO (Either RpcError ListSearchAttributesResponse)
+listSearchAttributes = call @OperatorService @"listSearchAttributes" hs_list_search_attributes
+
+
+foreign import ccall "hs_remove_remote_cluster" hs_remove_remote_cluster :: PrimRpcCall
+
+
+removeRemoteCluster :: Client -> RemoveRemoteClusterRequest -> IO (Either RpcError RemoveRemoteClusterResponse)
+removeRemoteCluster = call @OperatorService @"removeRemoteCluster" hs_remove_remote_cluster
+
+
+foreign import ccall "hs_remove_search_attributes" hs_remove_search_attributes :: PrimRpcCall
+
+
+removeSearchAttributes :: Client -> RemoveSearchAttributesRequest -> IO (Either RpcError RemoveSearchAttributesResponse)
+removeSearchAttributes = call @OperatorService @"removeSearchAttributes" hs_remove_search_attributes
diff --git a/src/Temporal/Core/Client/TestService.hs b/src/Temporal/Core/Client/TestService.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/Client/TestService.hs
@@ -0,0 +1,90 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeApplications #-}
+
+module Temporal.Core.Client.TestService where
+
+import Data.ProtoLens (Message (defMessage))
+import Proto.Temporal.Api.Testservice.V1.RequestResponse
+import Proto.Temporal.Api.Testservice.V1.Service
+import Temporal.Core.Client
+import Temporal.Internal.FFI
+
+
+foreign import ccall "hs_get_current_time" hs_get_current_time :: PrimRpcCall
+
+
+{- | GetCurrentTime returns the current Temporal Test Server time
+
+This time might not be equal to {@link System#currentTimeMillis()} due to time skipping.
+-}
+getCurrentTime :: Client -> IO (Either RpcError GetCurrentTimeResponse)
+getCurrentTime client = call @TestService @"getCurrentTime" hs_get_current_time client defMessage
+
+
+foreign import ccall "hs_lock_time_skipping" hs_lock_time_skipping :: PrimRpcCall
+
+
+{- | lockTimeSkipping increments Time Locking Counter by one.
+
+If Time Locking Counter is positive, time skipping is locked (disabled).
+When time skipping is disabled, the time in test server is moving normally, with a real time pace.
+Test Server is typically started with locked time skipping and Time Locking Counter = 1.
+
+LockTimeSkipping and UnlockTimeSkipping calls are counted.
+-}
+lockTimeSkipping :: Client -> LockTimeSkippingRequest -> IO (Either RpcError LockTimeSkippingResponse)
+lockTimeSkipping = call @TestService @"lockTimeSkipping" hs_lock_time_skipping
+
+
+foreign import ccall "hs_sleep_until" hs_sleep_until :: PrimRpcCall
+
+
+{- | This call returns only when the Test Server Time advances to the specified timestamp.
+
+If the current Test Server Time is beyond the specified timestamp, returns immediately.
+This is an EXPERIMENTAL API.
+-}
+sleepUntil :: Client -> SleepUntilRequest -> IO (Either RpcError SleepResponse)
+sleepUntil = call @TestService @"sleepUntil" hs_sleep_until
+
+
+foreign import ccall "hs_sleep" hs_sleep :: PrimRpcCall
+
+
+{- | This call returns only when the Test Server Time advances by the specified duration.
+This is an EXPERIMENTAL API.
+-}
+sleep :: Client -> SleepRequest -> IO (Either RpcError SleepResponse)
+sleep = call @TestService @"sleep" hs_sleep
+
+
+foreign import ccall "hs_unlock_time_skipping_with_sleep" hs_unlock_time_skipping_with_sleep :: PrimRpcCall
+
+
+{- | UnlockTimeSkippingWhileSleep decreases time locking counter by one and increases it back
+once the Test Server Time advances by the duration specified in the request.
+
+This call returns only when the Test Server Time advances by the specified duration.
+
+If it is called when Time Locking Counter is
+  - more than 1 and no other unlocks are coming in, rpc call will block for the specified duration, time will not be fast forwarded.
+  - 1, it will lead to fast forwarding of the time by the duration specified in the request and quick return of this rpc call.
+  - 0 will lead to rpc call failure same way as an unbalanced UnlockTimeSkipping.
+-}
+unlockTimeSkippingWithSleep :: Client -> SleepRequest -> IO (Either RpcError SleepResponse)
+unlockTimeSkippingWithSleep = call @TestService @"unlockTimeSkippingWithSleep" hs_unlock_time_skipping_with_sleep
+
+
+{- | UnlockTimeSkipping decrements Time Locking Counter by one.
+
+If the counter reaches 0, it unlocks time skipping and fast forwards time.
+LockTimeSkipping and UnlockTimeSkipping calls are counted. Calling UnlockTimeSkipping does not
+guarantee that time is going to be fast forwarded as another lock can be holding it.
+
+Time Locking Counter can't be negative, unbalanced calls to UnlockTimeSkipping will lead to rpc call failure
+-}
+foreign import ccall "hs_unlock_time_skipping" hs_unlock_time_skipping :: PrimRpcCall
+
+
+unlockTimeSkipping :: Client -> UnlockTimeSkippingRequest -> IO (Either RpcError UnlockTimeSkippingResponse)
+unlockTimeSkipping = call @TestService @"unlockTimeSkipping" hs_unlock_time_skipping
diff --git a/src/Temporal/Core/Client/WorkflowService.hs b/src/Temporal/Core/Client/WorkflowService.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/Client/WorkflowService.hs
@@ -0,0 +1,619 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TypeApplications #-}
+
+module Temporal.Core.Client.WorkflowService (
+  countWorkflowExecutions,
+  createSchedule,
+  deleteSchedule,
+  deprecateNamespace,
+  describeNamespace,
+  describeSchedule,
+  describeTaskQueue,
+  describeWorkflowExecution,
+  getClusterInfo,
+  getSearchAttributes,
+  getSystemInfo,
+  getWorkerBuildIdCompatibility,
+  getWorkflowExecutionHistory,
+  getWorkflowExecutionHistoryReverse,
+  listArchivedWorkflowExecutions,
+  listClosedWorkflowExecutions,
+  listNamespaces,
+  listOpenWorkflowExecutions,
+  listScheduleMatchingTimes,
+  listSchedules,
+  listTaskQueuePartitions,
+  listWorkflowExecutions,
+  patchSchedule,
+  pollActivityTaskQueue,
+  pollWorkflowExecutionUpdate,
+  pollWorkflowTaskQueue,
+  queryWorkflow,
+  recordActivityTaskHeartbeat,
+  recordActivityTaskHeartbeatById,
+  registerNamespace,
+  requestCancelWorkflowExecution,
+  resetStickyTaskQueue,
+  resetWorkflowExecution,
+  respondActivityTaskCanceled,
+  respondActivityTaskCanceledById,
+  respondActivityTaskCompleted,
+  respondActivityTaskCompletedById,
+  respondActivityTaskFailed,
+  respondActivityTaskFailedById,
+  respondQueryTaskCompleted,
+  respondWorkflowTaskCompleted,
+  respondWorkflowTaskFailed,
+  scanWorkflowExecutions,
+  signalWithStartWorkflowExecution,
+  signalWorkflowExecution,
+  startWorkflowExecution,
+  terminateWorkflowExecution,
+  updateNamespace,
+  updateSchedule,
+  updateWorkflowExecution,
+  updateWorkerBuildIdCompatibility,
+) where
+
+import Proto.Temporal.Api.Workflowservice.V1.RequestResponse
+import Proto.Temporal.Api.Workflowservice.V1.Service
+import Temporal.Core.Client
+
+
+-- TODO the way that the generated protobuf code is structured, it might be nicer to just have a single
+-- workflow service call that ensures the protobuf in question is the right one.
+foreign import ccall "hs_count_workflow_executions" hs_count_workflow_executions :: PrimRpcCall
+
+
+-- | CountWorkflowExecutions is a visibility API to count of workflow executions in a specific namespace.
+countWorkflowExecutions :: Client -> CountWorkflowExecutionsRequest -> IO (Either RpcError CountWorkflowExecutionsResponse)
+countWorkflowExecutions = call @WorkflowService @"countWorkflowExecutions" hs_count_workflow_executions
+
+
+foreign import ccall "hs_create_schedule" hs_create_schedule :: PrimRpcCall
+
+
+-- | Creates a new schedule.
+createSchedule :: Client -> CreateScheduleRequest -> IO (Either RpcError CreateScheduleResponse)
+createSchedule = call @WorkflowService @"createSchedule" hs_create_schedule
+
+
+foreign import ccall "hs_delete_schedule" hs_delete_schedule :: PrimRpcCall
+
+
+-- | Deletes a schedule, removing it from the system.
+deleteSchedule :: Client -> DeleteScheduleRequest -> IO (Either RpcError DeleteScheduleResponse)
+deleteSchedule = call @WorkflowService @"deleteSchedule" hs_delete_schedule
+
+
+foreign import ccall "hs_deprecate_namespace" hs_deprecate_namespace :: PrimRpcCall
+
+
+-- | Returns the schedule description and current state of an existing schedule.
+deprecateNamespace :: Client -> DeprecateNamespaceRequest -> IO (Either RpcError DeprecateNamespaceResponse)
+deprecateNamespace = call @WorkflowService @"deprecateNamespace" hs_deprecate_namespace
+
+
+foreign import ccall "hs_describe_namespace" hs_describe_namespace :: PrimRpcCall
+
+
+-- |  DescribeNamespace returns the information and configuration for a registered namespace.
+describeNamespace :: Client -> DescribeNamespaceRequest -> IO (Either RpcError DescribeNamespaceResponse)
+describeNamespace = call @WorkflowService @"describeNamespace" hs_describe_namespace
+
+
+foreign import ccall "hs_describe_schedule" hs_describe_schedule :: PrimRpcCall
+
+
+describeSchedule :: Client -> DescribeScheduleRequest -> IO (Either RpcError DescribeScheduleResponse)
+describeSchedule = call @WorkflowService @"describeSchedule" hs_describe_schedule
+
+
+foreign import ccall "hs_describe_task_queue" hs_describe_task_queue :: PrimRpcCall
+
+
+-- | DescribeTaskQueue returns information about the target task queue.
+describeTaskQueue :: Client -> DescribeTaskQueueRequest -> IO (Either RpcError DescribeTaskQueueResponse)
+describeTaskQueue = call @WorkflowService @"describeTaskQueue" hs_describe_task_queue
+
+
+foreign import ccall "hs_describe_workflow_execution" hs_describe_workflow_execution :: PrimRpcCall
+
+
+-- | DescribeWorkflowExecution returns information about the specified workflow execution.
+describeWorkflowExecution :: Client -> DescribeWorkflowExecutionRequest -> IO (Either RpcError DescribeWorkflowExecutionResponse)
+describeWorkflowExecution = call @WorkflowService @"describeWorkflowExecution" hs_describe_workflow_execution
+
+
+foreign import ccall "hs_get_cluster_info" hs_get_cluster_info :: PrimRpcCall
+
+
+-- | GetClusterInfo returns information about temporal cluster
+getClusterInfo :: Client -> GetClusterInfoRequest -> IO (Either RpcError GetClusterInfoResponse)
+getClusterInfo = call @WorkflowService @"getClusterInfo" hs_get_cluster_info
+
+
+foreign import ccall "hs_get_search_attributes" hs_get_search_attributes :: PrimRpcCall
+
+
+-- | GetSearchAttributes is a visibility API to get all legal keys that could be used in list APIs
+getSearchAttributes :: Client -> GetSearchAttributesRequest -> IO (Either RpcError GetSearchAttributesResponse)
+getSearchAttributes = call @WorkflowService @"getSearchAttributes" hs_get_search_attributes
+
+
+foreign import ccall "hs_get_system_info" hs_get_system_info :: PrimRpcCall
+
+
+-- | GetSystemInfo returns information about the system.
+getSystemInfo :: Client -> GetSystemInfoRequest -> IO (Either RpcError GetSystemInfoResponse)
+getSystemInfo = call @WorkflowService @"getSystemInfo" hs_get_system_info
+
+
+foreign import ccall "hs_get_worker_build_id_compatibility" hs_get_worker_build_id_compatibility :: PrimRpcCall
+
+
+-- | Fetches the worker build id versioning sets for some task queue and related metadata.
+getWorkerBuildIdCompatibility :: Client -> GetWorkerBuildIdCompatibilityRequest -> IO (Either RpcError GetWorkerBuildIdCompatibilityResponse)
+getWorkerBuildIdCompatibility = call @WorkflowService @"getWorkerBuildIdCompatibility" hs_get_worker_build_id_compatibility
+
+
+foreign import ccall "hs_get_workflow_execution_history" hs_get_workflow_execution_history :: PrimRpcCall
+
+
+{- |
+GetWorkflowExecutionHistory returns the history of specified workflow execution. Fails with
+`NotFound` if the specified workflow execution is unknown to the service.
+-}
+getWorkflowExecutionHistory :: Client -> GetWorkflowExecutionHistoryRequest -> IO (Either RpcError GetWorkflowExecutionHistoryResponse)
+getWorkflowExecutionHistory = call @WorkflowService @"getWorkflowExecutionHistory" hs_get_workflow_execution_history
+
+
+foreign import ccall "hs_get_workflow_execution_history_reverse" hs_get_workflow_execution_history_reverse :: PrimRpcCall
+
+
+{- |
+GetWorkflowExecutionHistoryReverse returns the history of specified workflow execution in reverse
+order (starting from last event). Fails with`NotFound` if the specified workflow execution is
+unknown to the service.
+-}
+getWorkflowExecutionHistoryReverse :: Client -> GetWorkflowExecutionHistoryReverseRequest -> IO (Either RpcError GetWorkflowExecutionHistoryReverseResponse)
+getWorkflowExecutionHistoryReverse = call @WorkflowService @"getWorkflowExecutionHistoryReverse" hs_get_workflow_execution_history_reverse
+
+
+foreign import ccall "hs_list_archived_workflow_executions" hs_list_archived_workflow_executions :: PrimRpcCall
+
+
+-- | ListArchivedWorkflowExecutions is a visibility API to list archived workflow executions in a specific namespace.
+listArchivedWorkflowExecutions :: Client -> ListArchivedWorkflowExecutionsRequest -> IO (Either RpcError ListArchivedWorkflowExecutionsResponse)
+listArchivedWorkflowExecutions = call @WorkflowService @"listArchivedWorkflowExecutions" hs_list_archived_workflow_executions
+
+
+foreign import ccall "hs_list_closed_workflow_executions" hs_list_closed_workflow_executions :: PrimRpcCall
+
+
+-- | ListClosedWorkflowExecutions is a visibility API to list the closed executions in a specific namespace.
+listClosedWorkflowExecutions :: Client -> ListClosedWorkflowExecutionsRequest -> IO (Either RpcError ListClosedWorkflowExecutionsResponse)
+listClosedWorkflowExecutions = call @WorkflowService @"listClosedWorkflowExecutions" hs_list_closed_workflow_executions
+
+
+foreign import ccall "hs_list_namespaces" hs_list_namespaces :: PrimRpcCall
+
+
+-- | ListNamespaces returns the information and configuration for all namespaces.
+listNamespaces :: Client -> ListNamespacesRequest -> IO (Either RpcError ListNamespacesResponse)
+listNamespaces = call @WorkflowService @"listNamespaces" hs_list_namespaces
+
+
+foreign import ccall "hs_list_open_workflow_executions" hs_list_open_workflow_executions :: PrimRpcCall
+
+
+-- | ListOpenWorkflowExecutions is a visibility API to list the open executions in a specific namespace.
+listOpenWorkflowExecutions :: Client -> ListOpenWorkflowExecutionsRequest -> IO (Either RpcError ListOpenWorkflowExecutionsResponse)
+listOpenWorkflowExecutions = call @WorkflowService @"listOpenWorkflowExecutions" hs_list_open_workflow_executions
+
+
+foreign import ccall "hs_list_schedule_matching_times" hs_list_schedule_matching_times :: PrimRpcCall
+
+
+-- | ListWorkflowExecutions is a visibility API to list workflow executions in a specific namespace.
+listScheduleMatchingTimes :: Client -> ListScheduleMatchingTimesRequest -> IO (Either RpcError ListScheduleMatchingTimesResponse)
+listScheduleMatchingTimes = call @WorkflowService @"listScheduleMatchingTimes" hs_list_schedule_matching_times
+
+
+foreign import ccall "hs_list_schedules" hs_list_schedules :: PrimRpcCall
+
+
+-- | Lists matching times within a range.
+listSchedules :: Client -> ListSchedulesRequest -> IO (Either RpcError ListSchedulesResponse)
+listSchedules = call @WorkflowService @"listSchedules" hs_list_schedules
+
+
+foreign import ccall "hs_list_task_queue_partitions" hs_list_task_queue_partitions :: PrimRpcCall
+
+
+listTaskQueuePartitions :: Client -> ListTaskQueuePartitionsRequest -> IO (Either RpcError ListTaskQueuePartitionsResponse)
+listTaskQueuePartitions = call @WorkflowService @"listTaskQueuePartitions" hs_list_task_queue_partitions
+
+
+foreign import ccall "hs_list_workflow_executions" hs_list_workflow_executions :: PrimRpcCall
+
+
+-- |  ListWorkflowExecutions is a visibility API to list workflow executions in a specific namespace.
+listWorkflowExecutions :: Client -> ListWorkflowExecutionsRequest -> IO (Either RpcError ListWorkflowExecutionsResponse)
+listWorkflowExecutions = call @WorkflowService @"listWorkflowExecutions" hs_list_workflow_executions
+
+
+foreign import ccall "hs_patch_schedule" hs_patch_schedule :: PrimRpcCall
+
+
+-- | Makes a specific change to a schedule or triggers an immediate action.
+patchSchedule :: Client -> PatchScheduleRequest -> IO (Either RpcError PatchScheduleResponse)
+patchSchedule = call @WorkflowService @"patchSchedule" hs_patch_schedule
+
+
+foreign import ccall "hs_poll_activity_task_queue" hs_poll_activity_task_queue :: PrimRpcCall
+
+
+{- |
+PollActivityTaskQueue is called by workers to process activity tasks from a specific task
+queue.
+
+The worker is expected to call one of the `RespondActivityTaskXXX` methods when it is done
+processing the task.
+
+An activity task is dispatched whenever a `SCHEDULE_ACTIVITY_TASK` command is produced during
+workflow execution. An in memory `ACTIVITY_TASK_STARTED` event is written to mutable state
+before the task is dispatched to the worker. The started event, and the final event
+(`ACTIVITY_TASK_COMPLETED` / `ACTIVITY_TASK_FAILED` / `ACTIVITY_TASK_TIMED_OUT`) will both be
+written permanently to Workflow execution history when Activity is finished. This is done to
+avoid writing many events in the case of a failure/retry loop.
+-}
+pollActivityTaskQueue :: Client -> PollActivityTaskQueueRequest -> IO (Either RpcError PollActivityTaskQueueResponse)
+pollActivityTaskQueue = call @WorkflowService @"pollActivityTaskQueue" hs_poll_activity_task_queue
+
+
+foreign import ccall "hs_poll_workflow_execution_update" hs_poll_workflow_execution_update :: PrimRpcCall
+
+
+pollWorkflowExecutionUpdate :: Client -> PollWorkflowExecutionUpdateRequest -> IO (Either RpcError PollWorkflowExecutionUpdateResponse)
+pollWorkflowExecutionUpdate = call @WorkflowService @"pollWorkflowExecutionUpdate" hs_poll_workflow_execution_update
+
+
+foreign import ccall "hs_poll_workflow_task_queue" hs_poll_workflow_task_queue :: PrimRpcCall
+
+
+{- |
+PollWorkflowTaskQueue is called by workers to make progress on workflows.
+
+A WorkflowTask is dispatched to callers for active workflow executions with pending workflow
+tasks. The worker is expected to call `RespondWorkflowTaskCompleted` when it is done
+processing the task. The service will create a `WorkflowTaskStarted` event in the history for
+this task before handing it to the worker.
+-}
+pollWorkflowTaskQueue :: Client -> PollWorkflowTaskQueueRequest -> IO (Either RpcError PollWorkflowTaskQueueResponse)
+pollWorkflowTaskQueue = call @WorkflowService @"pollWorkflowTaskQueue" hs_poll_workflow_task_queue
+
+
+foreign import ccall "hs_query_workflow" hs_query_workflow :: PrimRpcCall
+
+
+{- |
+QueryWorkflow requests a query be executed for a specified workflow execution.
+-}
+queryWorkflow :: Client -> QueryWorkflowRequest -> IO (Either RpcError QueryWorkflowResponse)
+queryWorkflow = call @WorkflowService @"queryWorkflow" hs_query_workflow
+
+
+foreign import ccall "hs_record_activity_task_heartbeat" hs_record_activity_task_heartbeat :: PrimRpcCall
+
+
+{- |
+RecordActivityTaskHeartbeat is optionally called by workers while they execute activities.
+
+If worker fails to heartbeat within the `heartbeat_timeout` interval for the activity task,
+then it will be marked as timed out and an `ACTIVITY_TASK_TIMED_OUT` event will be written to
+the workflow history. Calling `RecordActivityTaskHeartbeat` will fail with `NotFound` in
+such situations, in that event, the SDK should request cancellation of the activity.
+-}
+recordActivityTaskHeartbeat :: Client -> RecordActivityTaskHeartbeatRequest -> IO (Either RpcError RecordActivityTaskHeartbeatResponse)
+recordActivityTaskHeartbeat = call @WorkflowService @"recordActivityTaskHeartbeat" hs_record_activity_task_heartbeat
+
+
+foreign import ccall "hs_record_activity_task_heartbeat_by_id" hs_record_activity_task_heartbeat_by_id :: PrimRpcCall
+
+
+{- |
+See `RecordActivityTaskHeartbeat`. This version allows clients to record heartbeats by
+namespace/workflow id/activity id instead of task token.
+-}
+recordActivityTaskHeartbeatById :: Client -> RecordActivityTaskHeartbeatByIdRequest -> IO (Either RpcError RecordActivityTaskHeartbeatByIdResponse)
+recordActivityTaskHeartbeatById = call @WorkflowService @"recordActivityTaskHeartbeatById" hs_record_activity_task_heartbeat_by_id
+
+
+foreign import ccall "hs_register_namespace" hs_register_namespace :: PrimRpcCall
+
+
+{-
+RegisterNamespace creates a new namespace which can be used as a container for all resources.
+
+A Namespace is a top level entity within Temporal, and is used as a container for resources
+like workflow executions, task queues, etc. A Namespace acts as a sandbox and provides
+isolation for all resources within the namespace. All resources belongs to exactly one namespace.
+-}
+registerNamespace :: Client -> RegisterNamespaceRequest -> IO (Either RpcError RegisterNamespaceResponse)
+registerNamespace = call @WorkflowService @"registerNamespace" hs_register_namespace
+
+
+foreign import ccall "hs_request_cancel_workflow_execution" hs_request_cancel_workflow_execution :: PrimRpcCall
+
+
+{- |
+RequestCancelWorkflowExecution is called by workers when they want to request cancellation of
+a workflow execution.
+
+This results in a new `WORKFLOW_EXECUTION_CANCEL_REQUESTED` event being written to the
+workflow history and a new workflow task created for the workflow. It returns success if the requested
+workflow is already closed. It fails with 'NotFound' if the requested workflow doesn't exist.
+-}
+requestCancelWorkflowExecution :: Client -> RequestCancelWorkflowExecutionRequest -> IO (Either RpcError RequestCancelWorkflowExecutionResponse)
+requestCancelWorkflowExecution = call @WorkflowService @"requestCancelWorkflowExecution" hs_request_cancel_workflow_execution
+
+
+foreign import ccall "hs_reset_sticky_task_queue" hs_reset_sticky_task_queue :: PrimRpcCall
+
+
+{- |
+ResetStickyTaskQueue resets the sticky task queue related information in the mutable state of
+a given workflow. This is prudent for workers to perform if a workflow has been paged out of
+their cache.
+
+Things cleared are:
+1. StickyTaskQueue
+2. StickyScheduleToStartTimeout
+-}
+resetStickyTaskQueue :: Client -> ResetStickyTaskQueueRequest -> IO (Either RpcError ResetStickyTaskQueueResponse)
+resetStickyTaskQueue = call @WorkflowService @"resetStickyTaskQueue" hs_reset_sticky_task_queue
+
+
+foreign import ccall "hs_reset_workflow_execution" hs_reset_workflow_execution :: PrimRpcCall
+
+
+{- |
+ResetWorkflowExecution will reset an existing workflow execution to a specified
+`WORKFLOW_TASK_COMPLETED` event (exclusive). It will immediately terminate the current
+execution instance.
+-}
+
+-- TODO: Does exclusive here mean *just* the completed event, or also WFT started? Otherwise the task is doomed to time out?
+resetWorkflowExecution :: Client -> ResetWorkflowExecutionRequest -> IO (Either RpcError ResetWorkflowExecutionResponse)
+resetWorkflowExecution = call @WorkflowService @"resetWorkflowExecution" hs_reset_workflow_execution
+
+
+foreign import ccall "hs_respond_activity_task_canceled" hs_respond_activity_task_canceled :: PrimRpcCall
+
+
+{- |
+RespondActivityTaskFailed is called by workers when processing an activity task fails.
+
+This results in a new `ACTIVITY_TASK_CANCELED` event being written to the workflow history
+and a new workflow task created for the workflow. Fails with `NotFound` if the task token is
+no longer valid due to activity timeout, already being completed, or never having existed.
+-}
+respondActivityTaskCanceled :: Client -> RespondActivityTaskCanceledRequest -> IO (Either RpcError RespondActivityTaskCanceledResponse)
+respondActivityTaskCanceled = call @WorkflowService @"respondActivityTaskCanceled" hs_respond_activity_task_canceled
+
+
+foreign import ccall "hs_respond_activity_task_canceled_by_id" hs_respond_activity_task_canceled_by_id :: PrimRpcCall
+
+
+{- |
+See `RecordActivityTaskCanceled`. This version allows clients to record failures by
+namespace/workflow id/activity id instead of task token.
+-}
+respondActivityTaskCanceledById :: Client -> RespondActivityTaskCanceledByIdRequest -> IO (Either RpcError RespondActivityTaskCanceledByIdResponse)
+respondActivityTaskCanceledById = call @WorkflowService @"respondActivityTaskCanceledById" hs_respond_activity_task_canceled_by_id
+
+
+foreign import ccall "hs_respond_activity_task_completed" hs_respond_activity_task_completed :: PrimRpcCall
+
+
+{- |
+RespondActivityTaskCompleted is called by workers when they successfully complete an activity
+task.
+
+This results in a new `ACTIVITY_TASK_COMPLETED` event being written to the workflow history
+and a new workflow task created for the workflow. Fails with `NotFound` if the task token is
+no longer valid due to activity timeout, already being completed, or never having existed.
+-}
+respondActivityTaskCompleted :: Client -> RespondActivityTaskCompletedRequest -> IO (Either RpcError RespondActivityTaskCompletedResponse)
+respondActivityTaskCompleted = call @WorkflowService @"respondActivityTaskCompleted" hs_respond_activity_task_completed
+
+
+foreign import ccall "hs_respond_activity_task_completed_by_id" hs_respond_activity_task_completed_by_id :: PrimRpcCall
+
+
+{- |
+See `RecordActivityTaskCompleted`. This version allows clients to record completions by
+namespace/workflow id/activity id instead of task token.
+-}
+respondActivityTaskCompletedById :: Client -> RespondActivityTaskCompletedByIdRequest -> IO (Either RpcError RespondActivityTaskCompletedByIdResponse)
+respondActivityTaskCompletedById = call @WorkflowService @"respondActivityTaskCompletedById" hs_respond_activity_task_completed_by_id
+
+
+foreign import ccall "hs_respond_activity_task_failed" hs_respond_activity_task_failed :: PrimRpcCall
+
+
+{- |
+RespondActivityTaskFailed is called by workers when processing an activity task fails.
+
+This results in a new `ACTIVITY_TASK_FAILED` event being written to the workflow history and
+a new workflow task created for the workflow. Fails with `NotFound` if the task token is no
+longer valid due to activity timeout, already being completed, or never having existed.
+-}
+respondActivityTaskFailed :: Client -> RespondActivityTaskFailedRequest -> IO (Either RpcError RespondActivityTaskFailedResponse)
+respondActivityTaskFailed = call @WorkflowService @"respondActivityTaskFailed" hs_respond_activity_task_failed
+
+
+foreign import ccall "hs_respond_activity_task_failed_by_id" hs_respond_activity_task_failed_by_id :: PrimRpcCall
+
+
+{- |
+See `RecordActivityTaskCompleted`. This version allows clients to record completions by
+namespace/workflow id/activity id instead of task token.
+-}
+respondActivityTaskFailedById :: Client -> RespondActivityTaskFailedByIdRequest -> IO (Either RpcError RespondActivityTaskFailedByIdResponse)
+respondActivityTaskFailedById = call @WorkflowService @"respondActivityTaskFailedById" hs_respond_activity_task_failed_by_id
+
+
+foreign import ccall "hs_respond_query_task_completed" hs_respond_query_task_completed :: PrimRpcCall
+
+
+{- |
+RespondQueryTaskCompleted is called by workers to complete queries which were delivered on
+the `query` (not `queries`) field of a `PollWorkflowTaskQueueResponse`.
+
+Completing the query will unblock the corresponding client call to `QueryWorkflow` and return
+the query result a response.
+-}
+respondQueryTaskCompleted :: Client -> RespondQueryTaskCompletedRequest -> IO (Either RpcError RespondQueryTaskCompletedResponse)
+respondQueryTaskCompleted = call @WorkflowService @"respondQueryTaskCompleted" hs_respond_query_task_completed
+
+
+foreign import ccall "hs_respond_workflow_task_completed" hs_respond_workflow_task_completed :: PrimRpcCall
+
+
+{- |
+RespondWorkflowTaskCompleted is called by workers to successfully complete workflow tasks
+they received from `PollWorkflowTaskQueue`.
+
+Completing a WorkflowTask will write a `WORKFLOW_TASK_COMPLETED` event to the workflow's
+history, along with events corresponding to whatever commands the SDK generated while
+executing the task (ex timer started, activity task scheduled, etc).
+-}
+respondWorkflowTaskCompleted :: Client -> RespondWorkflowTaskCompletedRequest -> IO (Either RpcError RespondWorkflowTaskCompletedResponse)
+respondWorkflowTaskCompleted = call @WorkflowService @"respondWorkflowTaskCompleted" hs_respond_workflow_task_completed
+
+
+foreign import ccall "hs_respond_workflow_task_failed" hs_respond_workflow_task_failed :: PrimRpcCall
+
+
+{- |
+RespondWorkflowTaskFailed is called by workers to indicate the processing of a workflow task
+failed.
+
+This results in a `WORKFLOW_TASK_FAILED` event written to the history, and a new workflow
+task will be scheduled. This API can be used to report unhandled failures resulting from
+applying the workflow task.
+
+Temporal will only append first WorkflowTaskFailed event to the history of workflow execution
+for consecutive failures.
+-}
+respondWorkflowTaskFailed :: Client -> RespondWorkflowTaskFailedRequest -> IO (Either RpcError RespondWorkflowTaskFailedResponse)
+respondWorkflowTaskFailed = call @WorkflowService @"respondWorkflowTaskFailed" hs_respond_workflow_task_failed
+
+
+foreign import ccall "hs_scan_workflow_executions" hs_scan_workflow_executions :: PrimRpcCall
+
+
+-- | ScanWorkflowExecutions is a visibility API to list large amount of workflow executions in a specific namespace without order.
+scanWorkflowExecutions :: Client -> ScanWorkflowExecutionsRequest -> IO (Either RpcError ScanWorkflowExecutionsResponse)
+scanWorkflowExecutions = call @WorkflowService @"scanWorkflowExecutions" hs_scan_workflow_executions
+
+
+foreign import ccall "hs_signal_with_start_workflow_execution" hs_signal_with_start_workflow_execution :: PrimRpcCall
+
+
+{- |
+SignalWithStartWorkflowExecution is used to ensure a signal is sent to a workflow, even if
+it isn't yet started.
+
+If the workflow is running, a `WORKFLOW_EXECUTION_SIGNALED` event is recorded in the history
+and a workflow task is generated.
+
+If the workflow is not running or not found, then the workflow is created with
+`WORKFLOW_EXECUTION_STARTED` and `WORKFLOW_EXECUTION_SIGNALED` events in its history, and a
+workflow task is generated.
+-}
+signalWithStartWorkflowExecution :: Client -> SignalWithStartWorkflowExecutionRequest -> IO (Either RpcError SignalWithStartWorkflowExecutionResponse)
+signalWithStartWorkflowExecution = call @WorkflowService @"signalWithStartWorkflowExecution" hs_signal_with_start_workflow_execution
+
+
+foreign import ccall "hs_signal_workflow_execution" hs_signal_workflow_execution :: PrimRpcCall
+
+
+{- |
+SignalWorkflowExecution is used to send a signal to a running workflow execution.
+
+This results in a `WORKFLOW_EXECUTION_SIGNALED` event recorded in the history and a workflow
+task being created for the execution.
+-}
+signalWorkflowExecution :: Client -> SignalWorkflowExecutionRequest -> IO (Either RpcError SignalWorkflowExecutionResponse)
+signalWorkflowExecution = call @WorkflowService @"signalWorkflowExecution" hs_signal_workflow_execution
+
+
+foreign import ccall "hs_start_workflow_execution" hs_start_workflow_execution :: PrimRpcCall
+
+
+{-
+  Starts a new workflow execution.
+
+  It will create the execution with a `WORKFLOW_EXECUTION_STARTED` event in its history and
+  also schedule the first workflow task. Returns `WorkflowExecutionAlreadyStarted`, if an
+  instance already exists with same workflow id.
+-}
+startWorkflowExecution :: Client -> StartWorkflowExecutionRequest -> IO (Either RpcError StartWorkflowExecutionResponse)
+startWorkflowExecution = call @WorkflowService @"startWorkflowExecution" hs_start_workflow_execution
+
+
+foreign import ccall "hs_terminate_workflow_execution" hs_terminate_workflow_execution :: PrimRpcCall
+
+
+{- |
+terminates an existing workflow execution by recording a
+`WORKFLOW_EXECUTION_TERMINATED` event in the history and immediately terminating the
+execution instance.
+-}
+terminateWorkflowExecution :: Client -> TerminateWorkflowExecutionRequest -> IO (Either RpcError TerminateWorkflowExecutionResponse)
+terminateWorkflowExecution = call @WorkflowService @"terminateWorkflowExecution" hs_terminate_workflow_execution
+
+
+foreign import ccall "hs_update_namespace" hs_update_namespace :: PrimRpcCall
+
+
+{- | UpdateNamespace is used to update the information and configuration of a registered
+namespace.
+-}
+updateNamespace :: Client -> UpdateNamespaceRequest -> IO (Either RpcError UpdateNamespaceResponse)
+updateNamespace = call @WorkflowService @"updateNamespace" hs_update_namespace
+
+
+foreign import ccall "hs_update_schedule" hs_update_schedule :: PrimRpcCall
+
+
+-- |  Changes the configuration or state of an existing schedule.
+updateSchedule :: Client -> UpdateScheduleRequest -> IO (Either RpcError UpdateScheduleResponse)
+updateSchedule = call @WorkflowService @"updateSchedule" hs_update_schedule
+
+
+foreign import ccall "hs_update_workflow_execution" hs_update_workflow_execution :: PrimRpcCall
+
+
+-- | Invokes the specified update function on user workflow code.
+updateWorkflowExecution :: Client -> UpdateWorkflowExecutionRequest -> IO (Either RpcError UpdateWorkflowExecutionResponse)
+updateWorkflowExecution = call @WorkflowService @"updateWorkflowExecution" hs_update_workflow_execution
+
+
+foreign import ccall "hs_update_worker_build_id_compatibility" hs_update_worker_build_id_compatibility :: PrimRpcCall
+
+
+{- |
+Allows users to specify sets of worker build id versions on a per task queue basis. Versions
+are ordered, and may be either compatible with some extant version, or a new incompatible
+version, forming sets of ids which are incompatible with each other, but whose contained
+members are compatible with one another.
+-}
+updateWorkerBuildIdCompatibility :: Client -> UpdateWorkerBuildIdCompatibilityRequest -> IO (Either RpcError UpdateWorkerBuildIdCompatibilityResponse)
+updateWorkerBuildIdCompatibility = call @WorkflowService @"updateWorkerBuildIdCompatibility" hs_update_worker_build_id_compatibility
diff --git a/src/Temporal/Core/EphemeralServer.hs b/src/Temporal/Core/EphemeralServer.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/EphemeralServer.hs
@@ -0,0 +1,173 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Temporal.Core.EphemeralServer where
+
+import Control.Monad
+import Data.Aeson
+import Data.Aeson.TH
+import Data.ByteString (ByteString, useAsCString)
+import qualified Data.ByteString.Lazy as BL
+import Data.Word
+import Foreign.C.String hiding (withCString)
+import Foreign.ForeignPtr
+import Foreign.Ptr
+import Foreign.Storable
+import Temporal.Core.CTypes
+import Temporal.Internal.FFI
+import Temporal.Runtime
+
+
+data SDKDefault = SDKDefault {sdkName :: String, sdkVersion :: String}
+
+
+data EphemeralExeVersion
+  = -- | Use a default version for the given SDK name and version.
+    Default SDKDefault
+  | -- | Specific version.
+    Fixed String
+
+
+instance ToJSON EphemeralExeVersion where
+  toJSON (Default (SDKDefault name version)) =
+    object
+      [ "type" .= String "SDKDefault"
+      , "contents"
+          .= object
+            [ "sdk_name" .= name
+            , "sdk_version" .= version
+            ]
+      ]
+  toJSON (Fixed version) =
+    object
+      [ "type" .= String "Fixed"
+      , "contents" .= version
+      ]
+
+
+data EphemeralExe
+  = -- | Existing path on the filesystem for the executable.
+    ExistingPath FilePath
+  | -- | Download the executable if not already there.
+    CachedDownload EphemeralExeVersion (Maybe FilePath) (Maybe Word64)
+
+
+instance ToJSON EphemeralExe where
+  toJSON (ExistingPath path) =
+    object
+      [ "type" .= String "ExistingPath"
+      , "contents" .= path
+      ]
+  toJSON (CachedDownload version destDir ttl) =
+    object
+      [ "type" .= String "CachedDownload"
+      , "contents"
+          .= object
+            [ "version" .= version
+            , "dest_dir" .= destDir
+            ]
+      , "ttl" .= ttl
+      ]
+
+
+data TemporalDevServerConfig = TemporalDevServerConfig
+  { exe :: EphemeralExe
+  , namespace :: FilePath
+  , ip :: String
+  , port :: Maybe Word16
+  , dbFilename :: Maybe FilePath
+  , ui :: Bool
+  , uiPort :: Maybe Word16
+  , log :: (String, String)
+  , extraArgs :: [String]
+  }
+
+
+deriveToJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''TemporalDevServerConfig
+
+
+defaultTemporalDevServerConfig :: TemporalDevServerConfig
+defaultTemporalDevServerConfig =
+  TemporalDevServerConfig
+    { exe = CachedDownload (Default $ SDKDefault "community-haskell" "0.1.0.0") Nothing Nothing
+    , namespace = "default"
+    , ip = "127.0.0.1"
+    , port = Nothing
+    , dbFilename = Nothing
+    , ui = False
+    , uiPort = Nothing
+    , log = ("pretty", "warn")
+    , extraArgs = []
+    }
+
+
+newtype EphemeralServer = EphemeralServer {ephemeralServerPtr :: ForeignPtr EphemeralServer}
+
+
+foreign import ccall "hs_temporal_start_dev_server"
+  raw_startDevServer
+    :: Ptr Runtime
+    -> CString
+    -> TokioCall (CArray Word8) EphemeralServer
+
+
+startDevServer :: Runtime -> TemporalDevServerConfig -> IO (Either ByteString EphemeralServer)
+startDevServer r c = withRuntime r $ \rp -> useAsCString (BL.toStrict (encode c)) $ \cstr -> do
+  res <-
+    makeTokioAsyncCall
+      (raw_startDevServer rp cstr)
+      (Just rust_dropByteArray)
+      Nothing
+  case res of
+    Left err -> Left <$> withForeignPtr err (peek >=> cArrayToByteString)
+    Right srv -> pure $ Right $ EphemeralServer srv
+
+
+foreign import ccall "hs_temporal_shutdown_ephemeral_server" raw_shutdownEphemeralServer :: Ptr EphemeralServer -> TokioCall (CArray Word8) CUnit
+
+
+shutdownEphemeralServer :: EphemeralServer -> IO (Either ByteString ())
+shutdownEphemeralServer (EphemeralServer e) = withForeignPtr e $ \ep -> do
+  res <-
+    makeTokioAsyncCall
+      (raw_shutdownEphemeralServer ep)
+      (Just rust_dropByteArray)
+      (Just rust_dropUnit)
+  case res of
+    Left err -> Left <$> withForeignPtr err (peek >=> cArrayToByteString)
+    Right _ -> pure $ Right ()
+
+
+-- TODO
+-- startDevServerWithOutput
+
+data TemporalTestServerConfig = TemporalTestServerConfig
+  { exe :: EphemeralExe
+  , port :: Maybe Word16
+  , extraArgs :: [String]
+  }
+
+
+deriveToJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''TemporalTestServerConfig
+
+
+foreign import ccall "hs_temporal_start_test_server"
+  raw_startTestServer
+    :: Ptr Runtime
+    -> CString
+    -> TokioCall (CArray Word8) EphemeralServer
+
+
+startTestServer :: Runtime -> TemporalTestServerConfig -> IO (Either ByteString EphemeralServer)
+startTestServer r conf = withRuntime r $ \rp -> useAsCString (BL.toStrict $ encode conf) $ \cstr -> do
+  res <-
+    makeTokioAsyncCall
+      (raw_startTestServer rp cstr)
+      (Just rust_dropByteArray)
+      Nothing
+  case res of
+    Left err -> Left <$> withForeignPtr err (peek >=> cArrayToByteString)
+    Right srv -> pure $ Right $ EphemeralServer srv
diff --git a/src/Temporal/Core/Worker.hs b/src/Temporal/Core/Worker.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Core/Worker.hs
@@ -0,0 +1,433 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Temporal.Core.Worker (
+  Worker,
+  getWorkerClient,
+  WorkerConfig (..),
+  getWorkerConfig,
+  defaultWorkerConfig,
+  WorkerError (..),
+  WorkerErrorCode (..),
+  WorkerType (..),
+  SWorkerType (..),
+  SomeWorkerType (..),
+  newWorker,
+  validateWorker,
+  newReplayWorker,
+  closeWorker,
+  InactiveForReplay,
+  WorkflowActivation,
+  pollWorkflowActivation,
+  ActivityTask,
+  pollActivityTask,
+  WorkflowActivationCompletion,
+  completeWorkflowActivation,
+  ActivityTaskCompletion,
+  completeActivityTask,
+  ActivityHeartbeat,
+  recordActivityHeartbeat,
+  requestWorkflowEviction,
+  initiateShutdown,
+  finalizeShutdown,
+  HistoryPusher,
+  History,
+  pushHistory,
+  closeHistory,
+  KnownWorkerType (..),
+) where
+
+import Control.Exception
+import Control.Monad
+import Data.Aeson
+import Data.Aeson.TH
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Lazy as BL
+import Data.IORef
+import Data.ProtoLens.Encoding (decodeMessageOrDie, encodeMessage)
+import Data.Text (Text)
+import Data.Void (Void)
+import Data.Word
+import Foreign.C.String
+import Foreign.ForeignPtr
+import Foreign.Marshal
+import Foreign.Ptr
+import Foreign.Storable
+import Proto.Temporal.Api.History.V1.Message (History)
+import Proto.Temporal.Sdk.Core.ActivityTask.ActivityTask (ActivityTask)
+import Proto.Temporal.Sdk.Core.CoreInterface (ActivityHeartbeat, ActivityTaskCompletion)
+import Proto.Temporal.Sdk.Core.WorkflowActivation.WorkflowActivation (WorkflowActivation)
+import Proto.Temporal.Sdk.Core.WorkflowCompletion.WorkflowCompletion (WorkflowActivationCompletion)
+import Temporal.Core.CTypes
+import Temporal.Core.Client
+import Temporal.Internal.FFI
+import Temporal.Runtime
+
+
+data WorkerType = Real | Replay
+
+
+-- | A singleton type for 'WorkerType'.
+data SWorkerType (ty :: WorkerType) where
+  SReal :: SWorkerType 'Real
+  SReplay :: SWorkerType 'Replay
+
+
+-- Promote a 'WorkerType' to a singleton type.
+data SomeWorkerType where
+  SomeWorkerType :: SWorkerType ty -> SomeWorkerType
+
+
+type family InactiveForReplay (ty :: WorkerType) a where
+  InactiveForReplay 'Real a = a
+  InactiveForReplay 'Replay _ = ()
+
+
+class KnownWorkerType (ty :: WorkerType) where
+  knownWorkerType :: SWorkerType ty
+
+
+instance KnownWorkerType 'Real where
+  knownWorkerType = SReal
+
+
+instance KnownWorkerType 'Replay where
+  knownWorkerType = SReplay
+
+
+singFor :: KnownWorkerType ty => proxy ty -> SWorkerType ty
+singFor _ = knownWorkerType
+
+
+data Worker (ty :: WorkerType) = Worker
+  { workerPtr :: {-# UNPACK #-} !(IORef (ForeignPtr (Worker ty)))
+  , workerConfig :: !WorkerConfig
+  , workerClient :: !(InactiveForReplay ty Client)
+  , workerRuntime :: {-# UNPACK #-} !Runtime
+  }
+
+
+withWorker :: forall ty a. KnownWorkerType ty => Worker ty -> (Ptr (Worker ty) -> IO a) -> IO a
+withWorker w@(Worker ptrRef _ c r) f = withRuntime r $ \_ ->
+  let keepClientAlive :: IO a -> IO a
+      keepClientAlive = case singFor w of
+        SReal -> \m -> do
+          a <- m
+          touchClient c
+          pure a
+        SReplay -> id
+  in keepClientAlive $ do
+      ptr <- readIORef ptrRef
+      withForeignPtr ptr f
+
+
+getWorkerClient :: Worker 'Real -> Client
+getWorkerClient = workerClient
+
+
+getWorkerConfig :: Worker ty -> WorkerConfig
+getWorkerConfig = workerConfig
+
+
+newtype HistoryPusher = HistoryPusher {historyPusher :: Ptr HistoryPusher}
+
+
+type Proto = ByteString
+
+
+type RunId = ByteString
+
+
+type WorkflowId = ByteString
+
+
+data WorkerConfig = WorkerConfig
+  { namespace :: Text
+  , taskQueue :: Text
+  , buildId :: Text
+  , identityOverride :: Maybe Text
+  , maxCachedWorkflows :: Word64
+  , maxOutstandingWorkflowTasks :: Word64
+  , maxOutstandingActivities :: Word64
+  , maxOutstandingLocalActivities :: Word64
+  , maxConcurrentWorkflowTaskPolls :: Word64
+  , nonstickyToStickyPollRatio :: Float
+  , maxConcurrentActivityTaskPolls :: Word64
+  , noRemoteActivities :: Bool
+  , stickyQueueScheduleToStartTimeoutMillis :: Word64
+  , maxHeartbeatThrottleIntervalMillis :: Word64
+  , defaultHeartbeatThrottleIntervalMillis :: Word64
+  , maxActivitiesPerSecond :: Maybe Double
+  , maxTaskQueueActivitiesPerSecond :: Maybe Double
+  , gracefulShutdownPeriodMillis :: Word64
+  , nondeterminismAsWorkflowFail :: Bool
+  , nondeterminismAsWorkflowFailForTypes :: [Text]
+  -- TODO:
+  -- useWorkerVersioning
+  -- tuner
+  }
+
+
+deriveJSON (defaultOptions {fieldLabelModifier = camelTo2 '_'}) ''WorkerConfig
+
+
+defaultWorkerConfig :: WorkerConfig
+defaultWorkerConfig =
+  WorkerConfig
+    { namespace = "default"
+    , taskQueue = "default"
+    , buildId = ""
+    , identityOverride = Nothing
+    , maxCachedWorkflows = 100000
+    , maxOutstandingWorkflowTasks = 1000
+    , maxOutstandingActivities = 1000
+    , maxOutstandingLocalActivities = 1000
+    , maxConcurrentWorkflowTaskPolls = 5
+    , nonstickyToStickyPollRatio = 0.85
+    , maxConcurrentActivityTaskPolls = 5
+    , noRemoteActivities = False
+    , stickyQueueScheduleToStartTimeoutMillis = 60000
+    , maxHeartbeatThrottleIntervalMillis = 300000
+    , defaultHeartbeatThrottleIntervalMillis = 300000
+    , maxActivitiesPerSecond = Nothing
+    , maxTaskQueueActivitiesPerSecond = Nothing
+    , gracefulShutdownPeriodMillis = 0
+    , nondeterminismAsWorkflowFail = False
+    , nondeterminismAsWorkflowFailForTypes = []
+    }
+
+
+foreign import ccall "hs_temporal_new_worker" raw_newWorker :: Ptr CoreClient -> Ptr (CArray Word8) -> Ptr (Ptr (Worker 'Real)) -> Ptr (Ptr CWorkerError) -> IO ()
+
+
+foreign import ccall "hs_temporal_validate_worker" raw_validateWorker :: Ptr (Worker ty) -> TokioCall CWorkerValidationError CUnit
+
+
+validateWorker :: Worker 'Real -> IO (Either WorkerValidationError ())
+validateWorker w = withWorker w $ \wp -> do
+  res <- makeTokioAsyncCall (raw_validateWorker wp) (Just rust_dropWorkerValidationError) (Just rust_dropUnit)
+  case res of
+    Left err -> Left <$> withForeignPtr err (peek >=> peekWorkerValidationError)
+    Right _ -> pure $ Right ()
+
+
+foreign import ccall "&hs_temporal_drop_worker" raw_closeWorker :: FinalizerPtr (Worker ty)
+
+
+getWorkerError :: Ptr CWorkerError -> IO WorkerError
+getWorkerError errPtr = do
+  fp <- newForeignPtr rust_dropWorkerError errPtr
+  withForeignPtr fp (peek >=> peekWorkerError)
+
+
+-- note: removed the Runtime argument from the C function since the runtime can be accessed from the client. Might want to add it back later if
+-- it is some sort of load-bearing memory management thing.
+newWorker :: Client -> WorkerConfig -> IO (Either WorkerError (Worker 'Real))
+newWorker c wc = withClient c $ \cPtr -> do
+  withCArrayBS (BL.toStrict $ encode wc) $ \wcPtr -> do
+    wPtrPtrFP <- mallocForeignPtr
+    errPtrPtrFP <- mallocForeignPtr
+    withForeignPtr wPtrPtrFP $ \wPtrPtr -> do
+      withForeignPtr errPtrPtrFP $ \errPtrPtr -> do
+        poke wPtrPtr nullPtr
+        poke errPtrPtr nullPtr
+
+        mask_ $ do
+          raw_newWorker cPtr wcPtr wPtrPtr errPtrPtr
+          errPtr <- peek errPtrPtr
+          if errPtr == nullPtr
+            then do
+              wPtr <- peek wPtrPtr
+              wPtrFP <- newForeignPtr raw_closeWorker wPtr
+              wPtrRef <- newIORef wPtrFP
+              pure $ Right $ Worker wPtrRef wc c (clientRuntime c)
+            else Left <$> getWorkerError errPtr
+
+
+data WorkerAlreadyClosed = WorkerAlreadyClosed
+  deriving stock (Show)
+
+
+instance Exception WorkerAlreadyClosed
+
+
+closeWorker :: Worker ty -> IO ()
+closeWorker (Worker w _ _ _) = mask_ $ do
+  wp <- atomicModifyIORef' w $ \wp -> (throw WorkerAlreadyClosed, wp)
+  finalizeForeignPtr wp
+
+
+foreign import ccall "hs_temporal_new_replay_worker" raw_newReplayWorker :: Ptr Runtime -> Ptr (CArray Word8) -> Ptr (Ptr (Worker 'Replay)) -> Ptr (Ptr HistoryPusher) -> Ptr (Ptr CWorkerError) -> IO ()
+
+
+newReplayWorker :: Runtime -> WorkerConfig -> IO (Either WorkerError (Worker 'Replay, HistoryPusher))
+newReplayWorker r conf = withRuntime r $ \rPtr -> do
+  alloca $ \wPtrPtr -> do
+    alloca $ \hpPtrPtr -> do
+      withCArrayBS (BL.toStrict $ encode conf) $ \confPtr -> do
+        alloca $ \errPtrPtr -> do
+          poke wPtrPtr nullPtr
+          poke hpPtrPtr nullPtr
+          poke errPtrPtr nullPtr
+
+          raw_newReplayWorker rPtr confPtr wPtrPtr hpPtrPtr errPtrPtr
+          errPtr <- peek errPtrPtr
+          if errPtr == nullPtr
+            then do
+              wPtr <- peek wPtrPtr
+              hpPtr <- peek hpPtrPtr
+              w <- newForeignPtr raw_closeWorker wPtr
+              wRef <- newIORef w
+              pure $ Right (Worker wRef conf () r, HistoryPusher hpPtr)
+            else Left <$> getWorkerError errPtr
+
+
+foreign import ccall "hs_temporal_worker_poll_workflow_activation" raw_pollWorkflowActivation :: Ptr (Worker ty) -> TokioCall CWorkerError (CArray Word8)
+
+
+pollWorkflowActivation :: KnownWorkerType ty => Worker ty -> IO (Either WorkerError WorkflowActivation)
+pollWorkflowActivation w = withWorker w $ \wp -> do
+  res <-
+    makeTokioAsyncCall
+      (raw_pollWorkflowActivation wp)
+      (Just rust_dropWorkerError)
+      (Just rust_dropByteArray)
+  case res of
+    Left err -> Left <$> withForeignPtr err (peek >=> peekWorkerError)
+    Right ok -> Right . decodeMessageOrDie <$> withForeignPtr ok (peek >=> cArrayToByteString)
+
+
+foreign import ccall "hs_temporal_worker_poll_activity_task" raw_pollActivityTask :: Ptr (Worker ty) -> TokioCall CWorkerError (CArray Word8)
+
+
+pollActivityTask :: KnownWorkerType ty => Worker ty -> IO (Either WorkerError ActivityTask)
+pollActivityTask w = withWorker w $ \wp -> do
+  res <-
+    makeTokioAsyncCall
+      (raw_pollActivityTask wp)
+      (Just rust_dropWorkerError)
+      (Just rust_dropByteArray)
+  case res of
+    Left err -> Left <$> withForeignPtr err (peek >=> peekWorkerError)
+    Right res -> Right . decodeMessageOrDie <$> withForeignPtr res (peek >=> cArrayToByteString)
+
+
+foreign import ccall "hs_temporal_worker_complete_workflow_activation" raw_completeWorkflowActivation :: Ptr (Worker ty) -> Ptr (CArray Word8) -> TokioCall CWorkerError CUnit
+
+
+completeWorkflowActivation :: KnownWorkerType ty => Worker ty -> WorkflowActivationCompletion -> IO (Either WorkerError ())
+completeWorkflowActivation w p = withWorker w $ \wp ->
+  withCArrayBS (encodeMessage p) $ \pPtr -> do
+    res <-
+      makeTokioAsyncCall
+        (raw_completeWorkflowActivation wp pPtr)
+        (Just rust_dropWorkerError)
+        (Just rust_dropUnit)
+    case res of
+      Left err -> Left <$> withForeignPtr err (peek >=> peekWorkerError)
+      Right _ -> pure $ Right ()
+
+
+foreign import ccall "hs_temporal_worker_complete_activity_task" raw_completeActivityTask :: Ptr (Worker ty) -> Ptr (CArray Word8) -> TokioCall CWorkerError CUnit
+
+
+completeActivityTask :: KnownWorkerType ty => Worker ty -> ActivityTaskCompletion -> IO (Either WorkerError ())
+completeActivityTask w p = withWorker w $ \wp ->
+  withCArrayBS (encodeMessage p) $ \pPtr -> do
+    res <-
+      makeTokioAsyncCall
+        (raw_completeActivityTask wp pPtr)
+        (Just rust_dropWorkerError)
+        (Just rust_dropUnit)
+    case res of
+      Left err -> Left <$> withForeignPtr err (peek >=> peekWorkerError)
+      Right _ -> pure $ Right ()
+
+
+foreign import ccall "hs_temporal_worker_record_activity_heartbeat" raw_recordActivityHeartbeat :: Ptr (Worker ty) -> Ptr (CArray Word8) -> Ptr (Ptr CWorkerError) -> Ptr (Ptr CUnit) -> IO ()
+
+
+recordActivityHeartbeat :: KnownWorkerType ty => Worker ty -> ActivityHeartbeat -> IO (Either WorkerError ())
+recordActivityHeartbeat w p = withWorker w $ \wp ->
+  withCArrayBS (encodeMessage p) $ \pPtr -> do
+    alloca $ \errPtrPtr -> do
+      alloca $ \resPtrPtr -> mask_ $ do
+        poke errPtrPtr nullPtr
+        poke resPtrPtr nullPtr
+        raw_recordActivityHeartbeat wp pPtr errPtrPtr resPtrPtr
+        errPtr <- peek errPtrPtr
+        if errPtr == nullPtr
+          then do
+            rust_dropUnitNow =<< peek resPtrPtr
+            pure $ Right ()
+          else Left <$> getWorkerError errPtr
+
+
+foreign import ccall "hs_temporal_worker_request_workflow_eviction" raw_requestWorkflowEviction :: Ptr (Worker ty) -> Ptr (CArray Word8) -> IO ()
+
+
+requestWorkflowEviction :: KnownWorkerType ty => Worker ty -> RunId -> IO ()
+requestWorkflowEviction w r = withWorker w $ \wp ->
+  withCArrayBS r $ \rPtr -> do
+    raw_requestWorkflowEviction wp rPtr
+
+
+foreign import ccall "hs_temporal_worker_initiate_shutdown" raw_initiateShutdown :: Ptr (Worker ty) -> IO ()
+
+
+-- | Initiate shutdown.
+initiateShutdown :: KnownWorkerType ty => Worker ty -> IO ()
+initiateShutdown w = withWorker w raw_initiateShutdown
+
+
+foreign import ccall "hs_temporal_worker_finalize_shutdown" raw_finalizeShutdown :: Ptr (Worker ty) -> TokioCall CWorkerError CUnit
+
+
+{- |
+Completes shutdown and frees all resources. You should avoid simply dropping workers, as
+this does not allow async tasks to report any panics that may have occurred cleanly.
+
+This should be called only after 'initiateShutdown' has resolved and/or both polling
+functions have returned `ShutDown` errors.
+-}
+finalizeShutdown :: KnownWorkerType ty => Worker ty -> IO (Either WorkerError ())
+finalizeShutdown w = withWorker w $ \wp -> do
+  res <-
+    makeTokioAsyncCall
+      (raw_finalizeShutdown wp)
+      (Just rust_dropWorkerError)
+      (Just rust_dropUnit)
+  case res of
+    Left err -> Left <$> withForeignPtr err (peek >=> peekWorkerError)
+    Right _ -> pure $ Right ()
+
+
+foreign import ccall "hs_temporal_history_pusher_push_history" raw_pushHistory :: Ptr HistoryPusher -> Ptr (CArray Word8) -> Ptr (CArray Word8) -> TokioCall CWorkerError CUnit
+
+
+pushHistory :: HistoryPusher -> WorkflowId -> Either ByteString History -> IO (Either WorkerError ())
+pushHistory (HistoryPusher hp) wf p =
+  withCArrayBS wf $ \wfPtr -> do
+    withCArrayBS (either id encodeMessage p) $ \pPtr -> do
+      res <-
+        makeTokioAsyncCall
+          (raw_pushHistory hp wfPtr pPtr)
+          (Just rust_dropWorkerError)
+          (Just rust_dropUnit)
+      case res of
+        Left err -> Left <$> withForeignPtr err (peek >=> peekWorkerError)
+        Right _ -> pure $ Right ()
+
+
+foreign import ccall "hs_temporal_history_pusher_close" raw_closeHistoryPusher :: Ptr HistoryPusher -> IO ()
+
+
+closeHistory :: HistoryPusher -> IO ()
+closeHistory (HistoryPusher hp) =
+  raw_closeHistoryPusher hp
diff --git a/src/Temporal/Internal/FFI.hs b/src/Temporal/Internal/FFI.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Internal/FFI.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Temporal.Internal.FFI where
+
+import Control.Concurrent
+import Control.Exception
+import Control.Monad
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as ByteString
+import Data.Coerce
+import Data.Kind (Type)
+import Data.Proxy
+import Data.Text (Text)
+import qualified Data.Text as Text
+import qualified Data.Text.Foreign as Text
+import qualified Data.Vector.Storable as Vector
+import Data.Word
+import Foreign.C.String
+import Foreign.C.Types
+import Foreign.ForeignPtr
+import Foreign.Marshal.Alloc
+import qualified Foreign.Marshal.Utils as Marshal
+import Foreign.Ptr
+import Foreign.StablePtr
+import Foreign.Storable
+import GHC.Conc (PrimMVar, newStablePtrPrimMVar)
+import Temporal.Core.CTypes
+
+
+withCArray :: Storable a => Vector.Vector a -> (Ptr (CArray a) -> IO b) -> IO b
+withCArray v f = Vector.unsafeWith v $ \vPtr ->
+  Marshal.with (CArray vPtr (fromIntegral (Vector.length v))) f
+
+
+withCArrayBS :: ByteString -> (Ptr (CArray Word8) -> IO b) -> IO b
+withCArrayBS bs f = ByteString.useAsCStringLen bs $ \(bytes, len) ->
+  Marshal.with (CArray (castPtr bytes) (fromIntegral len)) f
+
+
+withCArrayText :: Text -> (Ptr (CArray Word8) -> IO b) -> IO b
+withCArrayText txt f = Text.withCStringLen txt $ \(bytes, len) ->
+  Marshal.with (CArray (castPtr bytes) (fromIntegral len)) f
+
+
+withTokioResult :: TokioResult a -> (Ptr (Ptr a) -> IO b) -> IO b
+withTokioResult fp f = withForeignPtr fp $ \ptr -> do
+  poke ptr nullPtr
+  f ptr
+
+
+peekTokioResult :: TokioSlot a -> Maybe (FinalizerPtr a) -> IO (Maybe (ForeignPtr a))
+peekTokioResult slot mfp = do
+  inner <- peek slot
+  if inner == nullPtr
+    then return Nothing
+    else
+      Just <$> case mfp of
+        Nothing -> newForeignPtr_ inner
+        Just fp -> newForeignPtr fp inner
+
+
+type TokioCall e a = StablePtr PrimMVar -> Int -> TokioSlot e -> TokioSlot a -> IO ()
+
+
+type TokioSlot a = Ptr (Ptr a)
+
+
+type TokioResult a = ForeignPtr (Ptr a)
+
+
+{- | Dropping can't be done automatically if the result is returned without async exceptions
+intervening, because we don't want to drop things like `Client` while they're still in use.
+So we should return ForeignPtrs for things that need to stay alive, and then we can drop when we're done.
+-}
+makeTokioAsyncCall
+  :: TokioCall err res
+  -> Maybe (FinalizerPtr err)
+  -> Maybe (FinalizerPtr res)
+  -> IO (Either (ForeignPtr err) (ForeignPtr res))
+makeTokioAsyncCall call readErr readSuccess = uninterruptibleMask $ \restore -> do
+  mvar <- newEmptyMVar
+  sp <- newStablePtrPrimMVar mvar
+  errorSlot <- mallocForeignPtr
+  resultSlot <- mallocForeignPtr
+  withTokioResult errorSlot $ \err -> withTokioResult resultSlot $ \res -> do
+    let peekEither = do
+          e <- peekTokioResult err readErr
+          case e of
+            Nothing -> do
+              r <- peekTokioResult res readSuccess
+              case r of
+                Nothing -> error "Both error and result are null"
+                Just r -> return (Right r)
+            Just e -> return (Left e)
+
+    (cap, _) <- threadCapability =<< myThreadId
+    call sp cap err res
+    let handleCleanup = forkIO $ do
+          takeMVar mvar
+          -- We still need to get the result out of the slot and into a ForeignPtr so that we can drop it
+          void peekEither
+    () <- restore (takeMVar mvar) `onException` handleCleanup
+    peekEither
diff --git a/src/Temporal/Runtime.hs b/src/Temporal/Runtime.hs
new file mode 100644
--- /dev/null
+++ b/src/Temporal/Runtime.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module Temporal.Runtime (
+  Runtime,
+  TelemetryOptions (..),
+  Periodicity (..),
+  initializeRuntime,
+  withRuntime,
+  fetchLogs,
+  CoreLog (..),
+  LogLevel (..),
+) where
+
+import Control.Concurrent
+import Control.Exception
+import Data.Aeson
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Vector as V
+import Foreign.C.String
+import Foreign.C.Types (CInt)
+import Foreign.ForeignPtr
+import Foreign.Marshal
+import Foreign.Ptr
+import Foreign.StablePtr
+import Foreign.Storable
+import System.IO.Unsafe
+import Temporal.Core.CTypes
+import Temporal.Internal.FFI
+
+
+-- | Initialize the Rust runtime and thread-pool.
+initializeRuntime :: TelemetryOptions -> IO Runtime
+initializeRuntime opts = withCArrayBS (BL.toStrict $ encode opts) $ \optsP ->
+  mask_ $ do
+    rtP <- initRuntime optsP tryPutMVarPtr
+    Runtime <$> newForeignPtr freeRuntime rtP
+
+
+-- | Access the underlying 'Runtime' pointer for calling out to Rust.
+withRuntime :: Runtime -> (Ptr Runtime -> IO a) -> IO a
+withRuntime (Runtime rvar) = withForeignPtr rvar
+
+
+{- | The Rust runtime exports logs to the Haskell runtime. This function fetches
+those logs so they can be fed through a logging framework.
+-}
+fetchLogs :: Runtime -> IO (V.Vector CoreLog)
+fetchLogs r = withRuntime r $ \p -> do
+  bracket (raw_fetchLogs p) raw_freeLogs $ \clogs -> do
+    logs <- peek clogs
+    vec <- cArrayToVector cArrayToByteString logs
+    V.mapM throwDecodeStrict vec
diff --git a/temporal-sdk-core.cabal b/temporal-sdk-core.cabal
new file mode 100644
--- /dev/null
+++ b/temporal-sdk-core.cabal
@@ -0,0 +1,109 @@
+cabal-version: 3.0
+
+-- This file has been generated from package.yaml by hpack version 0.36.1.
+--
+-- see: https://github.com/sol/hpack
+
+name:           temporal-sdk-core
+version:        2025.10.1.0
+description:    Temporal is a durable execution system that transparently makes your code durable, fault-tolerant, and simple. This is the core FFI bindings for the high-level Temporal SDK. Note that it requires Rust/Cargo to build.
+category:       Concurrency
+author:         Ian Duncan
+maintainer:     temporal@mercury.com
+license:        BSD-3-Clause
+license-file:   LICENSE
+build-type:     Custom
+extra-source-files:
+    rust/Cargo.toml
+    rust/Cargo.lock
+    rust/src/client.rs
+    rust/src/ephemeral_server.rs
+    rust/src/lib.rs
+    rust/src/rpc.rs
+    rust/src/runtime.rs
+    rust/src/worker.rs
+    rust/temporal_bridge.h
+
+custom-setup
+  setup-depends:
+      Cabal >=3.0.0.0 && <3.15.0.0
+    , base >=4.7 && <5
+    , directory >=1.3.6.0
+    , filepath >=1.3.0.2
+    , unix
+
+flag external_lib
+  description: Use external library (don't compile automatically)
+  manual: True
+  default: False
+
+library
+  exposed-modules:
+      Temporal.Core.Client
+      Temporal.Core.Client.OperatorService
+      Temporal.Core.Client.TestService
+      Temporal.Core.Client.WorkflowService
+      Temporal.Core.EphemeralServer
+      Temporal.Core.Worker
+      Temporal.Runtime
+  other-modules:
+      Temporal.Core.CTypes
+      Temporal.Core.Client.HealthService
+      Temporal.Internal.FFI
+  hs-source-dirs:
+      src
+  default-extensions:
+      BangPatterns
+      BlockArguments
+      DataKinds
+      DerivingStrategies
+      FlexibleContexts
+      FlexibleInstances
+      GADTs
+      GeneralizedNewtypeDeriving
+      InstanceSigs
+      LambdaCase
+      MultiParamTypeClasses
+      NamedFieldPuns
+      NumericUnderscores
+      RankNTypes
+      OverloadedRecordDot
+      OverloadedStrings
+      RecordWildCards
+      ScopedTypeVariables
+      StandaloneDeriving
+      TypeApplications
+      TypeFamilies
+      TypeOperators
+      UndecidableInstances
+      ViewPatterns
+  ghc-options: -g -Wall
+  include-dirs:
+      rust
+  extra-libraries:
+      temporal_bridge
+  build-depends:
+      aeson
+    , async
+    , base >=4.14 && <5
+    , bytestring
+    , containers
+    , lens-family
+    , monad-logger
+    , mtl
+    , network-bsd
+    , proto-lens
+    , stm
+    , temporal-api-protos
+    , text
+    , unix
+    , unliftio
+    , unordered-containers
+    , uuid
+    , vector
+  default-language: Haskell2010
+  if os(darwin)
+    frameworks:
+        Security
+        CoreFoundation
+        SystemConfiguration
