diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,3 @@
 # OsString [![Hackage version](https://img.shields.io/hackage/v/os-string.svg?label=Hackage)](https://hackage.haskell.org/package/os-string)
 
-This package provides functionality for manipulating @OsString@ values, and is shipped with <https://www.haskell.org/ghc/ GHC>.
-
+This package provides functionality for manipulating `OsString` values, and is shipped with [GHC](https://www.haskell.org/ghc/).
diff --git a/System/OsString.hs b/System/OsString.hs
--- a/System/OsString.hs
+++ b/System/OsString.hs
@@ -43,6 +43,7 @@
 
   -- * Word construction
   , unsafeFromChar
+  , fromWord
 
   -- * Word deconstruction
   , toChar
@@ -135,6 +136,7 @@
 
 import System.OsString.Internal
     ( unsafeFromChar
+    , fromWord
     , toChar
     , encodeUtf
     , unsafeEncodeUtf
diff --git a/System/OsString/Common.hs b/System/OsString/Common.hs
--- a/System/OsString/Common.hs
+++ b/System/OsString/Common.hs
@@ -57,6 +57,7 @@
 
   -- * Word construction
   , unsafeFromChar
+  , fromWord
 
   -- * Word deconstruction
   , toChar
@@ -210,6 +211,11 @@
 import qualified System.OsString.Data.ByteString.Short.Word16 as BS16
 import qualified System.OsString.Data.ByteString.Short as BS8
 
+#ifdef WINDOWS
+import Data.Word (Word16)
+#else
+import Data.Word (Word8)
+#endif
 
 
 #ifdef WINDOWS_DOC
@@ -538,6 +544,9 @@
 -- Note that using this in conjunction with 'unsafeFromChar' to
 -- convert from @[Char]@ to platform string is probably not what
 -- you want, because it will truncate unicode code points.
+--
+-- Additionally, a platform word is a byte (or wide char on windows) in an encoded byte sequence,
+-- so we're not operating on unicode code points or graphemes here.
 pack :: [PLATFORM_WORD] -> PLATFORM_STRING
 pack = coerce BSP.pack
 
@@ -547,13 +556,38 @@
 empty :: PLATFORM_STRING
 empty = mempty
 
+#ifdef WINDOWS
+-- | Convert from 'Word16'.
+--
+-- @since 2.0.11
+fromWord :: Word16 -> PLATFORM_WORD
+fromWord = WindowsChar
+#else
+-- | Convert from 'Word8'.
+--
+-- @since 2.0.11
+fromWord :: Word8 -> PLATFORM_WORD
+fromWord = PosixChar
+#endif
 
 #ifdef WINDOWS
 -- | Truncates to 2 octets.
+--
+-- Note that 'WindowsChar' is a "wide char" in a UCS-2 encoded byte sequence
+-- and is not morally a unicode code point by any means, so
+-- this conversion is rarely what you want.
+--
+-- Consider using 'fromWord' instead.
 unsafeFromChar :: Char -> PLATFORM_WORD
 unsafeFromChar = WindowsChar . fromIntegral . fromEnum
 #else
 -- | Truncates to 1 octet.
+--
+-- Note that 'PosixChar' is a byte in an encoded byte sequence
+-- and is not morally a unicode code point by any means, so
+-- this conversion is rarely what you want.
+--
+-- Consider using 'fromWord' instead.
 unsafeFromChar :: Char -> PLATFORM_WORD
 unsafeFromChar = PosixChar . fromIntegral . fromEnum
 #endif
diff --git a/System/OsString/Internal.hs b/System/OsString/Internal.hs
--- a/System/OsString/Internal.hs
+++ b/System/OsString/Internal.hs
@@ -49,6 +49,7 @@
 import GHC.Stack (HasCallStack)
 import Data.Coerce (coerce)
 import Data.Type.Coercion (coerceWith)
+import Data.Word (Word8)
 
 
 
@@ -242,6 +243,9 @@
 -- Note that using this in conjunction with 'unsafeFromChar' to
 -- convert from @[Char]@ to 'OsString' is probably not what
 -- you want, because it will truncate unicode code points.
+--
+-- Additionally, 'OsChar' is a byte (or wide char on windows) in an encoded byte sequence,
+-- so we're not operating on unicode code points or graphemes here.
 pack :: [OsChar] -> OsString
 pack = coerce PF.pack
 
@@ -253,8 +257,24 @@
 
 
 -- | Truncates on unix to 1 and on Windows to 2 octets.
+--
+-- Note that 'OsChar' is a byte in an encoded byte sequence
+-- and is not morally a unicode code point by any means, so
+-- this conversion is rarely what you want.
+--
+-- Consider using 'fromWord' instead.
 unsafeFromChar :: Char -> OsChar
 unsafeFromChar = coerce PF.unsafeFromChar
+
+-- | Convert from 'Word8'.
+--
+-- @since 2.0.11
+fromWord :: Word8 -> OsChar
+#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
+fromWord = OsChar . WindowsChar . fromIntegral
+#else
+fromWord = OsChar . PosixChar
+#endif
 
 -- | Converts back to a unicode codepoint (total).
 toChar :: OsChar -> Char
diff --git a/System/OsString/Internal/Types.hs b/System/OsString/Internal/Types.hs
--- a/System/OsString/Internal/Types.hs
+++ b/System/OsString/Internal/Types.hs
@@ -114,14 +114,22 @@
 type PlatformString = PosixString
 #endif
 
+-- | This represents a "wide char" on windows.
+--
+-- A better name would maybe have been @WindowsWord@, since
+-- this is just @Word16@ in a UCS-2 sequence.
 newtype WindowsChar = WindowsChar { getWindowsChar :: Word16 }
-  deriving (Eq, Ord, Typeable, Generic, NFData)
+  deriving (Eq, Ord, Typeable, Generic, NFData, Lift)
 
 instance Show WindowsChar where
   show (WindowsChar wc) = show wc
 
+-- | This represents a byte.
+--
+-- A better name would maybe have been @PosixWord@, since
+-- it is just @Word8@ in an encoded byte sequence.
 newtype PosixChar   = PosixChar { getPosixChar :: Word8 }
-  deriving (Eq, Ord, Typeable, Generic, NFData)
+  deriving (Eq, Ord, Typeable, Generic, NFData, Lift)
 
 instance Show PosixChar where
   show (PosixChar pc) = show pc
@@ -205,8 +213,11 @@
 --
 -- On Windows, this is restricted to two-octet codepoints 'Word16',
 -- on POSIX one-octet ('Word8').
+--
+-- This should maybe have been worded @OsWord@, since it is not
+-- a unicode code point by any means. It represents a byte in a
 newtype OsChar = OsChar { getOsChar :: PlatformChar }
-  deriving (Typeable, Generic, NFData)
+  deriving (Typeable, Generic, NFData, Lift)
 
 instance Show OsChar where
   show (OsChar pc) = show pc
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,10 @@
 # Changelog for [`os-string` package](http://hackage.haskell.org/package/os-string)
 
+## 2.0.11 *Jun 2026*
+
+* Add Lift instance to `OsChar`, `PosixChar` and `WindowsChar`
+* Add `fromWord`
+
 ## 2.0.10 *Jan 2026*
 
 * fix build on GHC 9.14 wrt [#40](https://github.com/haskell/os-string/issues/40)
diff --git a/os-string.cabal b/os-string.cabal
--- a/os-string.cabal
+++ b/os-string.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               os-string
-version:            2.0.10
+version:            2.0.11
 
 -- NOTE: Don't forget to update ./changelog.md
 license:            BSD-3-Clause
@@ -16,14 +16,11 @@
 build-type:         Simple
 synopsis:           Library for manipulating Operating system strings.
 tested-with:
-  GHC ==8.6.5
-   || ==8.8.4
-   || ==8.10.7
-   || ==9.0.2
-   || ==9.2.8
-   || ==9.4.8
-   || ==9.6.3
-   || ==9.8.1
+  GHC ==9.6.7
+   || ==9.8.4
+   || ==9.10.3
+   || ==9.12.4
+   || ==9.14.1
 
 description:
   This package provides functionality for manipulating @OsString@ values, and is shipped with <https://www.haskell.org/ghc/ GHC>.
@@ -98,7 +95,7 @@
     , base
     , bytestring  >=0.11.3.0
     , os-string
-    , QuickCheck  >=2.7      && <2.16
+    , QuickCheck  >=2.7      && <2.19
 
 test-suite encoding-tests
   default-language: Haskell2010
@@ -116,7 +113,7 @@
     , bytestring  >=0.11.3.0
     , deepseq
     , os-string
-    , QuickCheck  >=2.7      && <2.16
+    , QuickCheck  >=2.7      && <2.19
     , quickcheck-classes-base ^>=0.6.2
 
 benchmark bench
