diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@
 
 ```bash
 cabal update
-cabal install --overwrite-policy=always phino-0.0.0.58
+cabal install --overwrite-policy=always phino-0.0.0.59
 phino --version
 ```
 
@@ -137,7 +137,7 @@
 and print it in canonical syntax:
 
 ```bash
-$ echo 'Q -> [[ @ -> QQ.io.stdout("hello") ]]' | phino rewrite
+$ echo 'Q -> [[ @ -> Q.io.stdout("hello") ]]' | phino rewrite
 Φ ↦ ⟦
   φ ↦ Φ.io.stdout(
     α0 ↦ Φ.string(
diff --git a/phino.cabal b/phino.cabal
--- a/phino.cabal
+++ b/phino.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: phino
-version: 0.0.0.59
+version: 0.0.0.60
 license: MIT
 synopsis: Command-Line Manipulator of 𝜑-Calculus Expressions
 description: Please see the README on GitHub at <https://github.com/objectionary/phino#readme>
@@ -49,6 +49,7 @@
     Lining
     Locator
     Logger
+    Margin
     Matcher
     Merge
     Misc
@@ -163,6 +164,7 @@
     process ^>=1.6.19.0,
     silently ^>=1.2.5.4,
     text ^>=2.0.2,
+    time ^>=1.12,
     xml-conduit ^>=1.10,
     yaml ^>=0.11.11.2,
 
diff --git a/src/CLI.hs b/src/CLI.hs
--- a/src/CLI.hs
+++ b/src/CLI.hs
@@ -25,10 +25,11 @@
 import Encoding (Encoding (UNICODE))
 import qualified Filter as F
 import Functions (buildTerm)
-import LaTeX (LatexContext (LatexContext), explainRules, expressionToLaTeX, programToLaTeX, rewrittensToLatex)
+import LaTeX (LatexContext (LatexContext), defaultMeetLength, defaultMeetPopularity, explainRules, expressionToLaTeX, programToLaTeX, rewrittensToLatex)
 import Lining (LineFormat (MULTILINE, SINGLELINE))
 import Locator (locatedExpression)
 import Logger
+import Margin (defaultMargin)
 import Merge (merge)
 import Misc (ensuredFile)
 import qualified Misc
@@ -50,6 +51,7 @@
 data PrintProgramContext = PrintProgCtx
   { _sugar :: SugarType
   , _line :: LineFormat
+  , _margin :: Int
   , _xmirCtx :: XmirContext
   , _nonumber :: Bool
   , _compress :: Bool
@@ -108,6 +110,7 @@
   , _compress :: Bool
   , _maxDepth :: Int
   , _maxCycles :: Int
+  , _margin :: Int
   , _meetPopularity :: Maybe Int
   , _meetLength :: Maybe Int
   , _hide :: [String]
@@ -150,6 +153,7 @@
   , _compress :: Bool
   , _maxDepth :: Int
   , _maxCycles :: Int
+  , _margin :: Int
   , _meetPopularity :: Maybe Int
   , _meetLength :: Maybe Int
   , _rules :: [FilePath]
@@ -174,6 +178,7 @@
   , _flat :: LineFormat
   , _omitListing :: Bool
   , _omitComments :: Bool
+  , _margin :: Int
   , _targetFile :: Maybe FilePath
   , _inputs :: [FilePath]
   }
@@ -199,17 +204,14 @@
     parseLogLevel
     ( long "log-level"
         <> metavar "LEVEL"
-        <> help ("Log level (" <> intercalate ", " (map show [DEBUG, INFO, WARNING, ERROR, NONE]) <> ")")
-        <> value INFO
+        <> help ("Log level (" <> intercalate ", " (map show [DEBUG, ERROR, NONE]) <> ")")
+        <> value ERROR
         <> showDefault
     )
   where
     parseLogLevel :: ReadM LogLevel
     parseLogLevel = eitherReader $ \lvl -> case map toUpper lvl of
       "DEBUG" -> Right DEBUG
-      "INFO" -> Right INFO
-      "WARNING" -> Right WARNING
-      "WARN" -> Right WARNING
       "ERROR" -> Right ERROR
       "ERR" -> Right ERROR
       "NONE" -> Right NONE
@@ -255,6 +257,12 @@
     (auto >>= validateIntOption (> 0) "--max-cycles must be positive")
     (long "max-cycles" <> metavar "CYCLES" <> help "Maximum number of rewriting cycles across all rules" <> value 25 <> showDefault)
 
+optMargin :: Parser Int
+optMargin =
+  option
+    (auto >>= validateIntOption (> 0) "--margin must be positive")
+    (long "margin" <> help "The maximum right margin for the printed 𝜑-programs or 𝜑-expressions" <> value defaultMargin <> showDefault)
+
 optMeetPopularity :: Parser (Maybe Int)
 optMeetPopularity =
   optional
@@ -263,7 +271,10 @@
             >>= validateIntOption (> 0) "--meet-popularity must be positive"
             >>= validateIntOption (< 100) "--meet-popularity must be <= 100"
         )
-        (long "meet-popularity" <> metavar "PERCENTAGE" <> help "The minimum popularity of an expression in order to be suitable for \\phiMeet{}, in percentage (default: 50)")
+        ( long "meet-popularity"
+            <> metavar "PERCENTAGE"
+            <> help (printf "The minimum popularity of an expression in order to be suitable for \\phiMeet{}, in percentage (default: %d)" defaultMeetPopularity)
+        )
     )
 
 optMeetLength :: Parser (Maybe Int)
@@ -271,7 +282,10 @@
   optional
     ( option
         (auto >>= validateIntOption (> 0) "--meet-length must be positive")
-        (long "meet-length" <> metavar "NODES" <> help "The minimum length of an expression that fits into \\phiMeet{}, in AST nodes (default: 8)")
+        ( long "meet-length"
+            <> metavar "NODES"
+            <> help (printf "The minimum length of an expression that fits into \\phiMeet{}, in AST nodes (default: %d)" defaultMeetLength)
+        )
     )
 
 optDepthSensitive :: Parser Bool
@@ -391,6 +405,7 @@
             <*> optCompress
             <*> optMaxDepth
             <*> optMaxCycles
+            <*> optMargin
             <*> optMeetPopularity
             <*> optMeetLength
             <*> optHide
@@ -434,6 +449,7 @@
             <*> optCompress
             <*> optMaxDepth
             <*> optMaxCycles
+            <*> optMargin
             <*> optMeetPopularity
             <*> optMeetLength
             <*> optRule
@@ -461,6 +477,7 @@
             <*> optLineFormat'
             <*> optOmitListing
             <*> optOmitComments
+            <*> optMargin
             <*> optTarget
             <*> many (argument str (metavar "[FILE]" <> help "Paths to input files"))
         )
@@ -529,7 +546,7 @@
       input <- readInput _inputFile
       rules <- getRules _normalize _shuffle _rules
       program <- parseProgram input _inputFormat
-      let listing = if null rules then const input else (\prog -> P.printProgram' prog (_sugarType, UNICODE, _flat))
+      let listing = if null rules then const input else (\prog -> P.printProgram' prog (_sugarType, UNICODE, _flat, _margin))
           xmirCtx = XmirContext _omitListing _omitComments listing
           printCtx = printProgCtx xmirCtx foc
           canonize = if _canonize then C.canonize else id
@@ -587,6 +604,7 @@
           PrintProgCtx
             _sugarType
             _flat
+            _margin
             xmirCtx
             _nonumber
             _compress
@@ -638,6 +656,7 @@
           PrintProgCtx
             _sugarType
             _flat
+            _margin
             defaultXmirContext
             _nonumber
             _compress
@@ -664,7 +683,7 @@
       inputs' <- traverse (readInput . Just) _inputs
       progs <- traverse (`parseProgram` _inputFormat) inputs'
       prog <- merge progs
-      let listing = const (P.printProgram' prog (_sugarType, UNICODE, _flat))
+      let listing = const (P.printProgram' prog (_sugarType, UNICODE, _flat, _margin))
           xmirCtx = XmirContext _omitListing _omitComments listing
           printCtx = printProgCtx xmirCtx
       prog' <- printProgram printCtx prog
@@ -681,6 +700,7 @@
           PrintProgCtx
             _sugarType
             _flat
+            _margin
             xmirCtx
             False
             False
@@ -703,16 +723,16 @@
           substs <- matchProgramWithRule prog (rule ptn condition) (RuleContext buildTerm)
           if null substs
             then logDebug "Provided pattern was not matched, no substitutions are built"
-            else putStrLn (P.printSubsts' substs (_sugarType, UNICODE, _flat))
+            else putStrLn (P.printSubsts' substs (_sugarType, UNICODE, _flat, defaultMargin))
       where
         rule :: Expression -> Maybe Y.Condition -> Y.Rule
         rule ptn cnd = Y.Rule Nothing Nothing ptn ExGlobal cnd Nothing Nothing
 
 justMeetPopularity :: Maybe Int -> Int
-justMeetPopularity = fromMaybe 50
+justMeetPopularity = fromMaybe defaultMeetPopularity
 
 justMeetLength :: Maybe Int -> Int
-justMeetLength = fromMaybe 8
+justMeetLength = fromMaybe defaultMeetLength
 
 -- Prepare saveStepFunc
 saveStepFunc :: Maybe FilePath -> PrintProgramContext -> SaveStepFunc
@@ -786,23 +806,23 @@
 
 printRewrittens :: PrintProgramContext -> [Rewritten] -> IO String
 printRewrittens ctx@PrintProgCtx{..} rewrittens
-  | _outputFormat == LATEX && _sequence = rewrittensToLatex rewrittens (LatexContext _sugar _line _nonumber _compress _meetPopularity _meetLength _focus _expression _label _meetPrefix)
+  | _outputFormat == LATEX && _sequence = rewrittensToLatex rewrittens (LatexContext _sugar _line _margin _nonumber _compress _meetPopularity _meetLength _focus _expression _label _meetPrefix)
   | _focus == ExGlobal = mapM (printProgram ctx . fst) rewrittens <&> intercalate "\n"
   | otherwise = mapM (\(prog, _) -> locatedExpression _focus prog >>= printExpression ctx) rewrittens <&> intercalate "\n"
 
 printExpression :: PrintProgramContext -> Expression -> IO String
 printExpression PrintProgCtx{..} ex = case _outputFormat of
-  PHI -> pure (P.printExpression' ex (_sugar, UNICODE, _line))
+  PHI -> pure (P.printExpression' ex (_sugar, UNICODE, _line, _margin))
   XMIR -> throwIO CouldNotPrintExpressionInXMIR
-  LATEX -> pure (expressionToLaTeX ex (LatexContext _sugar _line _nonumber _compress _meetPopularity _meetLength _focus _expression _label _meetPrefix))
+  LATEX -> pure (expressionToLaTeX ex (LatexContext _sugar _line _margin _nonumber _compress _meetPopularity _meetLength _focus _expression _label _meetPrefix))
 
 -- Convert
 -- Convert program to corresponding String format
 printProgram :: PrintProgramContext -> Program -> IO String
 printProgram PrintProgCtx{..} prog = case _outputFormat of
-  PHI -> pure (P.printProgram' prog (_sugar, UNICODE, _line))
+  PHI -> pure (P.printProgram' prog (_sugar, UNICODE, _line, _margin))
   XMIR -> programToXMIR prog _xmirCtx <&> printXMIR
-  LATEX -> pure (programToLaTeX prog (LatexContext _sugar _line _nonumber _compress _meetPopularity _meetLength _focus _expression _label _meetPrefix))
+  LATEX -> pure (programToLaTeX prog (LatexContext _sugar _line _margin _nonumber _compress _meetPopularity _meetLength _focus _expression _label _meetPrefix))
 
 -- Get rules for rewriting depending on provided flags
 getRules :: Bool -> Bool -> [FilePath] -> IO [Y.Rule]
diff --git a/src/CST.hs b/src/CST.hs
--- a/src/CST.hs
+++ b/src/CST.hs
@@ -1,8 +1,6 @@
 {-# LANGUAGE DuplicateRecordFields #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE InstanceSigs #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE PatternSynonyms #-}
 {-# OPTIONS_GHC -Wno-partial-fields -Wno-name-shadowing #-}
 
 -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
@@ -12,7 +10,7 @@
 
 import AST
 import Data.Maybe (isJust)
-import Misc (btsToNum, btsToStr, matchDataObject, pattern BaseObject, pattern DataNumber, pattern DataString)
+import Misc
 
 data LCB = LCB | BIG_LCB
   deriving (Eq, Show)
@@ -56,9 +54,6 @@
 data GLOBAL = Φ | Q
   deriving (Eq, Show)
 
-data DEF_PACKAGE = Φ̇ | QQ
-  deriving (Eq, Show)
-
 data TERMINATION = DEAD | T
   deriving (Eq, Show)
 
@@ -170,33 +165,33 @@
   deriving (Eq, Show)
 
 programToCST :: Program -> PROGRAM
-programToCST prog = toCST prog 0 EOL
+programToCST prog = toCST prog (0, EOL)
 
 expressionToCST :: Expression -> EXPRESSION
-expressionToCST ex = toCST ex 0 EOL
+expressionToCST ex = toCST ex (0, EOL)
 
 -- This class is used to convert AST to CST
 -- CST is created with sugar and unicode
--- All further transformations much consider that
+-- All further transformations must consider that
 class ToCST a b where
-  toCST :: a -> Int -> EOL -> b
+  toCST :: a -> (Int, EOL) -> b
 
 instance ToCST Program PROGRAM where
-  toCST (Program expr) tabs eol = PR_SWEET LCB (toCST expr tabs eol) RCB
+  toCST (Program expr) ctx = PR_SWEET LCB (toCST expr ctx) RCB
 
 instance ToCST Expression EXPRESSION where
-  toCST ExGlobal _ _ = EX_GLOBAL Φ
-  toCST ExThis _ _ = EX_XI XI
-  toCST (ExMeta mt) _ _ = EX_META (MT_EXPRESSION (tail mt))
-  toCST (ExMetaTail expr mt) tabs eol = EX_META_TAIL (toCST expr tabs eol) (MT_TAIL (tail mt))
-  toCST ExTermination _ _ = EX_TERMINATION DEAD
-  toCST (ExFormation [BiVoid AtRho]) _ eol = toCST (ExFormation []) 0 eol
-  toCST (ExFormation []) _ _ = EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY NO_TAB) NO_EOL NO_TAB RSB
-  toCST (ExPhiMeet prefix idx expr) tabs eol = EX_PHI_MEET prefix idx (toCST expr tabs eol)
-  toCST (ExPhiAgain prefix idx expr) tabs eol = EX_PHI_AGAIN prefix idx (toCST expr tabs eol)
-  toCST (ExFormation bds) tabs eol =
+  toCST ExGlobal _ = EX_GLOBAL Φ
+  toCST ExThis _ = EX_XI XI
+  toCST (ExMeta mt) _ = EX_META (MT_EXPRESSION (tail mt))
+  toCST (ExMetaTail expr mt) ctx = EX_META_TAIL (toCST expr ctx) (MT_TAIL (tail mt))
+  toCST ExTermination _ = EX_TERMINATION DEAD
+  toCST (ExPhiMeet prefix idx expr) ctx = EX_PHI_MEET prefix idx (toCST expr ctx)
+  toCST (ExPhiAgain prefix idx expr) ctx = EX_PHI_AGAIN prefix idx (toCST expr ctx)
+  toCST (ExFormation [BiVoid AtRho]) ctx = toCST (ExFormation []) ctx
+  toCST (ExFormation []) _ = EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY NO_TAB) NO_EOL NO_TAB RSB
+  toCST (ExFormation bds) (tabs, eol) =
     let next = tabs + 1
-        bds' = toCST (withoutLastVoidRho bds) next eol :: BINDING
+        bds' = toCST (withoutLastVoidRho bds) (next, eol) :: BINDING
      in EX_FORMATION
           LSB
           EOL
@@ -209,25 +204,24 @@
       withoutLastVoidRho :: [Binding] -> [Binding]
       withoutLastVoidRho [] = []
       withoutLastVoidRho [BiVoid AtRho] = []
-      withoutLastVoidRho (bd : [BiVoid AtRho]) = [bd]
       withoutLastVoidRho (bd : bds') = bd : withoutLastVoidRho bds'
-  toCST (DataString bts) tabs _ = EX_STRING (btsToStr bts) (TAB tabs) []
-  toCST (DataNumber bts) tabs _ = EX_NUMBER (btsToNum bts) (TAB tabs) []
-  toCST (ExDispatch ExThis attr) tabs eol = EX_ATTR (toCST attr tabs eol)
-  toCST (ExDispatch expr attr) tabs eol = EX_DISPATCH (toCST expr tabs eol) (toCST attr tabs eol)
+  toCST (DataString bts) (tabs, _) = EX_STRING (btsToStr bts) (TAB tabs) []
+  toCST (DataNumber bts) (tabs, _) = EX_NUMBER (btsToNum bts) (TAB tabs) []
+  toCST (ExDispatch ExThis attr) ctx = EX_ATTR (toCST attr ctx)
+  toCST (ExDispatch expr attr) ctx = EX_DISPATCH (toCST expr ctx) (toCST attr ctx)
   -- Since we convert AST to CST in sweet notation, here we're trying to get rid of unnecessary rho bindings
   -- in primitives (more details here: https://github.com/objectionary/phino/issues/451)
   -- If we find something similar to:
-  -- `QQ.number(~0 -> QQ.bytes(...), ^ -> ..., ^ -> ...)`
+  -- `Q.number(~0 -> Q.bytes(...), ^ -> ..., ^ -> ...)`
   -- We remove unnecessary rho bindings and save them to EX_STRING or EX_NUMBER so they can be successfully
   -- converted to salty notation without losing information.
   -- In the end we just get CST with data primitive which is printed correctly.
   -- If given application is not such primitive - we just convert it to one of the applications:
   -- 1. either with pure expression with arguments, which means there are incremented only alpha bindings
   -- 2. or with just bindings
-  toCST app@(ExApplication _ _) tabs eol =
+  toCST app@(ExApplication _ _) ctx@(tabs, eol) =
     let (ex, ts, exs) = complexApplication app
-        ex' = toCST ex tabs eol :: EXPRESSION
+        ex' = toCST ex ctx :: EXPRESSION
         next = tabs + 1
         (ts', rs) = withoutRhosInPrimitives ex ts
         obj = ExApplication ex (head ts')
@@ -236,25 +230,23 @@
           else
             if null exs
               then
-                let eol' = inlinedEOL (not (hasEOL ts))
-                 in EX_APPLICATION_TAUS
-                      ex'
-                      eol'
-                      (tabOfEOL eol' next)
-                      (toCST ts next eol' :: BINDING)
-                      eol'
-                      (tabOfEOL eol' tabs)
-                      next
+                EX_APPLICATION_TAUS
+                  ex'
+                  eol
+                  (TAB next)
+                  (toCST ts (next, eol) :: BINDING)
+                  eol
+                  (TAB tabs)
+                  next
               else
-                let eol' = inlinedEOL (not (hasEOL exs))
-                 in EX_APPLICATION_EXPRS
-                      ex'
-                      eol'
-                      (tabOfEOL eol' next)
-                      (toCST exs next eol')
-                      eol'
-                      (tabOfEOL eol' tabs)
-                      next
+                EX_APPLICATION_EXPRS
+                  ex'
+                  eol
+                  (TAB next)
+                  (toCST exs (next, eol))
+                  eol
+                  (TAB tabs)
+                  next
     where
       primitives :: [String]
       primitives = ["number", "string"]
@@ -303,97 +295,64 @@
           complexApplication' expr = (expr, [], [])
 
 instance ToCST [Expression] APP_ARG where
-  toCST (expr : exprs) tabs eol = APP_ARG (toCST expr tabs eol) (toCST exprs tabs eol)
-  toCST [] _ _ = error "toCST APP_ARG requires non-empty expression list"
+  toCST (expr : exprs) ctx = APP_ARG (toCST expr ctx) (toCST exprs ctx)
+  toCST [] _ = error "toCST APP_ARG requires non-empty expression list"
 
 instance ToCST [Expression] APP_ARGS where
-  toCST [] _ _ = AAS_EMPTY
-  toCST (expr : exprs) tabs eol = AAS_EXPR eol (tabOfEOL eol tabs) (toCST expr tabs eol) (toCST exprs tabs eol)
+  toCST [] _ = AAS_EMPTY
+  toCST (expr : exprs) ctx@(tabs, eol) = AAS_EXPR eol (TAB tabs) (toCST expr ctx) (toCST exprs ctx)
 
 instance ToCST [Binding] BINDING where
-  toCST [] tabs _ = BI_EMPTY (TAB tabs)
-  toCST (BiMeta mt : bds) tabs eol = BI_META (MT_BINDING (tail mt)) (toCST bds tabs eol) (tabOfEOL eol tabs)
-  toCST (bd : bds) tabs eol = BI_PAIR (toCST bd tabs eol) (toCST bds tabs eol) (tabOfEOL eol tabs)
+  toCST [] (tabs, _) = BI_EMPTY (TAB tabs)
+  toCST (BiMeta mt : bds) ctx@(tabs, _) = BI_META (MT_BINDING (tail mt)) (toCST bds ctx) (TAB tabs)
+  toCST (bd : bds) ctx@(tabs, _) = BI_PAIR (toCST bd ctx) (toCST bds ctx) (TAB tabs)
 
 instance ToCST [Binding] BINDINGS where
-  toCST [] tabs _ = BDS_EMPTY (TAB tabs)
-  toCST (BiMeta mt : bds) tabs eol = BDS_META eol (tabOfEOL eol tabs) (MT_BINDING (tail mt)) (toCST bds tabs eol)
-  toCST (bd : bds) tabs eol = BDS_PAIR eol (tabOfEOL eol tabs) (toCST bd tabs eol) (toCST bds tabs eol)
+  toCST [] (tabs, _) = BDS_EMPTY (TAB tabs)
+  toCST (BiMeta mt : bds) ctx@(tabs, eol) = BDS_META eol (TAB tabs) (MT_BINDING (tail mt)) (toCST bds ctx)
+  toCST (bd : bds) ctx@(tabs, eol) = BDS_PAIR eol (TAB tabs) (toCST bd ctx) (toCST bds ctx)
 
 instance ToCST Binding PAIR where
-  toCST (BiTau attr exp@(ExFormation bds)) tabs eol =
+  toCST (BiTau attr exp@(ExFormation bds)) ctx =
     let voids' = voids bds
-        attr' = toCST attr tabs eol
+        attr' = toCST attr ctx
      in if null voids'
-          then PA_TAU attr' ARROW (toCST exp tabs eol)
+          then PA_TAU attr' ARROW (toCST exp ctx)
           else
             let (_voids, _bds) = if length voids' == length bds && last voids' == AtRho then (init voids', []) else (voids', drop (length voids') bds)
              in PA_FORMATION
                   attr'
-                  (map (\at -> toCST at tabs eol) _voids)
+                  (map (`toCST` ctx) _voids)
                   ARROW
-                  (toCST (ExFormation _bds) tabs eol)
+                  (toCST (ExFormation _bds) ctx)
     where
       voids :: [Binding] -> [Attribute]
       voids [] = []
       voids (bd : bds) = case bd of
         BiVoid attr -> attr : voids bds
         _ -> []
-  toCST (BiTau attr exp) tabs eol = PA_TAU (toCST attr tabs eol) ARROW (toCST exp tabs eol)
-  toCST (BiVoid attr) tabs eol = PA_VOID (toCST attr tabs eol) ARROW EMPTY
-  toCST (BiDelta bts) tabs eol = PA_DELTA (toCST bts tabs eol)
-  toCST (BiLambda func) _ _ = PA_LAMBDA func
-  toCST (BiMetaLambda mt) _ _ = PA_META_LAMBDA (MT_FUNCTION (tail mt))
-  toCST (BiMeta mt) _ _ = error $ "BiMeta binding " ++ mt ++ " cannot be converted to PAIR"
+  toCST (BiTau attr exp) ctx = PA_TAU (toCST attr ctx) ARROW (toCST exp ctx)
+  toCST (BiVoid attr) ctx = PA_VOID (toCST attr ctx) ARROW EMPTY
+  toCST (BiDelta bts) ctx = PA_DELTA (toCST bts ctx)
+  toCST (BiLambda func) _ = PA_LAMBDA func
+  toCST (BiMetaLambda mt) _ = PA_META_LAMBDA (MT_FUNCTION (tail mt))
+  toCST (BiMeta mt) _ = error $ "BiMeta binding " ++ mt ++ " cannot be converted to PAIR"
 
 instance ToCST Binding APP_BINDING where
-  toCST bd@(BiTau _ _) tabs eol = APP_BINDING (toCST bd tabs eol :: PAIR)
-  toCST bd _ _ = error $ "Only BiTau binding can be converted to APP_BINDING, got: " ++ show bd
+  toCST bd@(BiTau _ _) ctx = APP_BINDING (toCST bd ctx :: PAIR)
+  toCST bd _ = error $ "Only BiTau binding can be converted to APP_BINDING, got: " ++ show bd
 
 instance ToCST Bytes BYTES where
-  toCST BtEmpty _ _ = BT_EMPTY
-  toCST (BtOne byte) _ _ = BT_ONE byte
-  toCST (BtMany bts) _ _ = BT_MANY bts
-  toCST (BtMeta mt) _ _ = BT_META (MT_BYTES (tail mt))
+  toCST BtEmpty _ = BT_EMPTY
+  toCST (BtOne byte) _ = BT_ONE byte
+  toCST (BtMany bts) _ = BT_MANY bts
+  toCST (BtMeta mt) _ = BT_META (MT_BYTES (tail mt))
 
 instance ToCST Attribute ATTRIBUTE where
-  toCST (AtLabel label) _ _ = AT_LABEL label
-  toCST (AtAlpha idx) _ _ = AT_ALPHA ALPHA idx
-  toCST AtPhi _ _ = AT_PHI PHI
-  toCST AtRho _ _ = AT_RHO RHO
-  toCST AtDelta _ _ = AT_DELTA DELTA
-  toCST AtLambda _ _ = AT_LAMBDA LAMBDA
-  toCST (AtMeta mt) _ _ = AT_META (MT_ATTRIBUTE (tail mt))
-
-inlinedEOL :: Bool -> EOL
-inlinedEOL True = NO_EOL
-inlinedEOL False = EOL
-
-tabOfEOL :: EOL -> Int -> TAB
-tabOfEOL EOL indent = TAB indent
-tabOfEOL NO_EOL _ = TAB'
-
-class HasEOL a where
-  hasEOL :: a -> Bool
-
-instance HasEOL [Binding] where
-  hasEOL [] = False
-  hasEOL (bd : rest) = hasEOL bd || hasEOL rest
-
-instance HasEOL Binding where
-  hasEOL (BiTau _ expr) = hasEOL expr
-  hasEOL _ = False
-
-instance HasEOL [Expression] where
-  hasEOL [] = False
-  hasEOL (expr : rest) = hasEOL expr || hasEOL rest
-
-instance HasEOL Expression where
-  hasEOL (ExFormation []) = False
-  hasEOL (ExFormation _) = True
-  hasEOL (DataNumber _) = False
-  hasEOL (DataString _) = False
-  hasEOL (BaseObject _) = False
-  hasEOL (ExDispatch expr _) = hasEOL expr
-  hasEOL (ExApplication expr tau) = hasEOL expr || hasEOL tau
-  hasEOL _ = False
+  toCST (AtLabel label) _ = AT_LABEL label
+  toCST (AtAlpha idx) _ = AT_ALPHA ALPHA idx
+  toCST AtPhi _ = AT_PHI PHI
+  toCST AtRho _ = AT_RHO RHO
+  toCST AtDelta _ = AT_DELTA DELTA
+  toCST AtLambda _ = AT_LAMBDA LAMBDA
+  toCST (AtMeta mt) _ = AT_META (MT_ATTRIBUTE (tail mt))
diff --git a/src/Canonizer.hs b/src/Canonizer.hs
--- a/src/Canonizer.hs
+++ b/src/Canonizer.hs
@@ -1,6 +1,9 @@
 -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
 -- SPDX-License-Identifier: MIT
 
+-- Canonization is the process of replacing function names attrached to
+-- lambda bindings with numbered identifiers started from 'F'
+-- like 'F1', 'F2', etc.
 module Canonizer (canonize) where
 
 import AST
diff --git a/src/Encoding.hs b/src/Encoding.hs
--- a/src/Encoding.hs
+++ b/src/Encoding.hs
@@ -11,8 +11,8 @@
   deriving (Eq, Show)
 
 withEncoding :: (ToASCII a) => Encoding -> a -> a
-withEncoding UNICODE prog = prog
-withEncoding ASCII prog = toASCII prog
+withEncoding UNICODE node = node
+withEncoding ASCII node = toASCII node
 
 class ToASCII a where
   toASCII :: a -> a
diff --git a/src/LaTeX.hs b/src/LaTeX.hs
--- a/src/LaTeX.hs
+++ b/src/LaTeX.hs
@@ -12,6 +12,8 @@
   , programToLaTeX
   , expressionToLaTeX
   , defaultLatexContext
+  , defaultMeetLength
+  , defaultMeetPopularity
   , LatexContext (..)
   , meetInPrograms
   , meetInProgram
@@ -24,6 +26,7 @@
 import Encoding (Encoding (ASCII), ToASCII, withEncoding)
 import Lining (LineFormat (MULTILINE), ToSingleLine, withLineFormat)
 import Locator (locatedExpression)
+import Margin (WithMargin, defaultMargin, withMargin)
 import Matcher
 import Misc
 import Render (Render (render))
@@ -36,6 +39,7 @@
 data LatexContext = LatexContext
   { _sugar :: SugarType
   , _line :: LineFormat
+  , _margin :: Int
   , _nonumber :: Bool
   , _compress :: Bool
   , _meetPopularity :: Int
@@ -47,8 +51,14 @@
   }
 
 defaultLatexContext :: LatexContext
-defaultLatexContext = LatexContext SWEET MULTILINE False False 50 8 ExGlobal Nothing Nothing Nothing
+defaultLatexContext = LatexContext SWEET MULTILINE defaultMargin False False defaultMeetPopularity defaultMeetLength ExGlobal Nothing Nothing Nothing
 
+defaultMeetPopularity :: Int
+defaultMeetPopularity = 50
+
+defaultMeetLength :: Int
+defaultMeetLength = 8
+
 meetInProgram :: Program -> Int -> Program -> [Expression]
 meetInProgram (Program expr) len = meetInExpression expr
   where
@@ -112,8 +122,8 @@
     popularity :: Double
     popularity = toDouble _meetPopularity / 100.0
 
-renderToLatex :: (ToSalty a, ToASCII a, ToSingleLine a, ToLaTeX a, Render a) => a -> LatexContext -> String
-renderToLatex renderable LatexContext{..} = render (toLaTeX $ withLineFormat _line $ withEncoding ASCII $ withSugarType _sugar renderable)
+renderToLatex :: (ToSalty a, ToASCII a, ToSingleLine a, ToLaTeX a, WithMargin a, Render a) => a -> LatexContext -> String
+renderToLatex renderable LatexContext{..} = render (toLaTeX $ withLineFormat _line $ withMargin _margin $ withEncoding ASCII $ withSugarType _sugar renderable)
 
 phiquation :: LatexContext -> String
 phiquation LatexContext{_nonumber = True} = "phiquation*"
@@ -121,12 +131,11 @@
 
 preamble :: LatexContext -> String
 preamble ctx@LatexContext{..} =
-  let equation = phiquation ctx
-   in concat
-        [ printf "\\begin{%s}\n" equation
-        , maybe "" (printf "\\label{%s}\n") _label
-        , maybe "" (printf "\\phiExpression{%s} ") _expression
-        ]
+  concat
+    [ printf "\\begin{%s}\n" (phiquation ctx)
+    , maybe "" (printf "\\label{%s}\n") _label
+    , maybe "" (printf "\\phiExpression{%s} ") _expression
+    ]
 
 body :: [(a, Maybe String)] -> (a -> String) -> String
 body printed toLatex =
@@ -143,8 +152,8 @@
 ending :: LatexContext -> String
 ending ctx = printf "{.}\n\\end{%s}" (phiquation ctx)
 
-metRewrittens :: [Rewritten] -> LatexContext -> [Rewritten]
-metRewrittens rewrittens ctx@LatexContext{..} =
+compressedRewrittens :: [Rewritten] -> LatexContext -> [Rewritten]
+compressedRewrittens rewrittens ctx@LatexContext{..} =
   let (progs, rules) = unzip rewrittens
    in if _compress then zip (meetInPrograms progs ctx) rules else rewrittens
 
@@ -153,12 +162,12 @@
   pure
     ( concat
         [ preamble ctx
-        , body (metRewrittens rewrittens ctx) (\prog -> renderToLatex (programToCST prog) ctx)
+        , body (compressedRewrittens rewrittens ctx) (\prog -> renderToLatex (programToCST prog) ctx)
         , ending ctx
         ]
     )
 rewrittensToLatex rewrittens ctx@LatexContext{..} = do
-  let (progs, rules) = unzip (metRewrittens rewrittens ctx)
+  let (progs, rules) = unzip (compressedRewrittens rewrittens ctx)
   exprs <- mapM (locatedExpression _focus) progs
   pure
     ( concat
diff --git a/src/Lining.hs b/src/Lining.hs
--- a/src/Lining.hs
+++ b/src/Lining.hs
@@ -9,8 +9,8 @@
 import CST
 
 withLineFormat :: (ToSingleLine a) => LineFormat -> a -> a
-withLineFormat MULTILINE prog = prog
-withLineFormat SINGLELINE prog = toSingleLine prog
+withLineFormat MULTILINE node = node
+withLineFormat SINGLELINE node = toSingleLine node
 
 data LineFormat = SINGLELINE | MULTILINE
   deriving (Show, Eq)
diff --git a/src/Logger.hs b/src/Logger.hs
--- a/src/Logger.hs
+++ b/src/Logger.hs
@@ -5,11 +5,9 @@
 
 module Logger
   ( logDebug
-  , logInfo
-  , logWarning
   , logError
   , setLogConfig
-  , LogLevel (DEBUG, INFO, WARNING, ERROR, NONE)
+  , LogLevel (DEBUG, ERROR, NONE)
   )
 where
 
@@ -19,14 +17,14 @@
 import GHC.IO (unsafePerformIO)
 import System.IO
 
-data LogLevel = DEBUG | INFO | WARNING | ERROR | NONE
+data LogLevel = DEBUG | ERROR | NONE
   deriving (Show, Ord, Eq, Bounded, Enum, Read)
 
 data Logger = Logger {level :: LogLevel, lns :: Int}
 
 logger :: IORef Logger
 {-# NOINLINE logger #-}
-logger = unsafePerformIO (newIORef (Logger INFO 25))
+logger = unsafePerformIO (newIORef (Logger ERROR 25))
 
 setLogConfig :: LogLevel -> Int -> IO ()
 setLogConfig lvl cnt = writeIORef logger (Logger lvl cnt)
@@ -45,8 +43,6 @@
        in hPutStrLn stderr ("[" ++ show lvl ++ "]: " ++ DL.intercalate "\n" msg)
     )
 
-logDebug, logInfo, logWarning, logError :: String -> IO ()
+logDebug, logError :: String -> IO ()
 logDebug = logMessage DEBUG
-logInfo = logMessage INFO
-logWarning = logMessage WARNING
 logError = logMessage ERROR
diff --git a/src/Margin.hs b/src/Margin.hs
new file mode 100644
--- /dev/null
+++ b/src/Margin.hs
@@ -0,0 +1,115 @@
+{-# LANGUAGE ConstrainedClassMethods #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE RecordWildCards #-}
+
+-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
+-- SPDX-License-Identifier: MIT
+
+module Margin (defaultMargin, withMargin, WithMargin) where
+
+import CST
+import Lining (ToSingleLine (..))
+import Render (Render (..))
+
+defaultMargin :: Int
+defaultMargin = 80
+
+withMargin :: (WithMargin a) => Int -> a -> a
+withMargin margin = withMargin' (0, margin)
+
+class WithMargin a where
+  withMargin' :: (Int, Int) -> a -> a
+
+instance WithMargin PROGRAM where
+  withMargin' (_, margin) PR_SWEET{..} = PR_SWEET lcb (withMargin' (2, margin) expr) rcb
+  withMargin' (_, margin) PR_SALTY{..} =
+    let before = lengthOf global + lengthOf arrow + 2 -- 'Q -> '
+     in PR_SALTY global arrow (withMargin' (before, margin) expr)
+
+instance WithMargin EXPRESSION where
+  withMargin' _ ex@EX_FORMATION{binding = BI_EMPTY{}} = ex
+  withMargin' (extra, margin) ex@EX_FORMATION{tab = tab@(TAB indent), ..} =
+    let single = toSingleLine ex
+        ex' = EX_FORMATION lsb EOL tab (withMargin' (indent, margin) binding) EOL tab' rsb
+     in if lengthOf single + extra <= margin then single else ex'
+  withMargin' _ num@EX_NUMBER{} = num
+  withMargin' _ str@EX_STRING{} = str
+  withMargin' cfg EX_DISPATCH{..} = EX_DISPATCH (withMargin' cfg expr) attr
+  withMargin' cfg EX_META_TAIL{..} = EX_META_TAIL (withMargin' cfg expr) meta
+  withMargin' cfg EX_PHI_AGAIN{..} = EX_PHI_AGAIN prefix idx (withMargin' cfg expr)
+  withMargin' cfg EX_PHI_MEET{..} = EX_PHI_MEET prefix idx (withMargin' cfg expr)
+  withMargin' cfg@(extra, margin) ex@EX_APPLICATION{tab = tab@(TAB indt), ..} =
+    let single = toSingleLine ex
+        main = withMargin' cfg expr
+        singleMain = toSingleLine main
+        extra' = length (last (lines (render main))) + 4 -- 2 spaces + 2 braces around argument
+        arg = withMargin' (indt, margin) tau
+        singleArg = toSingleLine arg
+     in if
+          | lengthOf single + extra <= margin -> single
+          | lengthOf singleMain + extra <= margin -> EX_APPLICATION singleMain EOL tab arg EOL tab' indent
+          | lengthOf singleArg + extra' <= margin -> EX_APPLICATION main NO_EOL TAB' singleArg NO_EOL TAB' indent
+          | otherwise -> EX_APPLICATION main EOL tab arg EOL tab' indent
+  withMargin' cfg@(extra, margin) ex@EX_APPLICATION_EXPRS{tab = tab@(TAB indt), ..} =
+    let single = toSingleLine ex
+        main = withMargin' cfg expr
+        singleMain = toSingleLine main
+        extra' = length (last (lines (render main))) + 4 -- 2 spaces + 2 braces around arguments
+        exprs = withMargin' (indt, margin) args
+        singleExprs = toSingleLine exprs
+     in if
+          | lengthOf single + extra <= margin -> single
+          | lengthOf singleMain + extra <= margin -> EX_APPLICATION_EXPRS singleMain EOL tab exprs EOL tab' indent
+          | lengthOf singleExprs + extra' <= margin -> EX_APPLICATION_EXPRS main NO_EOL TAB' singleExprs NO_EOL TAB' indent
+          | otherwise -> EX_APPLICATION_EXPRS main EOL tab exprs EOL tab' indent
+  withMargin' cfg@(extra, margin) ex@EX_APPLICATION_TAUS{tab = tab@(TAB indt), ..} =
+    let single = toSingleLine ex
+        main = withMargin' cfg expr
+        singleMain = toSingleLine main
+        extra' = length (last (lines (render main))) + 4 -- 2 spaces + 2 braces around arguments
+        taus' = withMargin' (indt, margin) taus
+        singleTaus = toSingleLine taus'
+     in if
+          | lengthOf single + extra <= margin -> single
+          | lengthOf singleMain + extra <= margin -> EX_APPLICATION_TAUS singleMain EOL tab taus' EOL tab' indent
+          | lengthOf singleTaus + extra' <= margin -> EX_APPLICATION_TAUS main NO_EOL TAB' singleTaus NO_EOL TAB' indent
+          | otherwise -> EX_APPLICATION_TAUS main EOL tab taus' EOL tab' indent
+  withMargin' _ ex = ex
+
+instance WithMargin APP_BINDING where
+  withMargin' cfg APP_BINDING{..} = APP_BINDING (withMargin' cfg pair)
+
+instance WithMargin APP_ARG where
+  withMargin' cfg@(extra, margin) arg@APP_ARG{..} =
+    let single = toSingleLine arg
+     in if lengthOf single + extra <= margin then single else APP_ARG (withMargin' cfg expr) (withMargin' cfg args)
+
+instance WithMargin APP_ARGS where
+  withMargin' cfg AAS_EXPR{..} = AAS_EXPR EOL tab (withMargin' cfg expr) (withMargin' cfg args)
+  withMargin' _ args = args
+
+instance WithMargin BINDING where
+  withMargin' cfg BI_PAIR{..} = BI_PAIR (withMargin' cfg pair) (withMargin' cfg bindings) tab
+  withMargin' cfg BI_META{..} = BI_META meta (withMargin' cfg bindings) tab
+  withMargin' _ bd = bd
+
+instance WithMargin BINDINGS where
+  withMargin' cfg BDS_PAIR{..} = BDS_PAIR EOL tab (withMargin' cfg pair) (withMargin' cfg bindings)
+  withMargin' cfg BDS_META{..} = BDS_META EOL tab meta (withMargin' cfg bindings)
+  withMargin' _ bds = bds
+
+instance WithMargin PAIR where
+  withMargin' (extra, margin) pa@PA_TAU{..} =
+    let single = toSingleLine pa
+        extra' = extra + lengthOf attr + lengthOf arrow + 2 -- indent + attr + arrow + 2 spaces
+        pa' = PA_TAU attr arrow (withMargin' (extra', margin) expr)
+     in if lengthOf single + extra <= margin then single else pa'
+  withMargin' (extra, margin) pa@PA_FORMATION{..} =
+    let single = toSingleLine pa
+        extra' = extra + lengthOf attr + lengthOf voids + lengthOf arrow + 4 -- indent + 2 braces + 2 spaces + voids
+        pa' = PA_FORMATION attr voids arrow (withMargin' (extra', margin) expr)
+     in if lengthOf single + extra <= margin then single else pa'
+  withMargin' _ pa = pa
+
+lengthOf :: Render a => a -> Int
+lengthOf renderable = length (render renderable)
diff --git a/src/Printer.hs b/src/Printer.hs
--- a/src/Printer.hs
+++ b/src/Printer.hs
@@ -26,38 +26,39 @@
 import qualified Data.Map.Strict as Map
 import Encoding
 import Lining
+import Margin (defaultMargin, withMargin)
 import Matcher
 import Render
 import Sugar
 import Yaml (ExtraArgument (ArgAttribute, ArgBinding, ArgBytes, ArgExpression))
 import Prelude hiding (print)
 
-type PrintConfig = (SugarType, Encoding, LineFormat)
+type PrintConfig = (SugarType, Encoding, LineFormat, Int)
 
 defaultPrintConfig :: PrintConfig
-defaultPrintConfig = (SWEET, UNICODE, MULTILINE)
+defaultPrintConfig = (SWEET, UNICODE, MULTILINE, defaultMargin)
 
-logPrintConfig :: (SugarType, Encoding, LineFormat)
-logPrintConfig = (SWEET, UNICODE, SINGLELINE)
+logPrintConfig :: (SugarType, Encoding, LineFormat, Int)
+logPrintConfig = (SWEET, UNICODE, SINGLELINE, defaultMargin)
 
 printProgram' :: Program -> PrintConfig -> String
-printProgram' prog (sugar, encoding, line) = render (withLineFormat line $ withEncoding encoding $ withSugarType sugar $ programToCST prog)
+printProgram' prog (sugar, encoding, line, margin) = render (withLineFormat line $ withMargin margin $ withEncoding encoding $ withSugarType sugar $ programToCST prog)
 
 printProgram :: Program -> String
 printProgram prog = printProgram' prog defaultPrintConfig
 
 printExpression' :: Expression -> PrintConfig -> String
-printExpression' ex (sugar, encoding, line) = render (withLineFormat line $ withEncoding encoding $ withSugarType sugar $ expressionToCST ex)
+printExpression' ex (sugar, encoding, line, margin) = render (withLineFormat line $ withMargin margin $ withEncoding encoding $ withSugarType sugar $ expressionToCST ex)
 
 printExpression :: Expression -> String
 printExpression ex = printExpression' ex defaultPrintConfig
 
 printAttribute' :: Attribute -> Encoding -> String
-printAttribute' att encoding = render (withEncoding encoding (toCST att 0 NO_EOL :: ATTRIBUTE))
+printAttribute' att encoding = render (withEncoding encoding (toCST att (0, NO_EOL) :: ATTRIBUTE))
 
 printAttribute :: Attribute -> String
 printAttribute att =
-  let (_, encoding, _) = defaultPrintConfig
+  let (_, encoding, _, _) = defaultPrintConfig
    in printAttribute' att encoding
 
 printBinding' :: Binding -> PrintConfig -> String
@@ -67,10 +68,10 @@
 printBinding bd = printBinding' bd defaultPrintConfig
 
 printBytes :: Bytes -> String
-printBytes bts = render (toCST bts 0 NO_EOL :: BYTES)
+printBytes bts = render (toCST bts (0, NO_EOL) :: BYTES)
 
 printExtraArg' :: ExtraArgument -> PrintConfig -> String
-printExtraArg' (ArgAttribute att) (_, encoding, _) = printAttribute' att encoding
+printExtraArg' (ArgAttribute att) (_, encoding, _, _) = printAttribute' att encoding
 printExtraArg' (ArgBinding bd) config = printBinding' bd config
 printExtraArg' (ArgExpression ex) config = printExpression' ex config
 printExtraArg' (ArgBytes bts) _ = printBytes bts
@@ -80,10 +81,10 @@
 
 printTail :: Tail -> PrintConfig -> String
 printTail (TaApplication bd) config = "(" <> printBinding' bd config <> ")"
-printTail (TaDispatch att) (_, encoding, _) = "." <> printAttribute' att encoding
+printTail (TaDispatch att) (_, encoding, _, _) = "." <> printAttribute' att encoding
 
 printMetaValue :: MetaValue -> PrintConfig -> String
-printMetaValue (MvAttribute att) (_, encoding, _) = printAttribute' att encoding
+printMetaValue (MvAttribute att) (_, encoding, _, _) = printAttribute' att encoding
 printMetaValue (MvExpression ex _) config = printExpression' ex config
 printMetaValue (MvBytes bts) _ = printBytes bts
 printMetaValue (MvBindings bds) config = printExpression' (ExFormation bds) config
diff --git a/src/Render.hs b/src/Render.hs
--- a/src/Render.hs
+++ b/src/Render.hs
@@ -81,10 +81,6 @@
   render Φ = "Φ"
   render Q = "Q"
 
-instance Render DEF_PACKAGE where
-  render Φ̇ = "Φ̇"
-  render QQ = "QQ"
-
 instance Render TERMINATION where
   render DEAD = "⊥"
   render T = "T"
@@ -119,7 +115,7 @@
   render ALPHA' = "~"
 
 instance Render TAB where
-  render TAB{..} = intercalate "" (replicate indent "  ")
+  render TAB{..} = concat (replicate indent "  ")
   render TAB' = " "
   render NO_TAB = ""
 
@@ -130,7 +126,7 @@
 instance Render PAIR where
   render PA_TAU{..} = render attr <> render SPACE <> render arrow <> render SPACE <> render expr
   render PA_FORMATION{voids = [], attr, arrow, expr} = render (PA_TAU attr arrow expr)
-  render PA_FORMATION{..} = render attr <> "(" <> intercalate ", " (map render voids) <> ")" <> render SPACE <> render arrow <> render SPACE <> render expr
+  render PA_FORMATION{..} = render attr <> "(" <> render voids <> ")" <> render SPACE <> render arrow <> render SPACE <> render expr
   render PA_LAMBDA{..} = render LAMBDA <> render SPACE <> render DASHED_ARROW <> render SPACE <> render func
   render PA_LAMBDA'{..} = "L> " <> func
   render PA_VOID{..} = render attr <> render SPACE <> render arrow <> render SPACE <> render void
@@ -177,6 +173,9 @@
   render EX_META_TAIL{..} = render expr <> " * " <> render meta
   render EX_PHI_MEET{..} = "\\phiMeet{" <> maybe "" (++ ":") prefix <> render idx <> "}{ " <> render expr <> " }"
   render EX_PHI_AGAIN{..} = "\\phiAgain{" <> maybe "" (++ ":") prefix <> render idx <> "}"
+
+instance Render [ATTRIBUTE] where
+  render attrs = intercalate ", " (map render attrs)
 
 instance Render ATTRIBUTE where
   render AT_LABEL{..} = label
diff --git a/src/Sugar.hs b/src/Sugar.hs
--- a/src/Sugar.hs
+++ b/src/Sugar.hs
@@ -14,8 +14,8 @@
 import Misc (numToBts, strToBts, toDouble, pattern BaseObject)
 
 withSugarType :: (ToSalty a) => SugarType -> a -> a
-withSugarType SWEET prog = prog
-withSugarType SALTY prog = toSalty prog
+withSugarType SWEET node = node
+withSugarType SALTY node = toSalty node
 
 voidRho :: PAIR
 voidRho = PA_VOID (AT_RHO RHO) ARROW EMPTY
@@ -39,18 +39,18 @@
 
 -- By default CST is generated with all possible syntax sugar
 -- The main purpose of this class is to get rid of syntax sugar
---  |----------------------------|-------------------------------------------------------|
---  | sugar                      | verbose version                                       |
---  |----------------------------|-------------------------------------------------------|
---  | {e}                        | Q -> e                                                |
---  | a1 -> a2                   | a1 ↦ $.a2                                             |
---  | a -> 42                    | QQ.number(QQ.bytes([[ D> 40-45-00-00-00-00-00-00 ]])) |
---  | a -> "Hey"                 | QQ.number(QQ.bytes([[ D> 48-65-79 ]]))                |
---  | [[ B ]]                    | [[ B, ^ -> ? ]], if rho is absent in 'B'              |
---  | a1(a2, a3, ...) -> [[ B ]] | a1 -> [[ a2 -> ?, a3 -> ?, ..., B ]]                  |
---  | e(e0, e1, ...)             | e(~0 -> e0, ~1 -> e1, ...)                            |
---  | e(a1 -> e1, a2 -> e2, ...) | e(a1 -> e1)(a2 -> e2)...                              |
---  |----------------------------|-------------------------------------------------------|
+--  |----------------------------|-----------------------------------------------------|
+--  | sugar                      | verbose version                                     |
+--  |----------------------------|-----------------------------------------------------|
+--  | {e}                        | Q -> e                                              |
+--  | a1 -> a2                   | a1 ↦ $.a2                                           |
+--  | a -> 42                    | Q.number(Q.bytes([[ D> 40-45-00-00-00-00-00-00 ]])) |
+--  | a -> "Hey"                 | Q.number(Q.bytes([[ D> 48-65-79 ]]))                |
+--  | [[ B ]]                    | [[ B, ^ -> ? ]], if rho is absent in 'B'            |
+--  | a1(a2, a3, ...) -> [[ B ]] | a1 -> [[ a2 -> ?, a3 -> ?, ..., B ]]                |
+--  | e(e0, e1, ...)             | e(~0 -> e0, ~1 -> e1, ...)                          |
+--  | e(a1 -> e1, a2 -> e2, ...) | e(a1 -> e1)(a2 -> e2)...                            |
+--  |----------------------------|-----------------------------------------------------|
 class ToSalty a where
   toSalty :: a -> a
 
@@ -93,16 +93,16 @@
       argsToBindings AAS_EXPR{..} idx tb = BDS_PAIR eol tb (PA_TAU (AT_ALPHA ALPHA idx) ARROW expr) (argsToBindings args (idx + 1) tb)
   toSalty EX_NUMBER{num, tab = tab@TAB{..}, rhos} =
     saltifyPrimitive
-      (toCST (BaseObject "number") (indent + 1) EOL)
-      (toCST (BaseObject "bytes") (indent + 2) EOL)
-      (toCST (ExFormation [BiDelta (numToBts (either toDouble id num))]) (indent + 2) EOL)
+      (toCST (BaseObject "number") (indent + 1, EOL))
+      (toCST (BaseObject "bytes") (indent + 2, EOL))
+      (toCST (ExFormation [BiDelta (numToBts (either toDouble id num))]) (indent + 2, EOL))
       tab
       rhos
   toSalty EX_STRING{str, tab = tab@TAB{..}, rhos} =
     saltifyPrimitive
-      (toCST (BaseObject "string") (indent + 1) EOL)
-      (toCST (BaseObject "bytes") (indent + 2) EOL)
-      (toCST (ExFormation [BiDelta (strToBts str)]) (indent + 2) EOL)
+      (toCST (BaseObject "string") (indent + 1, EOL))
+      (toCST (BaseObject "bytes") (indent + 2, EOL))
+      (toCST (ExFormation [BiDelta (strToBts str)]) (indent + 2, EOL))
       tab
       rhos
   toSalty EX_PHI_MEET{..} = EX_PHI_MEET prefix idx (toSalty expr)
@@ -131,7 +131,7 @@
                         (indent + 2)
                     )
                 )
-                (toCST rhos (indent + 1) EOL)
+                (toCST rhos (indent + 1, EOL))
                 next
             )
             EOL
diff --git a/src/XMIR.hs b/src/XMIR.hs
--- a/src/XMIR.hs
+++ b/src/XMIR.hs
@@ -20,7 +20,7 @@
 
 import AST
 import Control.Exception (Exception (displayException), throwIO)
-import qualified Data.Bifunctor
+import Data.Bifunctor (bimap)
 import Data.Foldable (foldlM)
 import Data.List (intercalate)
 import qualified Data.Map as M
@@ -75,10 +75,10 @@
 toName str = Name (T.pack str) Nothing Nothing
 
 element :: String -> [(String, String)] -> [Node] -> Element
-element name attrs children = do
+element name attrs children =
   let name' = toName name
-      attrs' = M.fromList (map (Data.Bifunctor.bimap toName T.pack) attrs)
-  Element name' attrs' children
+      attrs' = M.fromList (map (bimap toName T.pack) attrs)
+   in Element name' attrs' children
 
 object :: [(String, String)] -> [Node] -> Node
 object attrs children = NodeElement (element "o" attrs children)
@@ -245,13 +245,13 @@
             ]
         )
     time :: UTCTime -> String
-    time now = do
+    time now =
       let base = formatTime defaultTimeLocale "%Y-%m-%dT%H:%M:%S" now
           posix = utcTimeToPOSIXSeconds now
           fractional :: Double
           fractional = realToFrac posix - fromInteger (floor posix)
           nanos = floor (fractional * 1_000_000_000) :: Int
-      base ++ "." ++ printf "%09d" nanos ++ "Z"
+       in base ++ "." ++ printf "%09d" nanos ++ "Z"
 programToXMIR prog _ = throwIO (UnsupportedProgram prog)
 
 -- Add indentation (2 spaces per level).
diff --git a/test/CLISpec.hs b/test/CLISpec.hs
--- a/test/CLISpec.hs
+++ b/test/CLISpec.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# OPTIONS_GHC -Wno-unused-do-bind #-}
 
@@ -11,13 +10,14 @@
 import Control.Exception
 import Control.Monad (forM_, unless, when)
 import Data.List (intercalate, isInfixOf)
+import Data.Time.Clock.POSIX (getPOSIXTime)
 import Data.Version (showVersion)
 import GHC.IO.Handle
 import Paths_phino (version)
-import System.Directory (doesDirectoryExist, doesFileExist, listDirectory, removeDirectoryRecursive, removeFile)
+import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, getTemporaryDirectory, listDirectory, removeDirectoryRecursive, removeFile)
 import System.Exit (ExitCode (ExitFailure))
+import System.FilePath ((</>))
 import System.IO
-import System.Info (os)
 import Test.Hspec
 import Text.Printf (printf)
 
@@ -100,9 +100,6 @@
 rule :: String -> String
 rule file = "--rule=" <> resource file
 
-isWindows :: Bool
-isWindows = os == "mingw32"
-
 spec :: Spec
 spec = do
   it "prints version" $
@@ -114,7 +111,7 @@
       ["Phino - CLI Manipulator of 𝜑-Calculus Expressions", "Usage:"]
 
   it "prints debug info with --log-level=DEBUG" $
-    withStdin "Q -> [[]]" $
+    withStdin "{[[]]}" $
       testCLISucceeded ["rewrite", "--log-level=DEBUG"] ["[DEBUG]:"]
 
   describe "rewriting" $ do
@@ -138,7 +135,7 @@
             ["--max-depth must be positive"]
 
       it "with --normalize and --must=1" $
-        withStdin "Q -> [[ x -> [[ y -> 5 ]].y ]].x" $
+        withStdin "{[[ x -> [[ y -> 5 ]].y ]].x}" $
           testCLIFailed
             ["rewrite", "--max-cycles=2", "--max-depth=1", "--normalize", "--must=1"]
             ["it's expected rewriting cycles to be in range [1], but rewriting has already reached 2"]
@@ -179,101 +176,107 @@
           ]
 
       it "with --output != latex and --nonumber" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--nonumber", "--output=xmir"]
             ["The --nonumber option can stay together with --output=latex only"]
 
       it "with --omit-listing and --output != xmir" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--omit-listing", "--output=phi"]
             ["--omit-listing"]
 
       it "with --omit-comments and --output != xmir" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--omit-comments", "--output=phi"]
             ["--omit-comments"]
 
       it "with --expression and --output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--expression=foo", "--output=phi"]
             ["--expression option can stay together with --output=latex only"]
 
       it "with --label and --output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--label=foo", "--output=phi"]
             ["--label option can stay together with --output=latex only"]
 
       it "with --compress and --output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--compress", "--output=phi"]
             ["--compress option can stay together with --output=latex only"]
 
       it "with --meet-prefix and --output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--meet-prefix=foo", "--output=phi"]
             ["--meet-prefix option can stay together with --output=latex only"]
 
       it "with wrong --hide option" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--hide=Q.x(Q.y)"]
             ["[ERROR]: Invalid set of arguments: Only dispatch expression", "but given: Φ.x( Φ.y )"]
 
       it "with many --show options" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--show=Q.x.y", "--show=hello"]
             ["The option --show can be used only once"]
 
       it "with wrong --show option" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--show=Q.x(Q.y)"]
             ["[ERROR]:", "Only dispatch expression started with Φ (or Q) can be used in --show"]
 
       it "with --meet-popularity < 0" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--meet-popularity=-1"]
             ["[ERROR]:", "--meet-popularity must be positive"]
 
       it "with --meet-popularity > 100" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--meet-popularity=102"]
             ["[ERROR]:", "--meet-popularity must be <= 100"]
 
       it "with --meet-popularity and output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--meet-popularity=51", "--output=phi"]
             ["[ERROR]:", "--meet-popularity option can stay together with --output=latex only"]
 
       it "with --meet-length and output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--meet-length=4", "--output=phi"]
             ["[ERROR]:", "--meet-length option can stay together with --output=latex only"]
 
       it "with non-dispatch --focus" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--focus=Q.x(Q.y)"]
             ["[ERROR]"]
 
       it "with --focus!=Q and --output=XMIR" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["rewrite", "--focus=Q.x", "--output=xmir"]
             ["[ERROR]"]
 
+      it "with --margin < 0" $
+        withStdin "" $
+          testCLIFailed
+            ["rewrite", "--margin=-1"]
+            ["[ERROR]"]
+
     it "prints help" $
       testCLISucceeded
         ["rewrite", "--help"]
@@ -297,11 +300,11 @@
     it "desugares without any rules flag from file" $
       testCLISucceeded
         ["rewrite", resource "desugar.phi"]
-        ["Φ ↦ ⟦\n  foo ↦ ξ.x,\n  ρ ↦ ∅\n⟧"]
+        ["Φ ↦ ⟦ foo ↦ ξ.x, ρ ↦ ∅ ⟧"]
 
     it "desugares with without any rules flag from stdin" $
       withStdin "{[[foo ↦ x]]}" $
-        testCLISucceeded ["rewrite"] ["Φ ↦ ⟦\n  foo ↦ ξ.x,\n  ρ ↦ ∅\n⟧"]
+        testCLISucceeded ["rewrite"] ["Φ ↦ ⟦ foo ↦ ξ.x, ρ ↦ ∅ ⟧"]
 
     it "rewrites with single rule" $
       withStdin "{T(x -> Q.y)}" $
@@ -309,7 +312,7 @@
 
     it "normalizes with --normalize flag" $
       testCLISucceeded
-        ["rewrite", "--normalize", resource "normalize.phi"]
+        ["rewrite", "--normalize", resource "normalize.phi", "--margin=25"]
         [ unlines
             [ "Φ ↦ ⟦"
             , "  x ↦ ⟦"
@@ -326,7 +329,7 @@
     it "normalizes from stdin" $
       withStdin "Φ ↦ ⟦ a ↦ ⟦ b ↦ ∅ ⟧ (b ↦ [[ ]]) ⟧" $
         testCLISucceeded
-          ["rewrite", "--normalize"]
+          ["rewrite", "--normalize", "--margin=20"]
           [ unlines
               [ "Φ ↦ ⟦"
               , "  a ↦ ⟦"
@@ -342,7 +345,7 @@
       withStdin "Q -> [[ x -> 5]]" $
         testCLISucceeded
           ["rewrite", "--sweet"]
-          ["{⟦\n  x ↦ 5\n⟧}"]
+          ["{⟦ x ↦ 5 ⟧}"]
 
     it "rewrites as XMIR" $
       withStdin "Q -> [[ x -> Q.y ]]" $
@@ -406,14 +409,7 @@
       withStdin "<object><o name=\"app\"><o name=\"x\" base=\"Φ.number\"/></o></object>" $
         testCLISucceeded
           ["rewrite", "--input=xmir", "--sweet"]
-          [ unlines
-              [ "{⟦"
-              , "  app ↦ ⟦"
-              , "    x ↦ Φ.number"
-              , "  ⟧"
-              , "⟧}"
-              ]
-          ]
+          ["{⟦ app ↦ ⟦ x ↦ Φ.number ⟧ ⟧}"]
 
     it "rewrites as XMIR with omit-listing flag" $
       withStdin "Q -> [[ x -> Q.y ]]" $
@@ -662,18 +658,13 @@
         hClose h
         testCLISucceeded ["rewrite", rule "simple.yaml", "--in-place", "--sweet", path] []
         content <- readFile path
-        content `shouldBe` "{⟦\n  x ↦ \"bar\"\n⟧}"
+        content `shouldBe` "{⟦ x ↦ \"bar\" ⟧}"
 
     it "rewrites with cycles" $
       withStdin "Q -> [[ x -> \"x\" ]]" $
         testCLISucceeded
           ["rewrite", "--sweet", rule "infinite.yaml", "--max-depth=1", "--max-cycles=2"]
-          [ unlines
-              [ "{⟦"
-              , "  x ↦ \"x_hi_hi\""
-              , "⟧}"
-              ]
-          ]
+          ["{⟦ x ↦ \"x_hi_hi\" ⟧}"]
 
     it "hides default package" $
       withStdin "{[[ org -> [[ eolang -> [[ number -> [[]] ]]]], x -> 42 ]]}" $
@@ -716,14 +707,11 @@
     it "reduces log message" $
       withStdin "{[[ x -> [[ y -> ? ]](y -> 5) ]]}" $
         testCLISucceeded
-          ["rewrite", "--log-level=debug", "--log-lines=4", "--normalize"]
+          ["rewrite", "--log-level=debug", "--log-lines=1", "--normalize"]
           [ intercalate
               "\n"
               [ "[DEBUG]: Applied 'COPY' (44 nodes -> 39 nodes)"
-              , "⟦"
-              , "  x ↦ ⟦"
-              , "    y ↦ 5"
-              , "---| log is limited by --log-lines=4 option |---"
+              , "---| log is limited by --log-lines=1 option |---"
               ]
           ]
 
@@ -779,37 +767,37 @@
 
     describe "fails" $ do
       it "with --output != latex and --nonumber" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["dataize", "--nonumber", "--output=xmir"]
             ["The --nonumber option can stay together with --output=latex only"]
 
       it "with --omit-listing and --output != xmir" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["dataize", "--omit-listing", "--output=phi"]
             ["--omit-listing"]
 
       it "with --omit-comments and --output != xmir" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["dataize", "--omit-comments", "--output=phi"]
             ["--omit-comments"]
 
       it "with --expression and --output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["dataize", "--expression=foo", "--output=phi"]
             ["--expression option can stay together with --output=latex only"]
 
       it "with --label and --output != latex" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["dataize", "--label=foo", "--output=phi"]
             ["--label option can stay together with --output=latex only"]
 
       it "with wrong --hide option" $
-        withStdin "{[[]]}" $
+        withStdin "" $
           testCLIFailed
             ["dataize", "--hide=Q.x(Q.y)"]
             ["[ERROR]: Invalid set of arguments: Only dispatch expression", "but given: Φ.x( Φ.y )"]
@@ -836,19 +824,22 @@
         ["Either --rule or --normalize must be specified"]
 
     it "writes to target file" $
-      if isWindows
-        then pendingWith "Skipped on Windows due to file locking issues"
-        else
-          bracket
-            (openTempFile "." "explainXXXXXX.tex")
-            (\(path, _) -> removeFile path)
-            ( \(path, h) -> do
-                hClose h
-                testCLISucceeded ["explain", "--normalize", printf "--target=%s" path] []
-                content <- readFile path
-                content `shouldContain` "\\documentclass{article}"
-                content `shouldContain` "\\begin{document}"
-            )
+      bracket
+        ( do
+            tmp <- getTemporaryDirectory
+            stamp <- getPOSIXTime
+            let dir = tmp </> ("phino-test-" ++ show (floor stamp :: Integer))
+            createDirectoryIfMissing True dir
+            pure (dir </> "explain.tex", dir)
+        )
+        (\(_, dir) -> removeDirectoryRecursive dir)
+        ( \(path, _) -> do
+            testCLISucceeded ["explain", "--normalize", printf "--target=%s" path] []
+            content <- readFile path
+            _ <- evaluate (length content)
+            content `shouldContain` "\\documentclass{article}"
+            content `shouldContain` "\\begin{document}"
+        )
 
   describe "merge" $ do
     it "merges single program" $
@@ -858,7 +849,7 @@
 
     it "merges EO programs" $
       testCLISucceeded
-        ["merge", "--sweet", resource "number.phi", resource "bytes.phi", resource "string.phi"]
+        ["merge", "--sweet", resource "number.phi", resource "bytes.phi", resource "string.phi", "--margin=25"]
         [ unlines
             [ "{⟦"
             , "  org ↦ ⟦"
@@ -918,7 +909,7 @@
     it "builds with condition from file" $
       testCLISucceeded
         ["match", "--pattern=[[ !B ]]", "--when=eq(length(!B),2)", "test-resources/cli/foo.phi"]
-        ["B >> ⟦\n  foo ↦ Φ.org.eolang.x,\n  ρ ↦ ∅\n⟧"]
+        ["B >> ⟦ foo ↦ Φ.org.eolang.x, ρ ↦ ∅ ⟧"]
 
     it "fails on parsing --when condition" $
       withStdin "{[[]]}" $
diff --git a/test/CSTSpec.hs b/test/CSTSpec.hs
--- a/test/CSTSpec.hs
+++ b/test/CSTSpec.hs
@@ -14,6 +14,7 @@
 import Encoding (Encoding (ASCII), withEncoding)
 import GHC.Generics (Generic)
 import Lining (LineFormat (SINGLELINE), withLineFormat)
+import Margin (defaultMargin, withMargin)
 import Misc
 import Parser (parseProgramThrows)
 import Render (Render (render))
@@ -74,7 +75,7 @@
       , ("number(bytes(again(data)))", app number (bt (app bts (bt (again form)))))
       , ("again(number)(again(bytes)(again(data)))", app (again number) (bt (app (again bts) (bt (again form)))))
       ]
-      (\(desc, ex) -> it desc (toCST ex 0 EOL `shouldSatisfy` isCSTNumber))
+      (\(desc, ex) -> it desc (toCST ex (0, EOL) `shouldSatisfy` isCSTNumber))
 
   describe "CST printing packs" $ do
     let resources = "test-resources/cst/printing-packs"
@@ -84,7 +85,7 @@
       ( \pth -> it (makeRelative resources pth) $ do
           pack <- cstPack pth
           prog <- parseProgramThrows (program pack)
-          render (programToCST prog) `shouldBe` result pack
+          render (withMargin defaultMargin (programToCST prog)) `shouldBe` result pack
       )
 
   describe "converts to salty CST" $ do
@@ -109,7 +110,7 @@
           pack <- cstPack pth
           prog <- parseProgramThrows (program pack)
           let cst = programToCST prog
-              ascii = withEncoding ASCII cst
+              ascii = withMargin defaultMargin (withEncoding ASCII cst)
           render ascii `shouldBe` result pack
       )
 
diff --git a/test/FilterSpec.hs b/test/FilterSpec.hs
--- a/test/FilterSpec.hs
+++ b/test/FilterSpec.hs
@@ -11,7 +11,6 @@
 -}
 module FilterSpec where
 
-import AST
 import Control.Monad (forM_, when)
 import Data.Aeson
 import Data.Yaml qualified as Yaml
@@ -19,6 +18,7 @@
 import Filter qualified as F
 import GHC.Generics (Generic)
 import Lining (LineFormat (MULTILINE))
+import Margin (defaultMargin)
 import Misc
 import Parser (parseExpressionThrows, parseProgramThrows)
 import Printer (printProgram')
@@ -38,218 +38,27 @@
 yamlPack = Yaml.decodeFileThrow
 
 spec :: Spec
-spec = do
-  describe "filter packs" $ do
-    let resources = "test-resources/filter-packs"
-    packs <- runIO (allPathsIn resources)
-    forM_
-      packs
-      ( \pth -> it (makeRelative resources pth) $ do
-          YamlPack{..} <- yamlPack pth
-          prog <- parseProgramThrows program
-          included <- traverse parseExpressionThrows shown
-          excluded <- traverse parseExpressionThrows hidden
-          res <- parseProgramThrows result
-          let [(prog', _)] = F.exclude (F.include [(prog, Nothing)] included) excluded
-          prog' `shouldBe` res
-          when
-            (prog' /= res)
-            ( expectationFailure
-                ( "Expected:\n"
-                    ++ printProgram' res (SALTY, UNICODE, MULTILINE)
-                    ++ "\nbut got:\n"
-                    ++ printProgram' prog' (SALTY, UNICODE, MULTILINE)
-                )
-            )
-      )
-
-  describe "exclude with empty expression list" $
-    it "returns programs unchanged" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      let result = F.exclude [(prog, Nothing)] []
-      result `shouldBe` [(prog, Nothing)]
-
-  describe "exclude with empty program list" $
-    it "returns empty list" $ do
-      fqn <- parseExpressionThrows "Q.x"
-      let result = F.exclude [] [fqn]
-      result `shouldBe` []
-
-  describe "exclude with non-formation program" $
-    it "returns program unchanged" $ do
-      let prog = Program ExGlobal
-          fqn = ExDispatch ExGlobal (AtLabel "x")
-          result = F.exclude [(prog, Nothing)] [fqn]
-      result `shouldBe` [(prog, Nothing)]
-
-  describe "exclude with termination program" $
-    it "returns program unchanged" $ do
-      let prog = Program ExTermination
-          fqn = ExDispatch ExGlobal (AtLabel "x")
-          result = F.exclude [(prog, Nothing)] [fqn]
-      result `shouldBe` [(prog, Nothing)]
-
-  describe "exclude with non-dispatch FQN" $
-    it "handles non-dispatch expression gracefully" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      let fqn = ExGlobal
-          [(prog', _)] = F.exclude [(prog, Nothing)] [fqn]
-      prog' `shouldBe` prog
-
-  describe "exclude with xi FQN" $
-    it "handles xi expression gracefully" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      let fqn = ExThis
-          [(prog', _)] = F.exclude [(prog, Nothing)] [fqn]
-      prog' `shouldBe` prog
-
-  describe "exclude multiple programs" $
-    it "processes all programs in list" $ do
-      prog1 <- parseProgramThrows "{[[ x -> Q, y -> $ ]]}"
-      prog2 <- parseProgramThrows "{[[ a -> Q, b -> $ ]]}"
-      fqn <- parseExpressionThrows "Q.x"
-      let result = F.exclude [(prog1, Nothing), (prog2, Nothing)] [fqn]
-      length result `shouldBe` 2
-
-  describe "include with empty expression list" $
-    it "returns programs unchanged" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      let result = F.include [(prog, Nothing)] []
-      result `shouldBe` [(prog, Nothing)]
-
-  describe "include with empty program list" $
-    it "returns empty list" $ do
-      fqn <- parseExpressionThrows "Q.x"
-      let result = F.include [] [fqn]
-      result `shouldBe` []
-
-  describe "include with non-formation program" $
-    it "returns empty formation" $ do
-      let prog = Program ExGlobal
-          fqn = ExDispatch ExGlobal (AtLabel "x")
-          [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-      prog' `shouldBe` Program (ExFormation [BiVoid AtRho])
-
-  describe "include with termination program" $
-    it "returns empty formation" $ do
-      let prog = Program ExTermination
-          fqn = ExDispatch ExGlobal (AtLabel "x")
-          [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-      prog' `shouldBe` Program (ExFormation [BiVoid AtRho])
-
-  describe "include with non-existent attribute" $
-    it "returns empty formation" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      fqn <- parseExpressionThrows "Q.nonexistent"
-      let [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-      prog' `shouldBe` Program (ExFormation [BiVoid AtRho])
-
-  describe "include with non-matching nested attribute" $
-    it "returns empty formation when path doesnt exist" $ do
-      prog <- parseProgramThrows "{[[ x -> [[ y -> Q ]] ]]}"
-      fqn <- parseExpressionThrows "Q.x.nonexistent"
-      let [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-      prog' `shouldBe` Program (ExFormation [BiVoid AtRho])
-
-  describe "include with non-dispatch FQN" $
-    it "handles non-dispatch expression gracefully" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      let fqn = ExGlobal
-          [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-      prog' `shouldBe` Program (ExFormation [BiVoid AtRho])
-
-  describe "include with xi FQN" $
-    it "handles xi expression gracefully" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      let fqn = ExThis
-          [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-      prog' `shouldBe` Program (ExFormation [BiVoid AtRho])
-
-  describe "include multiple programs" $
-    it "processes all programs in list" $ do
-      prog1 <- parseProgramThrows "{[[ x -> Q, y -> $ ]]}"
-      prog2 <- parseProgramThrows "{[[ a -> Q, b -> $ ]]}"
-      fqn <- parseExpressionThrows "Q.x"
-      let result = F.include [(prog1, Nothing), (prog2, Nothing)] [fqn]
-      length result `shouldBe` 2
-
-  describe "include with nested formation not matching" $
-    it "skips non-matching bindings to find target" $ do
-      prog <- parseProgramThrows "{[[ a -> Q, x -> [[ y -> Q ]] ]]}"
-      fqn <- parseExpressionThrows "Q.x.y"
-      let [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-          isFormation (Program (ExFormation _)) = True
-          isFormation _ = False
-      prog' `shouldSatisfy` isFormation
-
-  describe "include with deep nested path" $
-    it "follows multi-level FQN" $ do
-      prog <- parseProgramThrows "{[[ a -> [[ b -> [[ c -> Q ]] ]] ]]}"
-      fqn <- parseExpressionThrows "Q.a.b.c"
-      let [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-          isFormation (Program (ExFormation _)) = True
-          isFormation _ = False
-      prog' `shouldSatisfy` isFormation
-
-  describe "exclude with deep nested path" $
-    it "removes from multi-level FQN" $ do
-      prog <- parseProgramThrows "{[[ a -> [[ b -> [[ c -> Q, d -> $ ]] ]] ]]}"
-      fqn <- parseExpressionThrows "Q.a.b.c"
-      let [(prog', _)] = F.exclude [(prog, Nothing)] [fqn]
-          isFormation (Program (ExFormation _)) = True
-          isFormation _ = False
-      prog' `shouldSatisfy` isFormation
-
-  describe "exclude preserves rule metadata" $
-    it "keeps Nothing rule through exclude" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      fqn <- parseExpressionThrows "Q.y"
-      let [(_, rule)] = F.exclude [(prog, Nothing)] [fqn]
-      rule `shouldBe` Nothing
-
-  describe "include preserves rule metadata" $
-    it "keeps Nothing rule through include" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      fqn <- parseExpressionThrows "Q.x"
-      let [(_, rule)] = F.include [(prog, Nothing)] [fqn]
-      rule `shouldBe` Nothing
-
-  describe "exclude with non-formation nested binding" $
-    it "handles tau with non-formation value" $ do
-      prog <- parseProgramThrows "{[[ x -> Q ]]}"
-      fqn <- parseExpressionThrows "Q.x.y"
-      let [(prog', _)] = F.exclude [(prog, Nothing)] [fqn]
-      prog' `shouldBe` prog
-
-  describe "include with formation lacking target binding" $
-    it "returns empty formation when binding not found" $ do
-      prog <- parseProgramThrows "{[[ x -> [[ a -> Q ]] ]]}"
-      fqn <- parseExpressionThrows "Q.y.z"
-      let [(prog', _)] = F.include [(prog, Nothing)] [fqn]
-      prog' `shouldBe` Program (ExFormation [BiVoid AtRho])
-
-  describe "exclude with void binding" $
-    it "handles void bindings correctly" $ do
-      prog <- parseProgramThrows "{[[ x -> ?, y -> Q ]]}"
-      fqn <- parseExpressionThrows "Q.x"
-      let [(prog', _)] = F.exclude [(prog, Nothing)] [fqn]
-          Program (ExFormation bds) = prog'
-      length bds `shouldBe` 2
-
-  describe "exclude with meta binding" $
-    it "handles meta bindings correctly" $ do
-      let prog = Program (ExFormation [BiMeta "B", BiTau (AtLabel "x") ExGlobal])
-          fqn = ExDispatch ExGlobal (AtLabel "x")
-          [(prog', _)] = F.exclude [(prog, Nothing)] [fqn]
-          Program (ExFormation bds) = prog'
-      length bds `shouldBe` 1
-
-  describe "include uses only first FQN" $
-    it "ignores additional FQNs in list" $ do
-      prog <- parseProgramThrows "{[[ x -> Q, y -> $ ]]}"
-      fqn1 <- parseExpressionThrows "Q.x"
-      fqn2 <- parseExpressionThrows "Q.y"
-      let [(prog', _)] = F.include [(prog, Nothing)] [fqn1, fqn2]
-          Program (ExFormation bds) = prog'
-          names = [attr | BiTau attr _ <- bds]
-      AtLabel "x" `elem` names `shouldBe` True
+spec = describe "filter packs" $ do
+  let resources = "test-resources/filter-packs"
+  packs <- runIO (allPathsIn resources)
+  forM_
+    packs
+    ( \pth -> it (makeRelative resources pth) $ do
+        YamlPack{..} <- yamlPack pth
+        prog <- parseProgramThrows program
+        included <- traverse parseExpressionThrows shown
+        excluded <- traverse parseExpressionThrows hidden
+        res <- parseProgramThrows result
+        let [(prog', _)] = F.exclude (F.include [(prog, Nothing)] included) excluded
+            cfg = (SALTY, UNICODE, MULTILINE, defaultMargin)
+        prog' `shouldBe` res
+        when
+          (prog' /= res)
+          ( expectationFailure
+              ( "Expected:\n"
+                  ++ printProgram' res cfg
+                  ++ "\nbut got:\n"
+                  ++ printProgram' prog' cfg
+              )
+          )
+    )
diff --git a/test/PrinterSpec.hs b/test/PrinterSpec.hs
--- a/test/PrinterSpec.hs
+++ b/test/PrinterSpec.hs
@@ -9,10 +9,9 @@
 
 import AST
 import Control.Monad (forM_)
-import Data.Map.Strict qualified as Map
 import Encoding (Encoding (..))
 import Lining (LineFormat (..))
-import Matcher (MetaValue (..), Subst (..), Tail (..), defaultScope)
+import Margin (defaultMargin)
 import Printer
 import Sugar (SugarType (..))
 import Test.Hspec (Spec, describe, it, shouldBe, shouldContain)
@@ -25,65 +24,23 @@
       [ ("ξ renders as $", ExThis, "$")
       , ("Φ renders as Q", ExGlobal, "Q")
       , ("⊥ renders as T", ExTermination, "T")
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders formation with void" $
-    forM_
-      [ ("ρ void becomes empty", ExFormation [BiVoid AtRho], "[[]]")
+      , ("ρ void becomes empty", ExFormation [BiVoid AtRho], "[[]]")
       , ("φ void", ExFormation [BiVoid AtPhi], "[[ @ -> ? ]]")
       , ("label void", ExFormation [BiVoid (AtLabel "名前")], "[[ 名前 -> ? ]]")
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders formation with tau" $
-    forM_
-      [ ("x to Φ", ExFormation [BiTau (AtLabel "x") ExGlobal], "[[ x -> Q ]]")
+      , ("x to Φ", ExFormation [BiTau (AtLabel "x") ExGlobal], "[[ x -> Q ]]")
       , ("α0 to ξ", ExFormation [BiTau (AtAlpha 0) ExThis], "[[ ~0 -> $ ]]")
       , ("ρ to ⊥", ExFormation [BiTau AtRho ExTermination], "[[ ^ -> T ]]")
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders formation with delta" $
-    forM_
-      [ ("empty delta", ExFormation [BiDelta BtEmpty], "[[ D> -- ]]")
+      , ("empty delta", ExFormation [BiDelta BtEmpty], "[[ D> -- ]]")
       , ("single byte", ExFormation [BiDelta (BtOne "1F")], "[[ D> 1F- ]]")
       , ("multiple bytes", ExFormation [BiDelta (BtMany ["00", "01", "02"])], "[[ D> 00-01-02 ]]")
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders formation with lambda" $
-    forM_
-      [ ("función lambda", ExFormation [BiLambda "Función"], "[[ L> Función ]]")
+      , ("función lambda", ExFormation [BiLambda "Función"], "[[ L> Función ]]")
       , ("クラス lambda", ExFormation [BiLambda "クラス"], "[[ L> クラス ]]")
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders dispatch" $
-    forM_
-      [ ("Φ.org", ExDispatch ExGlobal (AtLabel "org"), "Q.org")
+      , ("Φ.org", ExDispatch ExGlobal (AtLabel "org"), "Q.org")
       , ("ξ.ρ as sugar", ExDispatch ExThis AtRho, "^")
       , ("ξ.φ as sugar", ExDispatch ExThis AtPhi, "@")
       , ("chained dispatch", ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "éolang"), "Q.org.éolang")
       , ("ξ.α0 as sugar", ExDispatch ExThis (AtAlpha 0), "~0")
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders application" $
-    forM_
-      [
+      ,
         ( "dispatch with app"
         , ExApplication (ExDispatch ExGlobal (AtLabel "x")) (BiTau (AtLabel "y") ExThis)
         , "Q.x( y -> $ )"
@@ -93,28 +50,14 @@
         , ExApplication (ExFormation [BiVoid AtRho]) (BiTau (AtAlpha 0) ExGlobal)
         , "[[]]( Q )"
         )
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders meta expressions" $
-    forM_
-      [ ("meta expr", ExMeta "e", "!e")
+      , ("meta expr", ExMeta "e", "!e")
       , ("meta tail", ExMetaTail ExGlobal "t", "Q * !t")
-      ]
-      ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
-  describe "printExpression with ASCII singleline renders meta bindings" $
-    forM_
-      [ ("meta binding", ExFormation [BiMeta "B"], "[[ !B ]]")
+      , ("meta binding", ExFormation [BiMeta "B"], "[[ !B ]]")
       , ("meta lambda", ExFormation [BiMetaLambda "F"], "[[ L> !F ]]")
       , ("meta attr tau", ExFormation [BiTau (AtMeta "a") ExThis], "[[ !a -> $ ]]")
       ]
       ( \(desc, expr, expected) ->
-          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
+          it desc (printExpression' expr (SWEET, ASCII, SINGLELINE, defaultMargin) `shouldBe` expected)
       )
 
   describe "printProgram with default config" $
@@ -139,16 +82,6 @@
           it desc (printAttribute attr `shouldBe` expected)
       )
 
-  describe "printAttribute in ASCII dispatch expression with sugar" $
-    forM_
-      [ ("ρ as caret", AtRho, "^")
-      , ("φ as at", AtPhi, "@")
-      , ("αN as tildeN", AtAlpha 42, "~42")
-      ]
-      ( \(desc, attr, expected) ->
-          it desc (printExpression' (ExDispatch ExThis attr) (SWEET, ASCII, SINGLELINE) `shouldBe` expected)
-      )
-
   describe "printBinding renders as formation" $
     forM_
       [ ("tau binding", BiTau (AtLabel "x") ExGlobal, "x ↦ Φ")
@@ -180,65 +113,3 @@
       ( \(desc, arg, expected) ->
           it desc (printExtraArg arg `shouldContain` expected)
       )
-
-  describe "printSubsts renders empty list" $
-    it "returns separator" $
-      printSubsts [] `shouldBe` "------"
-
-  describe "printSubsts renders attribute substitution" $
-    it "contains key and value" $
-      printSubsts [Subst (Map.singleton "α" (MvAttribute (AtLabel "ατρ")))]
-        `shouldContain` "α >> ατρ"
-
-  describe "printSubsts renders multiple substitutions" $
-    it "separates with dashed line" $
-      let substs =
-            [ Subst (Map.singleton "a" (MvAttribute AtRho))
-            , Subst (Map.singleton "b" (MvAttribute AtPhi))
-            ]
-       in printSubsts substs `shouldContain` "------"
-
-  describe "printSubsts renders expression value" $
-    it "contains expression" $
-      printSubsts [Subst (Map.singleton "e" (MvExpression ExGlobal defaultScope))]
-        `shouldContain` "e >> Φ"
-
-  describe "printSubsts renders bindings value" $
-    it "contains bindings header" $
-      printSubsts [Subst (Map.singleton "B" (MvBindings [BiVoid (AtLabel "x")]))]
-        `shouldContain` "B >> ⟦"
-
-  describe "printSubsts renders bytes value" $
-    it "contains bytes" $
-      printSubsts [Subst (Map.singleton "d" (MvBytes (BtMany ["AB", "CD"])))]
-        `shouldContain` "d >> AB-CD"
-
-  describe "printSubsts renders function value" $
-    it "contains function name" $
-      printSubsts [Subst (Map.singleton "F" (MvFunction "MyFunc"))]
-        `shouldContain` "F >> MyFunc"
-
-  describe "printSubsts renders tail value with dispatch" $
-    it "contains dispatch" $
-      printSubsts [Subst (Map.singleton "t" (MvTail [TaDispatch (AtLabel "attr")]))]
-        `shouldContain` "t >> .attr"
-
-  describe "printSubsts renders tail value with application" $
-    it "contains application" $
-      printSubsts [Subst (Map.singleton "t" (MvTail [TaApplication (BiTau (AtLabel "x") ExThis)]))]
-        `shouldContain` "(⟦"
-
-  describe "printExpression with salty config" $
-    it "adds explicit rho binding" $
-      printExpression' (ExFormation [BiVoid (AtLabel "x")]) (SALTY, UNICODE, SINGLELINE)
-        `shouldContain` "ρ ↦ ∅"
-
-  describe "printExpression with multiline format" $
-    it "adds newlines in formation" $
-      let expr = ExFormation [BiTau (AtLabel "x") ExGlobal, BiVoid (AtLabel "y")]
-          result = printExpression' expr (SWEET, UNICODE, MULTILINE)
-       in result `shouldContain` "\n"
-
-  describe "logPrintConfig" $
-    it "is sweet unicode singleline" $
-      logPrintConfig `shouldBe` (SWEET, UNICODE, SINGLELINE)
diff --git a/test/XMIRSpec.hs b/test/XMIRSpec.hs
--- a/test/XMIRSpec.hs
+++ b/test/XMIRSpec.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE OverloadedStrings #-}
 
 -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
 -- SPDX-License-Identifier: MIT
@@ -8,23 +9,20 @@
 module XMIRSpec where
 
 import AST
-import Control.Exception (bracket)
-import Control.Monad (filterM, forM_, unless)
+import Control.Monad (forM_, unless)
 import Data.Aeson
+import Data.Char (isDigit)
 import Data.List (intercalate)
+import Data.Text qualified as T
 import Data.Yaml qualified as Yaml
 import GHC.Generics (Generic)
-import GHC.IO (unsafePerformIO)
 import Misc (allPathsIn)
 import Parser (parseExpressionThrows, parseProgramThrows)
-import System.Directory (removeFile)
-import System.Exit (ExitCode (ExitSuccess))
 import System.FilePath (makeRelative)
-import System.IO (hClose, hPutStr, openTempFile)
-import System.Info (os)
-import System.Process (readProcessWithExitCode)
-import Test.Hspec (Spec, anyException, describe, expectationFailure, it, pendingWith, runIO, shouldBe, shouldThrow)
-import XMIR (defaultXmirContext, parseXMIRThrows, printXMIR, programToXMIR, xmirToPhi)
+import Test.Hspec (Spec, anyException, describe, expectationFailure, it, runIO, shouldBe, shouldThrow)
+import Text.XML (Document (..), Element (..))
+import Text.XML.Cursor qualified as C
+import XMIR (defaultXmirContext, parseXMIRThrows, printXMIR, programToXMIR, toName, xmirToPhi)
 
 data ParsePack = ParsePack
   { failure :: Maybe Bool
@@ -45,16 +43,148 @@
 printPack :: FilePath -> IO PrintPack
 printPack = Yaml.decodeFileThrow
 
--- Check if xmllint is available on the system
-isXmllintAvailable :: Bool
-isXmllintAvailable =
-  let (exitCode, _, _) = unsafePerformIO (readProcessWithExitCode "xmllint" ["--version"] "")
-   in (exitCode == ExitSuccess)
+-- | An XPath predicate that filters cursors.
+data Predicate
+  = AttrEquals String String
+  | ChildText String String
+  | ChildExists String [Predicate]
+  | PositionIs Int
+  | AndPred Predicate Predicate
+  deriving (Show)
 
--- Check if running on Windows
-isWindows :: Bool
-isWindows = os == "mingw32"
+-- | An XPath step with element name and predicates.
+data Step = Step String [Predicate]
+  deriving (Show)
 
+{- | Parse a simple XPath expression into steps.
+Supports: /element/element[@attr="val" and child="val" and child[N][@attr="val"]]
+-}
+xpath :: String -> [Step]
+xpath ('/' : rest) = steps rest
+xpath _ = []
+
+steps :: String -> [Step]
+steps "" = []
+steps str =
+  let (step, rest) = span (\c -> c /= '/' && c /= '[') str
+      (preds, remaining) = parsePredicate rest
+   in Step step preds : steps (dropWhile (== '/') remaining)
+
+parsePredicate :: String -> ([Predicate], String)
+parsePredicate ('[' : rest) =
+  let (inner, after) = splitBracket rest
+      pred' = parsePredicateInner inner
+      (more, final) = parsePredicate after
+   in (pred' : more, final)
+parsePredicate str = ([], str)
+
+splitBracket :: String -> (String, String)
+splitBracket = go (0 :: Int) ""
+  where
+    go :: Int -> String -> String -> (String, String)
+    go _ acc "" = (reverse acc, "")
+    go 0 acc (']' : rest) = (reverse acc, rest)
+    go n acc ('[' : rest) = go (n + 1) ('[' : acc) rest
+    go n acc (']' : rest) = go (n - 1) (']' : acc) rest
+    go n acc (c : rest) = go n (c : acc) rest
+
+parsePredicateInner :: String -> Predicate
+parsePredicateInner str
+  | " and " `isInfixOf'` str =
+      let parts = splitAnd str
+       in foldr1 AndPred (map parsePredicateInner parts)
+  | all isDigit str = PositionIs (read str)
+  | '@' : rest <- str = parseAttrPred rest
+  | otherwise = parseChildPred str
+  where
+    isInfixOf' needle haystack = needle `elem` tails haystack
+    tails [] = [[]]
+    tails s@(_ : xs) = s : tails xs
+
+splitAnd :: String -> [String]
+splitAnd = go (0 :: Int) ""
+  where
+    go :: Int -> String -> String -> [String]
+    go _ acc "" = [reverse acc | not (null acc)]
+    go n acc ('[' : rest) = go (n + 1) ('[' : acc) rest
+    go n acc (']' : rest) = go (n - 1) (']' : acc) rest
+    go 0 acc (' ' : 'a' : 'n' : 'd' : ' ' : rest) = reverse acc : go 0 "" rest
+    go n acc (c : rest) = go n (c : acc) rest
+
+parseAttrPred :: String -> Predicate
+parseAttrPred str =
+  let (name, rest) = break (== '=') str
+      val = extractQuoted (drop 1 rest)
+   in AttrEquals name val
+
+parseChildPred :: String -> Predicate
+parseChildPred str
+  | '[' `elem` str =
+      let (name, rest) = break (== '[') str
+          (preds, _) = parsePredicate rest
+       in ChildExists name preds
+  | '=' `elem` str =
+      let (name, rest) = break (== '=') str
+          val = extractQuoted (drop 1 rest)
+       in ChildText name val
+  | otherwise = ChildExists str []
+
+extractQuoted :: String -> String
+extractQuoted (q : rest)
+  | q == '"' || q == '\'' = takeWhile (/= q) rest
+extractQuoted s = s
+
+{- | Evaluate an XPath expression on a document, returning matched cursors.
+Note: fromDocument returns cursor at root element, so first step must match root.
+-}
+evaluate :: Document -> [Step] -> [C.Cursor]
+evaluate doc [] = [C.fromDocument doc]
+evaluate doc (Step name preds : rest) =
+  let root = C.fromDocument doc
+      rootName = elementName (documentRoot doc)
+   in if rootName == toName name
+        then foldl applyStep (applyPredicates [root] preds) rest
+        else []
+
+applyStep :: [C.Cursor] -> Step -> [C.Cursor]
+applyStep curs (Step name preds) = do
+  cur <- curs
+  child <- cur C.$/ C.element (toName name)
+  applyPredicates [child] preds
+
+applyPredicates :: [C.Cursor] -> [Predicate] -> [C.Cursor]
+applyPredicates = foldl applyPredicate
+
+applyPredicate :: [C.Cursor] -> Predicate -> [C.Cursor]
+applyPredicate curs pred' = case pred' of
+  AttrEquals name val -> filter (hasAttrValue name val) curs
+  ChildText name val -> filter (hasChildText name val) curs
+  ChildExists name nested -> filter (hasChild name nested) curs
+  PositionIs n -> take 1 (drop (n - 1) curs)
+  AndPred p1 p2 -> applyPredicate (applyPredicate curs p1) p2
+
+hasAttrValue :: String -> String -> C.Cursor -> Bool
+hasAttrValue name val cur = C.attribute (toName name) cur == [T.pack val]
+
+hasChildText :: String -> String -> C.Cursor -> Bool
+hasChildText name val cur =
+  let children = cur C.$/ C.element (toName name)
+   in any (hasTextContent val) children
+
+hasTextContent :: String -> C.Cursor -> Bool
+hasTextContent val cur =
+  let txt = concatMap T.unpack (cur C.$/ C.content)
+   in txt == val
+
+hasChild :: String -> [Predicate] -> C.Cursor -> Bool
+hasChild name nested cur =
+  let children = cur C.$/ C.element (toName name)
+   in not (null (applyPredicates children nested))
+
+-- | Check if an XPath expression matches anything in the document.
+matches :: Document -> String -> Bool
+matches doc path = not (null (evaluate doc (xpath path)))
+
 spec :: Spec
 spec = do
   describe "XMIR parsing packs" $ do
@@ -94,38 +224,17 @@
 
   describe "XMIR printing packs" $ do
     let resources = "test-resources/xmir-printing-packs"
-        available = isXmllintAvailable
     packs <- runIO (allPathsIn resources)
     forM_
       packs
       ( \pth ->
-          it (makeRelative resources pth) $
-            if isWindows
-              then pendingWith "Skipped on Windows due to xmllint Unicode issues"
-              else
-                if not available
-                  then pendingWith "The 'xmllint' is not available"
-                  else do
-                    pack <- printPack pth
-                    let PrintPack{phi = phi', xpaths = xpaths'} = pack
-                    prog <- parseProgramThrows phi'
-                    xmir' <- programToXMIR prog defaultXmirContext
-                    let xml = printXMIR xmir'
-                    bracket
-                      (openTempFile "." "xmirXXXXXX.tmp")
-                      (\(fp, _) -> removeFile fp)
-                      ( \(path, hTmp) -> do
-                          hPutStr hTmp xml
-                          hClose hTmp
-                          failed <-
-                            filterM
-                              ( \xpath -> do
-                                  (code, _, _) <- readProcessWithExitCode "xmllint" ["--xpath", xpath, path] ""
-                                  pure (code /= ExitSuccess)
-                              )
-                              xpaths'
-                          unless
-                            (null failed)
-                            (expectationFailure ("Failed xpaths:\n - " ++ intercalate "\n - " failed ++ "\nXMIR is:\n" ++ xml))
-                      )
+          it (makeRelative resources pth) $ do
+            pack <- printPack pth
+            let PrintPack{phi = phi', xpaths = xpaths'} = pack
+            prog <- parseProgramThrows phi'
+            xmir' <- programToXMIR prog defaultXmirContext
+            let failed = filter (not . matches xmir') xpaths'
+            unless
+              (null failed)
+              (expectationFailure ("Failed xpaths:\n - " ++ intercalate "\n - " failed ++ "\nXMIR is:\n" ++ printXMIR xmir'))
       )
