diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
       , actions =
         [ L.Action.Type.Move
             { inputPattern = "CCTV/(.*)/(\\d+)\\.mp4"
-            , newName = "sorted/\\2/\\1.mp4"
+            , newName = "sorted/$2/$1.mp4"
             }
         ]
       }
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,10 @@
 # Librarian
 
+## 0.2.0.0
+
+* Replace `regexpr` with `pcre2`. Replacement strings now use `$N` instead of `\N`
+  (e.g. `sorted/$2/$1.mp4`); patterns are unchanged.
+
 ## 0.1.0.1
 
 * @blackheaven
diff --git a/librarian.cabal b/librarian.cabal
--- a/librarian.cabal
+++ b/librarian.cabal
@@ -1,6 +1,6 @@
 cabal-version:       3.0
 name:                librarian
-version:             0.1.0.1
+version:             0.2.0.0
 author:              Gautier DI FOLCO
 maintainer:          gautier.difolco@gmail.com
 category:            Data
@@ -23,8 +23,9 @@
     , directory
     , easy-file
     , Glob
+    , pcre2
     , pretty-show
-    , regexpr
+    , text
     , time
   hs-source-dirs: src
   exposed-modules:
diff --git a/src/Librarian.hs b/src/Librarian.hs
--- a/src/Librarian.hs
+++ b/src/Librarian.hs
@@ -46,6 +46,7 @@
 import Data.Ord (Down (Down))
 import Data.Sequence (Seq)
 import Data.String (IsString)
+import qualified Data.Text as Text
 import Data.Time
   ( UTCTime,
     addUTCTime,
@@ -68,7 +69,7 @@
   )
 import System.EasyFile (splitFileName)
 import System.FilePath.Glob (compile, globDir)
-import Text.RegexPR
+import qualified Text.Regex.Pcre2 as Pcre2
 
 data Rule = Rule
   { name :: RuleName,
@@ -91,12 +92,13 @@
   = Move {inputPattern :: String, newName :: String}
   | Copy {inputPattern :: String, newName :: String}
   | Remove {inputPattern :: String}
+  | Bundle {subAction :: [Action]}
   deriving stock (Eq, Show, Generic)
 
 data Grouping
   = FileGroup
   | forall a.
-    Ord a =>
+    (Ord a) =>
     Group
       { groupSource :: Source a,
         groupBucket :: GroupingBucket a,
@@ -109,8 +111,8 @@
   = AllF
   | AndF Filtering Filtering
   | OrF Filtering Filtering
-  | forall a. Ord a => GtF (Source a) (Source a)
-  | forall a. Ord a => LtF (Source a) (Source a)
+  | forall a. (Ord a) => GtF (Source a) (Source a)
+  | forall a. (Ord a) => LtF (Source a) (Source a)
 
 deriving stock instance Show Filtering
 
@@ -189,7 +191,7 @@
                 fetchBucket :: Source x -> FilePath -> IO String
                 fetchBucket source file =
                   bucket source <$> fetchSource source file
-                sorting :: Ord x => SortingOrder -> [(x, FilePath)] -> [(x, FilePath)]
+                sorting :: (Ord x) => SortingOrder -> [(x, FilePath)] -> [(x, FilePath)]
                 sorting =
                   \case
                     SortingAsc -> sortOn fst
@@ -248,11 +250,11 @@
               newPath inputPattern newName
                 <&> \newPath' -> ResolvedCopy {original = p, new = newPath', rule = rule}
             Remove {..} ->
-              matchRegexPR inputPattern p
+              guard (Pcre2.matches (Text.pack inputPattern) (Text.pack p))
                 $> ResolvedRemove {original = p, rule = rule}
         newPath :: String -> String -> Maybe FilePath
         newPath inputPattern' newName' =
-          mfilter (/= p) $ Just $ subRegexPR inputPattern' newName' p
+          mfilter (/= p) $ Just $ Text.unpack $ Pcre2.sub (Text.pack inputPattern') (Text.pack newName') (Text.pack p)
 
 displayPlan :: [ResolvedAction] -> IO ()
 displayPlan =
diff --git a/test/LibrarianSpec.hs b/test/LibrarianSpec.hs
--- a/test/LibrarianSpec.hs
+++ b/test/LibrarianSpec.hs
@@ -195,7 +195,7 @@
       match = "**/*.jpg",
       grouping = FileGroup,
       filtering = AllF,
-      actions = [Move "^.*/([^\\/]+)$" "out/pics/\\1"]
+      actions = [Move "^.*/([^\\/]+)$" "out/pics/$1"]
     }
 
 moveRule1Any :: Rule
@@ -215,7 +215,7 @@
       match = "**/*.txt",
       grouping = FileGroup,
       filtering = AllF,
-      actions = [Move "^.*/([^\\/]+)$" "out/\\1"]
+      actions = [Move "^.*/([^\\/]+)$" "out/$1"]
     }
 
 -- ** copy
@@ -230,7 +230,7 @@
       match = "**/*.jpg",
       grouping = FileGroup,
       filtering = AllF,
-      actions = [Copy "^.*/([^\\/]+)$" "out/pics/\\1"]
+      actions = [Copy "^.*/([^\\/]+)$" "out/pics/$1"]
     }
 
 copyRule1Any :: Rule
@@ -250,7 +250,7 @@
       match = "**/*.txt",
       grouping = FileGroup,
       filtering = AllF,
-      actions = [Copy "^.*/([^\\/]+)$" "out/\\1"]
+      actions = [Copy "^.*/([^\\/]+)$" "out/$1"]
     }
 
 -- ** remove
