diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,10 @@
 Changelog for Weeder
 
+0.1.3
+    #5, document how to install weeder
+    #8, detect unused imports, even import Foo()
+    #7, don't say modules with only instances are always redundant
+    #6, don't give partial pattern matches when reading .weeder.yaml
 0.1.2
     #3, deal with space-separated hs-source-dirs
 0.1.1
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -8,8 +8,12 @@
 
 ## Running Weeder
 
-To use `weeder` your code must have been built with [`stack`](https://www.haskellstack.org), as it piggy-backs off files that `stack` generates. If you don't normally build with `stack` a simple `stack init && weeder . --build` is likely to be sufficient to get you started.
+Weeder piggy-backs off files generated by [`stack`](https://www.haskellstack.org), so first obtain stack, then:
 
+* Install `weeder` by running `stack install weeder --resolver=nightly`.
+* Ensure your project has a `stack.yaml` file. If you don't normally build with `stack` then run `stack init` to generate one.
+* Run `weeder . --build`, which builds your project with `stack` and checks it for weeds.
+
 ## What does Weeder detect?
 
 Weeder detects a bunch of weeds, including:
@@ -28,7 +32,7 @@
 
 If you want your package to be detected as "weed free", but it has some weeds you know about but don't consider important, you can add a `.weeder.yaml` file adjacent to the `stack.yaml` with a list of exclusions. To generate an initial list of exclusions run `weeder . --yaml > .weeder.yaml`.
 
-You may then with to generalise/simplify the `.weeder.yaml` by removing anything above or below the interesting part. As an example of the [`.weeder.yaml` file from `ghcid`](https://github.com/ndmitchell/ghcid/blob/master/.weeder.yaml):
+You may wish to generalise/simplify the `.weeder.yaml` by removing anything above or below the interesting part. As an example of the [`.weeder.yaml` file from `ghcid`](https://github.com/ndmitchell/ghcid/blob/master/.weeder.yaml):
 
 ```yaml
 - message: Module reused between components
diff --git a/src/Check.hs b/src/Check.hs
--- a/src/Check.hs
+++ b/src/Check.hs
@@ -5,6 +5,7 @@
 import Hi
 import Cabal
 import Util
+import Data.Maybe
 import Data.List.Extra
 import Data.Tuple.Extra
 import qualified Data.HashSet as Set
@@ -24,7 +25,8 @@
     warnRedundantPackageDependency s ++
     warnIncorrectOtherModules s ++
     warnUnusedExport s ++
-    warnNotCompiled pkg sections2
+    warnNotCompiled pkg sections2 ++
+    warnUnusedImport s
     where
         s = S{..}
         sections = map (second $ \(a,b,c) -> let aa = nubOrd a in (aa,nubOrd b \\ aa)) sections2
@@ -56,7 +58,7 @@
     [ [Warning pkg [cabalSectionType] "Missing other-modules entry" Nothing (Just m) Nothing | m <- Set.toList missing] ++
       [Warning pkg [cabalSectionType] "Excessive other-modules entry" Nothing (Just m) Nothing | m <- Set.toList excessive]
     | (CabalSection{..}, (external, internal)) <- sections
-    , let imports = Map.fromList [(hiModuleName, Set.map identModule hiImportIdent) | Hi{..} <- map hi $ external ++ internal]
+    , let imports = Map.fromList [(hiModuleName, hiImportModule) | Hi{..} <- map hi $ external ++ internal]
     , let missing =  Set.filter (not . isPathsModule) $
                      Set.unions (Map.elems imports) `Set.difference`
                      Set.fromList (Map.keys imports)
@@ -64,6 +66,20 @@
                       reachable (\k -> maybe [] Set.toList $ Map.lookup k imports) (map (hiModuleName . hi) external)
     ]
 
+
+-- Primarily looking for import Foo() where Foo is not an orphan
+warnUnusedImport :: S -> [Warning]
+warnUnusedImport S{..} =
+    [ Warning pkg [cabalSectionType] "Unused import" Nothing (Just $ hiModuleName mod) (Just $ hiModuleName imp)
+    | (CabalSection{..}, (external, internal)) <- sections
+    , let mods = Map.fromList $ map ((hiModuleName &&& id) . hi) $ external ++ internal
+    , mod <- Map.elems mods
+    , imp <- mapMaybe (`Map.lookup` mods) $ Set.toList $
+        hiImportModule mod `Set.difference`
+        (Set.map identModule (hiImportIdent mod) `Set.union` hiImportOrphan mod)
+    , Set.null $ hiImportIdent mod `Set.intersection` hiExportIdent imp -- reexporting for someone else
+    , Set.null $ Set.map snd (hiImportPackageModule mod) `Set.intersection` Set.map identModule (hiExportIdent imp) -- reexporting for another package 
+    ]
 
 warnUnusedExport :: S -> [Warning]
 warnUnusedExport S{..} =
diff --git a/src/Hi.hs b/src/Hi.hs
--- a/src/Hi.hs
+++ b/src/Hi.hs
@@ -34,6 +34,13 @@
         -- ^ Identifiers exported by this module
     ,hiImportIdent :: Set.HashSet Ident
         -- ^ Identifiers used by this module
+    ,hiImportModule :: Set.HashSet ModuleName
+        -- ^ Modules imported and used by this module
+        --   Normally equivalent to @Set.map identModule hiImportIdent@, unless a module supplies only instances
+    ,hiImportOrphan :: Set.HashSet ModuleName
+        -- ^ Orphans that are in scope in this module
+    ,hiImportPackageModule :: Set.HashSet (PackageName, ModuleName)
+        -- ^ Modules imported from other packages
     ,hiSignatures :: Map.HashMap IdentName (Set.HashSet Ident)
         -- ^ Type signatures of functions defined in this module and the types they refer to
     ,hiFieldName :: Set.HashSet Ident
@@ -42,12 +49,15 @@
 instance Hashable Hi
 
 instance Monoid Hi where
-    mempty = Hi mempty mempty mempty mempty mempty mempty
+    mempty = Hi mempty mempty mempty mempty mempty mempty mempty mempty mempty
     mappend x y = Hi
         {hiModuleName = f (?:) hiModuleName
         ,hiImportPackage = f (<>) hiImportPackage
         ,hiExportIdent = f (<>) hiExportIdent
         ,hiImportIdent = f (<>) hiImportIdent
+        ,hiImportModule = f (<>) hiImportModule
+        ,hiImportPackageModule = f (<>) hiImportPackageModule
+        ,hiImportOrphan = f (<>) hiImportOrphan
         ,hiSignatures = f (Map.unionWith (<>)) hiSignatures
         ,hiFieldName = f (<>) hiFieldName
         }
@@ -79,10 +89,14 @@
         f (x,xs)
             | Just x <- stripPrefix "interface " x = mempty{hiModuleName = parseInterface x}
             | Just x <- stripPrefix "exports:" x = mconcat $ map parseExports xs
+            | Just x <- stripPrefix "orphans:" x = mempty{hiImportOrphan = Set.fromList $ map parseInterface $ concatMap words $ x:xs}
             | Just x <- stripPrefix "package dependencies:" x = mempty{hiImportPackage = Set.fromList $ map parsePackDep $ concatMap words $ x:xs}
             | Just x <- stripPrefix "import " x = case xs of
-                [] -> mempty -- these are imports of modules from another package, we don't know what is actually used
-                xs -> mempty{hiImportIdent = Set.fromList $ map (Ident (words x !! 1) . fst . word1) $ dropWhile ("exports:" `isPrefixOf`) xs}
+                [] | (pkg, mod) <- breakOn ":" $ words x !! 1 -> mempty
+                    {hiImportPackageModule = Set.singleton (takeWhile (/= '@') pkg, drop 1 mod)}
+                xs -> let m = words x !! 1 in mempty
+                    {hiImportModule = Set.singleton m
+                    ,hiImportIdent = Set.fromList $ map (Ident m . fst . word1) $ dropWhile ("exports:" `isPrefixOf`) xs}
             | length x == 32, all isHexDigit x,
                 (y,ys):_ <- parseHanging xs,
                 fun:"::":typ <- concatMap (wordsBy (`elem` ",()[]{} ")) $ y:ys,
diff --git a/src/Warning.hs b/src/Warning.hs
--- a/src/Warning.hs
+++ b/src/Warning.hs
@@ -64,6 +64,7 @@
 -- (section, name, children)
 data Val = Val String String [Val]
          | End String [String]
+           deriving Show
 
 valToValue :: [Val] -> Value
 valToValue = Array . V.fromList . map f
@@ -77,12 +78,17 @@
 valueToVal :: Value -> [Val]
 valueToVal = f
     where
+        badYaml want x = error $ "Failed to understand Yaml fragment, expected " ++ want ++ ", got:\n" ++ BS.unpack (Yaml.encode x)
+
         f (Array xs) = concatMap f $ V.toList xs
         f (Object mp) | [(k,v)] <- Map.toList mp = return $ case v of
             v | Just (n, rest) <- findName v -> Val (T.unpack k) (T.unpack n) $ f rest
-            Array xs -> End (T.unpack k) $ map (T.unpack . fromString) $ V.toList xs
+            Array xs | Just xs <- mapM fromString $ V.toList xs -> End (T.unpack k) xs
             String x -> End (T.unpack k) [T.unpack x]
-        fromString (String x) = x
+            _ -> badYaml "either a dict with 'name' or a list/single string" $ Object mp
+        f x = badYaml "either a dict or an array" x
+        fromString (String x) = Just $ T.unpack x
+        fromString x = Nothing
 
         findName (Array xs)
             | ([name], rest) <- partition (isJust . fromName) $ V.toList xs
@@ -113,7 +119,9 @@
 readWarningsFile :: FilePath -> IO [Warning]
 readWarningsFile file = do
     x <- either throwIO return =<< Yaml.decodeFileEither file
-    return $ map warningUnpath $ concatMap (f warningLabels) $ valueToVal x
+    let res = map warningUnpath $ concatMap (f warningLabels) $ valueToVal x
+    mapM_ evaluate res -- ensure exceptions happen immediately
+    return res
     where
         f :: [String] -> Val -> [[String]]
         f names (End sect ns) = concatMap (\n -> f names $ Val sect n []) ns
@@ -121,6 +129,10 @@
             | sect == name = if null xs
                 then [n : replicate (length names) ""]
                 else map (n:) $ concatMap (f names) xs
+            | sect `notElem` names = error $
+                "Warnings file " ++ file ++ ", invalid section name:\n" ++
+                "Wanted one of: " ++ show (name:names) ++ "\n" ++
+                "Got: " ++ show sect
             | otherwise = map ("":) $ f names val
 
 
diff --git a/weeder.cabal b/weeder.cabal
--- a/weeder.cabal
+++ b/weeder.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.18
 build-type:         Simple
 name:               weeder
-version:            0.1.2
+version:            0.1.3
 license:            BSD3
 license-file:       LICENSE
 category:           Development
