diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,16 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [0.6.0] - 2018-12-19
+
+### Added
+
+- Support for local dependencies (`resolved` field starts with `file:`)
+
+### Fixed
+
+- Semigroup is superclass of Monoid
+
 ## [0.5.0] - 2018-06-12
 
 ### Changed
diff --git a/src/Yarn/Lock.hs b/src/Yarn/Lock.hs
--- a/src/Yarn/Lock.hs
+++ b/src/Yarn/Lock.hs
@@ -81,7 +81,7 @@
 
 -- helpers
 astParse :: FilePath -> Text -> Either LockfileError [Parse.Package]
-astParse fp = first (ParseError . toS . MP.parseErrorPretty)
+astParse fp = first (ParseError . toS . MP.errorBundlePretty)
                 . MP.parse Parse.packageList fp
 
 toPackages :: [Parse.Package] -> Either LockfileError [T.Keyed T.Package]
diff --git a/src/Yarn/Lock/File.hs b/src/Yarn/Lock/File.hs
--- a/src/Yarn/Lock/File.hs
+++ b/src/Yarn/Lock/File.hs
@@ -120,7 +120,7 @@
         -- implementing the heuristics of searching for types;
         -- it should of course not lead to false positives
         -- see tests/TestLock.hs
-        $ checkGit <|> checkFile
+        $ checkGit <|> checkFileLocal <|> checkFile
       where
         mToV :: e -> Maybe a -> V.Validation e a
         mToV err = V.eitherToValidation . note err
@@ -137,6 +137,7 @@
           [url', hash] -> (url', Just hash)
           _           -> panic "checkRemote: # should only appear exactly once!"
 
+        checkGit :: Maybe T.Remote
         checkGit = do
           resolved <- vToM $ getField text "resolved" fs
           -- either in uid field or after the hash in the “resolved” URL
@@ -149,12 +150,24 @@
           pure $ T.GitRemote
             { T.gitRepoUrl = noPrefix "git+" repo , .. }
 
-        -- | ensure the prefix is removed
-        noPrefix :: Text -> Text -> Text
-        noPrefix pref hay = maybe hay identity $ Text.stripPrefix pref hay
+        -- | resolved fields that are prefixed with @"file:"@
+        checkFileLocal :: Maybe T.Remote
+        checkFileLocal = do
+          resolved <- vToM $ getField text "resolved" fs
+          let (file, mayHash) = findUrlHash resolved
+          fileLocalSha1 <- mayHash
+          fileLocalPath <- if "file:" `Text.isPrefixOf` file
+                           then Just $ noPrefix "file:" file
+                           else Nothing
+          pure $ T.FileLocal{..}
 
+        checkFile :: Maybe T.Remote
         checkFile = do
           resolved <- vToM (getField text "resolved" fs)
           let (fileUrl, mayFileSha1) = findUrlHash resolved
           fileSha1 <- mayFileSha1
           pure $ T.FileRemote{..}
+
+        -- | ensure the prefix is removed
+        noPrefix :: Text -> Text -> Text
+        noPrefix pref hay = maybe hay identity $ Text.stripPrefix pref hay
diff --git a/src/Yarn/Lock/Parse.hs b/src/Yarn/Lock/Parse.hs
--- a/src/Yarn/Lock/Parse.hs
+++ b/src/Yarn/Lock/Parse.hs
@@ -47,7 +47,7 @@
 --
 -- The actual conversion to semantic structures needs to be done afterwards.
 newtype PackageFields = PackageFields (Map Text (Either Text PackageFields))
-  deriving (Show, Eq, Monoid)
+  deriving (Show, Eq, Semigroup, Monoid)
 
 -- | A parsed 'Package' AST has one or more keys, a position in the original files
 -- and a collection of fields.
@@ -80,7 +80,7 @@
 -- @
 packageEntry :: Parser (YLT.Keyed (SourcePos, PackageFields))
 packageEntry = label "package entry" $ do
-  pos <- getPosition
+  pos <- getSourcePos
   -- A package entry is a non-indented
   (keys, pkgs) <- nonIndented
             -- block that has a header of package keys
diff --git a/src/Yarn/Lock/Types.hs b/src/Yarn/Lock/Types.hs
--- a/src/Yarn/Lock/Types.hs
+++ b/src/Yarn/Lock/Types.hs
@@ -72,4 +72,9 @@
   | GitRemote
   { gitRepoUrl  :: Text -- ^ valid git remote URL
   , gitRev      :: Text -- ^ git tree-ish (commit, branch, &c.)
+  }
+  -- this is a bit of an oddidity, but what isn’t
+  | FileLocal
+  { fileLocalPath :: Text -- ^ (relative) path to file on the local machine
+  , fileLocalSha1 :: Text -- ^ sha1 hash of the file (attached to the link)
   } deriving (Eq, Show)
diff --git a/tests/TestFile.hs b/tests/TestFile.hs
--- a/tests/TestFile.hs
+++ b/tests/TestFile.hs
@@ -58,6 +58,22 @@
       a -> assertFailure ("should be FileRemote, is " <> show a)
   astToPackageFailureWith (pure File.UnknownRemoteType) bad
 
+case_fileLocal :: Assertion
+case_fileLocal = do
+  let good = minimalAst $
+        [ ("resolved"
+          , Left $ "file:../extensions/jupyterlab-toc-0.6.0.tgz#393fe") ]
+      bad = minimalAst $
+        [ ("resolved"
+          , Left $ "\"file:some/file/nohash\"") ]
+  astToPackageSuccess good
+    <&> T.remote >>= \case
+      T.FileLocal{..} -> do
+        assertEqual "file path" "../extensions/jupyterlab-toc-0.6.0.tgz" fileLocalPath
+        assertEqual "file sha" "393fe" fileLocalSha1
+      a -> assertFailure ("should be FileLocal, is " <> show a)
+  astToPackageFailureWith (pure File.UnknownRemoteType) bad
+
 case_missingField :: Assertion
 case_missingField = do
   astToPackageFailureWith
diff --git a/tests/TestParse.hs b/tests/TestParse.hs
--- a/tests/TestParse.hs
+++ b/tests/TestParse.hs
@@ -29,16 +29,6 @@
       assertBool "only foo"
         (keys == pure (PackageKey (SimplePackageKey "dummy-package") "foo"))
 
--- registryPackage :: Text
--- registryPackage = [text|
---   accepts@1.3.3, accepts@~1.3.3:
---     version "1.3.3"
---     resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
---     dependencies:
---       mime-types "~2.1.11"
---       negotiator "0.6.1"
---   |]
-
 nonsenseEntry :: Text
 nonsenseEntry = [text|
   foobar@~1.2.3, xyz@hehe:
@@ -152,7 +142,7 @@
     (Right a) -> pure a
     (Left err) -> do
       _ <- assertFailure ("parse should succeed, but: \n"
-                    <> MP.parseErrorPretty err
+                    <> MP.errorBundlePretty err
                     <> "for input\n" <> toS string <> "\n\"")
       panic "not reached"
 
diff --git a/yarn-lock.cabal b/yarn-lock.cabal
--- a/yarn-lock.cabal
+++ b/yarn-lock.cabal
@@ -1,11 +1,13 @@
--- This file has been generated from package.yaml by hpack version 0.27.0.
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.31.2.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 9195f2d20c7a3cd78e9ef32e7e18b231b383f572887111142cd2df1d76891703
+-- hash: d82313ce33d9f08b44f33c038434abea15c408bbc42e3798603a87412d1cb0ed
 
 name:           yarn-lock
-version:        0.5.0
+version:        0.6.1
 synopsis:       Represent and parse yarn.lock files
 description:    Types and parser for the lock file format of the npm successor yarn. All modules should be imported qualified.
 category:       Data
@@ -16,8 +18,6 @@
 license:        MIT
 license-file:   LICENSE
 build-type:     Simple
-cabal-version:  >= 1.10
-
 extra-source-files:
     CHANGELOG.md
 
@@ -42,7 +42,7 @@
       base ==4.*
     , containers
     , either >=4 && <6
-    , megaparsec ==6.*
+    , megaparsec ==7.*
     , protolude ==0.2.*
     , text
   default-language: Haskell2010
@@ -63,7 +63,7 @@
     , base ==4.*
     , containers
     , either >=4 && <6
-    , megaparsec ==6.*
+    , megaparsec ==7.*
     , neat-interpolation >=0.3
     , protolude
     , quickcheck-instances ==0.3.*
