diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -177,44 +177,69 @@
 Each pragma starts with `-- cabal-gild:`. Pragmas must be the last comment
 before a field.
 
-- `-- cabal-gild: discover [DIRECTORY ...]`: This pragma will discover any
-  Haskell files in any of the given directories and use those to populate the
-  list of modules or signatures. If no directories are given, defaults to `.`
-  (the current directory). For example, given this input:
+#### `discover`
 
-  ``` cabal
-  library
-    -- cabal-gild: discover source/library
-    exposed-modules: ...
-  ```
+```
+-- cabal-gild: discover [DIRECTORY ...] [--include=PATTERN ...] [--exclude=PATTERN ...]
+```
 
-  Assuming there is a single Haskell file at `source/library/M.hs`, Gild will
-  produce this output:
+This pragma will discover any Haskell files in any of the given directories and
+use those to populate the list of modules or signatures. If no directories are
+given, defaults to `.` (the directory of the package description). For example,
+given this input:
 
-  ``` cabal
-  library
-    -- cabal-gild: discover source/library
-    exposed-modules: M
-  ```
+``` cabal
+library
+  -- cabal-gild: discover
+  exposed-modules: ...
+```
 
-  This pragma only works with the `exposed-modules`, `other-modules`, and
-  `signatures` fields. It will be ignored on all other fields.
+Assuming there is a single Haskell file at `Example.hs`, Gild will produce this
+output:
 
-  Any existing modules or signatures in the list will be ignored. The entire
-  field will be replaced. This means adding, removing, and renaming modules or
-  signatures should be handled automatically.
+``` cabal
+library
+  -- cabal-gild: discover
+  exposed-modules: Example
+```
 
-  This pragma searches for files with any of the following extensions: `*.chs`,
-  `*.cpphs`, `*.gc`, `*.hs`, `*.hsc`, `*.hsig`, `*.lhs`, `*.lhsig`, `*.ly`,
-  `*.x`, or `*.y`,
+This pragma only works with the `exposed-modules`, `other-modules`, and
+`signatures` fields. It will be ignored on all other fields.
 
-  Directories can be quoted if they contain spaces.
+Any existing modules or signatures in the list will be ignored. The entire
+field will be replaced. This means adding, removing, and renaming modules or
+signatures should be handled automatically.
 
-  Discovered modules can be ignored by using the `--exclude=FILE` option. For
-  example:
+This pragma searches for files with any of the following extensions: `*.chs`,
+`*.cpphs`, `*.gc`, `*.hs`, `*.hsc`, `*.hsig`, `*.lhs`, `*.lhsig`, `*.ly`,
+`*.x`, or `*.y`,
 
-  ``` cabal
-  library
-    -- cabal-gild: discover source/library --exclude=source/library/Foo/Bar.hs
-    exposed-modules: ...
-  ```
+Directories can be quoted if they contain spaces. For example:
+
+``` cabal
+library
+  -- cabal-gild: discover "my modules"
+  exposed-modules: ...
+```
+
+By default, all files in any of the given directories are considered for
+discovery. To explicitly include only certain files, use the
+`--include=PATTERN` option. For example:
+
+``` cabal
+library
+  -- cabal-gild: discover --include=**/*Spec.hs
+  other-modules: ...
+```
+
+Files can be excluded from discovery by using the `--exclude=PATTERN` option.
+For example:
+
+``` cabal
+library
+  -- cabal-gild: discover --exclude=**/*Spec.hs
+  exposed-modules: ...
+```
+
+If a file would match both the `--include` pattern and the `--exclude` pattern,
+it will be excluded.
diff --git a/cabal-gild.cabal b/cabal-gild.cabal
--- a/cabal-gild.cabal
+++ b/cabal-gild.cabal
@@ -11,7 +11,7 @@
 maintainer: Taylor Fausak
 name: cabal-gild
 synopsis: Formats package descriptions.
-version: 1.3.2.0
+version: 1.3.3.0
 
 source-repository head
   type: git
diff --git a/source/library/CabalGild/Unstable/Action/EvaluatePragmas.hs b/source/library/CabalGild/Unstable/Action/EvaluatePragmas.hs
--- a/source/library/CabalGild/Unstable/Action/EvaluatePragmas.hs
+++ b/source/library/CabalGild/Unstable/Action/EvaluatePragmas.hs
@@ -14,6 +14,7 @@
 import qualified Control.Monad.Trans.Class as Trans
 import qualified Control.Monad.Trans.Maybe as MaybeT
 import qualified Data.Containers.ListUtils as List
+import qualified Data.Either as Either
 import qualified Data.Maybe as Maybe
 import qualified Data.Set as Set
 import qualified Distribution.Compat.Lens as Lens
@@ -60,12 +61,14 @@
   [String] ->
   MaybeT.MaybeT m (Fields.Field (p, [c]))
 discover p n fls ds = do
-  let (strs, args, opts, errs) =
+  let (flgs, args, opts, errs) =
         GetOpt.getOpt'
           GetOpt.Permute
-          [ GetOpt.Option [] ["exclude"] (GetOpt.ReqArg id "PATTERN") ""
+          [ GetOpt.Option [] ["include"] (GetOpt.ReqArg Right "PATTERN") "",
+            GetOpt.Option [] ["exclude"] (GetOpt.ReqArg Left "PATTERN") ""
           ]
           ds
+  let (excs, incs) = Either.partitionEithers flgs
   mapM_ (Exception.throwM . UnknownOption.fromString) opts
   mapM_ (Exception.throwM . InvalidOption.fromString) errs
   let root = FilePath.takeDirectory p
@@ -77,13 +80,12 @@
                 . FilePath.combine root
             )
           $ if null args then ["."] else args
-  let exclusions = List.nubOrd $ fmap (normalize . FilePath.combine root) strs
-  files <-
-    Trans.lift $
-      MonadWalk.walk
-        "."
-        (fmap (\d -> normalize $ FilePath.joinPath [d, "**"]) directories)
-        exclusions
+  let exclusions = List.nubOrd $ fmap (normalize . FilePath.combine root) excs
+      inclusions =
+        List.nubOrd
+          . fmap (normalize . FilePath.combine root)
+          $ if null incs then ["**"] else incs
+  files <- Trans.lift $ MonadWalk.walk "." inclusions exclusions
   let comments = concatMap (snd . FieldLine.annotation) fls
       position =
         maybe (fst $ Name.annotation n) (fst . FieldLine.annotation) $
diff --git a/source/test-suite/Main.hs b/source/test-suite/Main.hs
--- a/source/test-suite/Main.hs
+++ b/source/test-suite/Main.hs
@@ -1397,6 +1397,66 @@
       "f:\ng: a"
       "f:\ng: a\n"
 
+  Hspec.it "supports including a module" $ do
+    expectDiscover
+      [["M.hs"], ["N.hs"]]
+      "library\n -- cabal-gild: discover --include M.hs\n exposed-modules:"
+      "library\n  -- cabal-gild: discover --include M.hs\n  exposed-modules: M\n"
+
+  Hspec.it "supports including a pattern" $ do
+    expectDiscover
+      [["M1.hs"], ["M2.hs"], ["N.hs"]]
+      "library\n -- cabal-gild: discover --include M*.hs\n exposed-modules:"
+      "library\n  -- cabal-gild: discover --include M*.hs\n  exposed-modules:\n    M1\n    M2\n"
+
+  Hspec.it "supports including from multiple directories" $ do
+    -- Note that the include pattern needs to be `**/*X.hs` rather than just
+    -- `*X.hs`. That's because it's relative to the package description, not
+    -- the directories listed in the discover pragma.
+    expectDiscover
+      [["a", "AX.hs"], ["a", "M.hs"], ["b", "BX.hs"], ["b", "N.hs"]]
+      "library\n -- cabal-gild: discover a b --include **/*X.hs\n exposed-modules:"
+      "library\n  -- cabal-gild: discover a b --include **/*X.hs\n  exposed-modules:\n    AX\n    BX\n"
+
+  Hspec.it "supports including with multiple patterns" $ do
+    expectDiscover
+      [["M.hs"], ["N.hs"], ["O.hs"]]
+      "library\n -- cabal-gild: discover --include M.hs --include N.hs\n exposed-modules:"
+      "library\n  -- cabal-gild: discover --include M.hs --include N.hs\n  exposed-modules:\n    M\n    N\n"
+
+  Hspec.it "supports including and excluding at the same time" $ do
+    expectDiscover
+      [["XA.hs"], ["XASpec.hs"]]
+      "library\n -- cabal-gild: discover --include X*.hs --exclude *Spec.hs\n exposed-modules:"
+      "library\n  -- cabal-gild: discover --include X*.hs --exclude *Spec.hs\n  exposed-modules: XA\n"
+
+  Hspec.it "does not discover invalid module names" $ do
+    -- `a.M` is not a valid module name because `a` is lowercase. So it should
+    -- not be discovered even though it is included.
+    expectDiscover
+      [["a", "M.hs"]]
+      "library\n -- cabal-gild: discover --include a/**\n exposed-modules:"
+      "library\n  -- cabal-gild: discover --include a/**\n  exposed-modules:\n"
+
+  Hspec.it "discovers valid module names" $ do
+    -- Unlike the previous test, the module `M` should be discovered because
+    -- the directory `a` will be stripped off.
+    expectDiscover
+      [["a", "M.hs"]]
+      "library\n -- cabal-gild: discover a --include a/**\n exposed-modules:"
+      "library\n  -- cabal-gild: discover a --include a/**\n  exposed-modules: M\n"
+
+  Hspec.it "treats included patterns relative to cabal file" $ do
+    let d = "input"
+        (a, s, w) =
+          runGild
+            ["--input", FilePath.combine d "io.cabal"]
+            [(Input.File $ FilePath.combine d "io.cabal", String.toUtf8 "library\n -- cabal-gild: discover src --include src/M.hs\n exposed-modules:")]
+            [[d, "src", "M.hs"], [d, "src", "N.hs"]]
+    a `Hspec.shouldSatisfy` Either.isRight
+    w `Hspec.shouldBe` []
+    s `Hspec.shouldBe` Map.singleton Output.Stdout (String.toUtf8 "library\n  -- cabal-gild: discover src --include src/M.hs\n  exposed-modules: M\n")
+
   Hspec.around_ withTemporaryDirectory
     . Hspec.it "discovers modules on the file system"
     $ do
