diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # Changelog
 
+## 0.5.0.0 — 2026-08-22
+
+### Fixed
+
+- `kioku recall --strategy` now uses `Kioku.Api.Recall`'s canonical parser, enumeration, rendered
+  spellings, and invalid-value diagnostic. Accepted commands and the default remain unchanged;
+  the CLI no longer carries a second case expression or help-text list that can drift.
+
 ## 0.4.1.0 — 2026-08-18
 
 ### Changed
diff --git a/kioku-cli.cabal b/kioku-cli.cabal
--- a/kioku-cli.cabal
+++ b/kioku-cli.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.0
 name:            kioku-cli
-version:         0.4.1.0
+version:         0.5.0.0
 synopsis:        kioku command-line interface
 description:
   Command-line entry point for kioku demos and operational commands.
@@ -76,8 +76,8 @@
     , containers            >=0.6      && <0.8
     , directory             >=1.3      && <1.4
     , effectful             >=2.5      && <2.7
-    , kioku-api             ^>=0.4.1.0
-    , kioku-core            ^>=0.4.1.0
+    , kioku-api             ^>=0.5.0.0
+    , kioku-core            ^>=0.5.0.0
     , kiroku-store          ^>=0.8.0.0
     , optparse-applicative  >=0.18     && <0.20
     , text                  >=2.1      && <2.2
@@ -90,7 +90,7 @@
   ghc-options:    -threaded -rtsopts -with-rtsopts=-N
   build-depends:
     , base       >=4.21     && <5
-    , kioku-cli  ^>=0.4.1.0
+    , kioku-cli  ^>=0.5.0.0
 
 test-suite kioku-cli-test
   import:             warnings, shared
@@ -110,10 +110,10 @@
   build-depends:
     , base                           >=4.21     && <5
     , effectful                      >=2.5      && <2.7
-    , kioku-api                      ^>=0.4.1.0
-    , kioku-cli                      ^>=0.4.1.0
-    , kioku-core                     ^>=0.4.1.0
-    , kioku-migrations:test-support  ^>=0.4.1.0
+    , kioku-api                      ^>=0.5.0.0
+    , kioku-cli                      ^>=0.5.0.0
+    , kioku-core                     ^>=0.5.0.0
+    , kioku-migrations:test-support  ^>=0.5.0.0
     , kiroku-store                   ^>=0.8.0.0
     , optparse-applicative           >=0.18
     , process                        >=1.6      && <1.7
diff --git a/src/Kioku/Cli/Commands/Recall.hs b/src/Kioku/Cli/Commands/Recall.hs
--- a/src/Kioku/Cli/Commands/Recall.hs
+++ b/src/Kioku/Cli/Commands/Recall.hs
@@ -17,6 +17,9 @@
 -- @kioku recall --scope mori@ to a fraction of its rows, with no compiler to warn and a zero exit
 -- status, which is the direction @docs\/adr\/an-explicit-recall-target-replaces-the-overloaded-scope.md@
 -- records as the unsafe one.
+--
+-- The strategy spelling, enumeration, and invalid-value diagnostic are owned by
+-- "Kioku.Api.Recall"; this module only adapts that vocabulary to optparse-applicative.
 module Kioku.Cli.Commands.Recall
   ( RecallOptions (..),
     recallOptionsParser,
@@ -27,6 +30,7 @@
   )
 where
 
+import Data.Bifunctor (first)
 import Data.Text (Text)
 import Data.Text qualified as Text
 import Kioku.Api.Access (memoryContextSpace, memorySpaceIdText)
@@ -37,7 +41,16 @@
 import Kioku.Cli.Options (boundedIntReader)
 import Kioku.Cli.Scope (parseNamespaceOnly, parseScope)
 import Kioku.Memory.Embedding (EmbeddingConfig (..), resolveEmbeddingConfig, toEmbeddingModel)
-import Kioku.Recall (RecallHit (..), RecallStrategy (..), RecallTarget (..), mkRecallQuery, recall)
+import Kioku.Recall
+  ( RecallHit (..),
+    RecallStrategy (..),
+    RecallTarget (..),
+    allRecallStrategies,
+    mkRecallQuery,
+    parseRecallStrategy,
+    recall,
+    recallStrategyText,
+  )
 import Kioku.Recall.Capability (detectVectorCapability)
 import Kiroku.Store.Connection (defaultConnectionSettings)
 import Options.Applicative
@@ -60,9 +73,9 @@
     <$> (Text.pack <$> argument str (metavar "QUERY"))
     <*> recallTargetParser
     <*> option
-      (eitherReader parseStrategy)
+      (eitherReader (first Text.unpack . parseRecallStrategy . Text.pack))
       ( long "strategy"
-          <> metavar "keyword|embedding|hybrid"
+          <> metavar strategyMetavar
           <> value Hybrid
           <> help "Recall strategy"
       )
@@ -182,12 +195,9 @@
       Right (Right []) -> putStrLn "(no matches)"
       Right (Right hits) -> mapM_ (printHit opts.showScores) (zip [(1 :: Int) ..] hits)
 
-parseStrategy :: String -> Either String RecallStrategy
-parseStrategy = \case
-  "keyword" -> Right Keyword
-  "embedding" -> Right Embedding
-  "hybrid" -> Right Hybrid
-  other -> Left ("unknown strategy: " <> other)
+strategyMetavar :: String
+strategyMetavar =
+  Text.unpack (Text.intercalate "|" (recallStrategyText <$> allRecallStrategies))
 
 printHit :: Bool -> (Int, RecallHit) -> IO ()
 printHit showScores (index, hit)
diff --git a/test/Kioku/Cli/ParserSpec.hs b/test/Kioku/Cli/ParserSpec.hs
--- a/test/Kioku/Cli/ParserSpec.hs
+++ b/test/Kioku/Cli/ParserSpec.hs
@@ -17,7 +17,13 @@
 import Kioku.Cli.Scope (parseScope)
 import Kioku.Id (genMemoryId, genSessionId, idText)
 import Kioku.Memory.Embedding.Worker (EmbeddingBackfillScope (..))
-import Kioku.Recall (RecallTarget (..))
+import Kioku.Recall
+  ( RecallStrategy (..),
+    RecallTarget (..),
+    allRecallStrategies,
+    parseRecallStrategy,
+    recallStrategyText,
+  )
 import Options.Applicative
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.HUnit (assertBool, testCase, (@?=))
@@ -29,6 +35,7 @@
     [ sessionIdTests,
       scopeTests,
       recallTargetTests,
+      strategyTests,
       limitTests,
       demoGuardTests,
       redactionTests,
@@ -176,6 +183,33 @@
         assertBool
           ("failure should name the conflicting flag " <> rejected <> ": " <> err)
           (rejected `isInfixOf` err)
+
+-- | The API owns the strategy wire spelling, accepted enumeration, and diagnostic. The CLI
+-- adapts that vocabulary to optparse-applicative without restating any of it.
+strategyTests :: TestTree
+strategyTests =
+  testGroup
+    "recall strategy uses the API vocabulary"
+    [ testCase "every API strategy parses to itself" do
+        mapM_
+          (\expected -> strategy ["--strategy", Text.unpack (recallStrategyText expected)] @?= Right expected)
+          allRecallStrategies,
+      testCase "omission still defaults to hybrid" do
+        strategy [] @?= Right Hybrid,
+      testCase "an invalid value uses the API diagnostic and accepted list" do
+        let invalid = "fuzzy"
+            expected = either Text.unpack (const "unexpected success") (parseRecallStrategy invalid)
+        case strategy ["--strategy", Text.unpack invalid] of
+          Right parsed -> assertBool ("invalid strategy parsed as " <> show parsed) False
+          Left err ->
+            assertBool
+              ("CLI error does not contain the API diagnostic: " <> err)
+              (expected `isInfixOf` err)
+    ]
+  where
+    strategy extra =
+      fmap (.strategy) $
+        parseWith recallOptionsParser (["query", "--namespace-wide", "mori"] <> extra)
 
 -- | Out-of-range limits are a parse error, not a Postgres error (@--limit -1@ used to reach
 -- SQL and come back as @LIMIT must not be negative@).
