diff --git a/bin/rt.js b/bin/rt.js
new file mode 100755
index 0000000..397103c
--- /dev/null
+++ b/bin/rt.js
@@ -0,0 +1,6 @@
+#!/usr/bin/env node
+'use strict';
+var cli = require('../src/cli');
+var exitCode = cli.execute(process.argv);
+/*eslint no-process-exit:0*/
+process.exit(exitCode);
\ No newline at end of file
diff --git a/playground/playground.rt.js b/playground/playground.rt.js
index 45d3009..61cbace 100644
--- a/playground/playground.rt.js
+++ b/playground/playground.rt.js
@@ -15,7 +15,7 @@ module.exports = function () {
     return React.DOM.div({}, React.DOM.div({
         'id': 'myTab',
         'role': 'tabpanel',
-        'className': 'code-area ' + (this.props.direction || 'vertical')
+        'className': 'code-area ' + (this.props.direction === 'horizontal' && 'horizontal' || 'vertical')
     }    /*  Nav tabs  */, React.DOM.ul({
         'className': 'nav nav-pills',
         'role': 'tablist'
@@ -69,7 +69,7 @@ module.exports = function () {
         'readOnly': true
     })))), React.DOM.div({
         'key': 'result-area',
-        'className': 'result-area well ' + (this.props.direction || 'vertical'),
+        'className': 'result-area well ' + (this.props.direction === 'horizontal' && 'horizontal' || 'vertical'),
         'style': { marginTop: '48px' }
     }, React.DOM.h2({}, 'Preview:'), React.DOM.form({
         'className': 'sample-view',
diff --git a/src/api.js b/src/api.js
index a48f386..f4ff5e8 100644
--- a/src/api.js
+++ b/src/api.js
@@ -9,8 +9,9 @@ var convertTemplateToReact = reactTemplates.convertTemplateToReact;
  * @param {string} source
  * @param {{commonJS:boolean}?} options
  * @param {string} target
+ * @param {CONTEXT} context
  */
-function convertFile(source, target, options) {
+function convertFile(source, target, options, context) {
 //    if (path.extname(filename) !== ".html") {
 //        console.log('invalid file, only handle html files');
 //        return;// only handle html files
@@ -19,7 +20,7 @@ function convertFile(source, target, options) {
     var fsUtil = require('./fsUtil');
 
     if (!options.force && !fsUtil.isStale(source, target)) {
-        console.log('target file ' + chalk.cyan(target) + ' is up to date, skipping');
+        context.info('target file ' + chalk.cyan(target) + ' is up to date, skipping');
         return;
     }
 
@@ -34,5 +35,6 @@ function convertFile(source, target, options) {
 module.exports = {
 //    convertTemplateToReact: convertTemplateToReact,
     convertFile: convertFile,
+    context: require('./context'),
     _test: {}
 };
\ No newline at end of file
diff --git a/src/cli.js b/src/cli.js
index 7c1d98e..a546a75 100755
--- a/src/cli.js
+++ b/src/cli.js
@@ -12,26 +12,63 @@ var shell = require('./shell');
 var pkg = require('../package.json');
 var options = {commonJS: false, force: false, json: false};
 
-if (process.argv.length > 2) {
-    var files = [];
-    _.forEach(process.argv.slice(2),function (param) {
+//if (process.argv.length > 2) {
+//    var files = [];
+//    _.forEach(process.argv.slice(2),function (param) {
+//        if (param === '-v' || param === '--version') {
+//            console.log(pkg.version);
+//        } else if (param === '-h' || param === '--help') {
+//            printHelp();
+//        } else if (param === '-c' || param === '--common') {
+//            options.commonJS = true;
+//        } else if (param === '-f' || param === '--force') {
+//            options.force = true;
+//        } else if (param === '-j' || param === '--json') { // TODO use optionator
+//            context.options.format = 'json';
+//        } else if (param !== '--no-color') {
+//            files.push(param);
+//        }
+//    });
+//    _.forEach(files, handleSingleFile);
+//    shell.printResults(context);
+//} else {
+//    printHelp();
+//}
+
+function parseOptions(args) {
+    var parsedOptions = {_: [], version: false, commonJS: false, force: false, format: 'stylish'};
+    _.forEach(args, function (param) {
         if (param === '-v' || param === '--version') {
-            console.log(pkg.version);
+            parsedOptions.version = true;
         } else if (param === '-h' || param === '--help') {
             printHelp();
         } else if (param === '-c' || param === '--common') {
-            options.commonJS = true;
+            parsedOptions.commonJS = true;
         } else if (param === '-f' || param === '--force') {
-            options.force = true;
+            parsedOptions.force = true;
         } else if (param === '-j' || param === '--json') { // TODO use optionator
+            parsedOptions.format = 'json';
             context.options.format = 'json';
-        } else {
-            files.push(param);
+        } else if (param !== '--no-color') {
+            parsedOptions._.push(param);
         }
     });
-    _.forEach(files, handleSingleFile);
-} else {
-    printHelp();
+    return parsedOptions;
+}
+
+function executeOptions(currentOptions) {
+    var ret = 0;
+    if (currentOptions.help) {
+        printHelp();
+    } else if (currentOptions.version) {
+        console.log(pkg.version);
+    } else {
+        _.forEach(currentOptions._, function (f) {
+            handleSingleFile(f, currentOptions);
+        });
+        ret = shell.printResults(context);
+    }
+    return ret;
 }
 
 function printHelp() {
@@ -47,11 +84,12 @@ function printHelp() {
     console.log('  -j, --json           Report output format. [stylish,json]');
 //    console.log('  -ft, --format        Report output format. [stylish,json]');
     console.log('  --common             Use Common JS output. default: false');
+    console.log('  -f --force           Force creation of output. default: false');
 }
 
-function handleSingleFile(filename) {
+function handleSingleFile(filename, currentOptions) {
     if (path.extname(filename) !== '.rt') {
-        console.log('invalid file, only handle rt files');
+        context.error('invalid file, only handle rt files', filename);
         return;// only handle html files
     }
 //    var html = fs.readFileSync(filename).toString();
@@ -62,7 +100,7 @@ function handleSingleFile(filename) {
 //    var js = reactTemplates.convertTemplateToReact(html);
 //    fs.writeFileSync(filename + '.js', js);
     try {
-        api.convertFile(filename, filename + '.js', options);
+        api.convertFile(filename, filename + '.js', currentOptions, context);
     } catch (e) {
         context.error(e.message, filename, e.line || -1, -1, e.index || -1);
 //        if (options.json) {
@@ -74,6 +112,20 @@ function handleSingleFile(filename) {
         // if (options.stack)
         // console.log(e.stack);
     }
+}
 
-    shell.printResults(context);
-}
\ No newline at end of file
+/**
+ * Executes the CLI based on an array of arguments that is passed in.
+ * @param {string|Array|Object} args The arguments to process.
+ * @returns {int} The exit code for the operation.
+ */
+function execute(args) {
+    if (args.length > 2) {
+        var opts = parseOptions(args.slice(2));
+        return executeOptions(opts);
+    }
+    printHelp();
+    return 0;
+}
+
+module.exports = {execute: execute, executeOptions: executeOptions};
\ No newline at end of file
diff --git a/src/context.js b/src/context.js
index 44362a5..dbe4cdf 100644
--- a/src/context.js
+++ b/src/context.js
@@ -49,10 +49,7 @@ var context = {
         context.messages = [];
     },
     hasErrors: function () {
-        var firstError = _.find(context.messages, function(message) {
-            return message.level === MESSAGE_LEVEL.ERROR;
-        });
-        return !!firstError;
+        return _.some(context.messages, {level: MESSAGE_LEVEL.ERROR});
     },
     options: {
         verbose: false,
diff --git a/src/formatters/stylish.js b/src/formatters/stylish.js
index 35e3702..1336bee 100644
--- a/src/formatters/stylish.js
+++ b/src/formatters/stylish.js
@@ -29,17 +29,22 @@ module.exports = function (warnings, config) {
         return n === 1 ? single : plural;
     }
 
-//                    context.report(JSON.stringify(warnings, undefined, 2));
+    function lineText(line) {
+        return line < 1 ? '' : line;
+    }
+
+    // context.report(JSON.stringify(warnings, undefined, 2));
     var output = table(
         warnings.map(function (message) {
             return [
                 '',
-//                                message.line || 0,
-//                                message.column || 0,
+                message.file,
+                lineText(message.line || 0),
+                lineText(message.column || 0),
                 getMessageType(message),
-//                            message.message.replace(/\.$/, ""),
+                // message.message.replace(/\.$/, ""),
                 message.msg
-//                            chalk.gray(message.ruleId)
+                // chalk.gray(message.ruleId)
             ];
         }),
         {
diff --git a/src/reactTemplates.js b/src/reactTemplates.js
index 225806d..1749cbc 100644
--- a/src/reactTemplates.js
+++ b/src/reactTemplates.js
@@ -98,7 +98,11 @@ function generateInjectedFunc(context, namePrefix, body, params) {
     return generatedFuncName;
 }
 
-
+/**
+ * @param {string} html
+ * @param node
+ * @return {number}
+ */
 function getLine(html, node) {
     if (!node) {
         return 0;
@@ -360,5 +364,6 @@ function convertTemplateToReact(html, options) {
 
 module.exports = {
     convertTemplateToReact: convertTemplateToReact,
+    RTCodeError: RTCodeError,
     _test: {}
 };
diff --git a/test/data/invalid-scope.rt b/test/data/invalid-scope.rt
new file mode 100644
index 0000000..7bce3e7
--- /dev/null
+++ b/test/data/invalid-scope.rt
@@ -0,0 +1,3 @@
+<!doctype rt>
+<div rt-scope="a in a in a">
+</div
\ No newline at end of file
diff --git a/test/src/test.js b/test/src/test.js
index 2a23719..de1f7d5 100644
--- a/test/src/test.js
+++ b/test/src/test.js
@@ -9,6 +9,36 @@ var cheerio = require('cheerio');
 
 var dataPath = path.resolve(__dirname, '..', 'data');
 
+test('invalid tests', function (t) {
+    var files = [
+        {file: 'invalid-scope.rt', issue: new reactTemplates.RTCodeError('invalid scope part \'a in a in a\'', 14, 1)}
+    ];
+    t.plan(files.length);
+
+    files.forEach(check);
+
+    function check(testFile) {
+        var filename = path.join(dataPath, testFile.file);
+        var html = fs.readFileSync(filename).toString();
+        var error = null;
+        try {
+            reactTemplates.convertTemplateToReact(html);
+        } catch (e) {
+            error = e;
+        }
+        t.deepEqual(errorEqual(error), errorEqual(testFile.issue), 'Expect convertTemplateToReact to throw an error');
+    }
+});
+
+function errorEqual(err) {
+    return {
+        index: err.index,
+        line: err.line,
+        message: err.message,
+        name: err.name
+    };
+}
+
 test('conversion test', function (t) {
     var files = ['div.rt', 'test.rt', 'repeat.rt'];
     t.plan(files.length);
@@ -36,7 +66,7 @@ function normalizeHtml(html) {
 }
 
 test('html tests', function (t) {
-    var files = ['scope.rt', 'lambda.rt','eval.rt', 'props.rt'];
+    var files = ['scope.rt', 'lambda.rt', 'eval.rt', 'props.rt'];
     t.plan(files.length);
 
     files.forEach(check);
@@ -49,10 +79,10 @@ test('html tests', function (t) {
         var code = reactTemplates.convertTemplateToReact(html).replace(/\r/g, '');
         var defineMap = {react: React, lodash: _};
         var define = function (requirementsNames, content) {
-            var requirements = _.map(requirementsNames,function (reqName) {
+            var requirements = _.map(requirementsNames, function (reqName) {
                 return defineMap[reqName];
             });
-            return content.apply(this,requirements);
+            return content.apply(this, requirements);
         };
         var comp = React.createFactory(React.createClass({
             render: eval(code)