diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # Revision history for futhark-server
 
+## 1.3.1.0 -- 2026-03-10
+
+* Added `FieldName`.
+
+* Added some convenience instances to `Field`, `InputType`, and `OutputType`.
+
+* Added `cmdKind`, `cmdType`, `cmdElemtype`, `cmdShape`, `cmdIndex`, `cmdAttributes`.
+
 ## 1.3.0.0 -- 2026-03-05
 
 * `Futhark.Server.Values.getValue` now detects attempts to retrieve (some)
diff --git a/futhark-server.cabal b/futhark-server.cabal
--- a/futhark-server.cabal
+++ b/futhark-server.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               futhark-server
-version:            1.3.0.0
+version:            1.3.1.0
 synopsis: Client implementation of the Futhark server protocol.
 
 description: Provides an easy way to interact with a running Futhark
diff --git a/src/Futhark/Server.hs b/src/Futhark/Server.hs
--- a/src/Futhark/Server.hs
+++ b/src/Futhark/Server.hs
@@ -31,11 +31,15 @@
     -- * Commands
     Cmd,
     CmdFailure (..),
-    Field (..),
+    FieldName,
+    VariantName,
     VarName,
     TypeName,
     EntryName,
     TuningParamName,
+    Kind (..),
+    Variant (..),
+    Field (..),
     InputType (..),
     OutputType (..),
 
@@ -52,15 +56,24 @@
     -- ** Interrogation
     cmdTypes,
     cmdEntryPoints,
+    cmdKind,
+    cmdType,
 
+    -- * Arrays
+    cmdElemtype,
+    cmdShape,
+    cmdIndex,
+
     -- ** Records
     cmdNew,
     cmdProject,
     cmdFields,
 
-    -- * Arrays
-    cmdShape,
-    cmdIndex,
+    -- ** Sums
+    cmdVariants,
+    cmdConstruct,
+    cmdDestruct,
+    cmdVariant,
 
     -- ** Auxiliary
     cmdReport,
@@ -69,6 +82,7 @@
     cmdSetTuningParam,
     cmdTuningParams,
     cmdTuningParamClass,
+    cmdAttributes,
 
     -- * Utility
     cmdMaybe,
@@ -100,19 +114,13 @@
 data ServerException
   = -- | Human-readable error message.
     ServerException T.Text
-  deriving (Show)
+  deriving (Eq, Ord, Show)
 
 instance Exception ServerException
 
 -- | The name of a command.
 type Cmd = Text
 
--- | A record field
-data Field = Field
-  { fieldName :: Text,
-    fieldType :: TypeName
-  }
-
 -- | A handle to a running server.
 data Server = Server
   { serverStdin :: Handle,
@@ -327,6 +335,34 @@
 -- | The name of a tuning parameter.
 type TuningParamName = Text
 
+-- | The name of a field.
+type FieldName = Text
+
+-- | The name of a variant.
+type VariantName = Text
+
+data Kind
+  = Primitive
+  | Array
+  | Record
+  | Sum
+  | Opaque
+  deriving (Eq, Ord, Show)
+
+-- | A record field
+data Field = Field
+  { fieldName :: FieldName,
+    fieldType :: TypeName
+  }
+  deriving (Eq, Ord, Show)
+
+-- | A sum variant
+data Variant = Variant
+  { variantName :: VariantName,
+    variantTypes :: [TypeName]
+  }
+  deriving (Eq, Ord, Show)
+
 -- | The type of an input of an entry point.  If 'inputConsumed', then
 -- the value passed in a 'cmdCall' must not be used again (nor any of
 -- its aliases).
@@ -334,6 +370,7 @@
   { inputConsumed :: Bool,
     inputType :: TypeName
   }
+  deriving (Eq, Ord, Show)
 
 -- | The type of an output of an entry point.  If 'outputUnique', then
 -- the value returned does not alias any of the inputs.  See the
@@ -344,6 +381,7 @@
   { outputUnique :: Bool,
     outputType :: TypeName
   }
+  deriving (Eq, Ord, Show)
 
 inOutType :: (Bool -> TypeName -> a) -> Text -> a
 inOutType f t =
@@ -356,6 +394,12 @@
 helpCmd s cmd args =
   either Just (const Nothing) <$> sendCommand s cmd args
 
+sendCommandSL :: Server -> Cmd -> [Text] -> IO (Either CmdFailure Text)
+sendCommandSL s cmd args = fmap expectSingleLine <$> sendCommand s cmd args
+  where
+    expectSingleLine (a : _) = a
+    expectSingleLine [] = error $ "Expected output of command \"" ++ T.unpack (T.intercalate " " $ cmd : args) ++ "\""
+
 -- | @restore filename var0 type0 var1 type1...@.
 cmdRestore :: Server -> FilePath -> [(VarName, TypeName)] -> IO (Maybe CmdFailure)
 cmdRestore s fname vars = helpCmd s "restore" $ T.pack fname : concatMap f vars
@@ -417,6 +461,10 @@
 cmdTuningParamClass :: Server -> TuningParamName -> IO (Either CmdFailure Text)
 cmdTuningParamClass s param = fmap mconcat <$> sendCommand s "tuning_param_class" [param]
 
+-- | @attributes entry_point@
+cmdAttributes :: Server -> EntryName -> IO (Either CmdFailure [Text])
+cmdAttributes s entry = sendCommand s "attributes" [entry]
+
 -- | @types@
 cmdTypes :: Server -> IO (Either CmdFailure [TypeName])
 cmdTypes s = sendCommand s "types" []
@@ -425,9 +473,37 @@
 cmdEntryPoints :: Server -> IO (Either CmdFailure [EntryName])
 cmdEntryPoints s = sendCommand s "entry_points" []
 
+-- | @kind t@
+cmdKind :: Server -> TypeName -> IO (Either CmdFailure Kind)
+cmdKind s t = fmap parseKind <$> sendCommandSL s "kind" [t]
+  where
+    parseKind "primitive" = Primitive
+    parseKind "array" = Array
+    parseKind "record" = Record
+    parseKind "sum" = Sum
+    parseKind "opaque" = Opaque
+    parseKind _ = error $ "Invalid kind of type \"" ++ T.unpack t ++ "\""
+
+-- | @type v@
+cmdType :: Server -> VarName -> IO (Either CmdFailure TypeName)
+cmdType s v = sendCommandSL s "type" [v]
+
+-- | @elemtype t@
+cmdElemtype :: Server -> TypeName -> IO (Either CmdFailure TypeName)
+cmdElemtype s t = sendCommandSL s "elemtype" [t]
+
+-- | @shape v@
+cmdShape :: Server -> VarName -> IO (Either CmdFailure [Int])
+cmdShape s v = fmap (map (read . T.unpack) . T.words) <$> sendCommandSL s "shape" [v]
+
+-- | @index v0 v1 i0 ... iN-1@
+cmdIndex :: Server -> VarName -> VarName -> [Int] -> IO (Maybe CmdFailure)
+cmdIndex s v0 v1 is =
+  helpCmd s "index" $ [v0, v1] <> map (T.pack . show) is
+
 -- | @fields type@
 cmdFields :: Server -> TypeName -> IO (Either CmdFailure [Field])
-cmdFields s t = fmap (zipWith parseField [1..]) <$> sendCommand s "fields" [t]
+cmdFields s t = fmap (zipWith parseField [1 ..]) <$> sendCommand s "fields" [t]
   where
     parseField :: Int -> Text -> Field
     parseField l f =
@@ -443,14 +519,34 @@
 cmdProject :: Server -> VarName -> VarName -> Text -> IO (Maybe CmdFailure)
 cmdProject s to from field = helpCmd s "project" [to, from, field]
 
--- | @shape v@
-cmdShape :: Server -> VarName -> IO (Either CmdFailure [Int])
-cmdShape s v = fmap (map (read . T.unpack)) <$> sendCommand s "shape" [v]
+-- | @variants t@
+cmdVariants :: Server -> TypeName -> IO (Either CmdFailure [Variant])
+cmdVariants s t = fmap parseVariants <$> sendCommand s "variants" [t]
+  where
+    parseVariants :: [Text] -> [Variant]
+    parseVariants = map mkVariant . go []
+      where
+        go acc [] = [reverse acc]
+        go [] (l : ls) = go [l] ls
+        go acc (l : ls)
+          | "- " `T.isPrefixOf` l = go (T.drop 2 l : acc) ls
+          | otherwise = reverse acc : go [l] ls
 
--- | @index v0 v1 i0 ... iN-1@
-cmdIndex :: Server -> VarName -> VarName -> [Int] -> IO (Maybe CmdFailure)
-cmdIndex s v0 v1 is =
-  helpCmd s "index" $ [v0, v1] <> map (T.pack . show) is
+    mkVariant :: [Text] -> Variant
+    mkVariant (n : ts) = Variant n ts
+    mkVariant [] = error $ "Invalid output of \"variants " ++ T.unpack t ++ "\""
+
+-- | @construct var0 type variant var1...@
+cmdConstruct :: Server -> VarName -> TypeName -> VariantName -> [VarName] -> IO (Maybe CmdFailure)
+cmdConstruct s var0 t variant vars = helpCmd s "construct" $ var0 : t : variant : vars
+
+-- | @destruct var0 var1...@
+cmdDestruct :: Server -> VarName -> [VarName] -> IO (Maybe CmdFailure)
+cmdDestruct s var0 vars = helpCmd s "destruct" $ var0 : vars
+
+-- | @variant v@
+cmdVariant :: Server -> VarName -> IO (Either CmdFailure VariantName)
+cmdVariant s v = sendCommandSL s "variant" [v]
 
 -- | Turn a 'Maybe'-producing command into a monadic action.
 cmdMaybe :: (MonadError Text m, MonadIO m) => IO (Maybe CmdFailure) -> m ()
