diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2015 Ricardo Catalinas Jiménez
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,156 @@
+import Brick
+import Control.Concurrent
+import Control.Monad
+import Control.Monad.IO.Class
+import Data.Default
+import Data.List.Split
+import Data.Time.Units
+import Graphics.Vty hiding ((<|>))
+import Options.Applicative hiding (str)
+import System.Exit
+import System.Posix.IO
+import System.Posix.Terminal
+import System.Process
+import Text.Printf
+
+data AppEvent = Tick
+              | Terminal Event
+
+data AppState = AppState {
+    appCmds        :: [String]
+  , appCmdOuts     :: [[Double]]
+  , appCmdNames    :: [String]
+  , appRefreshRate :: Second
+  , appLogScale    :: Bool
+  , appSerieSize   :: Int
+  } deriving Show
+
+main :: IO ()
+main = execParser opts >>= runApp
+  where parser = AppState <$> many (strArgument (
+                                    metavar "CMD"
+                                 <> help "Command output to plot (<name>:<cmd>)"))
+                          <*> pure []
+                          <*> pure []
+                          <*> ((toPosNum <$> strOption (
+                                    short 'i'
+                                 <> long "interval"
+                                 <> metavar "INTERVAL"
+                                 <> help "Updates interval time (secs)"))
+                              <|> pure 1)
+                          <*> switch (
+                                    short 'l'
+                                 <> long "log"
+                                 <> help "Use logarithmic scale")
+                          <*> ((toPosNum <$> strOption (
+                                    short 's'
+                                 <> long "size"
+                                 <> metavar "SIZE"
+                                 <> help "Size of the time series buffer"))
+                              <|> pure 1024)
+        opts = info (helper <*> parser) mempty
+
+nonInteractivePlot :: Bool -> IO ()
+nonInteractivePlot useLog = do
+    series <- map (map toPosNum . concatMap (splitOn ",") . splitOn " ") . lines <$> getContents
+    if all ((== 1) . length) series
+        then putStrLn $ getBars' $ concat series
+        else mapM_ (putStrLn . getBars') series
+  where getBars' | useLog    = getBars . logScale
+                 | otherwise = getBars
+
+toPosNum :: (Ord a, Num a, Read a) => String -> a
+toPosNum s = case reads s of
+        [(v, _)] | v >= 0    -> v
+                 | otherwise -> error $ printf "negative numeric value: %v" s
+        _                    -> error $ printf "invalid numeric value: %v" s
+runCmd :: String -> IO String
+runCmd cmd = do
+    (exit, stdout, _) <- readCreateProcessWithExitCode (shell cmd) mempty
+    case exit of
+        ExitFailure _ -> error $ "Command failed: " ++ cmd
+        ExitSuccess   -> return stdout
+
+runApp :: AppState -> IO ()
+runApp app = do
+    let termApp         = App {
+        appDraw         = \a -> [renderApp a]
+      , appHandleEvent  = loopApp
+      , appStartEvent   = return
+      , appAttrMap      = def
+      , appLiftVtyEvent = Terminal
+      , appChooseCursor = neverShowCursor
+      }
+    isatty <- queryTerminal stdInput
+    if not isatty
+        then nonInteractivePlot $ appLogScale app
+        else
+            if null $ appCmds app
+                then error "no command to execute specified nor input from the stdin"
+                else do
+                    ticker <- runTicker $ appRefreshRate app
+                    void $ customMain (mkVty def) ticker termApp (initApp app)
+
+renderApp :: AppState -> Widget
+renderApp app = seriesNames <+> lastValues <+> vBox (map (str . getBars') $ appCmdOuts app)
+  where seriesNames                 = pad1 $ vBox (map str (appCmdNames app))
+        lastValues                  = pad1 $ vBox (map (str . showSeries) (appCmdOuts app))
+        pad1                        = padRight $ Pad 1
+        showSeries []               = ""
+        showSeries s                = show $ head s
+        getBars' | appLogScale app  = getBars . logScale
+                 | otherwise        = getBars
+
+loopApp :: AppState -> AppEvent -> EventM (Next AppState)
+loopApp app (Terminal (EvKey (KChar 'c') [MCtrl])) = halt app
+loopApp app (Terminal (EvKey KEsc _))              = halt app
+loopApp app _                                      = do
+    newOuts <- liftIO $ zipWithM (runAppCmd maxLen) (appCmds app) (appCmdOuts app)
+    continue $ app { appCmdOuts = newOuts }
+  where maxLen = appSerieSize app
+
+runAppCmd :: Int -> String -> [Double] -> IO [Double]
+runAppCmd maxLen cmd vals = do
+    cmdOut <- runCmd cmd
+    case reads cmdOut of
+        [(v, _)] | v >= 0    -> return $ take maxLen $ v:vals
+                 | otherwise -> error $ printf "negative numeric value: %v (from: %v)" cmdOut cmd
+        _                    -> error $ printf "invalid numeric value: %v (from: %v)" cmdOut cmd
+
+initApp :: AppState -> AppState
+initApp app =
+    let rawCmds       = appCmds app
+        (names, cmds) = unzip $ map splitNameCmd rawCmds
+        emptySeries   = replicate (length rawCmds) []
+    in app { appCmdNames = names, appCmds = cmds, appCmdOuts = emptySeries}
+
+splitNameCmd :: String -> (String, String)
+splitNameCmd s = case span (/= ':') s of
+        (name, cmd) | null name || null cmd -> error $ printf "missing name for command: %v" s
+                    | length cmd < 2        -> error $ printf "missing command: %v" s
+                    | otherwise             -> (name, tail cmd)
+
+runTicker :: Second -> IO (Chan AppEvent)
+runTicker rate = do
+    ch <- newChan
+    void $ forkIO $ forever $ do
+        writeChan ch Tick
+        threadDelay $ fromInteger $ toMicroseconds rate
+    return ch
+
+barChars :: String
+barChars = " ▁▂▃▄▅▆▇█"
+
+getBar :: Double -> Double -> Double -> Char
+getBar min' max' n | min' == max' = barChars !! round (fromIntegral (length barChars) / 2 :: Double)
+                   | otherwise    =
+    let len = fromIntegral $ length barChars
+        wid = (max' - min') / (len - 1)
+        idx = round $ (n - min') / wid
+    in barChars !! idx
+
+getBars :: [Double] -> String
+getBars l = map (getBar (minimum l) (maximum l)) l
+
+logScale :: [Double] -> [Double]
+logScale = map (logBase 10 . (+1))
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+Usage
+-----
+$ termplot                                         \
+	up1:'uptime | awk "{ print \$8 }"'         \
+	mem:'free | awk "/Mem:/ { print \$3 }"'    \
+	wlan0:'iw dev wlan0 link | awk "/bitrate/ { print \$3 }"'
+
+up1   0.0      ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
+mem   150464.0 ▆▇▇██▇▇▇▆▇▇▆▆▆▅▆▆▅▅▅▅▅▇▇▆▅▅▅▄▃▄▂▂
+wlan0 43.3     ▆▆▆▆▆▆▆▆▆▆█▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▄▄ ▄▆▆▄
+
+
++ Inspired by: https://github.com/holman/spark
++ Powered by the awesome library: https://hackage.haskell.org/package/brick
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/termplot.cabal b/termplot.cabal
new file mode 100644
--- /dev/null
+++ b/termplot.cabal
@@ -0,0 +1,29 @@
+name:                termplot
+version:             0.1.0.0
+synopsis:            Plot time series in your terminal using commands stdout
+description:         Use unicode characters to plot fancy time series in real-time in your terminal.
+homepage:            https://github.com/jimenezrick/termplot
+license:             MIT
+license-file:        LICENSE
+author:              Ricardo Catalinas Jiménez <r@untroubled.be>
+maintainer:          Ricardo Catalinas Jiménez <r@untroubled.be>
+copyright:           Copyright (c) 2015 Ricardo Catalinas Jiménez
+category:            Console
+build-type:          Simple
+extra-source-files:  README
+cabal-version:       >=1.10
+
+executable termplot
+  default-language:    Haskell2010
+  ghc-options:         -Wall -threaded
+  main-is:             Main.hs
+  build-depends:       base >=4.8 && <4.9
+                     , time-units >=1.0 && <1.1
+                     , transformers >=0.4 && <0.5
+                     , data-default >=0.5 && <0.6
+                     , vty >=5.4 && <5.5
+                     , brick >=0.2 && <0.3
+                     , optparse-applicative >=0.12 && <0.13
+                     , process >=1.2 && <1.3
+                     , unix >=2.7 && <2.8
+                     , split >=0.2 && <0.3
