diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 # Changelog
 
+## 0.7.0.0 — 2026-09-18
+
+### Changed
+
+- Requires the Kioku 0.7 cohort and optparse-applicative `>=0.19 && <0.20`.
+- Help renders at a stable 100-column width and groups recall targets, query/output controls, AI
+  configuration, and worker execution modes under semantic headings. Command names, option
+  spellings, defaults, and errors are unchanged.
+- Bash, zsh, and fish completion-script requests are covered as public parser behavior.
+
 ## 0.6.0.0 — 2026-09-08
 
 ### Breaking Changes
diff --git a/kioku-cli.cabal b/kioku-cli.cabal
--- a/kioku-cli.cabal
+++ b/kioku-cli.cabal
@@ -1,35 +1,40 @@
-cabal-version:   3.0
-name:            kioku-cli
-version:         0.6.0.0
-synopsis:        kioku command-line interface
+cabal-version: 3.0
+name: kioku-cli
+version: 0.7.0.0
+synopsis: kioku command-line interface
 description:
   Command-line entry point for kioku demos and operational commands.
 
-license:         BSD-3-Clause
-license-file:    LICENSE
-author:          Nadeem Bitar
-maintainer:      nadeem@gmail.com
-copyright:       2026 Nadeem Bitar
-category:        Data
-build-type:      Simple
-tested-with:     GHC >=9.12 && <9.13
-homepage:        https://github.com/shinzui/kioku
-bug-reports:     https://github.com/shinzui/kioku/issues
+license: BSD-3-Clause
+license-file: LICENSE
+author: Nadeem Bitar
+maintainer: nadeem@gmail.com
+copyright: 2026 Nadeem Bitar
+category: Data
+build-type: Simple
+tested-with: ghc >=9.12 && <9.13
+homepage: https://github.com/shinzui/kioku
+bug-reports: https://github.com/shinzui/kioku/issues
 extra-doc-files: CHANGELOG.md
 
 source-repository head
-  type:     git
+  type: git
   location: https://github.com/shinzui/kioku.git
-  subdir:   kioku-cli
+  subdir: kioku-cli
 
 common warnings
   ghc-options:
-    -Wall -Wcompat -Widentities -Wincomplete-record-updates
-    -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints
+    -Wall
+    -Wcompat
+    -Widentities
+    -Wincomplete-record-updates
+    -Wincomplete-uni-patterns
+    -Wpartial-fields
+    -Wredundant-constraints
     -Werror=incomplete-patterns
 
 common shared
-  default-language:   GHC2024
+  default-language: GHC2024
   default-extensions:
     BlockArguments
     DeriveAnyClass
@@ -42,8 +47,8 @@
     TemplateHaskell
 
 library
-  import:           warnings, shared
-  hs-source-dirs:   src
+  import: warnings, shared
+  hs-source-dirs: src
   exposed-modules:
     Kioku.Cli
     Kioku.Cli.AIConfig
@@ -72,61 +77,68 @@
   -- mori://MMZK1526/mmzk-typeid/upstream-issues/mmzk-typeid-kindid-ghc-9-12-4-profiling-coercionkind-panic
   ghc-prof-options: -fno-opt-coercion
   build-depends:
-    , async                 >=2.2       && <2.3
-    , baikai                ^>=0.7.0.0
-    , base                  >=4.21      && <5
-    , containers            >=0.6       && <0.8
-    , directory             >=1.3       && <1.4
-    , effectful             >=2.5       && <2.7
-    , keiro                 ^>=0.16.0.0
-    , kioku-api             ^>=0.6.0.0
-    , kioku-core            ^>=0.6.0.0
-    , kiroku-store          ^>=0.8.0.0
-    , optparse-applicative  >=0.18      && <0.20
-    , text                  >=2.1       && <2.2
-    , time                  >=1.12      && <1.15
-    , uuid                  >=1.3       && <1.4
+    async >=2.2 && <2.3,
+    baikai ^>=0.7.0.0,
+    base >=4.21 && <5,
+    containers >=0.6 && <0.8,
+    directory >=1.3 && <1.4,
+    effectful >=2.5 && <2.7,
+    keiro ^>=0.17.0.0,
+    kioku-api ^>=0.7.0.0,
+    kioku-core ^>=0.7.0.0,
+    kiroku-store ^>=0.8.0.0,
+    optparse-applicative >=0.19 && <0.20,
+    text >=2.1 && <2.2,
+    time >=1.12 && <1.15,
+    uuid >=1.3 && <1.4,
 
 executable kioku
-  import:         warnings, shared
-  main-is:        Main.hs
+  import: warnings, shared
+  main-is: Main.hs
   hs-source-dirs: app
-  ghc-options:    -threaded -rtsopts -with-rtsopts=-N
+  ghc-options:
+    -threaded
+    -rtsopts
+    -with-rtsopts=-N
+
   build-depends:
-    , base       >=4.21     && <5
-    , kioku-cli  ^>=0.6.0.0
+    base >=4.21 && <5,
+    kioku-cli ^>=0.7.0.0,
 
 test-suite kioku-cli-test
-  import:             warnings, shared
-  type:               exitcode-stdio-1.0
-  main-is:            Main.hs
-  hs-source-dirs:     test
+  import: warnings, shared
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  hs-source-dirs: test
   other-modules:
     Kioku.Cli.ParserSpec
     Kioku.Cli.RecallEndToEndSpec
 
-  ghc-options:        -threaded -rtsopts -with-rtsopts=-N
+  ghc-options:
+    -threaded
+    -rtsopts
+    -with-rtsopts=-N
 
   -- Kioku.Cli.RecallEndToEndSpec runs the real binary as a subprocess: stdout, stderr and the
   -- environment are process-wide, and tasty runs cases concurrently, so redirecting them in
   -- process would race the rest of the suite.
   build-tool-depends: kioku-cli:kioku
   build-depends:
-    , aeson                          >=2.2       && <2.3
-    , base                           >=4.21      && <5
-    , effectful                      >=2.5       && <2.7
-    , filepath                       >=1.4       && <1.6
-    , keiro                          ^>=0.16.0.0
-    , kioku-api                      ^>=0.6.0.0
-    , kioku-cli                      ^>=0.6.0.0
-    , kioku-core                     ^>=0.6.0.0
-    , kioku-migrations:test-support  ^>=0.6.0.0
-    , kiroku-store                   ^>=0.8.0.0
-    , optparse-applicative           >=0.18
-    , process                        >=1.6       && <1.7
-    , tasty                          >=1.5
-    , tasty-hunit                    >=0.10
-    , temporary                      >=1.3
-    , text                           >=2.1
-    , time                           >=1.12      && <1.15
-    , uuid                           >=1.3       && <1.4
+    aeson >=2.2 && <2.3,
+    base >=4.21 && <5,
+    effectful >=2.5 && <2.7,
+    filepath >=1.4 && <1.6,
+    keiro ^>=0.17.0.0,
+    kioku-api ^>=0.7.0.0,
+    kioku-cli ^>=0.7.0.0,
+    kioku-core ^>=0.7.0.0,
+    kioku-migrations:test-support ^>=0.7.0.0,
+    kiroku-store ^>=0.8.0.0,
+    optparse-applicative >=0.19 && <0.20,
+    process >=1.6 && <1.7,
+    tasty >=1.5,
+    tasty-hunit >=0.10,
+    temporary >=1.3,
+    text >=2.1,
+    time >=1.12 && <1.15,
+    uuid >=1.3 && <1.4,
diff --git a/src/Kioku/Cli.hs b/src/Kioku/Cli.hs
--- a/src/Kioku/Cli.hs
+++ b/src/Kioku/Cli.hs
@@ -1,5 +1,7 @@
 module Kioku.Cli
-  ( main,
+  ( cliParserInfo,
+    cliParserPrefs,
+    main,
   )
 where
 
@@ -16,15 +18,21 @@
 data Command = Artifacts ArtifactsOptions | Demo DemoOptions | DemoSession DemoSessionOptions | Distill DistillOptions | Persona PersonaOptions | Recall RecallOptions | Scenes ScenesOptions | Worker WorkerOptions
 
 main :: IO ()
-main = run =<< execParser opts
-  where
-    opts =
-      info
-        (commandParser <**> helper)
-        ( fullDesc
-            <> progDesc "kioku reusable agent memory tools"
-            <> header "kioku"
-        )
+main = run =<< customExecParser cliParserPrefs cliParserInfo
+
+-- | A fixed width makes help output stable in terminals, tests, and generated
+-- documentation instead of inheriting the invoking process's console width.
+cliParserPrefs :: ParserPrefs
+cliParserPrefs = prefs (columns 100)
+
+cliParserInfo :: ParserInfo Command
+cliParserInfo =
+  info
+    (commandParser <**> helper)
+    ( fullDesc
+        <> progDesc "kioku reusable agent memory tools"
+        <> header "kioku"
+    )
 
 commandParser :: Parser Command
 commandParser =
diff --git a/src/Kioku/Cli/Commands/Distill.hs b/src/Kioku/Cli/Commands/Distill.hs
--- a/src/Kioku/Cli/Commands/Distill.hs
+++ b/src/Kioku/Cli/Commands/Distill.hs
@@ -49,25 +49,32 @@
     <$> argument
       (eitherReader parseSessionId)
       (metavar "SESSION_ID")
-    <*> option
-      (eitherReader parseCandidateSource)
-      ( long "candidates"
-          <> metavar "scan|recall"
-          <> value CandidateScan
-          <> help "Candidate lookup source"
-      )
-    <*> option
-      (boundedIntReader "LIMIT" 1 50)
-      ( long "limit"
-          <> metavar "N"
-          <> value 5
-          <> help "Maximum merge candidates per extracted atom (1-50)"
-      )
-    <*> switch
-      ( long "force"
-          <> help "Re-run even when the session has no turns newer than the last successful pass"
-      )
-    <*> aiConfigOption
+    <*> parserOptionGroup "Candidate options" candidateSourceParser
+    <*> parserOptionGroup "Candidate options" candidateLimitParser
+    <*> parserOptionGroup "Execution options" forceParser
+    <*> parserOptionGroup "AI options" aiConfigOption
+  where
+    candidateSourceParser =
+      option
+        (eitherReader parseCandidateSource)
+        ( long "candidates"
+            <> metavar "scan|recall"
+            <> value CandidateScan
+            <> help "Candidate lookup source"
+        )
+    candidateLimitParser =
+      option
+        (boundedIntReader "LIMIT" 1 50)
+        ( long "limit"
+            <> metavar "N"
+            <> value 5
+            <> help "Maximum merge candidates per extracted atom (1-50)"
+        )
+    forceParser =
+      switch
+        ( long "force"
+            <> help "Re-run even when the session has no turns newer than the last successful pass"
+        )
 
 runDistill :: DistillOptions -> IO ()
 runDistill opts = do
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
@@ -72,26 +72,33 @@
 recallOptionsParser =
   RecallOptions
     <$> (Text.pack <$> argument str (metavar "QUERY"))
-    <*> recallTargetParser
-    <*> option
-      (eitherReader (first Text.unpack . parseRecallStrategy . Text.pack))
-      ( long "strategy"
-          <> metavar strategyMetavar
-          <> value Hybrid
-          <> help "Recall strategy"
-      )
-    <*> option
-      (boundedIntReader "LIMIT" 1 100)
-      ( long "limit"
-          <> metavar "N"
-          <> value 8
-          <> help "Maximum hits to return (1-100)"
-      )
-    <*> switch
-      ( long "show-scores"
-          <> help "Print fused scores and component ranks"
-      )
-    <*> aiConfigOption
+    <*> parserOptionGroup "Recall target" recallTargetParser
+    <*> parserOptionGroup "Query options" strategyParser
+    <*> parserOptionGroup "Query options" limitParser
+    <*> parserOptionGroup "Output options" showScoresParser
+    <*> parserOptionGroup "AI options" aiConfigOption
+  where
+    strategyParser =
+      option
+        (eitherReader (first Text.unpack . parseRecallStrategy . Text.pack))
+        ( long "strategy"
+            <> metavar strategyMetavar
+            <> value Hybrid
+            <> help "Recall strategy"
+        )
+    limitParser =
+      option
+        (boundedIntReader "LIMIT" 1 100)
+        ( long "limit"
+            <> metavar "N"
+            <> value 8
+            <> help "Maximum hits to return (1-100)"
+        )
+    showScoresParser =
+      switch
+        ( long "show-scores"
+            <> help "Print fused scores and component ranks"
+        )
 
 -- | Exactly one of the three target flags, and never two.
 --
diff --git a/src/Kioku/Cli/Commands/Worker.hs b/src/Kioku/Cli/Commands/Worker.hs
--- a/src/Kioku/Cli/Commands/Worker.hs
+++ b/src/Kioku/Cli/Commands/Worker.hs
@@ -61,7 +61,10 @@
   deriving stock (Eq, Show)
 
 workerOptionsParser :: Parser WorkerOptions
-workerOptionsParser = (\config mode -> maybe mode (`WorkerConfigured` mode) config) <$> aiConfigOption <*> workerModeParser
+workerOptionsParser =
+  (\config mode -> maybe mode (`WorkerConfigured` mode) config)
+    <$> parserOptionGroup "AI options" aiConfigOption
+    <*> parserOptionGroup "Execution mode" workerModeParser
 
 workerModeParser :: Parser WorkerOptions
 workerModeParser =
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
@@ -10,6 +10,7 @@
 import Keiro.Timer (TimerId (..))
 import Kioku.Api.Access (mkMemorySpaceId)
 import Kioku.Api.Scope (MemoryScope (..), Namespace (..), ScopeKind (..))
+import Kioku.Cli (cliParserInfo, cliParserPrefs)
 import Kioku.Cli.Commands.Demo (DemoOptions (..), demoOptionsParser, demoScope)
 import Kioku.Cli.Commands.DemoSession (DemoSessionOptions (..), demoSessionOptionsParser)
 import Kioku.Cli.Commands.Distill (DistillOptions (..), distillOptionsParser)
@@ -27,6 +28,7 @@
     recallStrategyText,
   )
 import Options.Applicative
+import System.Exit (ExitCode (..))
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.HUnit (assertBool, testCase, (@?=))
 
@@ -41,7 +43,8 @@
       limitTests,
       demoGuardTests,
       redactionTests,
-      workerModeTests
+      workerModeTests,
+      cliContractTests
     ]
 
 -- | Run a parser against an argument list, rendering a failure the way the real CLI would.
@@ -157,7 +160,7 @@
           Left err -> do
             assertBool ("failure should say what is missing: " <> err) ("Missing:" `isInfixOf` err)
             mapM_
-              (\flag -> assertBool ("failure should list " <> flag <> ": " <> err) (flag `isInfixOf` err))
+              (\flagName -> assertBool ("failure should list " <> flagName <> ": " <> err) (flagName `isInfixOf` err))
               ["--scope", "--global-bucket", "--namespace-wide"],
       testCase "two targets is a parse error naming the second" do
         assertConflict "--namespace-wide" (target ["--scope", "a:b:c", "--namespace-wide", "mori"]),
@@ -347,3 +350,68 @@
 
     spaceNamed raw =
       either (error . Text.unpack) id (mkMemorySpaceId (Text.pack raw))
+
+-- | Help and completion are public CLI output even though the parser values are
+-- pure. Keep their structure stable without pinning incidental whitespace.
+cliContractTests :: TestTree
+cliContractTests =
+  testGroup
+    "top-level help and completion contract"
+    [ testCase "top-level help lists every command at the stable width" do
+        rendered <- renderHelp ["--help"]
+        mapM_
+          (\commandName -> assertBool ("help should list " <> commandName) (commandName `isInfixOf` rendered))
+          [ "demo",
+            "demo-session",
+            "distill",
+            "migrate-artifacts",
+            "persona",
+            "recall",
+            "scenes",
+            "worker"
+          ]
+        assertStableWidth rendered,
+      testCase "worker help exposes semantic option groups" do
+        rendered <- renderHelp ["worker", "--help"]
+        assertBool ("worker help should show the AI group:\n" <> rendered) ("AI options" `isInfixOf` rendered)
+        assertBool ("worker help should show the execution group:\n" <> rendered) ("Execution mode" `isInfixOf` rendered)
+        assertStableWidth rendered,
+      testCase "recall help exposes target, query, and output groups" do
+        rendered <- renderHelp ["recall", "--help"]
+        mapM_
+          (\heading -> assertBool ("recall help should show " <> heading <> ":\n" <> rendered) (heading `isInfixOf` rendered))
+          ["Recall target", "Query options", "Output options", "AI options"]
+        assertStableWidth rendered,
+      testCase "bash completion script is generated" do
+        script <- renderCompletion "--bash-completion-script"
+        assertBool "bash completion script should name kioku" (not (null script) && "kioku" `isInfixOf` script),
+      testCase "zsh completion script is generated" do
+        script <- renderCompletion "--zsh-completion-script"
+        assertBool "zsh completion script should name kioku" (not (null script) && "kioku" `isInfixOf` script),
+      testCase "fish completion script is generated" do
+        script <- renderCompletion "--fish-completion-script"
+        assertBool "fish completion script should name kioku" (not (null script) && "kioku" `isInfixOf` script)
+    ]
+  where
+    renderHelp args =
+      case execParserPure cliParserPrefs cliParserInfo args of
+        Failure failure -> do
+          let (rendered, exitCode) = renderFailure failure "kioku"
+          exitCode @?= ExitSuccess
+          pure rendered
+        Success _ -> assertBool "--help unexpectedly parsed as a command" False >> pure ""
+        CompletionInvoked _ -> assertBool "--help unexpectedly invoked completion" False >> pure ""
+
+    renderCompletion flagName =
+      case execParserPure cliParserPrefs cliParserInfo [flagName, "kioku"] of
+        CompletionInvoked completion -> execCompletion completion "kioku"
+        Failure failure -> do
+          let (rendered, _) = renderFailure failure "kioku"
+          assertBool (flagName <> " failed:\n" <> rendered) False
+          pure ""
+        Success _ -> assertBool (flagName <> " unexpectedly parsed as a command") False >> pure ""
+
+    assertStableWidth rendered =
+      mapM_
+        (\line -> assertBool ("help line exceeds 100 columns: " <> show line) (length line <= 100))
+        (lines rendered)
