diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,31 @@
 # Revision history for symplectic-chp
 
+## 0.2.0.0 -- 2026-07-20
+
+### Breaking API Changes
+
+* **Deterministic `Clifford` monad**: `Clifford` now threads a `StdGen` instead of
+  living in `IO`. The type changed from
+  `SomeTableau -> IO (SomeTableau, a)` to
+  `SomeTableau -> StdGen -> (SomeTableau, StdGen, a)`.
+  This makes simulations reproducible when a seed is supplied.
+* **Seeded runner**: added `runWithSeed :: Int -> StdGen -> Clifford a -> (SomeTableau, a)`.
+* **LargeTableau gate unification**: removed `LargeLocalSymplectic` and
+  `LargeSymplecticGate`; `LargeTableau` now reuses `LocalSymplectic` and
+  `SymplecticGate` from `SymplecticCHP`.
+
+### Bug Fixes
+
+* **`--seed` flag now works**: the CLI seed was previously accepted but ignored;
+  random measurements now derive from the supplied seed.
+
+### Other Changes
+
+* Updated `stim-parser` dependency to `>= 0.4 && < 0.5` and adapted to the
+  `AnnTarget` change in annotation AST.
+* Removed unused/incomplete modules `SymplecticCHP.Core`, `SymplecticCHP.Types`,
+  and `SymplecticCHP.Storage`.
+
 ## 0.1.0.1 -- 2026-07-17
 
 * Support `stim-parser` 0.2.0.0: relax upper bound to `< 0.3`.  
diff --git a/app/Simulator.hs b/app/Simulator.hs
--- a/app/Simulator.hs
+++ b/app/Simulator.hs
@@ -11,7 +11,7 @@
   ) where
 
 import Control.Monad (foldM)
-import System.Random (randomIO)
+import System.Random (randomIO, mkStdGen)
 
 import SymplecticCHP
   ( Clifford
@@ -21,6 +21,7 @@
   , gate
   , measurePauli
   , runWith
+  , runWithSeed
   , getTableau
   , nQubitsSome
   , rowsSome
@@ -50,7 +51,8 @@
 runCHPCircuitWithSeed :: Int -> CHPCircuit -> IO SimulationResult
 runCHPCircuitWithSeed seed circuit = do
   let n = numQubits circuit
-  (tableau, outcomes) <- runWith n (runOperations (operations circuit))
+      gen = mkStdGen seed
+      (tableau, outcomes) = runWithSeed n gen (runOperations (operations circuit))
   return $ SimulationResult
     { finalTableau = tableau
     , measurementOutcomes = reverse outcomes  -- Reverse to get chronological order
diff --git a/app/StimToCHP.hs b/app/StimToCHP.hs
--- a/app/StimToCHP.hs
+++ b/app/StimToCHP.hs
@@ -12,6 +12,7 @@
   ) where
 
 import Data.Bits (setBit)
+import Data.Maybe (mapMaybe)
 import Data.Word (Word64)
 import qualified Data.Set as Set
 
@@ -211,7 +212,12 @@
     
     piQubit (PauliInd _ idx) = idx  -- PauliInd contains qubit index directly
     
-    annotationQubits (Ann _ _ _ qs) = Set.fromList $ map qubitIndex qs
+    annotationQubits (Ann _ _ _ targets) = Set.fromList $ mapMaybe annTargetQubit targets
+
+    annTargetQubit :: AnnTarget -> Maybe Int
+    annTargetQubit (AnnQ i)       = Just i
+    annTargetQubit (AnnPauli _ i) = Just i
+    annTargetQubit (AnnRec _)     = Nothing  -- record references are not qubits
 
 -- | Extract the qubit index from a Q value.
 qubitIndex :: Q -> Int
diff --git a/app/VerifyLargeTableau.hs b/app/VerifyLargeTableau.hs
--- a/app/VerifyLargeTableau.hs
+++ b/app/VerifyLargeTableau.hs
@@ -48,10 +48,10 @@
   | otherwise = 
       let tab0 = largeEmpty n
           -- Apply H to even qubits
-          tab1 = foldl (\t i -> largeApplyGate (LargeLocal (LargeHadamard i)) t) 
+          tab1 = foldl (\t i -> largeApplyGate (Local (Hadamard i)) t) 
                        tab0 [0,2..n-2]
           -- Apply CNOT from even to odd
-          tab2 = foldl (\t i -> largeApplyGate (LargeCNOT i (i+1)) t) 
+          tab2 = foldl (\t i -> largeApplyGate (CNOT i (i+1)) t) 
                        tab1 [0,2..n-2]
       in tab2
 
@@ -108,8 +108,8 @@
   | n < 2 = error "createRepCodeLarge: need at least 2 qubits"
   | otherwise =
       let tab0 = largeEmpty n
-          tab1 = largeApplyGate (LargeLocal (LargeHadamard 0)) tab0
-          tab2 = foldl (\t i -> largeApplyGate (LargeCNOT 0 i) t) tab1 [1..n-1]
+          tab1 = largeApplyGate (Local (Hadamard 0)) tab0
+          tab2 = foldl (\t i -> largeApplyGate (CNOT 0 i) t) tab1 [1..n-1]
       in tab2
 
 -- | Test 2: Repetition Code State
@@ -162,15 +162,15 @@
   
   -- Create |+⟩ states on all qubits
   let tab0 = largeEmpty n
-      tab1 = foldl (\t i -> largeApplyGate (LargeLocal (LargeHadamard i)) t) 
+      tab1 = foldl (\t i -> largeApplyGate (Local (Hadamard i)) t) 
                    tab0 [0..n-1]
   
   -- Apply S to all qubits (first time)
-  let tab2 = foldl (\t i -> largeApplyGate (LargeLocal (LargePhase i)) t) 
+  let tab2 = foldl (\t i -> largeApplyGate (Local (Phase i)) t) 
                    tab1 [0..n-1]
   
   -- Apply S to all qubits (second time)
-  let tab3 = foldl (\t i -> largeApplyGate (LargeLocal (LargePhase i)) t) 
+  let tab3 = foldl (\t i -> largeApplyGate (Local (Phase i)) t) 
                    tab2 [0..n-1]
   
   mid <- getCurrentTime
@@ -206,16 +206,16 @@
   case gateType of
     0 -> do -- Hadamard
       q <- randomRIO (0, n-1)
-      return $ largeApplyGate (LargeLocal (LargeHadamard q)) tab
+      return $ largeApplyGate (Local (Hadamard q)) tab
     1 -> do -- Phase
       q <- randomRIO (0, n-1)
-      return $ largeApplyGate (LargeLocal (LargePhase q)) tab
+      return $ largeApplyGate (Local (Phase q)) tab
     2 -> do -- CNOT
       c <- randomRIO (0, n-1)
       t <- randomRIO (0, n-1)
       if c == t 
         then return tab
-        else return $ largeApplyGate (LargeCNOT c t) tab
+        else return $ largeApplyGate (CNOT c t) tab
     _ -> return tab
 
 -- | Test 4: Random circuits preserve validity
@@ -269,13 +269,13 @@
     putStrLn $ "  Creation: " ++ show (diffUTCTime mid1 start)
     
     -- Apply 100 Hadamards
-    let tab1 = foldl (\t i -> largeApplyGate (LargeLocal (LargeHadamard (i `mod` n))) t) 
+    let tab1 = foldl (\t i -> largeApplyGate (Local (Hadamard (i `mod` n))) t) 
                      tab0 [0..99]
     mid2 <- getCurrentTime
     putStrLn $ "  100 Hadamards: " ++ show (diffUTCTime mid2 mid1)
     
     -- Apply 100 CNOTs
-    let tab2 = foldl (\t i -> largeApplyGate (LargeCNOT (i `mod` n) ((i+1) `mod` n)) t) 
+    let tab2 = foldl (\t i -> largeApplyGate (CNOT (i `mod` n) ((i+1) `mod` n)) t) 
                      tab1 [0..99]
     mid3 <- getCurrentTime
     putStrLn $ "  100 CNOTs: " ++ show (diffUTCTime mid3 mid2)
diff --git a/src/SymplecticCHP.hs b/src/SymplecticCHP.hs
--- a/src/SymplecticCHP.hs
+++ b/src/SymplecticCHP.hs
@@ -23,7 +23,7 @@
 import Data.Word
 import Data.Proxy (Proxy(..))
 import Data.Kind (Type)
-import System.Random (randomRIO)
+import System.Random (StdGen, mkStdGen, randomR, randomIO)
 import Data.List (sortOn, groupBy)
 import Data.Function (on)
 import Data.Maybe (fromJust, isJust)
@@ -561,14 +561,12 @@
 updateLagrangian :: KnownNat n => Finite n -> v -> Lagrangian n v -> Lagrangian n v
 updateLagrangian i v (Lagrangian vs) = Lagrangian (VS.unsafeUpd vs [(fromIntegral $ Finite.getFinite i, v)])
 
--- | Measurement as state update (symplectic transvection)
-measure :: forall n. KnownNat n => Tableau n Pauli -> Pauli -> IO (Tableau n Pauli, MeasurementResult)
-measure tab@(Tableau s d) p
-  | isDeterminate tab p = do
-      let outcome = computePhase tab p
-      return (tab, Determinate outcome)
+-- | Measurement as state update (symplectic transvection), pure variant using a StdGen.
+measureWithGen :: forall n. KnownNat n => Tableau n Pauli -> Pauli -> StdGen -> ((Tableau n Pauli, MeasurementResult), StdGen)
+measureWithGen tab@(Tableau s d) p g
+  | isDeterminate tab p = ((tab, Determinate detOutcome), g)
   
-  | otherwise = do
+  | otherwise =
       let Just j = findAntiCommutingStab tab p
           Just jFin = intToFinite j
           s_j = indexLagrangian s jFin
@@ -581,17 +579,26 @@
                    else s_k) (lagrangianBasis s)
           
           newDestabBasis = updateVector j s_j (lagrangianBasis d)
-      
-      outcome <- randomRIO (0, 1) :: IO Int
-      
-      let Pauli x z r = p
-          p' = Pauli x z ((r + if outcome == 0 then 2 else 0) `mod` 4)
+          
+          (randOutcome, g') = randomR (0, 1) g :: (Int, StdGen)
+          
+          Pauli x z r = p
+          p' = Pauli x z ((r + if randOutcome == 0 then 2 else 0) `mod` 4)
           finalStabBasis = updateVector j p' newStabBasis
           finalStabs = Lagrangian finalStabBasis
           newDestabs = Lagrangian newDestabBasis
       
-      return (Tableau finalStabs newDestabs, Random (outcome == 1))
+      in ((Tableau finalStabs newDestabs, Random (randOutcome == 1)), g')
+  where
+    detOutcome = computePhase tab p
 
+-- | Measurement as state update (symplectic transvection)
+measure :: forall n. KnownNat n => Tableau n Pauli -> Pauli -> IO (Tableau n Pauli, MeasurementResult)
+measure tab p = do
+  seed <- randomIO
+  let (result, _) = measureWithGen tab p (mkStdGen seed)
+  return result
+
 -- | Compute deterministic measurement outcome via symplectic decomposition
 computePhase :: forall n. KnownNat n => Tableau n Pauli -> Pauli -> Bool
 computePhase (Tableau s d) p = 
@@ -609,34 +616,42 @@
 data SomeTableau where
   SomeTableau :: KnownNat n => Tableau n Pauli -> SomeTableau
 
-newtype Clifford a = Clifford { runClifford :: SomeTableau -> IO (SomeTableau, a) }
+-- | Clifford monad threading both the tableau and a random-number generator.
+-- This makes simulations deterministic and reproducible when a seed is supplied.
+newtype Clifford a = Clifford { runClifford :: SomeTableau -> StdGen -> (SomeTableau, StdGen, a) }
 
 instance Functor Clifford where
-  fmap f (Clifford g) = Clifford $ \t -> do (t', x) <- g t; return (t', f x)
+  fmap f (Clifford g) = Clifford $ \t g0 ->
+    let (t', g1, x) = g t g0
+    in (t', g1, f x)
 
 instance Applicative Clifford where
-  pure x = Clifford $ \t -> return (t, x)
-  Clifford f <*> Clifford x = Clifford $ \t -> do
-    (t', f') <- f t; (t'', x') <- x t'; return (t'', f' x')
+  pure x = Clifford $ \t g -> (t, g, x)
+  Clifford f <*> Clifford x = Clifford $ \t g0 ->
+    let (t', g1, f') = f t g0
+        (t'', g2, x') = x t' g1
+    in (t'', g2, f' x')
 
 instance Monad Clifford where
   return = pure
-  Clifford x >>= f = Clifford $ \t -> do (t', x') <- x t; runClifford (f x') t'
+  Clifford x >>= f = Clifford $ \t g0 ->
+    let (t', g1, x') = x t g0
+    in runClifford (f x') t' g1
 
 gate :: SymplecticGate -> Clifford ()
-gate g = Clifford $ \t -> case t of
-  SomeTableau tab -> return (SomeTableau (evolveTableau tab g), ())
+gate g = Clifford $ \t g0 -> (evolveTableauSome t g, g0, ())
 
 measurePauli :: Pauli -> Clifford Bool
-measurePauli p = Clifford $ \t -> case t of
-  SomeTableau tab -> do
-    (t', res) <- measure tab p
-    case res of
-      Determinate b -> return (SomeTableau t', b)
-      Random b      -> return (SomeTableau t', b)
+measurePauli p = Clifford $ \t g0 -> case t of
+  SomeTableau tab ->
+    let ((tab', res), g1) = measureWithGen tab p g0
+        outcome = case res of
+          Determinate b -> b
+          Random b      -> b
+    in (SomeTableau tab', g1, outcome)
 
 getTableau :: Clifford SomeTableau
-getTableau = Clifford $ \t -> return (t, t)
+getTableau = Clifford $ \t g -> (t, g, t)
 
 withNatProxy :: KnownNat n => Proxy n -> (KnownNat n => Tableau n Pauli) -> Tableau n Pauli
 withNatProxy _ t = t
@@ -648,8 +663,17 @@
       GHC.TypeNats.SomeNat (proxy :: Proxy n) -> 
         SomeTableau (emptyTableau :: Tableau n Pauli)
 
+-- | Run a Clifford computation with a freshly generated random seed.
 runWith :: Int -> Clifford a -> IO (SomeTableau, a)
-runWith n (Clifford f) = f (emptyTableauN n)
+runWith n c = do
+  seed <- randomIO
+  return $ runWithSeed n (mkStdGen seed) c
+
+-- | Run a Clifford computation with an explicit random generator (for reproducibility).
+runWithSeed :: Int -> StdGen -> Clifford a -> (SomeTableau, a)
+runWithSeed n gen c =
+  let (t, _, a) = runClifford c (emptyTableauN n) gen
+  in (t, a)
 
 -- ============================================================================
 -- PART XIV: BACKWARD COMPATIBILITY HELPERS
diff --git a/src/SymplecticCHP/LargeTableau.hs b/src/SymplecticCHP/LargeTableau.hs
--- a/src/SymplecticCHP/LargeTableau.hs
+++ b/src/SymplecticCHP/LargeTableau.hs
@@ -11,9 +11,9 @@
   , lpPauliY
   , lpOmega
   , lpMultiply
-    -- * Gates (redefined to avoid circular imports)
-  , LargeLocalSymplectic(..)
-  , LargeSymplecticGate(..)
+    -- * Gates (reused from SymplecticCHP)
+  , SymplecticGate(..)
+  , LocalSymplectic(..)
   , LargeMeasurementResult(..)
     -- * Large Tableau
   , LargeTableau(..)
@@ -21,6 +21,7 @@
   , largeNQubits
   , largeApplyGate
   , largeMeasure
+  , largeMeasureWithGen
     -- * Validation
   , largeIsValid
   , largeIsDeterminate
@@ -29,24 +30,11 @@
 import Data.Bits (Bits(..), popCount, xor)
 import Data.Word (Word64)
 import SymplecticCHP.BitVec
+import SymplecticCHP (SymplecticGate(..), LocalSymplectic(..))
 
-import System.Random (randomRIO)
+import System.Random (StdGen, mkStdGen, randomR, randomIO)
 import qualified Data.Vector as V
 
--- ============================================================================
--- Gate Types (local copies to avoid circular imports)
--- ============================================================================
-
-data LargeLocalSymplectic 
-  = LargeHadamard !Int
-  | LargePhase !Int
-  deriving (Show, Eq)
-
-data LargeSymplecticGate
-  = LargeLocal !LargeLocalSymplectic
-  | LargeCNOT !Int !Int
-  deriving (Show, Eq)
-
 data LargeMeasurementResult = LargeDeterminate Bool | LargeRandom Bool
   deriving (Show, Eq)
 
@@ -118,13 +106,13 @@
 largeNQubits = ltN
 
 -- | Apply gate to large tableau
-largeApplyGate :: LargeSymplecticGate -> LargeTableau -> LargeTableau
+largeApplyGate :: SymplecticGate -> LargeTableau -> LargeTableau
 largeApplyGate g (LargeTableau s d n) =
   LargeTableau (V.map (lpApplyGate g) s) (V.map (lpApplyGate g) d) n
 
 -- | Apply gate to large Pauli
-lpApplyGate :: LargeSymplecticGate -> LargePauli -> LargePauli
-lpApplyGate (LargeLocal (LargeHadamard i)) (LargePauli x z r n) =
+lpApplyGate :: SymplecticGate -> LargePauli -> LargePauli
+lpApplyGate (Local (Hadamard i)) (LargePauli x z r n) =
   let xi = bvTestBit x i
       zi = bvTestBit z i
       x' = if zi then bvSetBit (bvClearBit x i) i else bvClearBit x i
@@ -132,7 +120,7 @@
       r' = (r + if xi && zi then 2 else 0) `mod` 4
   in LargePauli x' z' r' n
 
-lpApplyGate (LargeLocal (LargePhase i)) (LargePauli x z r n) =
+lpApplyGate (Local (Phase i)) (LargePauli x z r n) =
   let xi = bvTestBit x i
       zi = bvTestBit z i
       -- Z' = Z XOR X
@@ -140,7 +128,7 @@
       r' = (r + if xi && not zi then 1 else 0) `mod` 4
   in LargePauli x z' r' n
 
-lpApplyGate (LargeCNOT c t) (LargePauli x z r n) =
+lpApplyGate (CNOT c t) (LargePauli x z r n) =
   let xc = bvTestBit x c
       zc = bvTestBit z c
       xt = bvTestBit x t
@@ -153,16 +141,14 @@
       r' = (r + phaseTerm) `mod` 4
   in LargePauli x' z' r' n
 
--- | Measurement on large tableau
-largeMeasure :: LargeTableau -> LargePauli -> IO (LargeTableau, LargeMeasurementResult)
-largeMeasure tab@(LargeTableau s d n) p
-  | largeIsDeterminate tab p = do
-      let outcome = largeComputePhase tab p
-      return (tab, LargeDeterminate outcome)
-  | otherwise = do
+-- | Pure measurement on large tableau using an explicit random generator.
+largeMeasureWithGen :: LargeTableau -> LargePauli -> StdGen -> ((LargeTableau, LargeMeasurementResult), StdGen)
+largeMeasureWithGen tab@(LargeTableau s d n) p g
+  | largeIsDeterminate tab p = ((tab, LargeDeterminate detOutcome), g)
+  | otherwise =
       case largeFindAntiCommuting tab p of
-        Nothing -> error "Internal error in largeMeasure"
-        Just j -> do
+        Nothing -> error "Internal error in largeMeasureWithGen"
+        Just j ->
           let s_j = s V.! j
               -- Update other stabilizers
               newStabs = V.imap (\k s_k ->
@@ -173,12 +159,21 @@
                        else s_k) s
               -- New destabilizer is old stabilizer
               newDestabs = d V.// [(j, s_j)]
-          
-          outcome <- randomRIO (0, 1) :: IO Int
-          let p' = p { lpPhase = (lpPhase p + if outcome == 0 then 2 else 0) `mod` 4 }
+              
+              (randOutcome, g') = randomR (0, 1) g :: (Int, StdGen)
+              p' = p { lpPhase = (lpPhase p + if randOutcome == 0 then 2 else 0) `mod` 4 }
               finalStabs = newStabs V.// [(j, p')]
           
-          return (LargeTableau finalStabs newDestabs n, LargeRandom (outcome == 1))
+          in ((LargeTableau finalStabs newDestabs n, LargeRandom (randOutcome == 1)), g')
+  where
+    detOutcome = largeComputePhase tab p
+
+-- | Measurement on large tableau
+largeMeasure :: LargeTableau -> LargePauli -> IO (LargeTableau, LargeMeasurementResult)
+largeMeasure tab p = do
+  seed <- randomIO
+  let (result, _) = largeMeasureWithGen tab p (mkStdGen seed)
+  return result
 
 -- | Check if measurement is deterministic
 largeIsDeterminate :: LargeTableau -> LargePauli -> Bool
diff --git a/symplectic-chp.cabal b/symplectic-chp.cabal
--- a/symplectic-chp.cabal
+++ b/symplectic-chp.cabal
@@ -28,7 +28,7 @@
 -- PVP summary:     +-+------- breaking API changes
 --                  | | +----- non-breaking API additions
 --                  | | | +--- code changes with no API change
-version:            0.1.0.1
+version:            0.2.0.0
 
 -- A short (one-line) description of the package.
 synopsis:           CHP Clifford simulator using symplectic geometry
@@ -134,7 +134,7 @@
         , filepath            >= 1.4     && < 1.6
         , directory           >= 1.3     && < 1.4
         , containers          >= 0.6     && < 0.8
-        , stim-parser         >= 0.1     && < 0.3
+        , stim-parser         >= 0.4     && < 0.5
     build-tool-depends:
         hspec-discover:hspec-discover  >= 2.10 && < 2.12
     default-language: GHC2021
@@ -159,7 +159,7 @@
     -- Other library packages from which modules are imported.
     build-depends:
           , base                >= 4.17    && < 4.22
-          , stim-parser         >= 0.1     && < 0.3
+          , stim-parser         >= 0.4     && < 0.5
           , containers          >= 0.6     && < 0.8
           , symplectic-chp
           , random              >= 1.2     && < 1.3
