diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,92 @@
 
 ## [Unreleased]
 
+## [baikai 0.4.1.0] - 2026-07-20
+
+### Changed
+
+- Version bump only; no library API or code changes. Released so the umbrella
+  release tag `baikai-0.4.1.0` names a fresh core version alongside the breaking
+  `baikai-claude` / `baikai-openai` 0.4.0.0 releases, matching the tag
+  convention downstream consumers pin against.
+
+## [baikai-claude 0.4.0.0] - 2026-07-20
+
+### Changed
+
+- **Breaking:** `claudeCliCommand` now takes the `Options` record and forwards
+  `Options.thinking` to batch `claude -p` as `--effort <level>` (`minimal`
+  collapses to `low`, matching the interactive launcher and the claude CLI's
+  lack of a `minimal` value). `thinking = Nothing` emits no effort flag, keeping
+  existing argv byte-for-byte. The added parameter is a PVP-major signature
+  change.
+
+## [baikai-openai 0.4.0.0] - 2026-07-20
+
+### Changed
+
+- **Breaking:** `codexCliCommand` now takes the `Options` record and forwards
+  `Options.thinking` to `codex exec` as `-c model_reasoning_effort=<level>` for
+  all six effort levels. `thinking = Nothing` emits no override, keeping
+  existing argv byte-for-byte. The added parameter is a PVP-major signature
+  change.
+
+## [baikai 0.4.0.0] - 2026-07-20
+
+### Added
+
+- Added `ThinkingXHigh` and `ThinkingMax` to the exported `ThinkingLevel`
+  vocabulary and added a defaulted `InteractiveLaunchRequest.effort` field.
+  Extending the closed sum type is a PVP-major API change for downstream
+  exhaustive matches.
+
+## [baikai-claude 0.3.0.2] - 2026-07-20
+
+### Added
+
+- Added `--effort` rendering to interactive Claude Code launches and preserved
+  `xhigh` / `max` on native adaptive Anthropic API requests, with larger fixed
+  budgets for manual-thinking models.
+
+### Changed
+
+- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
+  baikai 0.4.0.0 release.
+
+## [baikai-openai 0.3.0.2] - 2026-07-20
+
+### Added
+
+- Added `model_reasoning_effort` overrides to interactive Codex launches and
+  preserved `xhigh` / `max` in native OpenAI request JSON; non-native
+  OpenAI-compatible request shapes continue to clamp them to `high`.
+
+### Changed
+
+- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
+  baikai 0.4.0.0 release.
+
+## [baikai-trace-otel 0.3.0.2] - 2026-07-20
+
+### Changed
+
+- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
+  baikai 0.4.0.0 release. No API changes.
+
+## [baikai-effectful 0.3.0.2] - 2026-07-20
+
+### Changed
+
+- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
+  baikai 0.4.0.0 release. No API changes.
+
+## [baikai-kit 0.1.0.3] - 2026-07-20
+
+### Changed
+
+- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
+  baikai 0.4.0.0 release. No API changes.
+
 ## [baikai 0.3.1.0] - 2026-07-15
 
 ### Added
diff --git a/baikai.cabal b/baikai.cabal
--- a/baikai.cabal
+++ b/baikai.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.4
 name:            baikai
-version:         0.3.1.0
+version:         0.4.1.0
 synopsis:        Unified Haskell interface for multiple AI providers
 description:
   baikai provides a unified, provider-agnostic Haskell interface for working
@@ -151,6 +151,7 @@
     InteractiveSpec
     StreamSpec
     SurfaceSpec
+    ThinkingLevelSpec
     TraceSpec
     UsageSpec
 
diff --git a/gen/GenModelsCore.hs b/gen/GenModelsCore.hs
--- a/gen/GenModelsCore.hs
+++ b/gen/GenModelsCore.hs
@@ -322,6 +322,7 @@
     dropTrailingEmpty
       ( header
           ++ concatMap (renderEntry . snd) entries
+          ++ renderAllModels (map (ident . snd) entries)
       )
   where
     dropTrailingEmpty = \case
@@ -371,6 +372,25 @@
         "import Data.Ratio ((%))",
         ""
       ]
+
+-- | Render the @allModels@ binding: every generated model in one list, in the
+-- same (identifier-sorted) order as the declarations above. Consumers can fold
+-- or filter this instead of hand-listing bindings, so a catalog change flows
+-- through automatically.
+renderAllModels :: [Text] -> [Text]
+renderAllModels idents =
+  "-- | Every model in the generated catalog, in declaration order."
+    : "allModels :: [Model]"
+    : "allModels ="
+    : case idents of
+      [] -> ["  []"]
+      _ ->
+        [ "  " <> prefix <> ident <> suffix
+        | (position, ident) <- zip [0 :: Int ..] idents,
+          let prefix = if position == 0 then "[ " else "  ",
+          let suffix = if position == length idents - 1 then "" else ","
+        ]
+          ++ ["  ]"]
 
 renderEntry :: GeneratedEntry -> [Text]
 renderEntry g =
diff --git a/src/Baikai/Interactive.hs b/src/Baikai/Interactive.hs
--- a/src/Baikai/Interactive.hs
+++ b/src/Baikai/Interactive.hs
@@ -15,6 +15,7 @@
     extraDirs,
     safety,
     extraArgs,
+    effort,
     InteractiveSafety (..),
     CodexSandboxMode (..),
     CodexApprovalPolicy (..),
@@ -31,6 +32,7 @@
 where
 
 import Baikai.Prelude
+import Baikai.ThinkingLevel (ThinkingLevel)
 import System.Exit (ExitCode)
 
 -- | Local interactive provider families that Baikai knows how to
@@ -56,7 +58,8 @@
     workingDir :: !(Maybe FilePath),
     extraDirs :: ![FilePath],
     safety :: !InteractiveSafety,
-    extraArgs :: ![Text]
+    extraArgs :: ![Text],
+    effort :: !(Maybe ThinkingLevel)
   }
   deriving stock (Eq, Show, Generic)
 
@@ -98,7 +101,8 @@
       workingDir = Nothing,
       extraDirs = [],
       safety = DefaultSafety,
-      extraArgs = []
+      extraArgs = [],
+      effort = Nothing
     }
 
 interactiveLaunchResult :: InteractiveProvider -> ExitCode -> InteractiveLaunchResult
diff --git a/src/Baikai/Models/Generated.hs b/src/Baikai/Models/Generated.hs
--- a/src/Baikai/Models/Generated.hs
+++ b/src/Baikai/Models/Generated.hs
@@ -841,3 +841,43 @@
       headers = Map.empty,
       compat = CompatNone
     }
+
+-- | Every model in the generated catalog, in declaration order.
+allModels :: [Model]
+allModels =
+  [ anthropic_claude_fable_5,
+    anthropic_claude_haiku_4_5,
+    anthropic_claude_opus_4_5,
+    anthropic_claude_opus_4_6,
+    anthropic_claude_opus_4_7,
+    anthropic_claude_opus_4_8,
+    anthropic_claude_sonnet_4_5,
+    anthropic_claude_sonnet_4_6,
+    anthropic_claude_sonnet_5,
+    deepseek_deepseek_chat,
+    deepseek_deepseek_reasoner,
+    openai_gpt_4_1,
+    openai_gpt_4_1_mini,
+    openai_gpt_4_1_nano,
+    openai_gpt_4o,
+    openai_gpt_4o_mini,
+    openai_gpt_5,
+    openai_gpt_5_1,
+    openai_gpt_5_2,
+    openai_gpt_5_4,
+    openai_gpt_5_4_mini,
+    openai_gpt_5_4_nano,
+    openai_gpt_5_5,
+    openai_gpt_5_6,
+    openai_gpt_5_6_luna,
+    openai_gpt_5_6_sol,
+    openai_gpt_5_6_terra,
+    openai_gpt_5_mini,
+    openai_gpt_5_nano,
+    openai_o1,
+    openai_o3,
+    openai_o3_mini,
+    openai_o4_mini,
+    openrouter_anthropic_claude_sonnet_4,
+    openrouter_openai_gpt_4o_mini
+  ]
diff --git a/src/Baikai/ThinkingLevel.hs b/src/Baikai/ThinkingLevel.hs
--- a/src/Baikai/ThinkingLevel.hs
+++ b/src/Baikai/ThinkingLevel.hs
@@ -2,10 +2,10 @@
 
 -- | Provider-agnostic reasoning-effort preference.
 --
--- Each provider maps the value to its own primitive: OpenAI uses
--- @reasoning_effort: "minimal" | "low" | "medium" | "high"@;
--- Anthropic uses a token budget on its @thinking@ field.
--- 'thinkingTokenBudget' provides the recommended budget for the
+-- Each provider maps the value to its own primitive. The canonical
+-- rendering spans @minimal@ through @max@, while provider boundaries
+-- may preserve, translate, or clamp values according to their APIs.
+-- 'thinkingTokenBudget' provides the recommended budget for
 -- token-based providers.
 module Baikai.ThinkingLevel
   ( ThinkingLevel (..),
@@ -19,24 +19,29 @@
 import GHC.Generics (Generic)
 import Numeric.Natural (Natural)
 
--- | The four buckets pi-mono settled on. Coarse enough that callers
--- do not need to learn each provider's TTL conventions, fine enough
--- to influence behaviour in a meaningful way.
+-- | Provider-neutral reasoning-effort buckets, ordered from least to
+-- most effort. Coarse enough that callers do not need to learn each
+-- provider's vocabulary, fine enough to influence behaviour in a
+-- meaningful way.
 data ThinkingLevel
   = ThinkingMinimal
   | ThinkingLow
   | ThinkingMedium
   | ThinkingHigh
+  | ThinkingXHigh
+  | ThinkingMax
   deriving stock (Eq, Ord, Show, Generic)
   deriving anyclass (FromJSON, ToJSON)
 
--- | The wire string OpenAI's @reasoning_effort@ field expects.
+-- | Render the canonical Baikai name for a reasoning-effort level.
 renderThinkingLevel :: ThinkingLevel -> Text
 renderThinkingLevel = \case
   ThinkingMinimal -> "minimal"
   ThinkingLow -> "low"
   ThinkingMedium -> "medium"
   ThinkingHigh -> "high"
+  ThinkingXHigh -> "xhigh"
+  ThinkingMax -> "max"
 
 -- | Recommended token budget for providers that take an explicit
 -- count (Anthropic's @thinking.budget_tokens@).
@@ -46,3 +51,5 @@
   ThinkingLow -> 2048
   ThinkingMedium -> 8192
   ThinkingHigh -> 16384
+  ThinkingXHigh -> 24576
+  ThinkingMax -> 32768
diff --git a/test/InteractiveSpec.hs b/test/InteractiveSpec.hs
--- a/test/InteractiveSpec.hs
+++ b/test/InteractiveSpec.hs
@@ -27,6 +27,7 @@
     req ^. #extraDirs @?= []
     req ^. #safety @?= DefaultSafety
     req ^. #extraArgs @?= []
+    req ^. #effort @?= Nothing
 
 providerRenderingTest :: TestTree
 providerRenderingTest =
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -27,6 +27,7 @@
 import Test.Tasty.HUnit (assertBool, testCase, (@?=))
 import Test.Tasty.QuickCheck (Gen)
 import Test.Tasty.QuickCheck qualified as QC
+import ThinkingLevelSpec qualified
 import TraceSpec qualified
 import UsageSpec qualified
 
@@ -101,6 +102,7 @@
         InteractiveSpec.tests,
         StreamSpec.tests,
         SurfaceSpec.tests,
+        ThinkingLevelSpec.tests,
         TraceSpec.tests,
         UsageSpec.tests
       ]
diff --git a/test/ThinkingLevelSpec.hs b/test/ThinkingLevelSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/ThinkingLevelSpec.hs
@@ -0,0 +1,36 @@
+module ThinkingLevelSpec (tests) where
+
+import Baikai.ThinkingLevel
+import Data.Text (Text)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (testCase, (@?=))
+
+tests :: TestTree
+tests =
+  testGroup
+    "ThinkingLevel"
+    [ testGroup "canonical rendering" renderTests,
+      testGroup "token budgets" budgetTests
+    ]
+
+levels :: [(String, ThinkingLevel, Text, Integer)]
+levels =
+  [ ("minimal", ThinkingMinimal, "minimal", 1024),
+    ("low", ThinkingLow, "low", 2048),
+    ("medium", ThinkingMedium, "medium", 8192),
+    ("high", ThinkingHigh, "high", 16384),
+    ("xhigh", ThinkingXHigh, "xhigh", 24576),
+    ("max", ThinkingMax, "max", 32768)
+  ]
+
+renderTests :: [TestTree]
+renderTests =
+  [ testCase name $ renderThinkingLevel level @?= expected
+  | (name, level, expected, _) <- levels
+  ]
+
+budgetTests :: [TestTree]
+budgetTests =
+  [ testCase name $ thinkingTokenBudget level @?= fromInteger expected
+  | (name, level, _, expected) <- levels
+  ]
