diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Revision history for drmaa
+
+## 0.1.0.0  -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, Kai Zhang
+
+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 Kai Zhang 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/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/drmaa.cabal b/drmaa.cabal
new file mode 100644
--- /dev/null
+++ b/drmaa.cabal
@@ -0,0 +1,37 @@
+-- Initial drmaa.cabal generated by cabal init.  For further documentation,
+--  see http://haskell.org/cabal/users-guide/
+
+name:                drmaa
+version:             0.1.0.0
+synopsis:            A simple Haskell bindings to DRMAA C library.
+description:         A simple Haskell bindings to DRMAA C library.
+license:             BSD3
+license-file:        LICENSE
+author:              Kai Zhang
+maintainer:          kai@kzhang.org
+-- copyright:
+category:            Language
+build-type:          Simple
+extra-source-files:  ChangeLog.md
+cabal-version:       >=1.10
+
+library
+  ghc-options:         -Wall
+  exposed-modules:
+    DRMAA
+
+  -- other-modules:
+  -- other-extensions:
+  build-depends:
+      base >=4.7 && <5.0
+    , bytestring
+    , binary
+    , async
+    , inline-c
+    , text
+    , shelly
+
+  hs-source-dirs:      src
+  c-sources:           src/DRMAA.c
+  extra-libraries:     drmaa
+  default-language:    Haskell2010
diff --git a/src/DRMAA.c b/src/DRMAA.c
new file mode 100644
--- /dev/null
+++ b/src/DRMAA.c
@@ -0,0 +1,146 @@
+
+#include "stddef.h"
+
+#include "stdio.h"
+
+#include "drmaa.h"
+
+int inline_c_DRMAA_0_54e600eaaa1f15b2d247a7799eeb2c2626774aa9(char * ptr_inline_c_0) {
+
+        int errnum = 0;
+        errnum = drmaa_init (NULL, ptr_inline_c_0, DRMAA_ERROR_STRING_BUFFER);
+        if (errnum != DRMAA_ERRNO_SUCCESS) {
+            return 1;
+        }
+        return 0;
+        
+}
+
+
+int inline_c_DRMAA_1_df791815daa185d543e0513c42f96dbbd8b8b214() {
+
+        char error[DRMAA_ERROR_STRING_BUFFER];
+        int errnum = 0;
+        errnum = drmaa_exit (error, DRMAA_ERROR_STRING_BUFFER);
+        if (errnum != DRMAA_ERRNO_SUCCESS) {
+            fprintf (stderr, "Could not shut down the DRMAA library: %s\n", error);
+            return 1;
+        }
+        return 0;
+        
+}
+
+
+int inline_c_DRMAA_2_8569c20fd54d45f727dd1560458a1febedbc42e1(char * wd_inline_c_0, const char ** envPtr_inline_c_1, char * native_inline_c_2, char * c_exec_inline_c_3, const char ** aptr_inline_c_4) {
+
+            int exception = 0;
+            char error[DRMAA_ERROR_STRING_BUFFER];
+            int errnum = 0;
+            drmaa_job_template_t *jt = NULL;
+
+            errnum = drmaa_allocate_job_template (&jt, error, DRMAA_ERROR_STRING_BUFFER);
+
+            if (errnum != DRMAA_ERRNO_SUCCESS) {
+                fprintf (stderr, "Could not create job template: %s\n", error);
+            } else {
+                /* set options */
+                errnum = drmaa_set_attribute (jt, DRMAA_WD, wd_inline_c_0,
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+                errnum = drmaa_set_vector_attribute (jt, DRMAA_V_ENV, envPtr_inline_c_1,
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+                errnum = drmaa_set_attribute (jt, DRMAA_NATIVE_SPECIFICATION, native_inline_c_2,
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+
+                errnum = drmaa_set_attribute (jt, DRMAA_REMOTE_COMMAND, c_exec_inline_c_3,
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+                if (errnum != DRMAA_ERRNO_SUCCESS) {
+                    fprintf (stderr, "Could not set attribute \"%s\": %s\n",
+                            DRMAA_REMOTE_COMMAND, error);
+                } else {
+                    errnum = drmaa_set_vector_attribute (jt, DRMAA_V_ARGV, aptr_inline_c_4, error,
+                                                        DRMAA_ERROR_STRING_BUFFER);
+                }
+
+                if (errnum != DRMAA_ERRNO_SUCCESS) {
+                    fprintf (stderr, "Could not set attribute \"%s\": %s\n",
+                            DRMAA_REMOTE_COMMAND, error);
+                } else {
+                    char jobid[DRMAA_JOBNAME_BUFFER];
+                    char jobid_out[DRMAA_JOBNAME_BUFFER];
+                    int status = 0;
+                    drmaa_attr_values_t *rusage = NULL;
+
+                    errnum = drmaa_run_job (jobid, DRMAA_JOBNAME_BUFFER, jt, error,
+                                           DRMAA_ERROR_STRING_BUFFER);
+
+                    if (errnum != DRMAA_ERRNO_SUCCESS) {
+                        fprintf (stderr, "Could not submit job: %s\n", error);
+                        exception = 1;
+                    } else {
+                        printf ("Your job has been submitted with id %s\n", jobid);
+
+                        errnum = drmaa_wait (jobid, jobid_out, DRMAA_JOBNAME_BUFFER, &status,
+                                            DRMAA_TIMEOUT_WAIT_FOREVER, &rusage, error,
+                                            DRMAA_ERROR_STRING_BUFFER);
+
+                        if (errnum != DRMAA_ERRNO_SUCCESS) {
+                            fprintf (stderr, "Could not wait for job: %s\n", error);
+                            exception = 1;
+                        } else {
+                            char usage[DRMAA_ERROR_STRING_BUFFER];
+                            int aborted = 0;
+
+                            drmaa_wifaborted(&aborted, status, NULL, 0);
+
+                            if (aborted == 1) {
+                                printf("Job %s never ran\n", jobid);
+                                exception = 1;
+                            } else {
+                                int exited = 0;
+
+                                drmaa_wifexited(&exited, status, NULL, 0);
+
+                                if (exited == 1) {
+                                    int exit_status = 0;
+
+                                    drmaa_wexitstatus(&exit_status, status, NULL, 0);
+                                    printf("Job %s finished regularly with exit status %d\n", jobid, exit_status);
+                                    exception = exit_status;
+                                } else {
+                                    int signaled = 0;
+
+                                    drmaa_wifsignaled(&signaled, status, NULL, 0);
+
+                                    if (signaled == 1) {
+                                        char termsig[DRMAA_SIGNAL_BUFFER+1];
+
+                                        drmaa_wtermsig(termsig, DRMAA_SIGNAL_BUFFER, status, NULL, 0);
+                                        printf("Job %s finished due to signal %s\n", jobid, termsig);
+                                    } else {
+                                        printf("Job %s finished with unclear conditions\n", jobid);
+                                    }
+                                } /* else */
+                            } /* else */
+
+                            printf ("Job Usage:\n");
+
+                            while (drmaa_get_next_attr_value (rusage, usage, DRMAA_ERROR_STRING_BUFFER) == DRMAA_ERRNO_SUCCESS) {
+                                printf ("  %s\n", usage);
+                            }
+
+                            drmaa_release_attr_values (rusage);
+                        } /* else */
+                    } /* else */
+                } /* else */
+
+                errnum = drmaa_delete_job_template (jt, error, DRMAA_ERROR_STRING_BUFFER);
+
+                if (errnum != DRMAA_ERRNO_SUCCESS) {
+                    fprintf (stderr, "Could not delete job template: %s\n", error);
+                }
+            } /* else */
+
+            return exception;
+            
+}
+
diff --git a/src/DRMAA.hs b/src/DRMAA.hs
new file mode 100644
--- /dev/null
+++ b/src/DRMAA.hs
@@ -0,0 +1,214 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes       #-}
+{-# LANGUAGE TemplateHaskell   #-}
+module DRMAA where
+
+import           Control.Exception        (bracket_, bracket)
+import qualified Data.Text                as T
+import           Shelly                   hiding (FilePath, withTmpDir)
+
+import           Foreign.C.String
+import           Foreign.Marshal.Alloc
+import           Foreign.Marshal.Array
+import           Foreign.Ptr
+import qualified Language.C.Inline        as C
+
+C.include "stddef.h"
+C.include "stdio.h"
+C.include "drmaa.h"
+
+withTmpFile :: FilePath -> (FilePath -> IO a) -> IO a
+withTmpFile dir = bracket create delete
+  where
+    create = shelly $ fmap (T.unpack . head . T.lines) $ silently $
+        run "mktemp" [T.pack $ dir ++ "/tmp_file_XXXXXXXX_delete.me"]
+    delete = shelly . rm_f . fromText . T.pack
+
+withTmpDir :: FilePath -> (FilePath -> IO a) -> IO a
+withTmpDir dir = bracket create delete
+  where
+    create = shelly $ fmap (T.unpack . head . T.lines) $ silently $
+        run "mktemp" ["-d", T.pack $ dir ++ "/tmp_dir_XXXXXXXX_delete.me"]
+    delete = shelly . rm_rf . fromText . T.pack
+
+withSGESession :: IO a -> IO a
+withSGESession f = bracket_ drmaaInit drmaaExit f
+
+drmaaScript :: String -> DrmaaAttribute -> IO ()
+drmaaScript script config = bracket
+    (shelly $ fmap (T.unpack . head . T.lines) $ silently $ run "mktemp" [template])
+    (shelly . rm . fromText . T.pack)
+    $ \tmpFl -> do
+        writeFile tmpFl $ "#!/bin/sh\n" ++ script
+        shelly $ run_ "chmod" ["+x", T.pack tmpFl]
+        drmaaRun tmpFl [] config
+  where
+    template = T.pack $ drmaa_wd config ++ "/drmaa_script.XXXXXXXX.delete.me.sh"
+
+-- | Initialize a session
+drmaaInit :: IO ()
+drmaaInit = alloca $ \ptr -> do
+    status <- [C.block| int {
+        int errnum = 0;
+        errnum = drmaa_init (NULL, $(char* ptr), DRMAA_ERROR_STRING_BUFFER);
+        if (errnum != DRMAA_ERRNO_SUCCESS) {
+            return 1;
+        }
+        return 0;
+        }|]
+    case status of
+        0 -> putStrLn "DRMAA session started"
+        _ -> peekCString ptr >>= error
+
+drmaaExit :: IO ()
+drmaaExit = do
+    r <- [C.block| int {
+        char error[DRMAA_ERROR_STRING_BUFFER];
+        int errnum = 0;
+        errnum = drmaa_exit (error, DRMAA_ERROR_STRING_BUFFER);
+        if (errnum != DRMAA_ERRNO_SUCCESS) {
+            fprintf (stderr, "Could not shut down the DRMAA library: %s\n", error);
+            return 1;
+        }
+        return 0;
+        }|]
+    case r of
+        0 -> putStrLn "DRMAA session closed"
+        _ -> error "Exit 1"
+
+data DrmaaAttribute = DrmaaAttribute
+    { drmaa_wd     :: !FilePath
+    , drmaa_env :: ![(String, String)]
+    , drmaa_native :: !String
+    } deriving (Show, Read)
+
+defaultDrmaaConfig :: DrmaaAttribute
+defaultDrmaaConfig = DrmaaAttribute
+    { drmaa_wd = "./"
+    , drmaa_env = [ ("DRMAA_ENV_HAS_SET", "True") ]
+    , drmaa_native = ""
+    }
+
+drmaaRun :: FilePath -> [String] -> DrmaaAttribute -> IO ()
+drmaaRun exec args config = do
+    c_exec <- newCString exec
+    c_args <- mapM newCString args
+
+    -- options
+    wd <- newCString $ drmaa_wd config
+    env <- mapM (\(a,b) -> newCString $ a ++ "=" ++ b) $ drmaa_env config
+    native <- newCString $ drmaa_native config
+
+    e <- withArray (c_args++[nullPtr]) $ \aptr ->
+        withArray (env ++ [nullPtr]) $ \envPtr -> do
+            [C.block| int {
+            int exception = 0;
+            char error[DRMAA_ERROR_STRING_BUFFER];
+            int errnum = 0;
+            drmaa_job_template_t *jt = NULL;
+
+            errnum = drmaa_allocate_job_template (&jt, error, DRMAA_ERROR_STRING_BUFFER);
+
+            if (errnum != DRMAA_ERRNO_SUCCESS) {
+                fprintf (stderr, "Could not create job template: %s\n", error);
+            } else {
+                /* set options */
+                errnum = drmaa_set_attribute (jt, DRMAA_WD, $(char* wd),
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+                errnum = drmaa_set_vector_attribute (jt, DRMAA_V_ENV, $(const char** envPtr),
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+                errnum = drmaa_set_attribute (jt, DRMAA_NATIVE_SPECIFICATION, $(char* native),
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+
+                errnum = drmaa_set_attribute (jt, DRMAA_REMOTE_COMMAND, $(char* c_exec),
+                                             error, DRMAA_ERROR_STRING_BUFFER);
+                if (errnum != DRMAA_ERRNO_SUCCESS) {
+                    fprintf (stderr, "Could not set attribute \"%s\": %s\n",
+                            DRMAA_REMOTE_COMMAND, error);
+                } else {
+                    errnum = drmaa_set_vector_attribute (jt, DRMAA_V_ARGV, $(const char** aptr), error,
+                                                        DRMAA_ERROR_STRING_BUFFER);
+                }
+
+                if (errnum != DRMAA_ERRNO_SUCCESS) {
+                    fprintf (stderr, "Could not set attribute \"%s\": %s\n",
+                            DRMAA_REMOTE_COMMAND, error);
+                } else {
+                    char jobid[DRMAA_JOBNAME_BUFFER];
+                    char jobid_out[DRMAA_JOBNAME_BUFFER];
+                    int status = 0;
+                    drmaa_attr_values_t *rusage = NULL;
+
+                    errnum = drmaa_run_job (jobid, DRMAA_JOBNAME_BUFFER, jt, error,
+                                           DRMAA_ERROR_STRING_BUFFER);
+
+                    if (errnum != DRMAA_ERRNO_SUCCESS) {
+                        fprintf (stderr, "Could not submit job: %s\n", error);
+                        exception = 1;
+                    } else {
+                        printf ("Your job has been submitted with id %s\n", jobid);
+
+                        errnum = drmaa_wait (jobid, jobid_out, DRMAA_JOBNAME_BUFFER, &status,
+                                            DRMAA_TIMEOUT_WAIT_FOREVER, &rusage, error,
+                                            DRMAA_ERROR_STRING_BUFFER);
+
+                        if (errnum != DRMAA_ERRNO_SUCCESS) {
+                            fprintf (stderr, "Could not wait for job: %s\n", error);
+                            exception = 1;
+                        } else {
+                            char usage[DRMAA_ERROR_STRING_BUFFER];
+                            int aborted = 0;
+
+                            drmaa_wifaborted(&aborted, status, NULL, 0);
+
+                            if (aborted == 1) {
+                                printf("Job %s never ran\n", jobid);
+                                exception = 1;
+                            } else {
+                                int exited = 0;
+
+                                drmaa_wifexited(&exited, status, NULL, 0);
+
+                                if (exited == 1) {
+                                    int exit_status = 0;
+
+                                    drmaa_wexitstatus(&exit_status, status, NULL, 0);
+                                    printf("Job %s finished regularly with exit status %d\n", jobid, exit_status);
+                                    exception = exit_status;
+                                } else {
+                                    int signaled = 0;
+
+                                    drmaa_wifsignaled(&signaled, status, NULL, 0);
+
+                                    if (signaled == 1) {
+                                        char termsig[DRMAA_SIGNAL_BUFFER+1];
+
+                                        drmaa_wtermsig(termsig, DRMAA_SIGNAL_BUFFER, status, NULL, 0);
+                                        printf("Job %s finished due to signal %s\n", jobid, termsig);
+                                    } else {
+                                        printf("Job %s finished with unclear conditions\n", jobid);
+                                    }
+                                } /* else */
+                            } /* else */
+
+                            printf ("Job Usage:\n");
+
+                            while (drmaa_get_next_attr_value (rusage, usage, DRMAA_ERROR_STRING_BUFFER) == DRMAA_ERRNO_SUCCESS) {
+                                printf ("  %s\n", usage);
+                            }
+
+                            drmaa_release_attr_values (rusage);
+                        } /* else */
+                    } /* else */
+                } /* else */
+
+                errnum = drmaa_delete_job_template (jt, error, DRMAA_ERROR_STRING_BUFFER);
+
+                if (errnum != DRMAA_ERRNO_SUCCESS) {
+                    fprintf (stderr, "Could not delete job template: %s\n", error);
+                }
+            } /* else */
+
+            return exception;
+            }|]
+    if e /= 0 then error ("status=" ++ show e) else return ()
