diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2009-2011, Sergey Astanin
+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 the Sergey Astanin 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 HOLDER 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/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/bitly-cli.cabal b/bitly-cli.cabal
new file mode 100644
--- /dev/null
+++ b/bitly-cli.cabal
@@ -0,0 +1,41 @@
+Name:          bitly-cli
+Version:       0.1
+Cabal-version: >= 1.2
+Build-type:    Simple
+
+Stability:     experimental
+Category:      Web, Utils
+License:       BSD3
+License-file:  LICENSE
+Maintainer:    Sergey Astanin <s.astanin@gmail.com>
+Homepage:      http://bitbucket.org/jetxee/hs-bitly/
+Bug-reports:   http://bitbucket.org/jetxee/hs-bitly/issues/
+
+Synopsis: A command line tool to access bit.ly URL shortener.
+Description:
+  This package provides a command line utility to shorten
+  and expand URLs using bit.ly/j.mp service. To use this tool, an API
+  key is required. Please find yours at <http://bit.ly/account/>.
+  .
+  Configuration file (`~/.bitly`) format:
+  .
+  > login = your_bit.ly_login
+  > apikey = your_API_key
+  .
+  Usage examples:
+  .
+  > $ echo "Text with an URL: http://example.com/" | bitly
+  > Text with an URL: http://bit.ly/2eSq1z
+  > $ bitly shorten http://example.com
+  > http://bit.ly/2eSq1z
+  > $ bitly expand http://bit.ly/2eSq1z
+  > http://example.com/
+
+Executable bitly
+  Main-is:     bitly.hs
+  Build-depends:
+               Bitly >= 0.0.6
+             , base >= 3 && < 5
+             , filepath >= 1.1
+             , directory >= 1.0 && < 1.1
+             , regexpr >= 0.5
diff --git a/bitly.hs b/bitly.hs
new file mode 100644
--- /dev/null
+++ b/bitly.hs
@@ -0,0 +1,83 @@
+module Main where
+
+import Network.Bitly
+
+import Control.Applicative ((<$>))
+import Data.Char (isSpace)
+import Data.Maybe (fromJust, fromMaybe, isJust, isNothing)
+import System.Directory (getHomeDirectory)
+import System.Environment (getArgs)
+import System.Exit (exitFailure, exitSuccess)
+import System.FilePath (makeValid, combine)
+import System.IO (hPutStrLn, stderr)
+import Text.RegexPR
+
+confFileName :: IO String
+confFileName = makeValid <$> flip combine ".bitly" <$> getHomeDirectory
+
+readConfig :: IO (Maybe Account)
+readConfig = do
+  file <- confFileName
+  conf <- map (brk '=') . lines <$> readFile file `catch` (\_ -> return "")
+  let l = lookup "login" conf
+  let k = lookup "apikey" conf
+  if isJust l && isJust k
+    then return $ Just bitlyAccount { login = fromJust l, apikey = fromJust k }
+    else return Nothing
+
+brk d str =
+  let (a,b) = break (== d) str
+  in  (trim a, trim . dropWhile (== d) $ b)
+
+trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse
+
+errorExit s = hPutStrLn stderr s >> exitFailure
+
+modifyUrl :: (String -> IO Result) -> String -> IO String
+modifyUrl op url = do
+  r <- op url
+  case r of
+    -- don't replace URL on error
+    Left _ -> return url
+    Right url' -> return url'
+
+urlRE = "(http|ftp|https)://\\w+(\\.\\w+)+(:[0-9]+)?(/\\S+)?/?"
+
+passThrough :: (String -> IO Result) -> String -> IO String
+passThrough op txt =
+  let m = matchRegexPR urlRE txt
+  in case m of
+    Nothing -> return txt
+    Just ((url,(b,a)),_) -> do
+      url' <- modifyUrl op url
+      return . ((b ++ url') ++) =<< passThrough op a
+
+-- process all given urls or read stdin and pass it through
+runOp :: (String -> IO Result) -> [String] -> IO ()
+runOp op [] = putStr =<< passThrough op =<< getContents
+runOp op urls = mapM_ putStrLn =<< mapM (modifyUrl op) urls
+
+usage = "Usage: bitly [ help | [shorten] [url ...] | expand [url ...] ]\n\n\
+\If no url is given, bitly acts as a filter and replaces all found URLs.\n\
+\Bitly shortens URLs by default.\n\n\
+\Configuration file format (~/.bitly):\n\
+\  login = your_bit.ly_login\n\
+\  apikey = your_API_key"
+
+main = do
+  args <- getArgs
+  if "help" `elem` args || "--help" `elem` args
+    then putStrLn usage >> exitSuccess
+    else do
+
+  conf <- readConfig
+  case conf of
+    Nothing -> do
+      f <- confFileName
+      errorExit $ "Configuration file is incomplete or not found (" ++ f ++ ")"
+    Just acc ->
+      case args of
+        ("expand":urls) -> runOp (expand acc) urls
+        ("shorten":urls) -> runOp (shorten acc) urls
+        _  -> runOp (shorten acc) args -- shorten by default
+
