diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+0.12.1
+	* Fix bug in "stripDir" and "isParentOf"
+	* add total basename' variant for relative dirs
+	* Improve documentation
 0.12.0
 	* Type-safe quasi-quoters wrt [MR #39](https://github.com/hasufell/hpath/pull/39)
 	* Allow "." as relative dir wrt #36
diff --git a/hpath.cabal b/hpath.cabal
--- a/hpath.cabal
+++ b/hpath.cabal
@@ -1,5 +1,5 @@
 name:                hpath
-version:             0.12.0
+version:             0.12.1
 synopsis:            Support for well-typed paths
 description:         Support for well-typed paths, utilizing ByteString under the hood.
 license:             BSD3
diff --git a/src/HPath.hs b/src/HPath.hs
--- a/src/HPath.hs
+++ b/src/HPath.hs
@@ -23,8 +23,8 @@
 module HPath
   (
   -- * Types
-   Abs
-  ,Path
+   Path
+  ,Abs
   ,Rel
   ,PathParseException
   ,PathException
@@ -46,6 +46,7 @@
   -- * Path Operations
   ,(</>)
   ,basename
+  ,basename'
   ,dirname
   ,getAllParents
   ,getAllComponents
@@ -64,7 +65,6 @@
   )
   where
 
-import           Control.Applicative ((<|>))
 import           Control.Exception (Exception)
 import           Control.Monad.Catch (MonadThrow(..))
 #if MIN_VERSION_bytestring(0,10,8)
@@ -128,20 +128,20 @@
 --
 -- Throws: 'PathParseException'
 --
--- >>> parseAbs "/abc"          :: Maybe (Path Abs)
--- Just "/abc"
--- >>> parseAbs "/"             :: Maybe (Path Abs)
--- Just "/"
--- >>> parseAbs "/abc/def"      :: Maybe (Path Abs)
--- Just "/abc/def"
--- >>> parseAbs "/abc/def/.///" :: Maybe (Path Abs)
--- Just "/abc/def"
--- >>> parseAbs "abc"           :: Maybe (Path Abs)
--- Nothing
--- >>> parseAbs ""              :: Maybe (Path Abs)
--- Nothing
--- >>> parseAbs "/abc/../foo"   :: Maybe (Path Abs)
--- Nothing
+-- >>> parseAbs "/abc"
+-- "/abc"
+-- >>> parseAbs "/"
+-- "/"
+-- >>> parseAbs "/abc/def"
+-- "/abc/def"
+-- >>> parseAbs "/abc/def/.///"
+-- "/abc/def"
+-- >>> parseAbs "abc"
+-- *** Exception: InvalidAbs "abc"
+-- >>> parseAbs ""
+-- *** Exception: InvalidAbs ""
+-- >>> parseAbs "/abc/../foo"
+-- *** Exception: InvalidAbs "/abc/../foo"
 parseAbs :: MonadThrow m
          => ByteString -> m (Path Abs)
 parseAbs filepath =
@@ -155,33 +155,33 @@
 -- | Get a location for a relative path. Produces a normalised
 -- path.
 --
--- Note that @filepath@ may contain any number of @./@.
--- It also may not contain a single @..@ anywhere.
+-- Note that @filepath@ may contain any number of @./@,
+-- but not a single @..@ anywhere.
 --
 -- Throws: 'PathParseException'
 --
--- >>> parseRel "abc"        :: Maybe (Path Rel)
--- Just "abc"
--- >>> parseRel "def/"       :: Maybe (Path Rel)
--- Just "def"
--- >>> parseRel "abc/def"    :: Maybe (Path Rel)
--- Just "abc/def"
--- >>> parseRel "abc/def/."  :: Maybe (Path Rel)
--- Just "abc/def"
--- >>> parseRel "/abc"       :: Maybe (Path Rel)
--- Nothing
--- >>> parseRel ""           :: Maybe (Path Rel)
--- Nothing
--- >>> parseRel "abc/../foo" :: Maybe (Path Rel)
--- Nothing
--- >>> parseRel "."          :: Maybe (Path Rel)
--- Just "."
--- >>> parseRel "././././."  :: Maybe (Path Rel)
--- Just "."
--- >>> parseRel "./..."      :: Maybe (Path Rel)
--- Just "..."
--- >>> parseRel ".."         :: Maybe (Path Rel)
--- Nothing
+-- >>> parseRel "abc"
+-- "abc"
+-- >>> parseRel "def/"
+-- "def"
+-- >>> parseRel "abc/def"
+-- "abc/def"
+-- >>> parseRel "abc/def/."
+-- "abc/def"
+-- >>> parseRel "/abc"
+-- *** Exception: InvalidRel "/abc"
+-- >>> parseRel ""
+-- *** Exception: InvalidRel ""
+-- >>> parseRel "abc/../foo"
+-- *** Exception: InvalidRel "abc/../foo"
+-- >>> parseRel "."
+-- "."
+-- >>> parseRel "././././."
+-- "."
+-- >>> parseRel "./..."
+-- "..."
+-- >>> parseRel ".."
+-- *** Exception: InvalidRel ".."
 parseRel :: MonadThrow m
          => ByteString -> m (Path Rel)
 parseRel filepath =
@@ -196,28 +196,26 @@
 
 -- | Parses a path, whether it's relative or absolute.
 --
--- Excludes '.' and '..'.
---
 -- Throws: 'PathParseException'
 --
--- >>> parseAny "/abc"       :: Maybe (Either (Path Abs) (Path Rel))
--- Just (Left "/abc")
--- >>> parseAny "..."        :: Maybe (Either (Path Abs) (Path Rel))
--- Just (Right "...")
--- >>> parseAny "abc/def"    :: Maybe (Either (Path Abs) (Path Rel))
--- Just (Right "abc/def")
--- >>> parseAny "abc/def/."  :: Maybe (Either (Path Abs) (Path Rel))
--- Just (Right "abc/def")
--- >>> parseAny "/abc"       :: Maybe (Either (Path Abs) (Path Rel))
--- Just (Left "/abc")
--- >>> parseAny ""           :: Maybe (Either (Path Abs) (Path Rel))
--- Nothing
--- >>> parseAny "abc/../foo" :: Maybe (Either (Path Abs) (Path Rel))
--- Nothing
--- >>> parseAny "."          :: Maybe (Either (Path Abs) (Path Rel))
--- Just (Right ".")
--- >>> parseAny ".."         :: Maybe (Either (Path Abs) (Path Rel))
--- Nothing
+-- >>> parseAny "/abc"
+-- Left "/abc"
+-- >>> parseAny "..."
+-- Right "..."
+-- >>> parseAny "abc/def"
+-- Right "abc/def"
+-- >>> parseAny "abc/def/."
+-- Right "abc/def"
+-- >>> parseAny "/abc"
+-- Left "/abc"
+-- >>> parseAny ""
+-- *** Exception: InvalidRel ""
+-- >>> parseAny "abc/../foo"
+-- *** Exception: InvalidRel "abc/../foo"
+-- >>> parseAny "."
+-- Right "."
+-- >>> parseAny ".."
+-- *** Exception: InvalidRel ".."
 parseAny :: MonadThrow m => ByteString -> m (Either (Path Abs) (Path Rel))
 parseAny filepath = case parseAbs filepath of
   Just p -> pure $ Left p
@@ -226,9 +224,11 @@
     Nothing       -> throwM (InvalidRel filepath)
 
 
+-- | The @"/"@ root path.
 rootPath :: Path Abs
 rootPath = (MkPath (BS.singleton _slash))
 
+-- | The @"."@ pwd path.
 pwdPath :: Path Rel
 pwdPath = (MkPath (BS.singleton _period))
 
@@ -264,17 +264,15 @@
 -- because this library is IO-agnostic and makes no assumptions about
 -- file types.
 --
--- >>> (MkPath "/")        </> (MkPath "file"     :: Path Rel)
+-- >>> [abs|/|] </> [rel|file|]
 -- "/file"
--- >>> (MkPath "/path/to") </> (MkPath "file"     :: Path Rel)
+-- >>> [abs|/path/to|] </> [rel|file|]
 -- "/path/to/file"
--- >>> (MkPath "/")        </> (MkPath "file/lal" :: Path Rel)
+-- >>> [abs|/|] </> [rel|file/lal|]
 -- "/file/lal"
--- >>> (MkPath "/")        </> (MkPath "file/"    :: Path Rel)
--- "/file"
--- >>> (MkPath "/")        </> (MkPath "."        :: Path Rel)
+-- >>> [abs|/|] </> [rel|.|]
 -- "/"
--- >>> (MkPath ".")        </> (MkPath "."        :: Path Rel)
+-- >>> [rel|.|] </> [rel|.|]
 -- "."
 (</>) :: Path b -> Path Rel -> Path b
 (</>) (MkPath a) (MkPath b) =
@@ -286,37 +284,37 @@
 --
 -- The bases must match.
 --
--- >>> (MkPath "/lal/lad")     `stripDir` (MkPath "/lal/lad/fad") :: Maybe (Path Rel)
--- Just "fad"
--- >>> (MkPath "lal/lad")      `stripDir` (MkPath "lal/lad/fad")  :: Maybe (Path Rel)
--- Just "fad"
--- >>> (MkPath "/")            `stripDir` (MkPath "/")            :: Maybe (Path Rel)
--- Just "."
--- >>> (MkPath "/lal/lad/fad") `stripDir` (MkPath "/lal/lad")     :: Maybe (Path Rel)
--- Nothing
--- >>> (MkPath "/abs")         `stripDir` (MkPath "/lal/lad")     :: Maybe (Path Rel)
--- Nothing
--- >>> (MkPath "fad")          `stripDir` (MkPath "fad")          :: Maybe (Path Rel)
--- Just "."
-stripDir :: MonadThrow m
-         => Path b -> Path b -> m (Path Rel)
-stripDir (MkPath p) (MkPath l) =
-  case stripPrefix p' l <|> stripPrefix p l of
-    Nothing -> throwM (Couldn'tStripPrefixTPS p' l)
-    Just ok -> if BS.null ok
-                 then return (MkPath $ BS.singleton _period)
-                 else return (MkPath ok)
-  where
-    p' = addTrailingPathSeparator p
+-- >>> [abs|/lal/lad|]     `stripDir` [abs|/lal/lad/fad|]
+-- "fad"
+-- >>> [rel|lal/lad|]      `stripDir` [rel|lal/lad/fad|]
+-- "fad"
+-- >>> [abs|/|]            `stripDir` [abs|/|]
+-- "."
+-- >>> [abs|/lal/lad/fad|] `stripDir` [abs|/lal/lad|]
+-- *** Exception: Couldn'tStripPrefixTPS "/lal/lad/fad" "/lal/lad"
+-- >>> [abs|/abs|]         `stripDir` [abs|/lal/lad|]
+-- *** Exception: Couldn'tStripPrefixTPS "/abs" "/lal/lad"
+-- >>> [rel|fad|]          `stripDir` [rel|fad|]
+-- "."
+-- >>> [rel|.|]            `stripDir` [rel|.|]
+-- "."
+-- >>> [rel|.|]            `stripDir` [rel|.foo|]
+-- *** Exception: Couldn'tStripPrefixTPS "." ".foo"
+stripDir :: MonadThrow m => Path b -> Path b -> m (Path Rel)
+stripDir (MkPath p) (MkPath l)
+  | p == l = return pwdPath
+  | otherwise = case stripPrefix (addTrailingPathSeparator p) l of
+    Nothing -> throwM (Couldn'tStripPrefixTPS p l)
+    Just ok -> return (MkPath ok)
 
 
 -- |Get all parents of a path.
 --
--- >>> getAllParents (MkPath "/abs/def/dod")
+-- >>> getAllParents [abs|/abs/def/dod|]
 -- ["/abs/def","/abs","/"]
--- >>> getAllParents (MkPath "/foo")
+-- >>> getAllParents [abs|/foo|]
 -- ["/"]
--- >>> getAllParents (MkPath "/")
+-- >>> getAllParents [abs|/|]
 -- []
 getAllParents :: Path Abs -> [Path Abs]
 getAllParents (MkPath p)
@@ -328,19 +326,21 @@
 
 -- | Gets all path components.
 --
--- >>> getAllComponents (MkPath "abs/def/dod")
+-- >>> getAllComponents [rel|abs/def/dod|]
 -- ["abs","def","dod"]
--- >>> getAllComponents (MkPath "abs")
+-- >>> getAllComponents [rel|abs|]
 -- ["abs"]
+-- >>> getAllComponents [rel|.|]
+-- ["."]
 getAllComponents :: Path Rel -> [Path Rel]
 getAllComponents (MkPath p) = fmap MkPath . splitDirectories $ p
 
 
 -- | Gets all path components after the "/" root directory.
 --
--- >>> getAllComponentsAfterRoot (MkPath "/abs/def/dod")
+-- >>> getAllComponentsAfterRoot [abs|/abs/def/dod|]
 -- ["abs","def","dod"]
--- >>> getAllComponentsAfterRoot (MkPath "/abs")
+-- >>> getAllComponentsAfterRoot [abs|/abs|]
 -- ["abs"]
 getAllComponentsAfterRoot :: Path Abs -> [Path Rel]
 getAllComponentsAfterRoot p = getAllComponents (fromJust $ stripDir rootPath p)
@@ -348,9 +348,9 @@
 
 -- | Extract the directory name of a path.
 --
--- >>> dirname (MkPath "/abc/def/dod")
+-- >>> dirname [abs|/abc/def/dod|]
 -- "/abc/def"
--- >>> dirname (MkPath "/")
+-- >>> dirname [abs|/|]
 -- "/"
 dirname :: Path Abs -> Path Abs
 dirname (MkPath fp) = MkPath (takeDirectory fp)
@@ -364,16 +364,16 @@
 --
 -- Throws: `PathException` if given the root path "/"
 --
--- >>> basename (MkPath "/abc/def/dod") :: Maybe (Path Rel)
--- Just "dod"
--- >>> basename (MkPath "abc/def/dod")  :: Maybe (Path Rel)
--- Just "dod"
--- >>> basename (MkPath "dod")          :: Maybe (Path Rel)
--- Just "dod"
--- >>> basename (MkPath ".")            :: Maybe (Path Rel)
--- Just "."
--- >>> basename (MkPath "/")            :: Maybe (Path Rel)
--- Nothing
+-- >>> basename [abs|/abc/def/dod|]
+-- "dod"
+-- >>> basename [rel|abc/def/dod|]
+-- "dod"
+-- >>> basename [rel|dod|]
+-- "dod"
+-- >>> basename [rel|.|]
+-- "."
+-- >>> basename [abs|/|]
+-- *** Exception: RootDirHasNoBasename
 basename :: MonadThrow m => Path b -> m (Path Rel)
 basename (MkPath l)
   | not (isAbsolute rl) = return $ MkPath rl
@@ -381,6 +381,20 @@
   where
     rl = last . splitPath $ l
 
+-- | Extract the file part of a relative path.
+--
+-- The following properties hold:
+--
+-- @basename' (p \<\/> a) == basename' a@
+--
+-- >>> basename' [rel|abc/def/dod|]
+-- "dod"
+-- >>> basename' [rel|dod|]
+-- "dod"
+-- >>> basename' [rel|.|]
+-- "."
+basename' :: Path Rel -> Path Rel
+basename' (MkPath l) = MkPath . last . splitPath $ l
 
 
 --------------------------------------------------------------------------------
@@ -389,16 +403,18 @@
 -- | Is p a parent of the given location? Implemented in terms of
 -- 'stripDir'. The bases must match.
 --
--- >>> (MkPath "/lal/lad")     `isParentOf` (MkPath "/lal/lad/fad")
+-- >>> [abs|/lal/lad|]     `isParentOf` [abs|/lal/lad/fad|]
 -- True
--- >>> (MkPath "lal/lad")      `isParentOf` (MkPath "lal/lad/fad")
+-- >>> [rel|lal/lad|]      `isParentOf` [rel|lal/lad/fad|]
 -- True
--- >>> (MkPath "/")            `isParentOf` (MkPath "/")
+-- >>> [abs|/|]            `isParentOf` [abs|/|]
 -- False
--- >>> (MkPath "/lal/lad/fad") `isParentOf` (MkPath "/lal/lad")
+-- >>> [abs|/lal/lad/fad|] `isParentOf` [abs|/lal/lad|]
 -- False
--- >>> (MkPath "fad")          `isParentOf` (MkPath "fad")
+-- >>> [rel|fad|]          `isParentOf` [rel|fad|]
 -- False
+-- >>> [rel|.|]            `isParentOf` [rel|.foo|]
+-- False
 isParentOf :: Path b -> Path b -> Bool
 isParentOf p l = case stripDir p l :: Maybe (Path Rel) of
   Nothing -> False
@@ -409,18 +425,18 @@
 
 -- | Check whether the given Path is the root "/" path.
 --
--- >>> isRootPath (MkPath "/lal/lad")
+-- >>> isRootPath [abs|/lal/lad|]
 -- False
--- >>> isRootPath (MkPath "/")
+-- >>> isRootPath [abs|/|]
 -- True
 isRootPath :: Path Abs -> Bool
 isRootPath = (== rootPath)
 
 -- | Check whether the given Path is the pwd "." path.
 --
--- >>> isPwdPath (MkPath "/lal/lad")
+-- >>> isPwdPath [rel|lal/lad|]
 -- False
--- >>> isPwdPath (MkPath ".")
+-- >>> isPwdPath [rel|.|]
 -- True
 isPwdPath :: Path Rel -> Bool
 isPwdPath = (== pwdPath)
diff --git a/src/HPath/Internal.hs b/src/HPath/Internal.hs
--- a/src/HPath/Internal.hs
+++ b/src/HPath/Internal.hs
@@ -14,15 +14,23 @@
 --
 -- The type variable 'b' is either:
 --
---   * Abs -- absolute path
---   * Rel -- relative path
+--   * 'HPath.Abs' -- absolute path (starting with a @"/"@)
+--   * 'HPath.Rel' -- relative path (not starting with a @"/"@)
 --
--- Internally is a ByteString. The path is guaranteed to
+-- Internally it is a ByteString. The path is guaranteed to
 -- be normalised and contain no trailing Path separators,
--- except for the '/' root path.
+-- except for the @"/"@ root path.
 --
 -- There are no duplicate path separators
--- @\/\/@, no @..@, no @.\/@, no @~\/@, etc.
+-- @"\/\/"@, no @".."@, no @".\/"@, etc.
+-- 
+-- Two special paths exist:
+--
+--  * @"/"@ -- the 'HPath.rootPath' (absolute)
+--  * @"."@ -- the 'HPath.pwdPath' (relative)
+--
+-- The constructor is not exposed. Instead, use the smart constructors
+-- 'HPath.parseAbs', 'HPath.parseRel' and 'HPath.parseAny'.
 data Path b = MkPath ByteString
   deriving (Typeable)
 
