diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Changelog for settei-formats
+
+## 0.2.0.0 — 2026-07-19
+
+- Initial experimental release.
+- Add tagged `FORMAT:PATH` configuration inputs, a shared loader dispatching to the
+  YAML, KDL, and Dhall adapters, and a reusable `--config FORMAT:PATH` option.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2026, shinzui
+All rights reserved.
+
+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/settei-formats.cabal b/settei-formats.cabal
new file mode 100644
--- /dev/null
+++ b/settei-formats.cabal
@@ -0,0 +1,81 @@
+cabal-version:   3.8
+name:            settei-formats
+version:         0.2.0.0
+synopsis:        Tagged multi-format configuration loading for Settei
+description:
+  Parse tagged FORMAT:PATH configuration inputs and load them through the
+  Settei YAML, KDL, and Dhall adapters with one shared dispatcher, so
+  multi-format applications stop hand-rolling the same reader and loader.
+
+homepage:        https://github.com/shinzui/settei
+bug-reports:     https://github.com/shinzui/settei/issues
+license:         BSD-3-Clause
+license-file:    LICENSE
+author:          shinzui
+maintainer:      shinzui
+category:        Configuration
+build-type:      Simple
+tested-with:     GHC ==9.12.4
+extra-doc-files: CHANGELOG.md
+data-files:
+  test/fixtures/*.dhall
+  test/fixtures/*.kdl
+  test/fixtures/*.yaml
+
+source-repository head
+  type:     git
+  location: https://github.com/shinzui/settei.git
+
+common common
+  default-language:   GHC2024
+  default-extensions:
+    DeriveAnyClass
+    DuplicateRecordFields
+    OverloadedLabels
+    OverloadedStrings
+
+  ghc-options:        -Wall -Wcompat
+
+library
+  import:          common
+  hs-source-dirs:  src
+  exposed-modules:
+    Settei.Formats
+    Settei.Formats.Optparse
+
+  build-depends:
+    , base                         >=4.21    && <5
+    , containers                   >=0.6.8   && <0.8
+    , generic-lens                 >=2.2     && <2.4
+    , optparse-applicative         >=0.19    && <0.20
+    , settei                       ==0.2.0.0
+    , settei-dhall                 ==0.2.0.0
+    , settei-kdl                   ==0.2.0.0
+    , settei-optparse-applicative  ==0.2.0.0
+    , settei-yaml                  ==0.2.0.0
+    , text                         >=2.1     && <2.2
+
+test-suite settei-formats-tests
+  import:          common
+  type:            exitcode-stdio-1.0
+  hs-source-dirs:  test
+  main-is:         Main.hs
+  other-modules:
+    Paths_settei_formats
+    Settei.FormatsOptparseTest
+    Settei.FormatsTest
+
+  autogen-modules: Paths_settei_formats
+  build-depends:
+    , base                  >=4.21    && <5
+    , containers            >=0.6.8   && <0.8
+    , generic-lens          >=2.2     && <2.4
+    , optparse-applicative  >=0.19    && <0.20
+    , settei                ==0.2.0.0
+    , settei-dhall          ==0.2.0.0
+    , settei-formats        ==0.2.0.0
+    , settei-kdl            ==0.2.0.0
+    , settei-yaml           ==0.2.0.0
+    , tasty                 >=1.5     && <1.6
+    , tasty-hunit           >=0.10.2  && <0.11
+    , text                  >=2.1     && <2.2
diff --git a/src/Settei/Formats.hs b/src/Settei/Formats.hs
new file mode 100644
--- /dev/null
+++ b/src/Settei/Formats.hs
@@ -0,0 +1,179 @@
+{-# LANGUAGE ImportQualifiedPost #-}
+
+-- |
+-- Module: Settei.Formats
+-- Description: Tagged multi-format configuration inputs and a shared adapter loader.
+module Settei.Formats
+  ( ConfigFormat (..),
+    ConfigInput,
+    FormatLoadError (..),
+    LoadOptions,
+    annotateLoadOptions,
+    configInput,
+    configInputFormat,
+    configInputPath,
+    defaultLoadOptions,
+    fromKubernetesMountedFile,
+    loadConfigInput,
+    loadOptionsAnnotations,
+    loadOptionsDhallImportPolicy,
+    loadOptionsKubernetesRef,
+    parseConfigInput,
+    renderFormatLoadErrorText,
+    withDhallImportPolicy,
+  )
+where
+
+import Data.Generics.Labels ()
+import Data.List.NonEmpty qualified as NonEmpty
+import Data.Map.Strict qualified as Map
+import Data.Text qualified as Text
+import Settei
+import Settei.Dhall qualified as Dhall
+import Settei.Kdl qualified as Kdl
+import Settei.Prelude
+import Settei.Yaml qualified as Yaml
+
+-- | Explicit format tag required for each configuration input.
+data ConfigFormat = YamlFormat | KdlFormat | DhallFormat
+  deriving stock (Generic, Eq, Ord, Show)
+
+-- | One ordered, explicitly tagged configuration file.
+data ConfigInput = ConfigInput
+  { format :: !ConfigFormat,
+    path :: !FilePath
+  }
+  deriving stock (Generic, Eq, Show)
+
+-- | Construct a tagged input programmatically.
+configInput :: ConfigFormat -> FilePath -> ConfigInput
+configInput format path = ConfigInput {format, path}
+
+-- | Return an input's explicit adapter tag.
+configInputFormat :: ConfigInput -> ConfigFormat
+configInputFormat value = value ^. #format
+
+-- | Return an input's filesystem path.
+configInputPath :: ConfigInput -> FilePath
+configInputPath value = value ^. #path
+
+-- | Parse the @FORMAT:PATH@ grammar: @yaml:PATH@, @kdl:PATH@, or @dhall:PATH@.
+--
+-- A missing colon or an empty path fails with @expected FORMAT:PATH@. Any other
+-- format name, including an empty one as in @:app.yaml@, fails with
+-- @FORMAT must be yaml, kdl, or dhall@.
+parseConfigInput :: String -> Either String ConfigInput
+parseConfigInput input =
+  let (formatName, separatorAndPath) = break (== ':') input
+      filePath = drop 1 separatorAndPath
+   in if null separatorAndPath || null filePath
+        then Left "expected FORMAT:PATH"
+        else case formatName of
+          "yaml" -> Right (configInput YamlFormat filePath)
+          "kdl" -> Right (configInput KdlFormat filePath)
+          "dhall" -> Right (configInput DhallFormat filePath)
+          _ -> Left "FORMAT must be yaml, kdl, or dhall"
+
+-- | How loaded sources should be annotated and how Dhall imports are policed.
+data LoadOptions = LoadOptions
+  { kubernetesReference :: !(Maybe KubernetesRef),
+    annotations :: !(Map Text Text),
+    dhallImportPolicy :: !Dhall.DhallImportPolicy
+  }
+  deriving stock (Generic)
+
+-- | No Kubernetes reference, no extra annotations, and @NoImports@ for Dhall.
+--
+-- The Dhall default is deliberately the most restrictive policy: a loader must
+-- never follow filesystem imports unless the caller explicitly names an allowed
+-- directory with 'withDhallImportPolicy'.
+defaultLoadOptions :: LoadOptions
+defaultLoadOptions =
+  LoadOptions
+    { kubernetesReference = Nothing,
+      annotations = Map.empty,
+      dhallImportPolicy = Dhall.NoImports
+    }
+
+-- | Attach a trusted Kubernetes reference for a mounted file. No cluster lookup occurs.
+fromKubernetesMountedFile :: KubernetesRef -> LoadOptions -> LoadOptions
+fromKubernetesMountedFile reference options =
+  options & #kubernetesReference ?~ reference
+
+-- | Add trusted, secret-safe annotations to every loaded source.
+annotateLoadOptions :: Map Text Text -> LoadOptions -> LoadOptions
+annotateLoadOptions extra options = options & #annotations %~ (extra <>)
+
+-- | Replace the Dhall import policy (default 'Dhall.NoImports').
+withDhallImportPolicy :: Dhall.DhallImportPolicy -> LoadOptions -> LoadOptions
+withDhallImportPolicy policy options = options & #dhallImportPolicy .~ policy
+
+-- | Return the optional mounted-file Kubernetes reference.
+loadOptionsKubernetesRef :: LoadOptions -> Maybe KubernetesRef
+loadOptionsKubernetesRef value = value ^. #kubernetesReference
+
+-- | Return caller-supplied trusted annotations.
+loadOptionsAnnotations :: LoadOptions -> Map Text Text
+loadOptionsAnnotations value = value ^. #annotations
+
+-- | Return the enforced Dhall import policy.
+loadOptionsDhallImportPolicy :: LoadOptions -> Dhall.DhallImportPolicy
+loadOptionsDhallImportPolicy value = value ^. #dhallImportPolicy
+
+-- | One failed tagged load, wrapping the originating adapter's full error list.
+data FormatLoadError
+  = YamlLoadError !(NonEmpty Yaml.YamlSourceError)
+  | KdlLoadError !(NonEmpty Kdl.KdlSourceError)
+  | DhallLoadError !(NonEmpty Dhall.DhallSourceError)
+  deriving stock (Generic, Eq, Show)
+
+-- | Load one tagged input through the adapter its format names.
+loadConfigInput ::
+  LoadOptions ->
+  ConfigInput ->
+  IO (Either (NonEmpty FormatLoadError) Source)
+loadConfigInput options input =
+  let sourceLabel = Text.pack (input ^. #path)
+      wrap wrapError = either (Left . NonEmpty.singleton . wrapError) Right
+      kubernetesAnnotationsOf =
+        maybe Map.empty kubernetesAnnotations (options ^. #kubernetesReference)
+   in case input ^. #format of
+        YamlFormat ->
+          let yamlOptions =
+                Yaml.annotateYamlSourceOptions
+                  (options ^. #annotations)
+                  ( maybe
+                      id
+                      Yaml.fromKubernetesMountedFile
+                      (options ^. #kubernetesReference)
+                      (Yaml.yamlSourceOptions sourceLabel)
+                  )
+           in wrap YamlLoadError <$> Yaml.readYamlSource yamlOptions (input ^. #path)
+        KdlFormat ->
+          let kdlOptions =
+                Kdl.annotateKdlSourceOptions
+                  (options ^. #annotations)
+                  ( maybe
+                      id
+                      Kdl.fromKubernetesMountedFile
+                      (options ^. #kubernetesReference)
+                      (Kdl.kdlSourceOptions sourceLabel)
+                  )
+           in wrap KdlLoadError <$> Kdl.readKdlSource kdlOptions (input ^. #path)
+        DhallFormat ->
+          let dhallOptions =
+                Dhall.annotateDhallSourceOptions
+                  (kubernetesAnnotationsOf <> options ^. #annotations)
+                  ( Dhall.dhallSourceOptions
+                      sourceLabel
+                      (options ^. #dhallImportPolicy)
+                  )
+           in wrap DhallLoadError
+                <$> Dhall.loadDhallSource dhallOptions (Dhall.DhallFile (input ^. #path))
+
+-- | Render one adapter load failure for operator-facing output.
+renderFormatLoadErrorText :: FormatLoadError -> Text
+renderFormatLoadErrorText = \case
+  YamlLoadError problems -> Yaml.renderYamlErrorsText problems
+  KdlLoadError problems -> Kdl.renderKdlErrorsText problems
+  DhallLoadError problems -> Dhall.renderDhallErrorsText problems
diff --git a/src/Settei/Formats/Optparse.hs b/src/Settei/Formats/Optparse.hs
new file mode 100644
--- /dev/null
+++ b/src/Settei/Formats/Optparse.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE ImportQualifiedPost #-}
+
+-- |
+-- Module: Settei.Formats.Optparse
+-- Description: Reusable @--config FORMAT:PATH@ options for tagged multi-format inputs.
+module Settei.Formats.Optparse
+  ( configInputOption,
+    configInputOptions,
+    configInputReader,
+  )
+where
+
+import Control.Applicative qualified as Applicative
+import Options.Applicative (Mod, OptionFields, Parser)
+import Options.Applicative qualified as Options
+import Settei.Formats
+
+-- | 'Options.ReadM' for the @FORMAT:PATH@ grammar of 'parseConfigInput'.
+configInputReader :: Options.ReadM ConfigInput
+configInputReader = Options.eitherReader parseConfigInput
+
+-- | Parse zero or more tagged inputs using caller-supplied option metadata.
+configInputOption :: Mod OptionFields ConfigInput -> Parser [ConfigInput]
+configInputOption modifiers =
+  Applicative.many (Options.option configInputReader modifiers)
+
+-- | Parse zero or more default @--config FORMAT:PATH@ occurrences.
+configInputOptions :: Parser [ConfigInput]
+configInputOptions =
+  configInputOption
+    ( Options.long "config"
+        <> Options.metavar "FORMAT:PATH"
+        <> Options.help "Load yaml:PATH, kdl:PATH, or dhall:PATH in occurrence order"
+    )
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,15 @@
+module Main (main) where
+
+import Settei.FormatsOptparseTest qualified
+import Settei.FormatsTest qualified
+import Test.Tasty (defaultMain, testGroup)
+
+main :: IO ()
+main =
+  defaultMain
+    ( testGroup
+        "settei-formats"
+        [ Settei.FormatsTest.tests,
+          Settei.FormatsOptparseTest.tests
+        ]
+    )
diff --git a/test/Settei/FormatsOptparseTest.hs b/test/Settei/FormatsOptparseTest.hs
new file mode 100644
--- /dev/null
+++ b/test/Settei/FormatsOptparseTest.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE ImportQualifiedPost #-}
+
+module Settei.FormatsOptparseTest (tests) where
+
+import Options.Applicative qualified as Options
+import Settei.Formats
+import Settei.Formats.Optparse
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (assertBool, testCase, (@?=))
+
+tests :: TestTree
+tests =
+  testGroup
+    "Settei.Formats.Optparse"
+    [ testCase "repeated --config inputs preserve occurrence order" $ do
+        parsed <-
+          expectParse
+            configInputOptions
+            ["--config", "yaml:a.yaml", "--config", "kdl:b.kdl"]
+        parsed
+          @?= [ configInput YamlFormat "a.yaml",
+                configInput KdlFormat "b.kdl"
+              ],
+      testCase "no --config occurrence produces an empty list" $ do
+        parsed <- expectParse configInputOptions []
+        parsed @?= [],
+      testCase "an unsupported format fails option parsing" $ do
+        let parsed = parse configInputOptions ["--config", "toml:x"]
+        assertBool
+          "unsupported format unexpectedly parsed"
+          (Options.getParseResult parsed == Nothing),
+      testCase "caller-supplied option metadata is honored" $ do
+        parsed <-
+          expectParse
+            (configInputOption (Options.long "input" <> Options.metavar "FORMAT:PATH"))
+            ["--input", "dhall:c.dhall"]
+        parsed @?= [configInput DhallFormat "c.dhall"]
+    ]
+
+parse :: Options.Parser a -> [String] -> Options.ParserResult a
+parse parser arguments =
+  Options.execParserPure Options.defaultPrefs (Options.info parser mempty) arguments
+
+expectParse :: Options.Parser a -> [String] -> IO a
+expectParse parser arguments = case parse parser arguments of
+  Options.Success value -> pure value
+  _ -> fail "expected command-line parsing to succeed"
diff --git a/test/Settei/FormatsTest.hs b/test/Settei/FormatsTest.hs
new file mode 100644
--- /dev/null
+++ b/test/Settei/FormatsTest.hs
@@ -0,0 +1,168 @@
+{-# LANGUAGE ImportQualifiedPost #-}
+
+module Settei.FormatsTest (tests) where
+
+import Data.Generics.Labels ()
+import Data.List.NonEmpty qualified as NonEmpty
+import Data.Map.Strict qualified as Map
+import Paths_settei_formats qualified as Paths
+import Settei
+import Settei.Dhall qualified as Dhall
+import Settei.Formats
+import Settei.Kdl qualified as Kdl
+import Settei.Prelude
+import Settei.Yaml qualified as Yaml
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (testCase, (@?=))
+
+tests :: TestTree
+tests =
+  testGroup
+    "Settei.Formats"
+    [ testGroup
+        "FORMAT:PATH grammar"
+        [ testCase "accepts yaml, kdl, and dhall tags" $ do
+            assertParsed "yaml:app.yaml" YamlFormat "app.yaml"
+            assertParsed "kdl:app.kdl" KdlFormat "app.kdl"
+            assertParsed "dhall:app.dhall" DhallFormat "app.dhall",
+          testCase "splits only at the first colon" $
+            assertParsed
+              "yaml:dir:with:colons.yaml"
+              YamlFormat
+              "dir:with:colons.yaml",
+          testCase "rejects missing separators and empty paths" $ do
+            parseConfigInput "app.yaml" @?= Left "expected FORMAT:PATH"
+            parseConfigInput "yaml:" @?= Left "expected FORMAT:PATH",
+          testCase "rejects unsupported and empty format names" $ do
+            parseConfigInput "toml:app.toml"
+              @?= Left "FORMAT must be yaml, kdl, or dhall"
+            parseConfigInput ":app.yaml"
+              @?= Left "FORMAT must be yaml, kdl, or dhall"
+        ],
+      testGroup
+        "adapter dispatch"
+        [ testCase "loads YAML and resolves a typed value" $
+            assertFixtureLoads YamlFormat "test/fixtures/app.yaml",
+          testCase "loads KDL and resolves a typed value" $
+            assertFixtureLoads KdlFormat "test/fixtures/app.kdl",
+          testCase "loads Dhall and resolves a typed value" $
+            assertFixtureLoads DhallFormat "test/fixtures/app.dhall"
+        ],
+      testCase "Kubernetes and caller annotations reach YAML and Dhall sources" $ do
+        yamlPath <- Paths.getDataFileName "test/fixtures/app.yaml"
+        dhallPath <- Paths.getDataFileName "test/fixtures/app.dhall"
+        let reference =
+              kubernetesRef
+                ConfigMapObject
+                Nothing
+                "settei-formats-test"
+                (Just "app.yaml")
+            options =
+              fromKubernetesMountedFile
+                reference
+                ( annotateLoadOptions
+                    (Map.singleton "team" "platform")
+                    defaultLoadOptions
+                )
+        yamlSource <- expectLoaded options (configInput YamlFormat yamlPath)
+        assertAnnotations yamlSource
+        dhallSource <- expectLoaded options (configInput DhallFormat dhallPath)
+        assertAnnotations dhallSource,
+      testCase "Dhall imports are denied by default and allowed explicitly" $ do
+        importPath <- Paths.getDataFileName "test/fixtures/imports.dhall"
+        fixturesDirectory <- Paths.getDataFileName "test/fixtures"
+        loadOptionsDhallImportPolicy defaultLoadOptions @?= Dhall.NoImports
+        denied <- loadConfigInput defaultLoadOptions (configInput DhallFormat importPath)
+        case denied of
+          Left outerErrors -> case NonEmpty.toList outerErrors of
+            [DhallLoadError problems] ->
+              fmap Dhall.dhallErrorCategory (NonEmpty.toList problems)
+                @?= [Dhall.DhallImportPolicyError]
+            _ -> fail "expected one Dhall load error"
+          Right _ -> fail "expected the default Dhall policy to reject imports"
+        imported <-
+          expectLoaded
+            ( withDhallImportPolicy
+                (Dhall.LocalImportsWithin fixturesDirectory)
+                defaultLoadOptions
+            )
+            (configInput DhallFormat importPath)
+        assertResolvedEndpoint imported,
+      testCase "a missing YAML file is a structured load error" $ do
+        missing <-
+          loadConfigInput
+            defaultLoadOptions
+            (configInput YamlFormat "settei-formats-missing.yaml")
+        case missing of
+          Left outerErrors -> case NonEmpty.toList outerErrors of
+            [YamlLoadError problems] ->
+              fmap Yaml.yamlErrorCategory (NonEmpty.toList problems)
+                @?= [Yaml.YamlIoError]
+            _ -> fail "expected one YAML load error"
+          Right _ -> fail "expected a missing YAML file to fail",
+      testCase "format load errors delegate to adapter renderers" $ do
+        yamlError <- expectLoadError YamlFormat "settei-formats-missing.yaml"
+        case yamlError of
+          YamlLoadError problems ->
+            renderFormatLoadErrorText yamlError @?= Yaml.renderYamlErrorsText problems
+          _ -> fail "expected a YAML load error"
+        kdlError <- expectLoadError KdlFormat "settei-formats-missing.kdl"
+        case kdlError of
+          KdlLoadError problems ->
+            renderFormatLoadErrorText kdlError @?= Kdl.renderKdlErrorsText problems
+          _ -> fail "expected a KDL load error"
+        dhallError <- expectLoadError DhallFormat "settei-formats-missing.dhall"
+        case dhallError of
+          DhallLoadError problems ->
+            renderFormatLoadErrorText dhallError @?= Dhall.renderDhallErrorsText problems
+          _ -> fail "expected a Dhall load error"
+    ]
+
+assertParsed :: String -> ConfigFormat -> FilePath -> IO ()
+assertParsed input expectedFormat expectedPath = case parseConfigInput input of
+  Left problem -> fail problem
+  Right parsed -> do
+    configInputFormat parsed @?= expectedFormat
+    configInputPath parsed @?= expectedPath
+
+assertFixtureLoads :: ConfigFormat -> FilePath -> IO ()
+assertFixtureLoads format relativePath = do
+  fixturePath <- Paths.getDataFileName relativePath
+  loaded <- expectLoaded defaultLoadOptions (configInput format fixturePath)
+  assertResolvedEndpoint loaded
+
+expectLoaded :: LoadOptions -> ConfigInput -> IO Source
+expectLoaded options input = do
+  result <- loadConfigInput options input
+  case result of
+    Left problems -> fail (show problems)
+    Right loaded -> pure loaded
+
+expectLoadError :: ConfigFormat -> FilePath -> IO FormatLoadError
+expectLoadError format path = do
+  result <- loadConfigInput defaultLoadOptions (configInput format path)
+  case result of
+    Left problems -> case NonEmpty.toList problems of
+      [problem] -> pure problem
+      _ -> fail "expected one format load error"
+    Right _ -> fail "expected format loading to fail"
+
+assertResolvedEndpoint :: Source -> IO ()
+assertResolvedEndpoint input =
+  case (resolve defaultResolveOptions [input] endpointConfig) ^. #answer of
+    Left problems -> fail (show problems)
+    Right endpoint -> endpoint @?= "https://example.test"
+
+assertAnnotations :: Source -> IO ()
+assertAnnotations input = do
+  Map.lookup "kubernetes.object-kind" (sourceAnnotations input) @?= Just "ConfigMap"
+  Map.lookup "kubernetes.object-name" (sourceAnnotations input)
+    @?= Just "settei-formats-test"
+  Map.lookup "team" (sourceAnnotations input) @?= Just "platform"
+
+endpointConfig :: Config Text
+endpointConfig =
+  required (publicSetting endpointKey "Service endpoint" textDecoder)
+
+endpointKey :: Key
+endpointKey = either (error . show) id (parseKey "service.endpoint")
diff --git a/test/fixtures/app.dhall b/test/fixtures/app.dhall
new file mode 100644
--- /dev/null
+++ b/test/fixtures/app.dhall
@@ -0,0 +1,1 @@
+{ service = { endpoint = "https://example.test" } }
diff --git a/test/fixtures/app.kdl b/test/fixtures/app.kdl
new file mode 100644
--- /dev/null
+++ b/test/fixtures/app.kdl
@@ -0,0 +1,3 @@
+service {
+  endpoint "https://example.test"
+}
diff --git a/test/fixtures/app.yaml b/test/fixtures/app.yaml
new file mode 100644
--- /dev/null
+++ b/test/fixtures/app.yaml
@@ -0,0 +1,2 @@
+service:
+  endpoint: https://example.test
diff --git a/test/fixtures/imports.dhall b/test/fixtures/imports.dhall
new file mode 100644
--- /dev/null
+++ b/test/fixtures/imports.dhall
@@ -0,0 +1,1 @@
+./app.dhall
