diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2016, Yuras Shumovich
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Yuras Shumovich nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# scanner-attoparsec
+Inject attoparsec parser with backtracking into non-backtracking scanner
+
+[![Build Status](https://travis-ci.org/Yuras/scanner-attoparsec.svg?branch=master)](https://travis-ci.org/Yuras/scanner-attoparsec)
+
+Backtracking kills performance, so scanner package doesn't support it.
+But sometimes you just need it. E.g. you have a mostly non-backtracking
+parser, but a small bit of its grammar is too complex to transform it
+to non-backtracking form. In that case you can inject a backtracking
+attoparsec parser into otherwise non-backtracking scanner.
+
+See also http://hackage.haskell.org/package/scanner
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,4 @@
+
+0.1
+
+* initial implementation
diff --git a/compat/Data/Either.hs b/compat/Data/Either.hs
new file mode 100644
--- /dev/null
+++ b/compat/Data/Either.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE PackageImports #-}
+{-# LANGUAGE CPP #-}
+
+module Data.Either
+(
+  module Export,
+#if MIN_VERSION_base(4,7,0)
+#else
+  isRight,
+  isLeft,
+#endif
+)
+where
+
+import "base" Data.Either as Export
+
+#if MIN_VERSION_base(4,7,0)
+#else
+isRight :: Either a b -> Bool
+isRight (Right _) = True
+isRight _ = False
+
+isLeft :: Either a b -> Bool
+isLeft = not . isRight
+#endif
diff --git a/lib/Scanner/Attoparsec.hs b/lib/Scanner/Attoparsec.hs
new file mode 100644
--- /dev/null
+++ b/lib/Scanner/Attoparsec.hs
@@ -0,0 +1,24 @@
+
+module Scanner.Attoparsec
+( atto
+)
+where
+
+import qualified Scanner
+import Scanner.Internal (Scanner (Scanner))
+
+import qualified Data.Attoparsec.ByteString as Atto
+
+{-# INLINE atto #-}
+atto :: Atto.Parser a -> Scanner a
+atto p = Scanner $ \bs next ->
+  case Atto.parse p bs of
+    Atto.Done bs' r -> next bs' r
+    Atto.Fail bs' _ err -> Scanner.Fail bs' err
+    Atto.Partial cont -> slowPath cont next
+  where
+  slowPath cont next = Scanner.More $ \bs ->
+    case cont bs of
+      Atto.Done bs' r -> next bs' r
+      Atto.Fail bs' _ err -> Scanner.Fail bs' err
+      Atto.Partial cont' -> slowPath cont' next
diff --git a/scanner-attoparsec.cabal b/scanner-attoparsec.cabal
new file mode 100644
--- /dev/null
+++ b/scanner-attoparsec.cabal
@@ -0,0 +1,46 @@
+name:                scanner-attoparsec
+version:             0.1
+synopsis:            Inject attoparsec parser with backtracking into non-backtracking scanner
+homepage:            https://github.com/Yuras/scanner-attoparsec
+license:             BSD3
+license-file:        LICENSE
+author:              Yuras Shumovich
+maintainer:          shumovichy@gmail.com
+copyright:           (c) Yuras Shumovich 2016
+category:            Parsing
+build-type:          Simple
+extra-source-files:  README.md changelog.md
+cabal-version:       >=1.10
+description:         Backtracking kills performance, so scanner package doesn't support it.
+                     But sometimes you just need it. E.g. you have a mostly non-backtracking
+                     parser, but a small bit of its grammar is too complex to transform it
+                     to non-backtracking form. In that case you can inject a backtracking
+                     attoparsec parser into otherwise non-backtracking scanner.
+                     .
+                     See also http://hackage.haskell.org/scanner
+
+source-repository head
+  type:                git
+  location:            git@github.com:Yuras/scanner-attoparsec.git
+
+library
+  exposed-modules:     Scanner.Attoparsec
+  other-modules:       Data.Either
+  ghc-options:         -O2
+  build-depends:       base <5
+                     , attoparsec
+                     , scanner
+  hs-source-dirs:      lib, compat
+  default-language:    Haskell2010
+
+test-suite spec
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      spec, compat
+  main-is:             spec.hs
+  build-depends:       base <5
+                     , bytestring
+                     , scanner
+                     , attoparsec
+                     , hspec
+                     , scanner-attoparsec
+  default-language:    Haskell2010
diff --git a/spec/spec.hs b/spec/spec.hs
new file mode 100644
--- /dev/null
+++ b/spec/spec.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main
+( main
+)
+where
+
+import Scanner
+import Scanner.Attoparsec
+
+import Data.Either
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Lazy as Lazy.ByteString
+import qualified Data.Attoparsec.ByteString as Atto
+import Control.Applicative
+import Control.Monad
+
+import Test.Hspec
+
+main :: IO ()
+main = hspec $ do
+  attoSpec
+
+attoSpec :: Spec
+attoSpec = describe "atto" $ do
+  it "should apply attoparsec parser" $ do
+    let bs = "+hello"
+    scanOnly p bs `shouldBe` Right "hello"
+
+  it "should backtrack" $ do
+    let bs = "-hell"
+    scanOnly p bs `shouldBe` Right "hell"
+
+  it "should consume input" $ do
+    let bs = "-hello"
+    scanOnly (p *> anyChar8) bs `shouldBe` Right 'o'
+
+  it "should fail on invalid input" $ do
+    let bs = "!hello"
+    scanOnly (p *> anyChar8) bs `shouldSatisfy` isLeft
+
+  it "should ask for more input" $ do
+    let bs = Lazy.ByteString.fromChunks
+          [ "+"
+          , "he"
+          , "ll"
+          , "o world"
+          ]
+    scanLazy p bs `shouldBe` Right "hello"
+
+p :: Scanner ByteString
+p = atto $ plusP <|> minusP
+
+plusP :: Atto.Parser ByteString
+plusP = do
+  void $ Atto.string "+"
+  Atto.take 5
+
+minusP :: Atto.Parser ByteString
+minusP = do
+  void $ Atto.string "-"
+  Atto.take 4
