diff --git a/language-dockerfile.cabal b/language-dockerfile.cabal
--- a/language-dockerfile.cabal
+++ b/language-dockerfile.cabal
@@ -1,9 +1,9 @@
--- This file has been generated from package.yaml by hpack version 0.14.0.
+-- This file has been generated from package.yaml by hpack version 0.17.0.
 --
 -- see: https://github.com/sol/hpack
 
 name:           language-dockerfile
-version:        0.3.5.0
+version:        0.3.6.0
 synopsis:       Dockerfile linter, parser, pretty-printer and embedded DSL
 description:     Forked from @hadolint@.
                 .
@@ -61,9 +61,17 @@
     , template-haskell
     , th-lift
     , th-lift-instances
+    , text
+    , yaml
+    , aeson
+    , Glob
+    , unordered-containers
+    , directory
+    , filepath
   exposed-modules:
       Language.Dockerfile
       Language.Dockerfile.Parser
+      Language.Dockerfile.Predef
       Language.Dockerfile.PrettyPrint
       Language.Dockerfile.Normalize
       Language.Dockerfile.Rules
@@ -97,6 +105,13 @@
     , template-haskell
     , th-lift
     , th-lift-instances
+    , text
+    , yaml
+    , aeson
+    , Glob
+    , unordered-containers
+    , directory
+    , filepath
     , language-dockerfile
   buildable: False
   if flag(dockerfmt)
@@ -122,6 +137,13 @@
     , template-haskell
     , th-lift
     , th-lift-instances
+    , text
+    , yaml
+    , aeson
+    , Glob
+    , unordered-containers
+    , directory
+    , filepath
     , language-dockerfile
   buildable: False
   if flag(hadolint)
@@ -135,7 +157,7 @@
   main-is: Test.hs
   hs-source-dirs:
       src
-    , test
+      test
   build-depends:
       ShellCheck
     , base >=4.8 && <5
@@ -149,6 +171,13 @@
     , template-haskell
     , th-lift
     , th-lift-instances
+    , text
+    , yaml
+    , aeson
+    , Glob
+    , unordered-containers
+    , directory
+    , filepath
     , HUnit >=1.2
     , test-framework
     , test-framework-hunit
@@ -163,6 +192,7 @@
       Language.Dockerfile.Lexer
       Language.Dockerfile.Normalize
       Language.Dockerfile.Parser
+      Language.Dockerfile.Predef
       Language.Dockerfile.PrettyPrint
       Language.Dockerfile.Rules
       Language.Dockerfile.Syntax
@@ -194,6 +224,13 @@
     , template-haskell
     , th-lift
     , th-lift-instances
+    , text
+    , yaml
+    , aeson
+    , Glob
+    , unordered-containers
+    , directory
+    , filepath
     , hspec
     , QuickCheck
     , language-dockerfile
diff --git a/src/Language/Dockerfile/Lexer.hs b/src/Language/Dockerfile/Lexer.hs
--- a/src/Language/Dockerfile/Lexer.hs
+++ b/src/Language/Dockerfile/Lexer.hs
@@ -7,12 +7,24 @@
 lexer :: Token.TokenParser ()
 lexer = Token.makeTokenParser style -- style
   where
-    names = ["FROM","ADD","RUN","WORKDIR","EXPOSE","VOLUME","ENTRYPOINT","MAINTAINER","ENV","LABEL","USER","STOPSIGNAL","CMD", "ONBUILD", "ARG"]
-    style = emptyDef {
-        -- Token.commentLine = "#",
-             -- ,
-             Token.reservedNames = names
-             }
+    names =
+      [ "FROM"
+      , "ADD"
+      , "RUN"
+      , "WORKDIR"
+      , "EXPOSE"
+      , "VOLUME"
+      , "ENTRYPOINT"
+      , "MAINTAINER"
+      , "ENV"
+      , "LABEL"
+      , "USER"
+      , "STOPSIGNAL"
+      , "CMD"
+      , "ONBUILD"
+      , "ARG"
+      ]
+    style = emptyDef {Token.caseSensitive = False, Token.reservedNames = names}
 
 reserved :: String -> Parser ()
 reserved = Token.reserved lexer
diff --git a/src/Language/Dockerfile/Predef.hs b/src/Language/Dockerfile/Predef.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Dockerfile/Predef.hs
@@ -0,0 +1,115 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+module Language.Dockerfile.Predef
+  where
+
+import           Control.Monad
+import           Control.Monad.Free.Class
+import           Control.Monad.IO.Class
+import           Data.Aeson                     (Value (..))
+import qualified Data.HashMap.Strict            as HashMap
+import           Data.Maybe
+import           Data.Monoid
+import           Data.Text                      (Text)
+import qualified Data.Text                      as Text
+import qualified Data.Text.IO                   as Text
+import qualified Data.Yaml                      as Yaml
+import           System.Directory
+import           System.FilePath
+import qualified System.FilePath.Glob           as Glob
+
+import           Language.Dockerfile
+import           Language.Dockerfile.EDSL.Types
+
+appendLnIfMissing :: FilePath -> Text -> IO ()
+appendLnIfMissing fp cts = do
+    e <- doesFileExist fp
+    unless e (Text.writeFile fp "")
+    txt <- Text.lines <$> Text.readFile fp
+    unless (cts `elem` txt) $
+        Text.writeFile fp (Text.unlines (txt <> [cts]))
+
+dockerIgnore :: Text -> IO ()
+dockerIgnore = appendLnIfMissing ".dockerignore"
+
+addGlob
+  :: (MonadIO m, MonadFree EInstruction m) =>
+     String -> Destination -> m ()
+addGlob pattern dest = do
+    fs <- liftIO $ do
+        fs <- Glob.glob pattern
+        cwd <- getCurrentDirectory
+        let fs' = map (makeRelative cwd . normalise) fs
+        forM fs' $ \f -> do
+             isdir <- doesDirectoryExist f
+             return $ if isdir
+                 then (f <> "/", dest <> takeBaseName f)
+                 else (f, dest <> takeBaseName f)
+    forM_ fs (uncurry add)
+
+copyGlob
+  :: (MonadIO m, MonadFree EInstruction m) =>
+     String -> Destination -> m ()
+copyGlob = addGlob
+
+stackBuild
+  :: (Monad m, MonadIO m,
+      MonadFree EInstruction m) =>
+     m ()
+stackBuild = do
+    sts <- liftIO getStackYamlResolver
+    stackBuild' sts (return ())
+  where
+    getStackYamlResolver = do
+        mhm <- Yaml.decodeFile "./stack.yaml" :: IO (Maybe Value)
+        return $ fromMaybe "latest" $ do
+            hm <- mhm
+            o <- case hm of
+                Object o -> return o
+                _ -> Nothing
+            rs <- HashMap.lookup "resolver" o
+            toString rs
+      where
+        toString (String m) = Just (Text.unpack m)
+        toString _ = Nothing
+
+stackBuild'
+  :: (Monad m, MonadIO m,
+      MonadFree EInstruction m) =>
+     String -> m () -> m ()
+stackBuild' tag extra = do
+    liftIO $ dockerIgnore ".stack-work"
+    liftIO $ dockerIgnore ".cabal-sandbox"
+
+    from ("fpco" `tagged` tag)
+    extra
+    add "./package.yaml" "/app/package.yaml"
+    addGlob "./*.cabal" "/app/"
+    add "./stack.yaml" "/app/stack.yaml"
+    workdir "/app/"
+    run "stack build --only-dependencies"
+    add "." "/app/stack.yaml"
+    run "stack build"
+
+nodejs
+  :: (Monad m, MonadIO m,
+      MonadFree EInstruction m) =>
+     m ()
+nodejs = nodejs' "6" (return ())
+
+nodejs'
+  :: (Monad m, MonadIO m,
+      MonadFree EInstruction m) =>
+     String -> m () -> m ()
+nodejs' tag extra = do
+    liftIO $ dockerIgnore "node_modules"
+    liftIO $ dockerIgnore "bower_components"
+
+    from ("node" `tagged` tag)
+    extra
+    add "./package.json" "/app/package.json"
+    workdir "/app/"
+    run "npm install"
+    add "." "/app/"
+    cmd "npm start"
diff --git a/test/Language/Dockerfile/ParserSpec.hs b/test/Language/Dockerfile/ParserSpec.hs
--- a/test/Language/Dockerfile/ParserSpec.hs
+++ b/test/Language/Dockerfile/ParserSpec.hs
@@ -7,8 +7,14 @@
 import           Text.Parsec
 
 spec :: Spec
-spec =
-    describe "expose" $ do
-        it "should handle number ports" $ do
-            let content = "EXPOSE 8080"
-            parse expose "" content `shouldBe` Right (Expose (Ports [8080]))
+spec = do
+  describe "expose" $ do
+    it "should handle number ports" $ do
+      let content = "EXPOSE 8080"
+      parse expose "" content `shouldBe` Right (Expose (Ports [8080]))
+  describe "syntax" $ do
+    it
+      "should handle lowercase instructions (#7 - https://github.com/beijaflor-io/haskell-language-dockerfile/issues/7)" $ do
+      let content = "from ubuntu"
+      parse dockerfile "" content `shouldBe`
+        Right [InstructionPos (From (UntaggedImage "ubuntu")) "" 1]
