diff --git a/Text/Parcom.hs b/Text/Parcom.hs
new file mode 100644
--- /dev/null
+++ b/Text/Parcom.hs
@@ -0,0 +1,88 @@
+-- | A parser-combinator library.
+--
+-- The primary goal in writing Parcom was to facilitate parsing Unicode string
+-- data from various source streams, including raw
+-- 'Data.ByteString.ByteString's - while Attoparsec can parse
+-- 'Data.ByteString.ByteString's, it sacrifices some convenience for
+-- performance, and using it to parse textual data is not as comfortable as I
+-- would like; Parsec can handle textual data much better, but it needs the
+-- input to be converetd to Unicode for this to work nicely. Nonetheless,
+-- Parcom\'s interface is quite obviously heavily inspired by both Parsec and
+-- Attoparsec.
+--
+-- Parcom supports 'String', 'Data.ByteString.ByteString' (lazy and strict) and
+-- 'Data.Text.Text' (lazy and strict) as its input format out-of-the-box. By
+-- implementing one or more of the typeclasses in 'Text.Parcom.Stream', you can
+-- extend Parcom to work on other input types as well.
+module Text.Parcom
+( module Text.Parcom.Prim
+, module Text.Parcom.Combinators
+, module Text.Parcom.Core
+-- * Getting Started
+-- | Parcom being a parser combinator library, the usual approach is to use
+-- predefined atomic parsers (defined in "Text.Parcom.Prim" and re-exported
+-- here for convenience) and combine them using predefined combinators (defined
+-- in "Text.Parcom.Combinators"). Anyone with prior exposure to Parsec or
+-- Attoparsec should be familiar with the concept. Here's an example that
+-- parses a value, which can be a positive integer literal or NULL:
+--
+-- > myParser :: Parcom String Char (Maybe Int)
+-- > myParser = intLiteral <|> nullLiteral <?> "value (integer or NULL)"
+-- >
+-- > intLiteral :: Parcom String Char (Maybe Int)
+-- > intLiteral = do
+-- >      x <- oneOf ['1'..'9']
+-- >      xs <- many (oneOf ['0'..'9'])
+-- >      return $ Just $ read (x:xs)
+-- > 
+-- > nullLiteral :: Parcom String Char (Maybe Int)
+-- > nullLiteral = do
+-- >      tokens "NULL"
+-- >      notFollowedBy (satisfy (not . isSpace))
+-- >      return Nothing
+--
+-- Such a parser can then be run against some input using 'parse' or 'parseT',
+-- the monadic equivalent.
+-- 
+-- > main = do
+-- >      src <- getContents
+-- >      let parseResult = parse myParser "<STDIN>" src
+-- >      case parseResult of
+-- >          Left err -> do
+-- >              putStrLn "Sorry, there has been an error, namely:"
+-- >              print err
+-- >          Right (Just i) -> putStrLn $ "Found an integer value: " ++ show i
+-- >          Right Nothing -> putStrLn "Found NULL"
+
+-- * Backtracking
+-- | As you build more complex parsers, you may encounter situations where a
+-- parser fails after having consumed some input already. Combining such a
+-- parser with other alternatives will yield undesired results: the parser
+-- fails, but it will not push the input it has already consumed back onto the
+-- input stream. To fix this, use the 'try' primitive, which modifies a parser
+-- such that when it fails, it undoes any input consumption it may have caused.
+
+-- * Input types other than 'String'
+-- | To support input from @Text@ or @ByteString@s, import one of the following
+-- modules:
+--
+--      * "Text.Parcom.Text" or "Text.Parcom.Text.Strict" for strict @Text@
+--
+--      * "Text.Parcom.Text.Lazy" for lazy @Text@
+--
+--      * "Text.Parcom.ByteString" or "ByteString.Parcom.ByteString.Strict" for strict @ByteString@
+--
+--      * "Text.Parcom.ByteString.Lazy" for lazy @ByteString@
+
+-- * Parsing textual data
+-- | Parcom provides two primitives for textual data: 'Text.Parcom.Textual.char'
+-- and 'Text.Parcom.Textual.string'. While textual data can be extracted from
+-- input streams that are textual already (e.g. 'String' or 'Data.Text.Text')
+-- using the normal token-based primities ('token', 'tokens', and 'prefix'),
+-- doing so for bytestrings isn't trivial. The textual-data 
+)
+where
+
+import Text.Parcom.Prim
+import Text.Parcom.Core
+import Text.Parcom.Combinators
diff --git a/Text/Parcom/Combinators.hs b/Text/Parcom/Combinators.hs
--- a/Text/Parcom/Combinators.hs
+++ b/Text/Parcom/Combinators.hs
@@ -1,3 +1,5 @@
+-- | A collection of predefined combinators. Use these to combine other parsers
+-- into more complex ones.
 module Text.Parcom.Combinators
 ( choice, namedChoice
 , before, between
@@ -17,7 +19,7 @@
 choice :: (Monad m, Stream s t) => [ParcomT s t m a] -> ParcomT s t m a
 choice xs = foldl (<|>) empty xs <?> "I tried to make a choice, but couldn't"
 
--- | Like @choice@, but each choice tagged with a human-readable name for
+-- | Like 'choice', but each choice tagged with a human-readable name for
 -- better error reporting.
 namedChoice :: (Monad m, Stream s t) => [(String, ParcomT s t m a)] -> ParcomT s t m a
 namedChoice xs = choice (map snd xs) <?> (formatOptionList . map fst) xs
diff --git a/Text/Parcom/Core.hs b/Text/Parcom/Core.hs
--- a/Text/Parcom/Core.hs
+++ b/Text/Parcom/Core.hs
@@ -1,3 +1,7 @@
+-- | The core functionality of a Parcom parser: defining and running parsers,
+-- lifting, getting tokens and characters from a stream, and the most basic
+-- primitive parsers and combinators that cannot easily be expressed in terms
+-- of other parsers and combinators.
 {-#LANGUAGE MultiParamTypeClasses #-}
 module Text.Parcom.Core
 ( ParcomError (..)
@@ -20,6 +24,8 @@
 import Control.Monad.Identity
 import Control.Monad.Trans.Class
 
+-- | Represents a position in a source file. Both lines and columns are
+-- 1-based.
 data SourcePosition =
     SourcePosition
         { posFileName :: String
@@ -28,22 +34,32 @@
         }
         deriving (Show)
 
+-- | A parser error.
 data ParcomError =
     ParcomError
-        { peErrorDescription :: String
-        , peSourcePosition :: SourcePosition
+        { peErrorDescription :: String -- ^ Human-readable description of the error
+        , peSourcePosition :: SourcePosition -- ^ Position in the source where the error was found.
         }
         deriving (Show)
 
+-- | The parser's internal state.
 data ParcomState s =
     ParcomState
-        { psSourcePosition :: SourcePosition
-        , psStream :: s
+        { psSourcePosition :: SourcePosition -- ^ Current source position, for error reporting
+        , psStream :: s -- ^ The remaining source stream
         }
 
+-- | Parcom as a pure parser
 type Parcom s t a = ParcomT s t Identity a
+
+-- | Parcom as a monad transformer. You can access the underlying monad stack
+-- using the usual lifting techniques.
 newtype ParcomT s t m a = ParcomT { runParcomT :: ParcomState s -> m (Either ParcomError a, ParcomState s) }
 
+-- | Parcom is a monad. Obviously. Since the Parcom monad handles both failure
+-- through 'Either' as well as carrying along its internal state, *and*
+-- supporting the transformed parent monad, the implementation is a tiny bit
+-- hairy.
 instance (Monad m) => Monad (ParcomT s t m) where
     return x = ParcomT (\s -> return (Right x, s))
     fail err = ParcomT (\s -> return (Left $ ParcomError err (psSourcePosition s), s))
@@ -54,6 +70,7 @@
             Right ma -> do
                 runParcomT (f ma) s'
 
+-- | ParcomT enables lifting by implementing 'MonadTrans'
 instance MonadTrans (ParcomT s t) where
     lift a = ParcomT $ \s -> do
         v <- a
@@ -70,6 +87,8 @@
     (<|>) = alt
     empty = fail "empty"
 
+-- | Wrapper that handles setting up a sensible initial state before running a
+-- ParcomT
 runParserT :: (Stream s t, Token t) => ParcomT s t m a -> String -> s -> m (Either ParcomError a, ParcomState s)
 runParserT p fn str =
     runParcomT p state
@@ -79,21 +98,27 @@
                 { psSourcePosition = SourcePosition fn 1 1
                 , psStream = str }
 
+-- | Run a parcom transformer and return the result
 parseT :: (Stream s t, Token t, Monad m) => ParcomT s t m a -> String -> s -> m (Either ParcomError a)
 parseT p fn str = fst `liftM` runParserT p fn str
 
+-- | Run a pure parcom parser and return the result
 parse :: (Stream s t, Token t) => Parcom s t a -> String -> s -> Either ParcomError a
 parse p fn str = runIdentity $ parseT p fn str
 
+-- | Get the internal parser state
 getState :: Monad m => ParcomT s t m (ParcomState s)
 getState = ParcomT $ \s -> return (Right s, s)
 
+-- | Get the internal parser state and apply a projection function
 useState :: Monad m => (ParcomState s -> a) -> ParcomT s t m a
 useState f = ParcomT $ \s -> return (Right $ f s, s)
 
+-- | Overwrite the internal parser state entirely
 setState :: Monad m => ParcomState s -> ParcomT s t m ()
 setState s = ParcomT $ \_ -> return (Right (), s)
 
+-- | Apply a modification function to the internal parser state
 modifyState :: Monad m => (ParcomState s -> ParcomState s) -> ParcomT s t m ()
 modifyState f = ParcomT $ \s -> return (Right (), f s)
 
@@ -142,7 +167,7 @@
 -- | Succeeds iff the given parser fails
 notFollowedBy :: (Monad m, Stream s t) => ParcomT s t m a -> ParcomT s t m ()
 notFollowedBy p = handle' p (\_ s _ -> return (Right (), s)) (\x s _ -> runParcomT (fail "something followed that shouldn't") s)
-    
+
 -- | Gets the next token from the stream without consuming it.
 -- Fails at end-of-input.
 peek :: (Monad m, Stream s t) => ParcomT s t m t
@@ -179,6 +204,9 @@
                 else modifyState $ \s -> s { psSourcePosition = nextColumn (psSourcePosition s) }
             return t
 
+-- | Get one character from the stream, but do not consume it. Fails when the
+-- input stream contains a sequence that does not represent a valid character,
+-- or when the end of the input stream has been reached.
 peekChar :: (Monad m, Stream s t, Token t, Textish s) => ParcomT s t m Char
 peekChar = do
     str <- psStream `liftM` getState
@@ -187,6 +215,9 @@
         Just c -> return c
         Nothing -> fail "Tokens do not form a valid character, or end of input reached"
     
+-- | Get one character from the stream, and consume it. Fails when the input
+-- stream contains a sequence that does not represent a valid character, or
+-- when the end of the input stream has been reached.
 nextChar :: (Monad m, Stream s t, Token t, Textish s) => ParcomT s t m Char
 nextChar = do
     str <- psStream `liftM` getState
@@ -197,5 +228,8 @@
             return c
         Nothing -> fail "Tokens do not form a valid character, or end of input reached"
 
+-- | Tags a parser with a human-readable description of the expected entity,
+-- generating an "Expected {entity}" type error message on failure.
+infixl 3 <?>
 (<?>) :: (Monad m, Stream s t) => ParcomT s t m a -> String -> ParcomT s t m a
 p <?> expected = p <|> fail ("Expected " ++ expected)
diff --git a/Text/Parcom/Prim.hs b/Text/Parcom/Prim.hs
--- a/Text/Parcom/Prim.hs
+++ b/Text/Parcom/Prim.hs
@@ -1,5 +1,13 @@
+-- | Primitive parsers.
+--
+-- Regarding consuming input, unless states otherwise, all of these behave as
+-- follows:
+--
+-- * If a parser succeeds, it consumes the input it matches
+--
+-- * If a parser fails, it does not consume any input at all
 module Text.Parcom.Prim
-( anyToken, oneOf, eof
+( anyToken, oneOf, noneOf, eof
 , satisfy
 , token, tokens, prefix
 )
@@ -19,10 +27,15 @@
 eof = notFollowedBy anyToken <?> "end of input"
 
 -- | Matches one token against a list of possible tokens; returns the
--- matching token.
+-- matching token or fails.
 oneOf :: (Monad m, Stream s t, Token t, Show t, Eq t) => [t] -> ParcomT s t m t
 oneOf xs = satisfy (`elem` xs) <?> (formatOptionList . map show) xs
 
+-- | Matches one token against a list of prohibited tokens; returns the
+-- non-matching token or fails.
+noneOf :: (Monad m, Stream s t, Token t, Show t, Eq t) => [t] -> ParcomT s t m t
+noneOf xs = satisfy (not . (`elem` xs)) <?> "anything but " ++ (formatOptionList . map show) xs
+
 -- | Succeeds if the given predicate is met for the next token.
 satisfy :: (Monad m, Stream s t, Token t) => (t -> Bool) -> ParcomT s t m t
 satisfy p = do
@@ -43,5 +56,10 @@
     cs <- tokens xs
     return (c:cs)
 
+-- | Match a series of tokens exactly. Unlike 'tokens', this parser accepts
+-- the target sequence by the stream's type instead of list-of-tokens.
+-- Depending on the stream's 'Listish' implementation, this may be more
+-- efficient than matching and consuming the tokens one-by-one, as 'tokens'
+-- does.
 prefix :: (Monad m, Stream s t, Token t, Eq t, Show t, Listish s t) => s -> ParcomT s t m s
 prefix str = fromList `liftM` tokens (toList str)
diff --git a/Text/Parcom/Stream.hs b/Text/Parcom/Stream.hs
--- a/Text/Parcom/Stream.hs
+++ b/Text/Parcom/Stream.hs
@@ -1,7 +1,19 @@
 {-#LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}
+-- | Typeclasses to describe various aspects of parsable streams and tokens.
+-- The standard range of Haskell string-like types ('String', and both the lazy
+-- and strict flavors of 'ByteString' and 'Text') is supported already, as well
+-- as any 'List', so under normal circumstances, you should not need to touch
+-- this module directly.
+
 module Text.Parcom.Stream
 where
 
+-- | Typeclass for types that are suitable as source streams. Note that
+-- implementing just 'Stream' gives you only a small subset of Parcom\'s
+-- features; if you want to implement your own 'Stream' instances, you will
+-- most likely also want to implement 'Token' for the corresponding token type,
+-- 'Listish' to enable parsers that need to convert to or from lists of tokens,
+-- and 'Textish' to enable parsers that work on Unicode text.
 class Stream s t | s -> t where
     peek :: s -> t
     atEnd :: s -> Bool
@@ -10,27 +22,53 @@
     consume = snd . pop
     pop s = (peek s, consume s)
 
+-- | All lists are instances of 'Stream', and the corresponding token type is
+-- the list element type. Obviously, this also includes 'String' ('[Char]') and
+-- '[Word8]'
 instance Stream [a] a where
     peek = head
     atEnd = null
     consume = tail
 
+-- | This typeclass is pretty much required to do anything useful with Parcom;
+-- it is needed for Parcom to detect line endings so that parser errors will
+-- report the correct source positions. If you need to parse streams that do
+-- not support any meaningful concept of lines, consider implementing a dummy
+-- instance, like so:
+-- @
+-- instance Token Foobar where
+--     isLineDelimiter _ = False
+-- @
+-- This will treat the entire input as a single line.
 class Token t where
     isLineDelimiter :: t -> Bool
 
+-- | Unicode characters are valid tokens.
 instance Token Char where
     isLineDelimiter '\n' = True
     isLineDelimiter _ = False
 
+-- | List-like types.
 class Listish s t | s -> t where
-    toList :: s -> [t]
+    toList :: s  -> [t]
     fromList :: [t] -> s
 
+-- | Any list is trivially list-like
 instance Listish [a] a where
     toList = id
     fromList = id
 
+-- | Enables parsing on a per-character basis rather than per-token. For stream
+-- types where the token type is 'Char' already, this is trivial, but for other
+-- streams (e.g., bytestrings), some extra processing is required to perform a
+-- conversion to Unicode.
 class Textish s where
+    -- | Character-wise equivalent of 'peek'. Returns a pair, where the first
+    -- element is 'Just' the parsed Unicode character, or Nothing on failure,
+    -- and the second element is the number of tokens that the character has
+    -- consumed. Generally, there are two reasons why parsing may fail:
+    -- end-of-input, and a token sequence that does not represent a valid
+    -- Unicode character according to the underlying stream's semantics.
     peekChar :: s -> (Maybe Char, Int)
 
 instance Textish [Char] where
diff --git a/parcom-lib.cabal b/parcom-lib.cabal
--- a/parcom-lib.cabal
+++ b/parcom-lib.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                parcom-lib
-version:             0.5.0.0
+version:             0.6.0.0
 synopsis:            A simple parser-combinator library, a bit like Parsec but without the frills
 description:         Parcom provides parser combinator functionality in a string-type-agnostic way;
                      it supports strict ByteStrings (with Word8 tokens) and any list type (with
@@ -20,7 +20,8 @@
 cabal-version:       >=1.8
 
 library
-  exposed-modules: Text.Parcom.Stream
+  exposed-modules: Text.Parcom
+                 , Text.Parcom.Stream
                  , Text.Parcom.Core
                  , Text.Parcom.Word8
                  , Text.Parcom.Internal
