diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# 0.1.0.0 — 2026-10-24
+
+## New Features
+
+Strict JSON manifests and check/list/run/report over the shared Heni library.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+BSD 3-Clause License
+
+Copyright (c) 2026, Nadeem Bitar
+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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# heni-cli
+
+The `heni` executable validates manifests, lists cases, runs mutation campaigns
+and renders stored reports through the matching Heni library. Version 0.1.0.0 is
+unreleased. Use `heni --help` and the [CLI reference](https://github.com/shinzui/heni/blob/master/docs/cli.md).
+
+`run` exits 0 for a met trustworthy contract, 1 for a failed contract, 2 for
+configuration/infrastructure failure, and 130 after SIGINT finalization. Generic
+commands need exact diagnostic/exit evidence; optional reporters provide named
+assertion evidence. Use fresh output directories; report artifacts move together.
diff --git a/app/Heni/Cli.hs b/app/Heni/Cli.hs
new file mode 100644
--- /dev/null
+++ b/app/Heni/Cli.hs
@@ -0,0 +1,179 @@
+-- | Command application: parsing and presentation only; the library owns behavior.
+module Heni.Cli (mainCli, selectDefinitions, exitCodeFor) where
+
+import Control.Exception
+import Control.Monad (forM_, unless)
+import Data.Aeson hiding (Options)
+import Data.ByteString.Lazy.Char8 qualified as LBS
+import Data.Map.Strict qualified as Map
+import Data.Set qualified as Set
+import Data.Text (Text)
+import Data.Text qualified as Text
+import Data.Version (showVersion)
+import Paths_heni_cli (version)
+import System.Environment (getArgs)
+import System.Exit
+import System.FilePath ((</>))
+import System.IO
+import Test.Heni
+import Text.Read (readMaybe)
+
+data Options = Options !Bool !String ![Text] ![Text] !(Maybe FilePath) !Int !Bool
+
+defaults :: Options
+defaults = Options False "auto" [] [] Nothing 0 False
+
+mainCli :: IO ()
+mainCli = do
+  args <- getArgs
+  case args of
+    ["--version"] -> putStrLn ("heni " ++ showVersion version)
+    [] -> putStrLn help >> exitWith (ExitFailure 2)
+    _ | "--help" `elem` args -> putStrLn help
+    command : path : rest | command `elem` ["check", "list", "run", "report"] -> case parseOptions command defaults rest of
+      Left why -> hPutStrLn stderr why >> exitWith (ExitFailure 2)
+      Right options -> do
+        attempted <- try (dispatch command path options)
+        case attempted of
+          Right code -> exitCode code
+          Left (e :: SomeException) -> case fromException e :: Maybe AsyncException of
+            Just UserInterrupt -> hPutStrLn stderr "Interrupted; inspect the partial report or recover the journal." >> exitWith (ExitFailure 130)
+            Just ThreadKilled -> exitWith (ExitFailure 130)
+            _ -> hPutStrLn stderr (diagnostic e) >> exitWith (ExitFailure 2)
+    _ -> hPutStrLn stderr "Expected check, list, run, or report and a path. Use --help." >> exitWith (ExitFailure 2)
+
+parseOptions :: String -> Options -> [String] -> Either String Options
+parseOptions _ options [] = Right options
+parseOptions command (Options _ color cases tags output jobs recover) ("--json" : rest) = parseOptions command (Options True color cases tags output jobs recover) rest
+parseOptions command (Options json _ cases tags output jobs recover) ("--color" : color : rest)
+  | color `elem` ["auto", "always", "never"] = parseOptions command (Options json color cases tags output jobs recover) rest
+parseOptions "run" (Options json color cases tags output jobs recover) ("--case" : ident : rest) = parseOptions "run" (Options json color (cases ++ [Text.pack ident]) tags output jobs recover) rest
+parseOptions "run" (Options json color cases tags output jobs recover) ("--tag" : tag : rest) = parseOptions "run" (Options json color cases (tags ++ [Text.pack tag]) output jobs recover) rest
+parseOptions "run" (Options json color cases tags _ jobs recover) ("--output" : path : rest) = parseOptions "run" (Options json color cases tags (Just path) jobs recover) rest
+parseOptions "run" (Options json color cases tags output _ recover) ("--jobs" : value : rest) = case readMaybe value of
+  Just jobs | jobs > 0 && jobs <= 256 -> parseOptions "run" (Options json color cases tags output jobs recover) rest
+  _ -> Left "--jobs must be between 1 and 256"
+parseOptions "report" (Options json color cases tags output jobs _) ("--recover" : rest) = parseOptions "report" (Options json color cases tags output jobs True) rest
+parseOptions _ _ (unknown : _) = Left ("Unknown, incomplete, or unsupported option: " ++ unknown)
+
+dispatch :: String -> FilePath -> Options -> IO Int
+dispatch "report" path (Options json color _ _ _ _ recover) = do
+  stored <- (if recover then recoverReport path else readReport path) >>= either throwIO pure
+  if json then LBS.putStrLn (encode (reportJSON stored)) else case stored of StoredReport {result} -> render color result
+  pure 0
+dispatch command path (Options json color cases tags output jobs _) = do
+  manifest <- readManifest path >>= either (throwIO . ConfigurationFailure) pure
+  let campaign = manifestCampaign manifest
+      definitions = campaignCases campaign
+  case command of
+    "list" -> do
+      if json
+        then LBS.putStrLn (encode (object ["schemaVersion" .= (1 :: Int), "cases" .= map caseDefinitionJSON definitions]))
+        else forM_ definitions $ \CaseDefinition {caseId, tags = caseTags, selector, expectation, description} ->
+          putStrLn (Text.unpack (caseIdText caseId) ++ "  tags=" ++ show (Set.toAscList caseTags) ++ " selector=" ++ show selector ++ " expect=" ++ show expectation ++ "\n  " ++ Text.unpack description)
+      pure 0
+    "check" -> do
+      checks <- checkManifest manifest >>= either (throwIO . ConfigurationFailure) pure
+      if json
+        then
+          LBS.putStrLn
+            ( encode
+                ( object
+                    [ "schemaVersion" .= (1 :: Int),
+                      "checksPerformed" .= (["static-validation", "command-availability", "isolated-edit-applicability"] :: [Text]),
+                      "testsExecuted" .= False,
+                      "cases" .= [object ["id" .= caseIdText caseId, "applicable" .= applicable, "diagnostics" .= diagnostics] | Applicability {caseId, applicable, diagnostics} <- checks]
+                    ]
+                )
+            )
+        else do
+          putStrLn "Checked structure, command availability and isolated edit applicability. Tests and discovery were not run."
+          forM_ checks $ \Applicability {caseId, applicable, diagnostics} -> putStrLn (Text.unpack (caseIdText caseId) ++ if applicable then ": applicable" else ": " ++ show diagnostics)
+      pure (if all (\Applicability {applicable} -> applicable) checks then 0 else 2)
+    "run" -> do
+      selected <- either (throwIO . ConfigurationFailure) pure (selectDefinitions cases tags definitions)
+      let directory = maybe (manifestSourceRoot manifest </> "mutation-results") id output
+          inheritedOptions = manifestRunOptions directory manifest
+          options =
+            inheritedOptions
+              { selectedCases = Just selected,
+                workers = if jobs == 0 then workers inheritedOptions else jobs,
+                progress = \case CaseStarted i -> hPutStrLn stderr ("running " ++ Text.unpack (caseIdText i)); _ -> pure ()
+              }
+      result <- runCampaign options campaign
+      if json
+        then LBS.putStrLn (encode (object ["schemaVersion" .= (1 :: Int), "reportPath" .= (directory </> "report.json"), "selectionRule" .= String "union within filter kind, intersection across case/tag kinds", "result" .= runResultJSON result]))
+        else render color result >> putStrLn ("Evidence: " ++ directory </> "report.json")
+      pure (exitCodeFor result)
+    _ -> error "validated command dispatch"
+
+-- | Union repeated values within a filter kind; intersect the case and tag sets.
+-- Unknown explicit IDs and empty intersections are configuration errors.
+selectDefinitions :: [Text] -> [Text] -> [CaseDefinition] -> Either ConfigError SelectedCases
+selectDefinitions requested tags definitions = do
+  ids <- mapM mkCaseId requested
+  let known = [caseId | CaseDefinition {caseId} <- definitions]
+  unless (all (`elem` known) ids) (Left (ConfigError "case" "unknown requested case ID"))
+  mkSelectedCases
+    [ caseId
+    | CaseDefinition {caseId, tags = caseTags} <- definitions,
+      (null ids || caseId `elem` ids) && (null tags || not (Set.null (Set.intersection (Set.fromList tags) caseTags)))
+    ]
+
+-- | Infrastructure has precedence because RunStatus is library-owned.
+exitCodeFor :: RunResult -> Int
+exitCodeFor RunResult {status} = case status of RunPassed -> 0; RunFailed -> 1; RunUntrustworthy -> 2; RunInterrupted -> 130
+
+exitCode :: Int -> IO ()
+exitCode 0 = exitSuccess
+exitCode n = exitWith (ExitFailure n)
+
+render :: String -> RunResult -> IO ()
+render color RunResult {results, status, score, failures} = do
+  terminal <- hIsTerminalDevice stdout
+  let colored = color == "always" || color == "auto" && terminal
+      paint text = if colored then "\ESC[" ++ (if status == RunPassed then "32" else "31") ++ "m" ++ text ++ "\ESC[0m" else text
+      counts = Map.fromListWith (+) [(show verdict, 1 :: Int) | CaseResult {verdict} <- results]
+  putStrLn (paint (show status) ++ "  " ++ show (Map.toAscList counts))
+  forM_ results $ \CaseResult {caseId, verdict, reason, evidence = CaseEvidence {stages}} -> do
+    putStrLn (Text.unpack (caseIdText caseId) ++ ": " ++ show verdict ++ " — " ++ Text.unpack reason)
+    forM_ stages $ \StageEvidence {transcript} -> unless (Text.null transcript) (putStrLn ("  witness: " ++ Text.unpack transcript))
+  forM_ score $ \(SemanticScore caught total complete) -> putStrLn ("Semantic detections: " ++ show caught ++ "/" ++ show total ++ if complete then "" else " (incomplete)")
+  forM_ failures (putStrLn . ("Run failure: " ++) . show)
+
+help :: String
+help =
+  unlines
+    [ "heni — deliberate mutation testing with attributable evidence",
+      "",
+      "Usage:",
+      "  heni check MANIFEST [--json]",
+      "  heni list MANIFEST [--json]",
+      "  heni run MANIFEST [--case ID] [--tag TAG] [--output DIRECTORY] [--jobs N] [--json]",
+      "  heni report REPORT.json [--json]",
+      "  heni report DIRECTORY --recover [--json]",
+      "",
+      "Selection:",
+      "  Repeated filters use union within each kind and intersection across case/tag kinds.",
+      "  Unknown explicit IDs and empty selection fail. Manifest paths resolve from its location.",
+      "  --output is an explicit caller-relative path; the default is SOURCE/mutation-results.",
+      "",
+      "Presentation:",
+      "  --color auto|always|never  Applies to human output only; redirected auto output has no ANSI.",
+      "  --json                   JSON on stdout, progress and errors on stderr.",
+      "  --help                   Show this help.",
+      "  --version                Show the source-package version without Git.",
+      "",
+      "Checks and exits:",
+      "  check runs static/availability/applicability checks, never tests or discovery.",
+      "  run: 0 met contract; 1 failed contract; 2 configuration/infrastructure; SIGINT 130.",
+      "  report renders stored evidence only; recovery never resumes commands.",
+      "  Runs require a new output directory. Inspect report.json or recover journal.jsonl after interruption."
+    ]
+
+diagnostic :: SomeException -> String
+diagnostic e = case fromException e of
+  Just (ConfigurationFailure (ConfigError field message)) -> Text.unpack field ++ ": " ++ Text.unpack message
+  Nothing -> case fromException e of
+    Just (ReportError message) -> Text.unpack message
+    Nothing -> displayException e
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,6 @@
+module Main (main) where
+
+import Heni.Cli (mainCli)
+
+main :: IO ()
+main = mainCli
diff --git a/heni-cli.cabal b/heni-cli.cabal
new file mode 100644
--- /dev/null
+++ b/heni-cli.cabal
@@ -0,0 +1,84 @@
+cabal-version: 3.4
+name: heni-cli
+version: 0.1.0.0
+synopsis: Command line interface to trustworthy deliberate mutation testing
+description:
+  Validate manifests, run checked mutations, and render portable
+  Heni evidence through the shared library runner.
+
+homepage: https://github.com/shinzui/heni
+bug-reports: https://github.com/shinzui/heni/issues
+license: BSD-3-Clause
+license-file: LICENSE
+author: Nadeem Bitar
+maintainer: nadeem@gmail.com
+copyright: 2026 Nadeem Bitar
+category: Testing
+build-type: Simple
+tested-with: ghc ==9.12.4
+extra-doc-files:
+  CHANGELOG.md
+  README.md
+
+data-files: test/corpus/*.json
+
+source-repository head
+  type: git
+  location: https://github.com/shinzui/heni.git
+  subdir: heni-cli
+
+common common
+  default-language: GHC2024
+  default-extensions:
+    DeriveAnyClass
+    DuplicateRecordFields
+    OverloadedLabels
+    OverloadedStrings
+
+  ghc-options:
+    -Wall
+    -Wcompat
+
+  build-depends:
+    aeson >=2.3.2 && <2.4,
+    base >=4.21.2 && <4.22,
+    bytestring >=0.12.2 && <0.13,
+    containers >=0.7 && <0.9,
+    directory >=1.3.10.1 && <1.4,
+    filepath >=1.5.5 && <1.6,
+    heni ==0.1.0.0,
+    text >=2.1.4 && <2.2,
+
+executable heni
+  import: common
+  hs-source-dirs: app
+  main-is: Main.hs
+  other-modules:
+    Heni.Cli
+    Paths_heni_cli
+
+  autogen-modules: Paths_heni_cli
+  ghc-options: -threaded
+
+test-suite heni-cli-test
+  import: common
+  type: exitcode-stdio-1.0
+  hs-source-dirs:
+    test
+    app
+
+  main-is: Main.hs
+  other-modules:
+    Heni.Cli
+    Paths_heni_cli
+
+  autogen-modules: Paths_heni_cli
+  build-depends:
+    process >=1.6.26.1 && <1.7,
+    unix >=2.8.8 && <2.9,
+
+  build-tool-depends:
+    heni:heni-fixture,
+    heni-cli:heni,
+
+  ghc-options: -threaded
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,168 @@
+module Main (main) where
+
+import Control.Concurrent (threadDelay)
+import Control.Exception hiding (handle)
+import Control.Monad (forM_, unless, when)
+import Data.Aeson
+import Data.Aeson.KeyMap qualified as KM
+import Data.ByteString qualified as BS
+import Data.ByteString.Lazy qualified as LBS
+import Data.Foldable (toList)
+import Data.List (isInfixOf, isPrefixOf)
+import Data.Text qualified as Text
+import Data.Text.Encoding qualified as Text
+import Heni.Cli (exitCodeFor, selectDefinitions)
+import Paths_heni_cli (getDataFileName)
+import System.Directory qualified as Dir
+import System.Environment (lookupEnv)
+import System.Exit (ExitCode (..))
+import System.FilePath (takeDirectory, (</>))
+import System.Posix.Signals (sigINT, sigKILL, signalProcess)
+import System.Posix.Temp (mkdtemp)
+import System.Process (readProcessWithExitCode)
+import System.Process qualified as P
+import System.Timeout (timeout)
+import Test.Heni
+
+assert' :: String -> Bool -> IO ()
+assert' name good = unless good (error name)
+
+checked :: (Show e) => Either e a -> a
+checked = either (error . show) id
+
+main :: IO ()
+main = bracket (Dir.getTemporaryDirectory >>= \tmp -> mkdtemp (tmp </> "heni-cli-test-")) Dir.removePathForcibly $ \root -> do
+  corpus <- getDataFileName "test/corpus"
+  names <- Dir.listDirectory corpus
+  forM_ names $ \name -> do
+    content <- BS.readFile (corpus </> name)
+    assert' ("shared schema/decoder corpus: " ++ name) ((case decodeManifest content of Right _ -> True; Left _ -> False) == ("valid-" `isPrefixOf` name))
+  let definition ident tags old new = object ["id" .= (ident :: String), "description" .= String "Detect the intended fault", "tags" .= (tags :: [String]), "edits" .= [object ["kind" .= String "replace", "path" .= String "input", "old" .= (old :: String), "new" .= (new :: String)]], "build" .= String "build", "test" .= String "test", "expect" .= object ["kind" .= String "diagnostic", "stage" .= String "test", "exitCode" .= (1 :: Int), "outputContains" .= String "capacity rule violated"]]
+      value =
+        object
+          [ "schemaVersion" .= (1 :: Int),
+            "sourceRoot" .= String "source",
+            "commands"
+              .= object
+                [ "build" .= object ["executable" .= String "heni-fixture", "arguments" .= (["exit", "0"] :: [String])],
+                  "test" .= object ["executable" .= String "heni-fixture", "arguments" .= (["check", "input", "diagnostic"] :: [String])]
+                ],
+            "cases" .= [definition "caught" ["regression"] "anchor" "mutant", definition "survivor" ["example"] "anchor" "harmless"]
+          ]
+      bytes = LBS.toStrict (encode value)
+      manifestPath = root </> "heni.json"
+      cli args = readProcessWithExitCode "heni" args ""
+  Dir.createDirectory (root </> "source")
+  BS.writeFile (root </> "source/input") "anchor\n"
+  BS.writeFile manifestPath bytes
+  manifest <- readManifest manifestPath >>= either (error . show) pure
+  let definitions = campaignCases (manifestCampaign manifest)
+  assert' "case union and tag intersection" (fmap selectedCaseIds (selectDefinitions ["caught", "caught", "survivor"] ["regression"] definitions) == Right [checked (mkCaseId "caught")])
+  assert' "unknown explicit case" (case selectDefinitions ["absent"] [] definitions of Left _ -> True; _ -> False)
+  assert' "empty selection" (case selectDefinitions [] ["absent"] definitions of Left _ -> True; _ -> False)
+  (versionExit, version, _) <- cli ["--version"]
+  assert' "archive-safe version" (versionExit == ExitSuccess && "heni 0.1.0.0" `isInfixOf` version)
+  (helpExit, help, _) <- cli ["--help"]
+  assert' "help selection/exit contract" (helpExit == ExitSuccess && "intersection" `isInfixOf` help && "SIGINT 130" `isInfixOf` help)
+  (checkExit, checkOutput, _) <- cli ["check", manifestPath, "--json"]
+  assert' "check states it did not execute tests" (checkExit == ExitSuccess && case eitherDecodeStrict (Text.encodeUtf8 (Text.pack checkOutput)) :: Either String Value of Right (Object o) -> KM.lookup "testsExecuted" o == Just (Bool False); _ -> False)
+  (listExit, listing, _) <- cli ["list", manifestPath, "--json"]
+  assert' "list is JSON" (listExit == ExitSuccess && case eitherDecodeStrict (Text.encodeUtf8 (Text.pack listing)) :: Either String Value of Right _ -> True; _ -> False)
+  library <- runCampaign ((manifestRunOptions (root </> "library") manifest) {selectedCases = Just (checked (selectDefinitions ["caught"] [] definitions))}) (manifestCampaign manifest)
+  (caughtExit, runOutput, progress) <- cli ["run", manifestPath, "--case", "caught", "--output", root </> "cli", "--json", "--color", "always"]
+  assert' "caught exit and clean machine stdout" (caughtExit == ExitSuccess && not ('\ESC' `elem` runOutput) && "running caught" `isInfixOf` progress)
+  cliStored <- readReport (root </> "cli/report.json") >>= either (error . show) pure
+  let signature RunResult {results} = [(caseIdText caseId, verdict, [(stage, outcome) | StageEvidence {stage, outcome} <- stages]) | CaseResult {caseId, verdict, evidence = CaseEvidence {stages}} <- results]
+  assert' "library/CLI share stage decisions and verdicts" (case cliStored of StoredReport {result} -> signature result == signature library && exitCodeFor result == 0)
+  let resourceValue = case value of
+        Object o ->
+          Object
+            ( KM.insert
+                "execution"
+                (object ["workers" .= (2 :: Int), "baselineReuse" .= object ["toolchain" .= String "self-contained-fixture/v1"]])
+                ( KM.insert
+                    "resources"
+                    (toJSON [object ["name" .= String "DB", "scope" .= String "case", "identity" .= String "local-fixture", "version" .= String "v1", "epoch" .= String "clean", "environment" .= object ["HENI_RESOURCE_DB_TOKEN" .= String "resource-private-secret"], "setup" .= String "build", "reset" .= String "build", "teardown" .= String "build"]])
+                    (KM.insert "cases" (case KM.lookup "cases" o of Just (Array cases) -> toJSON [case c of Object fields -> Object (KM.insert "resources" (toJSON (["DB"] :: [String])) fields); other -> other | c <- toList cases]; _ -> Null) o)
+                )
+            )
+        other -> other
+      resourceManifest = root </> "resources.json"
+  LBS.writeFile resourceManifest (encode resourceValue)
+  configured <- readManifest resourceManifest >>= either (error . show) pure
+  configuredLibrary <- runCampaign (manifestRunOptions (root </> "resource-library") configured) (manifestCampaign configured)
+  (resourceExit, _, _) <- cli ["run", resourceManifest, "--jobs", "2", "--output", root </> "resource-cli", "--json"]
+  resourceStored <- readReport (root </> "resource-cli/report.json") >>= either (error . show) pure
+  assert' "resource commands/workers/reuse share library and CLI outcomes" (resourceExit == ExitFailure 1 && case resourceStored of StoredReport {result} -> signature result == signature configuredLibrary)
+  reportWithResources <- BS.readFile (root </> "resource-cli/report.json")
+  assert' "resource command configuration is redacted" (not ("resource-private-secret" `BS.isInfixOf` reportWithResources))
+  fixtureOutput <- lookupEnv "HENI_SCHEMA_RESOURCE"
+  forM_ fixtureOutput $ \path -> do
+    Dir.createDirectoryIfMissing True (takeDirectory path)
+    BS.writeFile path reportWithResources
+  Dir.removeFile (root </> "resource-cli/resource-DB-case-caught-0.stdout.log")
+  missingResourceLog <- readReport (root </> "resource-cli/report.json")
+  assert' "missing setup command artifact invalidates portable report" (case missingResourceLog of Left _ -> True; _ -> False)
+  (survivorExit, human, _) <- cli ["run", manifestPath, "--case", "survivor", "--output", root </> "survivor"]
+  assert' "survivor exit and redirected output without ANSI" (survivorExit == ExitFailure 1 && not ('\ESC' `elem` human))
+  (emptyExit, _, _) <- cli ["run", manifestPath, "--tag", "absent", "--output", root </> "empty"]
+  assert' "empty run fails by default" (emptyExit == ExitFailure 2)
+  Dir.renameDirectory (root </> "cli") (root </> "moved")
+  (reportExit, storedOutput, _) <- cli ["report", root </> "moved/report.json", "--json"]
+  assert' "moved evidence renders" (reportExit == ExitSuccess && not (null storedOutput))
+  (recoveryExit, _, _) <- cli ["report", root </> "moved", "--recover"]
+  assert' "explicit recovery renders without execution" (recoveryExit == ExitSuccess)
+  let invalids =
+        [ Text.replace "\"schemaVersion\":1" "\"schemaVersion\":999" (Text.decodeUtf8 bytes),
+          Text.replace "\"schemaVersion\":1" "\"schemaVersion\":1,\"schemaVersion\":1" (Text.decodeUtf8 bytes),
+          Text.replace "\"schemaVersion\":1" "\"schemaVersion\":1,\"\\u0073chemaVersion\":1" (Text.decodeUtf8 bytes),
+          Text.replace "\"executable\":\"heni-fixture\"" "\"executable\":\"heni-fixture\",\"timeuotSeconds\":2" (Text.decodeUtf8 bytes),
+          Text.replace "\"executable\":\"heni-fixture\"" "\"executable\":\"heni-fixture\",\"timeoutSeconds\":0" (Text.decodeUtf8 bytes),
+          Text.replace "\"executable\":\"heni-fixture\"" "\"executable\":\"heni-fixture\",\"arguments\":null" (Text.decodeUtf8 bytes),
+          Text.replace "\"path\":\"input\"" "\"path\":\"../escape\"" (Text.decodeUtf8 bytes),
+          Text.replace "\"build\":\"build\"" "\"build\":\"absent\"" (Text.decodeUtf8 bytes)
+        ]
+  forM_ invalids $ \invalid -> assert' "invalid manifest rejected" (case decodeManifest (Text.encodeUtf8 invalid) of Left _ -> True; _ -> False)
+  -- Applicability checks and listing do not execute a command with visible effects.
+  let sentinel = root </> "must-not-execute"
+      noExecute = object ["schemaVersion" .= (1 :: Int), "sourceRoot" .= String "source", "commands" .= object ["build" .= object ["executable" .= String "heni-fixture", "arguments" .= ["counter", sentinel]], "test" .= object ["executable" .= String "heni-fixture", "arguments" .= (["exit", "0"] :: [String])]], "cases" .= [definition "caught" [] "anchor" "mutant"]]
+  LBS.writeFile (root </> "no-execute.json") (encode noExecute)
+  _ <- cli ["check", root </> "no-execute.json"]
+  _ <- cli ["list", root </> "no-execute.json"]
+  Dir.doesFileExist sentinel >>= assert' "check/list never execute tests or builds" . not
+  let interruptMarker = root </> "interrupted-child.pid"
+      interruptManifest =
+        object
+          [ "schemaVersion" .= (1 :: Int),
+            "sourceRoot" .= String "source",
+            "commands"
+              .= object
+                [ "build" .= object ["executable" .= String "heni-fixture", "arguments" .= (["exit", "0"] :: [String])],
+                  "test" .= object ["executable" .= String "heni-fixture", "arguments" .= ["check", "input", "timeout", interruptMarker]]
+                ],
+            "cases" .= [definition "caught" [] "anchor" "mutant"]
+          ]
+  LBS.writeFile (root </> "interrupt.json") (encode interruptManifest)
+  let process = (P.proc "heni" ["run", root </> "interrupt.json", "--output", root </> "interrupted"]) {P.std_out = P.Inherit, P.std_err = P.Inherit}
+  P.withCreateProcess process $ \_ _ _ handle -> do
+    let waitReady = do
+          exists <- Dir.doesFileExist interruptMarker
+          unless exists (threadDelay 5000 >> waitReady)
+        stopOwned = do
+          markerExists <- Dir.doesFileExist interruptMarker
+          when markerExists $ do
+            pid <- read <$> readFile interruptMarker
+            _ <- try (signalProcess sigKILL pid) :: IO (Either IOException ())
+            pure ()
+    ( do
+        ready <- timeout 5000000 waitReady
+        assert' "CLI interruption handshake" (ready == Just ())
+        pid <- P.getPid handle >>= maybe (error "missing owned CLI PID") pure
+        signalProcess sigINT pid
+        exited <- timeout 5000000 (P.waitForProcess handle)
+        assert' "SIGINT uses 130 after finalization" (exited == Just (ExitFailure 130))
+        partial <- readReport (root </> "interrupted/report.json")
+        assert' "SIGINT retains complete selected ledger" (case partial of Right StoredReport {result = RunResult {status = RunInterrupted, results = [CaseResult {verdict = NotRun}]}} -> True; _ -> False)
+      )
+      `finally` stopOwned
+  putStrLn "Strict manifest boundary, CLI exits, selection and library parity passed"
diff --git a/test/corpus/invalid-adapter-version.json b/test/corpus/invalid-adapter-version.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-adapter-version.json
@@ -0,0 +1,38 @@
+{
+  "schemaVersion": 1,
+  "sourceRoot": ".",
+  "commands": {
+    "build": {
+      "executable": "heni-hspec-fixture",
+      "arguments": [
+        "--heni-build"
+      ]
+    },
+    "test": {
+      "executable": "heni-hspec-fixture"
+    }
+  },
+  "cases": [
+    {
+      "id": "named",
+      "description": "Detect the intended assertion",
+      "adapter": "v999",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "intended"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "named-tests",
+        "failures": [
+          "suite/intended"
+        ]
+      }
+    }
+  ]
+}
diff --git a/test/corpus/invalid-budget.json b/test/corpus/invalid-budget.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-budget.json
@@ -0,0 +1,43 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ],
+      "timeoutSeconds": 0
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      }
+    }
+  ]
+}
diff --git a/test/corpus/invalid-duplicate-key.json b/test/corpus/invalid-duplicate-key.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-duplicate-key.json
@@ -0,0 +1,1 @@
+{"schemaVersion": 1, "schemaVersion": 1, "commands": {"build": {"executable": "heni-fixture", "arguments": ["exit", "0"]}, "test": {"executable": "heni-fixture", "arguments": ["check", "input", "diagnostic"]}}, "cases": [{"id": "caught", "description": "Detect the intended fault", "edits": [{"kind": "replace", "path": "input", "old": "anchor", "new": "mutant"}], "build": "build", "test": "test", "expect": {"kind": "diagnostic", "stage": "test", "exitCode": 1, "outputContains": "capacity rule violated"}}]}
diff --git a/test/corpus/invalid-named-without-adapter.json b/test/corpus/invalid-named-without-adapter.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-named-without-adapter.json
@@ -0,0 +1,37 @@
+{
+  "schemaVersion": 1,
+  "sourceRoot": ".",
+  "commands": {
+    "build": {
+      "executable": "heni-hspec-fixture",
+      "arguments": [
+        "--heni-build"
+      ]
+    },
+    "test": {
+      "executable": "heni-hspec-fixture"
+    }
+  },
+  "cases": [
+    {
+      "id": "named",
+      "description": "Detect the intended assertion",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "intended"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "named-tests",
+        "failures": [
+          "suite/intended"
+        ]
+      }
+    }
+  ]
+}
diff --git a/test/corpus/invalid-nested-key.json b/test/corpus/invalid-nested-key.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-nested-key.json
@@ -0,0 +1,43 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated",
+        "witness": "typo"
+      }
+    }
+  ]
+}
diff --git a/test/corpus/invalid-null-arguments.json b/test/corpus/invalid-null-arguments.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-null-arguments.json
@@ -0,0 +1,39 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": null
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      }
+    }
+  ]
+}
diff --git a/test/corpus/invalid-resource-unicode-name.json b/test/corpus/invalid-resource-unicode-name.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-resource-unicode-name.json
@@ -0,0 +1,63 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      },
+      "resources": [
+        "DB١"
+      ]
+    }
+  ],
+  "resources": [
+    {
+      "name": "DB١",
+      "scope": "case",
+      "identity": "fixture",
+      "version": "v1",
+      "epoch": "clean",
+      "setup": "build",
+      "reset": "build",
+      "teardown": "build"
+    }
+  ],
+  "execution": {
+    "workers": 2,
+    "baselineReuse": {
+      "toolchain": "fixture/v1"
+    }
+  }
+}
diff --git a/test/corpus/invalid-unknown-key.json b/test/corpus/invalid-unknown-key.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-unknown-key.json
@@ -0,0 +1,43 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      }
+    }
+  ],
+  "surprise": true
+}
diff --git a/test/corpus/invalid-unsafe-path.json b/test/corpus/invalid-unsafe-path.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-unsafe-path.json
@@ -0,0 +1,42 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "../escape",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      }
+    }
+  ]
+}
diff --git a/test/corpus/invalid-version.json b/test/corpus/invalid-version.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-version.json
@@ -0,0 +1,42 @@
+{
+  "schemaVersion": 99,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      }
+    }
+  ]
+}
diff --git a/test/corpus/invalid-workers.json b/test/corpus/invalid-workers.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/invalid-workers.json
@@ -0,0 +1,63 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      },
+      "resources": [
+        "DB"
+      ]
+    }
+  ],
+  "resources": [
+    {
+      "name": "DB",
+      "scope": "case",
+      "identity": "fixture",
+      "version": "v1",
+      "epoch": "clean",
+      "setup": "build",
+      "reset": "build",
+      "teardown": "build"
+    }
+  ],
+  "execution": {
+    "workers": 0,
+    "baselineReuse": {
+      "toolchain": "fixture/v1"
+    }
+  }
+}
diff --git a/test/corpus/valid-minimal.json b/test/corpus/valid-minimal.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/valid-minimal.json
@@ -0,0 +1,42 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      }
+    }
+  ]
+}
diff --git a/test/corpus/valid-named.json b/test/corpus/valid-named.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/valid-named.json
@@ -0,0 +1,38 @@
+{
+  "schemaVersion": 1,
+  "sourceRoot": ".",
+  "commands": {
+    "build": {
+      "executable": "heni-hspec-fixture",
+      "arguments": [
+        "--heni-build"
+      ]
+    },
+    "test": {
+      "executable": "heni-hspec-fixture"
+    }
+  },
+  "cases": [
+    {
+      "id": "named",
+      "description": "Detect the intended assertion",
+      "adapter": "heni-v1",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "intended"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "named-tests",
+        "failures": [
+          "suite/intended"
+        ]
+      }
+    }
+  ]
+}
diff --git a/test/corpus/valid-resources.json b/test/corpus/valid-resources.json
new file mode 100644
--- /dev/null
+++ b/test/corpus/valid-resources.json
@@ -0,0 +1,63 @@
+{
+  "schemaVersion": 1,
+  "commands": {
+    "build": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "exit",
+        "0"
+      ]
+    },
+    "test": {
+      "executable": "heni-fixture",
+      "arguments": [
+        "check",
+        "input",
+        "diagnostic"
+      ]
+    }
+  },
+  "cases": [
+    {
+      "id": "caught",
+      "description": "Detect the intended fault",
+      "edits": [
+        {
+          "kind": "replace",
+          "path": "input",
+          "old": "anchor",
+          "new": "mutant"
+        }
+      ],
+      "build": "build",
+      "test": "test",
+      "expect": {
+        "kind": "diagnostic",
+        "stage": "test",
+        "exitCode": 1,
+        "outputContains": "capacity rule violated"
+      },
+      "resources": [
+        "DB"
+      ]
+    }
+  ],
+  "resources": [
+    {
+      "name": "DB",
+      "scope": "case",
+      "identity": "fixture",
+      "version": "v1",
+      "epoch": "clean",
+      "setup": "build",
+      "reset": "build",
+      "teardown": "build"
+    }
+  ],
+  "execution": {
+    "workers": 2,
+    "baselineReuse": {
+      "toolchain": "fixture/v1"
+    }
+  }
+}
