Compiler cleanup with examples (#53)

diff --git a/.gitignore b/.gitignore
index 793f57e..d490e01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,3 +44,11 @@
 # VSCode
 .vscode
 
+# examples
+exec
+*.done
+*.zip
+*_launcher_.go
+test.json
+pkg/
+bin/
diff --git a/CREDITS.txt b/CREDITS.txt
index 0b41824..f3d5e6a 100644
--- a/CREDITS.txt
+++ b/CREDITS.txt
@@ -1,3 +1,7 @@
 Michele Sciabarra <michele@sciabarra.com>
 
-James Thomas <jthomas.uk@gmail.com>
\ No newline at end of file
+Carlos Santana 
+
+Rodric Rabbah <rodric@gmail.com>
+
+James Thomas <jthomas.uk@gmail.com>
diff --git a/README.md b/README.md
index 74c44d9..8a0dc0b 100644
--- a/README.md
+++ b/README.md
@@ -16,191 +16,21 @@
 # limitations under the License.
 #
 -->
-
 # Apache OpenWhisk Runtime for Go (and Generic executables)
 
 [![Build Status](https://travis-ci.org/apache/incubator-openwhisk-runtime-go.svg?branch=master)](https://travis-ci.org/apache/incubator-openwhisk-runtime-go)
 [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)
 [![Join Slack](https://img.shields.io/badge/join-slack-9B69A0.svg)](http://slack.openwhisk.org/)
 
-:warning: Work in progress :warning:
-
 This is an OpenWhisk runtime for Golang and Generic executables.
 
-- [Building it](#building)
-- [Developing it](#development)
-- [Using it with Go Sources](#gosources)
-- [Precompiling Go Sources](#precompile)
-- [Using it with Generic executables](#generic)
-
-<a name="building"/>
-
-# How to Build and Test
-
-You need a Linux or an OSX environment, with Java and Docker installed to build the sources.
-
-Prerequisites for running build and tests with gradle:
-
-- docker
-- jdk
-
-
-To compile go proxy *in amd64 architecture* for docker:
-
-```
-./gradlew build
-```
-
-To build the docker images after compiling go proxy:
-
-```
-./gradlew distDocker
-```
-
-This will build the images:
-
-* `actionloop-golang-v1.11`: an image supporting  Go sources
-* `actionloop`: the base image, supporting generic executables ans shell script
-
-The `actionloop` image can be used for supporting other compiled programming languages as long as they implement a `compile` script and the *action loop* protocol described below.
-
-To run tests
-```
-./gradlew test --info
-```
-<a name="development"/>
-
-# Local Development
-
-If you want to develop the proxy and run tests natively, you can on Linux or OSX.
-Tested on Ubuntu Linux (14.04) and OSX 10.13. Probably other distributions work, maybe even Windows with WSL, but since it is not tested YMMMV.
-
-You need of course [go 1.11.0](https://golang.org/doc/install)
-
-Then you need a set of utilities used in tests:
-
-- bc
-- zip
-- realpath
-
-Linux: `apt-get install bc zip realpath`
-OSX: `brew install zip coreutils`
-
-**NOTE**: Because tests build and cache some binary files, perform a `git clean -fx` and **do not share folders between linux and osx** because binaries are in different format...
-
-
-<a name="gosources"/>
-
-# Using it with Go Sources
-
-The image can execute, compiling them on the fly, Golang OpenWhisk actions in source format.
-
-An action must be a Go source file, placed in the `main` package and your action.
-
-Since `main.main` is reserved in Golang for the entry point of your program, and the entry point is used by support code, your action must be named `Main` (with capital `M`) even if your specify `main` as the name of the action (or you do not specify it, defaulting to `main`). If you specify a function name different than `main` the name of your functino  does not need to be capitalized.
-
-The expected signature for a `main` function is:
-
-`func Main(event map[string]interface{}) map[string]interface{}`
-
-For example:
-
-```go
-package main
-
-import "log"
-
-// Main is the function implementing the action
-func Main(obj map[string]interface{}) map[string]interface{} {
-  // do your work
-  name, ok := obj["name"].(string)
-  if !ok {
-    name = "Stranger"
-  }
-  msg := make(map[string]interface{})
-  msg["message"] = "Hello, " + name + "!"
-  // log in stdout or in stderr
-  log.Printf("name=%s\n", name)
-  // encode the result back in json
-  return msg
-}
-```
-
-You can also have multiple source files in an action. In this case you need to collect all the sources  in a zip file for posting.
-
-<a name="precompile"/>
-
-## Precompiling Go Sources Offline
-
-Compiling sources on the image can take some time when the images is initialised. You can speed up precompiling the sources using the image as an offline compiler. You need `docker` for doing that.
-
-The images accepts a `-compile <main>` flag, and expects you provide sources in standard input. It will then compile them, emit the binary in standard output and errors in stderr.
-
-If you have docker, you can do it this way:
-
-If you have a single source maybe in file `main.go`, with a function named `Main` just do this:
-
-`cat main.go | docker run openwhisk/actionloop-golang-v1.11 -compile main >main`
-
-If you have multiple sources in current directory, even with a subfolder with sources, you can compile it all with:
-
-`zip -r - * | docker run openwhisk/actionloop-golang-v1.11 -compile main >main`
-
-The  generated executable is suitable to be deployed in openwhisk:
-
-`wsk action create my/action main -docker openwhisk/actionloop-golang-v1.11`
-
-Note that the output is always in Linux AMS64 format so the executable can be run only inside a Docker Linux container.
-
-<a name="generic"/>
-
-# Using it with generic Binaries
-
-The `actionloop` image is designed to support generic linux executable in an efficient way.
-
-As such it works with any executable that supports the following simple protocol:
-
-Repeat forever:
-- read one line from standard input (file descriptor 0)
-- parse the line as a json object, that will be in format:
-
-```{
- "value": JSON,
- "namespace": String,
- "action_name": String,
- "api_host": String,
- "api_key": String,
- "activation_id": String,
- "deadline": Number
-}```
-
-Note that if you use libraries, those will expect the values in enviroment variables:
-
-- `__OW_NAMESPACE`
-- `__OW_ACTION_NAME`
-- `__OW_API_HOST`
-- `__OW_API_KEYS`
-- `__OW_ACTIVATION_ID`
-- `__OW_DEADLINE`
-
-- execute the action, using the `value` that contains the payload provided by the used and logging in standard output and in standard error (file descriptor 1 and 2)
-- write an answer in json format as a single line (without embedding newlines - newlines in strings must be quoted)
-
-The `actionloop` image works actually with executable in unix sense, so also scripts are acceptable. In the actionloop image there is `bash` and the `jq` command, so you can for example implement the actionloop with a shell script:
-
-```bash
-#!/bin/bash
-# read input forever line by line
-while read line
-do
-   # parse the in input with `jq`
-   name="$(echo $line | jq -r .name.value)"
-   # log in stdout
-   echo msg="hello $name"
-   # produce the result - note the fd3
-   echo '{"hello": "'$name'"}' >&3
-done
-```
-
-Note the `actionloop` image will accept any source and will try to run it (if it is possible), while the `actionloop-golang`  images will try to compile the sources instead.
+- If you are in a hurry, check the [examples](examples/EXAMPLES.md)
+- Writing Actions for the runtime in [Golang](docs/ACTION.md#golang)
+- How to deploy your [Golang](docs/DEPLOY.md#golang) sources
+- Precompiling [Golang](docs/DEPLOY.md#precompile) actions
+- Writing [Generic](docs/ACTION.md#generic) actions,  in bash or as a generic linux binary
+- Deployment for [Generic](docs/DEPLOY.md#generic)   actions
+- The [ActionLoop](docs/ACTION.md#actionloop) protocol for generic actions
+- How to use VSCode to write [Golang](docs/DEPLOY.md#vscode) actions
+- How to [Build](docs/BUILD.md#building) the runtime, with development notes
 
diff --git a/build.gradle b/build.gradle
index d3748e5..b2c8867 100644
--- a/build.gradle
+++ b/build.gradle
@@ -31,7 +31,7 @@
 dependencies {
     golang {
         build 'github.com/h2non/filetype@v1.0.5'
-        build 'github.com/apache/incubator-openwhisk-client-go#e452b524cd745f71c913c5acccf72a8daba6dc71'
+        build 'github.com/sirupsen/logrus@v1.1.0'
         test 'github.com/stretchr/testify@v1.2.1'
     }
 }
diff --git a/common/gobuild.py b/common/gobuild.py
index fe616e6..053ed69 100755
--- a/common/gobuild.py
+++ b/common/gobuild.py
@@ -26,40 +26,41 @@
 
 def sources(launcher, source_dir, main):
 
-    # if you choose main, then it must be upper case
-    func = "Main" if main == "main" else main
-
-    # copy the uploaded main code, if it exists
-    src = "%s/%s" % (source_dir, main)
+    func = main.capitalize()
     has_main = None
+
+    # copy the exec to exec.go
+    # also check if it has a main in it
+    src = "%s/exec" % source_dir
+    dst = "%s/exec__.go" % source_dir
     if os.path.isfile(src):
-        dst = "%s/func_%s_.go" % (source_dir, func)
-        with codecs.open(dst, 'w', 'utf-8') as d:
-            with codecs.open(src, 'r', 'utf-8') as s:
+        with codecs.open(src, 'r', 'utf-8') as s:
+            with codecs.open(dst, 'w', 'utf-8') as d:
                 body = s.read()
                 has_main = re.match(r".*package\s+main\W.*func\s+main\s*\(\s*\)", body, flags=re.DOTALL)
                 d.write(body)
 
-
     # copy the launcher fixing the main
     if not has_main:
-        dst = "%s/launch_%s_.go" % (source_dir, func)
+        dst = "%s/main__.go" % source_dir
         with codecs.open(dst, 'w', 'utf-8') as d:
             with codecs.open(launcher, 'r', 'utf-8') as e:
                 code = e.read()
                 code = code.replace("Main", func)
                 d.write(code)
 
-    return os.path.abspath(dst)
-
 def build(parent, source_dir, target):
     # compile...
+    env = {
+      "PATH": os.environ["PATH"],
+      "GOPATH": os.path.abspath(parent)
+    }
     p = subprocess.Popen(
-        ["go", "build", "-i", "-o", target],
+        ["go", "build", "-i", "-ldflags=-s -w",  "-o", target],
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
         cwd=source_dir,
-        env={ "GOPATH": os.path.abspath(parent), "PATH": os.environ["PATH"]})
+        env=env)
     (o, e) = p.communicate()
 
     # stdout/stderr may be either text or bytes, depending on Python
@@ -91,10 +92,10 @@
     source_dir = argv[2]
     target_dir = argv[3]
 
-    parent = os.path.dirname(source_dir)
-    source = sources(argv[0]+".launcher.go", source_dir, main)
-    target = os.path.abspath("%s/%s" % (target_dir, main))
+    parent = os.path.dirname(os.path.abspath(source_dir))
+    target = os.path.abspath("%s/exec" % target_dir)
 
+    sources(argv[0]+".launcher.go", source_dir, main)
     build(parent, source_dir, target)
 
 if __name__ == '__main__':
diff --git a/docs/ACTION.md b/docs/ACTION.md
new file mode 100644
index 0000000..2d9854c
--- /dev/null
+++ b/docs/ACTION.md
@@ -0,0 +1,143 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+# Writing actions for the Golang and ActionLoop runtime
+
+<a name="golang"/>
+
+## How to write Go Actions
+
+The `actionloop-golang-v1.11` runtime can execute actions written in the Go programming language in OpenWhisk, either precompiled binary or compiling sources on the fly.
+
+### Entry Point
+
+The source of one action is one or more Go source file. The entry point of the action is a function, placed in the `main` package. The obvious name for the default action would be `main`, but unfortunately `main.main` is the fixed entry point, for a go program, and its signature is `main()` (without arguments) so it cannot be used, unless you implement the [ActionLoop](#actionloopgo) directly, overwriting the one provided by the runtime, see below.
+
+When deploying an OpenWhisk action you can specify the `main` function, and the default value is of course `main`.
+
+The rule used by the runtime you use the  the *capitalized* name of the function specified as main. The default is of course `main.Main`' if you specify `hello` it will be `hello.Hello`. It will be also `main.Main` or `hello.Hello` if you specify the main function as, respectively, `Main` and `Hello`. The function must have a specific signature, as described next.
+
+*NOTE* The runtime does *not* support different packages from `main` for the entry point. If you specify `hello.main` the runtime will try to use `Hello.main`, that will be almost certainly incorrect. You can however have other packages in your sources, as described below.
+
+### Signature
+
+The expected signature for a `main` function is:
+
+`func Main(event map[string]interface{}) map[string]interface{}`
+
+So a very simple `hello world` function would be:
+
+```go
+package main
+
+import "log"
+
+// Main is the function implementing the action
+func Main(obj map[string]interface{}) map[string]interface{} {
+  // do your work
+  name, ok := obj["name"].(string)
+  if !ok {
+    name = "world"
+  }
+  msg := make(map[string]interface{})
+  msg["message"] = "Hello, " + name + "!"
+  // log in stdout or in stderr
+  log.Printf("name=%s\n", name)
+  // encode the result back in json
+  return msg
+}
+```
+
+You can also have multiple source files in an action, packages and vendor folders.  Check the [deployment](DEPLOYMENT.md) document for more details how to package and deploy actions.
+
+<a name="generic"/>
+
+## Using it with generic Binaries
+
+The `actionloop` runtime can execute  generic Linux executable in an efficient way. The actions should work reading input line by line, perform its work and produce output also line by line. In more detail it should respect the following protocol.
+
+<a name="actionloop">
+
+### The Action Loop Protocol
+
+The protocol can be specified informally as follow.
+
+- Read one line from standard input (file descriptor 0).
+- Parse the line as a JSON object. Currently the object will be in currently in the format:
+
+```
+{
+ "value": JSON,
+ "namespace": String,
+ "action_name": String,
+ "api_host": String,
+ "api_key": String,
+ "activation_id": String,
+ "deadline": Number
+}
+```
+
+Note however that more values could be provided in future.
+Usually this JSON is read and the values are stored in environment variables, converted to upper case the key and  and adding the prefix `__OW_`.
+
+- The payload of the request is stored in the key `value`. The action should read the field `value` assuming it is a JSON object (note, not an array, nor a string or number) and parse it.
+- The action can now perform its tasks as appropriate. The action can produce log writing  in standard output (file descriptor 1) and standard error (file descriptor 3) . Note that those corresponds to file descriptors 1 and 2.
+- The action will receive also file descriptor 3 for returning results. The result of the action must be a single line (without embedding newlines - newlines in strings must be quoted) written in file descriptor 3.
+- The action should not exit now, but continue the loop, reading the next line and processing as described before, continuing forever.
+
+### Using shell scripts
+
+The `actionloop` image works actually with executable in Linux sense, so also scripts are acceptable.
+
+In the current actionloop image there is `bash` and the `jq` command, so you can for example implement the actionloop with a shell script like this:
+
+```bash
+#!/bin/bash
+# read input forever line by line
+while read line
+do
+   # parse the in input with `jq`
+   name="$(echo $line | jq -r .name.value)"
+   # log in stdout
+   echo msg="hello $name"
+   # produce the result - note the fd3
+   echo '{"hello": "'$name'"}' >&3
+done
+```
+
+Note here we are just interested in the payload, but in general you may also want to retrieve other fields.
+
+Note the `actionloop` image will accept any source and will try to run it (if it is possible), while the `actionloop-golang-v1.11`  will instead try to compile the sources assuming it is Golang instead.
+
+<a name="actionloopgo">
+
+### Providing your own ActionLoop implementation
+
+By default the runtime expects you provide a main function that will serve one request, and will add a default implementation of the ActionLoop protocol when compiling.
+
+You can however overwrite the default protocol and provide your how implementation of the ActionLoop. If you do so, you will have to take care of opening file descriptors, reading input, parse JSON and set environment variables.
+
+To overwrite the default ActionLoop you can do this either sending a single file source actino or a zip action.
+
+If you send a single file, you have to provide your own implementation adding a function `func main()` in the `main` package.
+
+If you send a zip file, you have to provide your implementation in a file called `exec` (without extension `.go`!) placed in the top level of the zip file.
+
+If you provide your own `main.main()`, the default `main` will not be generated.
+
+An example named `golang-main-standalone` is provided.
diff --git a/docs/BUILD.md b/docs/BUILD.md
new file mode 100644
index 0000000..397fdb3
--- /dev/null
+++ b/docs/BUILD.md
@@ -0,0 +1,80 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+#  Developers Guide for Runtime itself
+
+<a name="building"/>
+
+## How to Build and run tests
+
+You need a Linux or an OSX environment, with Java and Docker installed to build the sources.
+
+Prerequisites for running build and tests with gradle:
+
+- docker
+- jdk
+
+To compile go proxy *in amd64 architecture* for docker:
+
+```
+./gradlew build
+```
+
+To build the docker images, after compiling go proxy:
+
+```
+./gradlew distDocker
+```
+
+This will build the images:
+
+* `actionloop-golang-v1.11`: an image supporting  Go sources
+* `actionloop`: the base image, supporting generic executables ans shell script
+
+The `actionloop` image can be used for supporting other compiled programming languages as long as they implement a `compile` script and the *action loop* protocol described below.
+
+To run tests:
+
+```
+./gradlew test --info
+```
+<a name="development"/>
+
+# Local Development
+
+If you want to develop the proxy and run tests natively, you can do it on Linux or OSX. Development has been tested on Ubuntu Linux (14.04) and OSX 10.13. Probably other distributions work, maybe even Windows with WSL, but since it is not tested YMMMV.
+
+You need to install, of course [go 1.11.0](https://golang.org/doc/install)
+
+Then you need a set of utilities used in tests:
+
+- bc
+- zip
+- realpath
+
+Linux: `apt-get install bc zip realpath`
+OSX: `brew install zip coreutils`
+
+**NOTE**: Because tests build and cache some binary files, perform a `git clean -fx` and **do not share folders between linux and osx** because binaries are in different format...
+
+You can also run the tests in go, without using `gradle` with
+
+```
+cd openwhisk
+go test
+```
diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md
new file mode 100644
index 0000000..583fae2
--- /dev/null
+++ b/docs/DEPLOY.md
@@ -0,0 +1,166 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# Deployment options
+
+THere are two images provided: the `actionloop` and the `actionloop-golang-v1.11` available. Each image accept different input in the deployment.
+
+<a name="actionloop">
+
+## Actionloop runtime
+
+The runtime `actionlooop` accepts:
+
+- single file executable
+- a zip file containing an executables
+
+If the input is a single file, it can be either a in ELF format for architecture AMD64 implementing the ActionLoop protocol.
+
+It can also be a script, identified by the `#!` hash-bang path at the beginning. The default `actionloop` can execute `bash` shell scripts and can use the `jq` command to parse JSON files and the `curl` command to invoke other actions.
+
+If the file is a zipped file, it must contain in the top level (*not* in a subdirectory) an file named `exec`. This file must be in the same format as a single binary, either a binary or a script.
+
+<a name="golang">
+
+## Golang runtime
+
+The runtime `actionloop-golang-v1.11` accepts:
+
+- executable binaries implementing the ActionLoop protocol as Linux ELF executable compiled for the AMD64 architecture (as the `actionloop` runtme)
+- zip files containing a binary executable named `exec` in the top level, and it must be again a Linux ELF executable compiled for the AMD64 architecture
+- a single file action that is not an executable binary will be interpreted as source code and it will be compiled in a binary as described in the document about [actions](ACTION.md)
+- a zip file not containing in the top level a binary file `exec` will  be interpreted as a collection of zip files, and it will be compiled in a binary as described in the document about [actions](ACTION.md)
+
+Please note in the separate the rules about the name of the main function (that defaults to `main.Main`), and the rules about how to overwrite the `main.main`.
+
+## Using packages and vendor folder
+
+When you deploy a zip file, you can:
+
+- have all your functions in the `main` package
+- have some functions placed in some packages, like `hello`
+- have some third party dependencies you want to include in your sources
+
+If all your functions are in the main package, just place all your sources in the top level of your zip file
+
+### Use a package folder
+
+If some functions belong to a package, like `hello/`, you need to be careful with the layout of your source. The layout supported is the following:
+
+```
+golang-main-package/
+├── Makefile
+└── src
+    ├── hello
+    │   ├── hello.go
+    │   └── hello_test.go
+    └── main.go
+```
+
+You need to use a `src` folder, place the sources that belongs to the main package in the `src` and place sources of your package in the `src/hello` folder.
+
+Then you should import it your subpackage with `import "hello"`.
+Note that this means if you want to compile locally you have to set your GOPATH to parent directory of your `src` packages. Check below for using [VcCode](#vscode) as an editor with this setup.
+
+When you send the image you will have to zip the content
+
+Check the example `golang-main-package` and the associated `Makefile` for an example including also how to deploy and precompile your sources.
+
+### Using vendor folders
+
+When you need to use third part libraries, the runtime does not download them from Internet. You have to provide them,  downloading and placing them using the `vendor` folder mechanism. We are going to show here how to use the vendor folder with the `dep` tool.
+
+*NOTE* the `vendor` folder does not work at the top level, you have to use a `src` folder and a package folder to have also the vendor folder.
+
+If you want for example use the library `github.com/sirupsen/logrus` to manage your logs (a widely used drop-in replacement for the standard `log` package), you have to include it in your source code *in a sub package*.
+
+For example consider you have in the file `src/hello/hello.go` the import:
+
+```
+import "github.com/sirupsen/logrus"
+```
+
+To create a vendor folder, you need to
+
+- install the [dep](https://github.com/golang/dep) tool
+- cd to the `src/hello` folder (*not* the `src` folder)
+- run `dep init` the first time (it will create 2 manifest files `Gopkg.lock` and `Gopkg.toml`) or `dep ensure` if you already have the manifest files.
+
+The layout will be something like this:
+
+```
+golang-hello-vendor
+├── Makefile
+└── src
+    ├── hello
+    │   ├── Gopkg.lock
+    │   ├── Gopkg.toml
+    │   ├── hello.go
+    │   ├── hello_test.go
+    │   └── vendor
+    │       ├── github.com/...
+    │       └── golang.org/...
+    └── hello.go
+```
+
+Check the example `golang-hello-vendor`.
+
+Note you do not need to store the `vendor` folder in the version control system as it can be regenerated (only the manifest files), but you need to include the entire vendor folder when you deploy the action.
+
+<a name="vscode">
+
+### Using VsCode
+
+If you are using [VsCode[(https://code.visualstudio.com/) as your Go development environment with the [VsCode Go](https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go) support, and you want to get rid of errors and have it working properly, you need to configure it to support the suggested:
+
+- you need to have a `src` folder in your source
+- you need either to open the `src` folder as the top level source or add it as a folder in the workspace (not just have it as a subfolder)
+- you need to enable the option `go.inferGopath`
+
+Using this option, the GOPATH will be set to the parent directory of your `src` folder and you will not have errors in your imports.
+
+<a name="precompile"/>
+
+## Precompiling Go Sources Offline
+
+Compiling sources on the image can take some time when the images is initialized. You can speed up precompiling the sources using the image `actionloop-golang-v1.11` as an offline compiler. You need `docker` for doing that.
+
+The images accepts a `-compile <main>` flag, and expects you provide sources in standard input. It will then compile them, emit the binary in standard output and errors in stderr. The output is always a zip file containing an executable.
+
+If you have docker, you can do it this way:
+
+If you have a single source maybe in file `main.go`, with a function named `Main` just do this:
+
+`docker run openwhisk/actionloop-golang-v1.11 -compile main <main.go >main.zip`
+
+If you have multiple sources in current directory, even with a subfolder with sources, you can compile it all with:
+
+`zip -r - * | docker run openwhisk/actionloop-golang-v1.11 -compile main >main.zip`
+
+The  generated executable is suitable to be deployed in OpenWhisk using just the generic `actionloop` runtime.
+
+`wsk action create my/action main.zip -docker openwhisk/actionloop`
+
+You can also use the full `actionloop-golang-v1.11` as runtime, it is only bigger.
+
+Note that the output is always a zip file in  Linux AMD64 format so the executable can be run only inside a Docker Linux container.
+
+
+
+
diff --git a/examples/EXAMPLES.md b/examples/EXAMPLES.md
new file mode 100644
index 0000000..a59d25e
--- /dev/null
+++ b/examples/EXAMPLES.md
@@ -0,0 +1,36 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+# Examples
+
+This is a collection of examples.
+Each examples has a  Makefile with 4 targets:
+
+- `make deploy` (or just make) deploys the action, precompiling it
+- `make devel`  deploys the action in source format, leaving the compilation to the runtime
+-  `make test` runs a simple test on the action; it should be already deployed
+- `clean` removes intermediate files
+
+Available examples:
+
+- [Simple Golang action](golang-main-single) main is `main.Main`
+- [Simple Golang action](golang-hello-single) main is `main.Hello`
+- [Golang action with a subpackage](golang-main-package) main is `main.Main` invoking a `hello.Hello`
+- [Golang action with a subpackage and vendor folder](golang-hello-vendor) main is `main.Hello` invoking a `hello.Hello` using a dependency `github.com/sirupsen/logrus`
+- [Standalone Golang Action](golang-main-standalone) main is `main.main`, implements the ActionLoop directly
+- [Simple Bash action](bash-hello) a simple bash script action implementing the ActionLoop directly
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000..3b65bbb
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,32 @@
+# prefix
+
+USER=msciab     	# devel
+#USER=openwhisk		# deploy
+
+all: .PHONY
+.PHONY: bash-hello golang-hello-single golang-main-single golang-main-standalone golang-main-package golang-hello-vendor 
+
+bash-hello:
+	OW_USER=$(USER) make deploy test -C bash-hello
+
+golang-main-single:
+	OW_USER=$(USER) make deploy test -C $@
+	OW_USER=$(USER) make deploy test -C $@
+
+golang-hello-single:
+	OW_USER=$(USER) make deploy test -C $@
+	OW_USER=$(USER) make deploy test -C $@
+
+golang-main-standalone:
+	OW_USER=$(USER) make deploy test -C $@
+	OW_USER=$(USER) make deploy test -C $@
+
+golang-main-package:
+	OW_USER=$(USER) make deploy test -C $@
+	OW_USER=$(USER) make deploy test -C $@
+
+golang-hello-vendor:
+	OW_USER=$(USER) make deploy test -C $@
+	OW_USER=$(USER) make deploy test -C $@
+
+
diff --git a/examples/bash-hello/Makefile b/examples/bash-hello/Makefile
new file mode 100644
index 0000000..da69f47
--- /dev/null
+++ b/examples/bash-hello/Makefile
@@ -0,0 +1,28 @@
+WSK?=wsk
+OW_USER?=openwhisk
+OW_RUNTIME?=$(OW_USER)/actionloop
+NAME=bash-hello
+PACKAGE=test
+SRC=hello.sh
+
+deploy: package.done
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --docker $(OW_RUNTIME)
+
+devel: deploy
+
+test: test.json
+	$(WSK) action invoke $(PACKAGE)/$(NAME) -r
+	$(WSK) action invoke $(PACKAGE)/$(NAME) -P test.json -r
+
+clean:
+	$(WSK) action delete $(PACKAGE)/$(NAME)
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+
+.PHONY: test devel deploy clean
diff --git a/examples/bash-hello/hello.sh b/examples/bash-hello/hello.sh
new file mode 100755
index 0000000..157eb69
--- /dev/null
+++ b/examples/bash-hello/hello.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+while read line
+do
+   name="$(echo $line | jq -r .value.name)"
+   test "$name" == "null" && name="world"
+   echo msg="hello $name"
+   echo '{"bash": "'$name'"}' >&3
+done
diff --git a/examples/golang-hello-single/Makefile b/examples/golang-hello-single/Makefile
new file mode 100644
index 0000000..d16f0e1
--- /dev/null
+++ b/examples/golang-hello-single/Makefile
@@ -0,0 +1,35 @@
+OW_USER?=openwhisk
+OW_RUNTIME?=$(OW_USER)/actionloop
+OW_COMPILER?=$(OW_USER)/actionloop-golang-v1.11
+WSK?=wsk
+MAIN=hello
+PACKAGE=test
+SRC=$(MAIN).go
+NAME=golang-$(MAIN)-single
+ZIP=$(MAIN).zip
+
+deploy: package.done $(ZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRC)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER)
+
+$(ZIP): $(SRC)
+	docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP)
+
+clean:
+	wsk action delete $(PACKAGE)/$(NAME)
+	rm $(ZIP) package.done
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy devel test clean
diff --git a/openwhisk/_test/hi1.src b/examples/golang-hello-single/hello.go
similarity index 72%
copy from openwhisk/_test/hi1.src
copy to examples/golang-hello-single/hello.go
index edb45f0..c2e3db7 100644
--- a/openwhisk/_test/hi1.src
+++ b/examples/golang-hello-single/hello.go
@@ -14,12 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package main
 
+import "fmt"
 
-func main() {
-	f := bufio.NewWriter(os.Stdout)
-	defer f.Flush()
-	f.Write([]byte("hi\n"))
+// Hello function for the action
+func Hello(obj map[string]interface{}) map[string]interface{} {
+	name, ok := obj["name"].(string)
+	if !ok {
+		name = "world"
+	}
+	fmt.Printf("name=%s\n", name)
+	msg := make(map[string]interface{})
+	msg["golang-hello-single"] = "Hello, " + name + "!"
+	return msg
 }
diff --git a/examples/golang-hello-vendor/Makefile b/examples/golang-hello-vendor/Makefile
new file mode 100644
index 0000000..8efada7
--- /dev/null
+++ b/examples/golang-hello-vendor/Makefile
@@ -0,0 +1,43 @@
+OW_USER?=openwhisk
+OW_RUNTIME?=$(OW_USER)/actionloop
+OW_COMPILER?=$(OW_USER)/actionloop-golang-v1.11
+WSK?=wsk
+MAIN=hello
+PACKAGE=test
+SRCS=src/$(MAIN).go src/hello/hello.go
+VENDORS=src/hello/vendor
+NAME=golang-$(MAIN)-vendor
+BINZIP=$(MAIN)-bin.zip
+SRCZIP=$(MAIN)-src.zip
+
+deploy: package.done $(BINZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(BINZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRCZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+src/%/vendor:
+	cd $(@D) ; dep ensure
+
+$(BINZIP): $(SRCS) $(VENDORS)
+	cd src ; zip - -r * | docker run -i $(OW_COMPILER) -compile $(MAIN) >../$(BINZIP)
+
+$(SRCZIP): $(SRCS) $(VENDORS)
+	cd src ; zip ../$(SRCZIP) -r *
+
+clean:
+	wsk action delete $(PACKAGE)/$(NAME)
+	rm  $(BINZIP) $(SRCZIP) package.done
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy devel test clean
diff --git a/openwhisk/_test/hi1.src b/examples/golang-hello-vendor/src/hello.go
similarity index 81%
copy from openwhisk/_test/hi1.src
copy to examples/golang-hello-vendor/src/hello.go
index edb45f0..6e477cd 100644
--- a/openwhisk/_test/hi1.src
+++ b/examples/golang-hello-vendor/src/hello.go
@@ -17,9 +17,13 @@
 
 package main
 
+import (
+	"fmt"
+	"hello"
+)
 
-func main() {
-	f := bufio.NewWriter(os.Stdout)
-	defer f.Flush()
-	f.Write([]byte("hi\n"))
+// Main forwading to Hello
+func Hello(args map[string]interface{}) map[string]interface{} {
+	fmt.Println("Entering Hello")
+	return hello.Hello(args)
 }
diff --git a/examples/golang-hello-vendor/src/hello/Gopkg.lock b/examples/golang-hello-vendor/src/hello/Gopkg.lock
new file mode 100644
index 0000000..e516dc9
--- /dev/null
+++ b/examples/golang-hello-vendor/src/hello/Gopkg.lock
@@ -0,0 +1,44 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
+  name = "github.com/konsorten/go-windows-terminal-sequences"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
+  version = "v1.0.1"
+
+[[projects]]
+  digest = "1:3f53e9e4dfbb664cd62940c9c4b65a2171c66acd0b7621a1a6b8e78513525a52"
+  name = "github.com/sirupsen/logrus"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "ad15b42461921f1fb3529b058c6786c6a45d5162"
+  version = "v1.1.1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
+  name = "golang.org/x/crypto"
+  packages = ["ssh/terminal"]
+  pruneopts = "UT"
+  revision = "a92615f3c49003920a58dedcf32cf55022cefb8d"
+
+[[projects]]
+  branch = "master"
+  digest = "1:f5aa274a0377f85735edc7fedfb0811d3cbc20af91633797cb359e29c3272271"
+  name = "golang.org/x/sys"
+  packages = [
+    "unix",
+    "windows",
+  ]
+  pruneopts = "UT"
+  revision = "fa43e7bc11baaae89f3f902b2b4d832b68234844"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = ["github.com/sirupsen/logrus"]
+  solver-name = "gps-cdcl"
+  solver-version = 1
diff --git a/examples/golang-hello-vendor/src/hello/Gopkg.toml b/examples/golang-hello-vendor/src/hello/Gopkg.toml
new file mode 100644
index 0000000..160eb0e
--- /dev/null
+++ b/examples/golang-hello-vendor/src/hello/Gopkg.toml
@@ -0,0 +1,34 @@
+# Gopkg.toml example
+#
+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#   name = "github.com/x/y"
+#   version = "2.4.0"
+#
+# [prune]
+#   non-go = false
+#   go-tests = true
+#   unused-packages = true
+
+
+[[constraint]]
+  name = "github.com/sirupsen/logrus"
+  version = "1.1.1"
+
+[prune]
+  go-tests = true
+  unused-packages = true
diff --git a/examples/golang-hello-vendor/src/hello/hello.go b/examples/golang-hello-vendor/src/hello/hello.go
new file mode 100644
index 0000000..d281621
--- /dev/null
+++ b/examples/golang-hello-vendor/src/hello/hello.go
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package hello
+
+import (
+	"os"
+
+	"github.com/sirupsen/logrus"
+)
+
+var log = logrus.New()
+
+// Hello receive an event in format
+// { "name": "Mike"}
+// and returns a greeting in format
+// { "greetings": "Hello, Mike"}
+func Hello(args map[string]interface{}) map[string]interface{} {
+	log.Out = os.Stdout
+	res := make(map[string]interface{})
+	greetings := "world"
+	name, ok := args["name"].(string)
+	if ok {
+		greetings = name
+	}
+	res["golang-hello-vendor"] = "Hello, " + greetings
+	log.WithFields(logrus.Fields{"greetings": greetings}).Info("Hello")
+	return res
+}
diff --git a/openwhisk/_test/hi1.src b/examples/golang-hello-vendor/src/hello/hello_test.go
similarity index 61%
copy from openwhisk/_test/hi1.src
copy to examples/golang-hello-vendor/src/hello/hello_test.go
index edb45f0..354e32a 100644
--- a/openwhisk/_test/hi1.src
+++ b/examples/golang-hello-vendor/src/hello/hello_test.go
@@ -14,12 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package hello
 
-package main
+import (
+	"encoding/json"
+	"testing"
+)
 
+func TestHello(t *testing.T) {
+	var input = make(map[string]interface{})
+	input["name"] = "Mike"
+	output := Hello(input)
+	json, _ := json.Marshal(output)
+	if string(json) != `{"golang-hello-vendor":"Hello, Mike"}` {
+		t.Fail()
+	}
+}
 
-func main() {
-	f := bufio.NewWriter(os.Stdout)
-	defer f.Flush()
-	f.Write([]byte("hi\n"))
+func TestHello_noName(t *testing.T) {
+	var input = make(map[string]interface{})
+	output := Hello(input)
+	json, _ := json.Marshal(output)
+	if string(json) != `{"golang-hello-vendor":"Hello, world"}` {
+		t.Fail()
+	}
 }
diff --git a/examples/golang-main-package/Makefile b/examples/golang-main-package/Makefile
new file mode 100644
index 0000000..cb266fd
--- /dev/null
+++ b/examples/golang-main-package/Makefile
@@ -0,0 +1,39 @@
+OW_USER?=openwhisk
+OW_RUNTIME?=$(OW_USER)/actionloop
+OW_COMPILER?=$(OW_USER)/actionloop-golang-v1.11
+WSK?=wsk
+MAIN=main
+PACKAGE=test
+SRCS=src/$(MAIN).go src/hello/hello.go
+NAME=golang-$(MAIN)-package
+BINZIP=$(MAIN)-bin.zip
+SRCZIP=$(MAIN)-src.zip
+
+deploy: package.done $(BINZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(BINZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRCZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+$(BINZIP): $(SRCS)
+	cd src ; zip - -r * | docker run -i $(OW_COMPILER) -compile $(MAIN) >../$(BINZIP)
+
+$(SRCZIP): $(SRCS)
+	cd src ; zip ../$(SRCZIP) -r *
+
+clean:
+	wsk action delete $(PACKAGE)/$(NAME)
+	rm  $(BINZIP) $(SRCZIP) package.done
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy devel test clean
diff --git a/openwhisk/_test/hi1.src b/examples/golang-main-package/src/hello/hello.go
similarity index 63%
copy from openwhisk/_test/hi1.src
copy to examples/golang-main-package/src/hello/hello.go
index edb45f0..da64077 100644
--- a/openwhisk/_test/hi1.src
+++ b/examples/golang-main-package/src/hello/hello.go
@@ -15,11 +15,24 @@
  * limitations under the License.
  */
 
-package main
+package hello
 
+import (
+	"fmt"
+)
 
-func main() {
-	f := bufio.NewWriter(os.Stdout)
-	defer f.Flush()
-	f.Write([]byte("hi\n"))
+// Hello receive an event in format
+// { "name": "Mike"}
+// and returns a greeting in format
+// { "greetings": "Hello, Mike"}
+func Hello(args map[string]interface{}) map[string]interface{} {
+	res := make(map[string]interface{})
+	greetings := "world"
+	name, ok := args["name"].(string)
+	if ok {
+		greetings = name
+	}
+	res["golang-main-package"] = "Hello, " + greetings
+	fmt.Printf("Hello, %s\n", greetings)
+	return res
 }
diff --git a/openwhisk/_test/hi1.src b/examples/golang-main-package/src/hello/hello_test.go
similarity index 60%
copy from openwhisk/_test/hi1.src
copy to examples/golang-main-package/src/hello/hello_test.go
index edb45f0..fe6e15b 100644
--- a/openwhisk/_test/hi1.src
+++ b/examples/golang-main-package/src/hello/hello_test.go
@@ -14,12 +14,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package hello
 
-package main
+import (
+	"encoding/json"
+	"fmt"
+)
 
+func ExampleHello() {
+	var input = make(map[string]interface{})
+	input["name"] = "Mike"
+	output := Hello(input)
+	json, _ := json.Marshal(output)
+	fmt.Printf("%s", json)
+	// Output:
+	// Hello, Mike
+	// {"golang-main-package":"Hello, Mike"}
+}
 
-func main() {
-	f := bufio.NewWriter(os.Stdout)
-	defer f.Flush()
-	f.Write([]byte("hi\n"))
+func ExampleHello_noName() {
+	var input = make(map[string]interface{})
+	output := Hello(input)
+	json, _ := json.Marshal(output)
+	fmt.Printf("%s", json)
+	// Output:
+	// Hello, world
+	// {"golang-main-package":"Hello, world"}
 }
diff --git a/openwhisk/_test/src/main b/examples/golang-main-package/src/main.go
similarity index 100%
copy from openwhisk/_test/src/main
copy to examples/golang-main-package/src/main.go
diff --git a/examples/golang-main-single/Makefile b/examples/golang-main-single/Makefile
new file mode 100644
index 0000000..1c16fcc
--- /dev/null
+++ b/examples/golang-main-single/Makefile
@@ -0,0 +1,35 @@
+OW_USER?=openwhisk
+OW_RUNTIME?=$(OW_USER)/actionloop
+OW_COMPILER?=$(OW_USER)/actionloop-golang-v1.11
+WSK?=wsk
+MAIN=main
+PACKAGE=test
+SRC=$(MAIN).go
+NAME=golang-$(MAIN)-single
+ZIP=$(MAIN).zip
+
+deploy: package.done $(ZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRC)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER)
+
+$(ZIP): $(SRC)
+	docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP)
+
+clean:
+	wsk action delete $(PACKAGE)/$(NAME)
+	rm $(ZIP) package.done
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy devel test clean
\ No newline at end of file
diff --git a/openwhisk/_test/hi1.src b/examples/golang-main-single/main.go
similarity index 72%
copy from openwhisk/_test/hi1.src
copy to examples/golang-main-single/main.go
index edb45f0..5fdaf5d 100644
--- a/openwhisk/_test/hi1.src
+++ b/examples/golang-main-single/main.go
@@ -14,12 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package main
 
+import "fmt"
 
-func main() {
-	f := bufio.NewWriter(os.Stdout)
-	defer f.Flush()
-	f.Write([]byte("hi\n"))
+// Main function for the action
+func Main(obj map[string]interface{}) map[string]interface{} {
+	name, ok := obj["name"].(string)
+	if !ok {
+		name = "world"
+	}
+	fmt.Printf("name=%s\n", name)
+	msg := make(map[string]interface{})
+	msg["golang-main-single"] = "Hello, " + name + "!"
+	return msg
 }
diff --git a/examples/golang-main-standalone/Makefile b/examples/golang-main-standalone/Makefile
new file mode 100644
index 0000000..208ca99
--- /dev/null
+++ b/examples/golang-main-standalone/Makefile
@@ -0,0 +1,35 @@
+OW_USER?=openwhisk
+OW_RUNTIME?=$(OW_USER)/actionloop
+OW_COMPILER?=$(OW_USER)/actionloop-golang-v1.11
+WSK?=wsk
+MAIN=main
+PACKAGE=test
+SRC=src/exec
+NAME=golang-$(MAIN)-standalone
+ZIP=$(MAIN).zip
+
+deploy: package.done $(ZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRC)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER)
+
+$(ZIP): $(SRC)
+	docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP)
+
+clean:
+	wsk action delete $(PACKAGE)/$(NAME)
+	rm $(ZIP) package.done
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy test clean
\ No newline at end of file
diff --git a/examples/golang-main-standalone/src/exec b/examples/golang-main-standalone/src/exec
new file mode 100644
index 0000000..d26b062
--- /dev/null
+++ b/examples/golang-main-standalone/src/exec
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"strings"
+)
+
+func main() {
+	// debugging
+	var debug = os.Getenv("OW_DEBUG") != ""
+
+	if debug {
+		filename := os.Getenv("OW_DEBUG")
+		f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
+		if err == nil {
+			log.SetOutput(f)
+			defer f.Close()
+		}
+		log.Printf("ACTION ENV: %v", os.Environ())
+	}
+
+	// assign the main function
+	type Action func(event map[string]interface{}) map[string]interface{}
+	var action Action
+	action = Main
+
+	// input
+	out := os.NewFile(3, "pipe")
+	defer out.Close()
+	reader := bufio.NewReader(os.Stdin)
+
+	// read-eval-print loop
+	if debug {
+		log.Println("started")
+	}
+	for {
+		// read one line
+		inbuf, err := reader.ReadBytes('\n')
+		if err != nil {
+			if err != io.EOF {
+				log.Println(err)
+			}
+			break
+		}
+		if debug {
+			log.Printf(">>>'%s'>>>", inbuf)
+		}
+		// parse one line
+		var input map[string]interface{}
+		err = json.Unmarshal(inbuf, &input)
+		if err != nil {
+			log.Println(err.Error())
+			fmt.Fprintf(out, "{ error: %q}\n", err.Error())
+			continue
+		}
+		if debug {
+			log.Printf("%v\n", input)
+		}
+		// set environment variables
+		err = json.Unmarshal(inbuf, &input)
+		for k, v := range input {
+			if k == "value" {
+				continue
+			}
+			if s, ok := v.(string); ok {
+				os.Setenv("__OW_"+strings.ToUpper(k), s)
+			}
+		}
+		// get payload if not empty
+		var payload map[string]interface{}
+		if value, ok := input["value"].(map[string]interface{}); ok {
+			payload = value
+		}
+		// process the request
+		result := action(payload)
+		// encode the answer
+		output, err := json.Marshal(&result)
+		if err != nil {
+			log.Println(err.Error())
+			fmt.Fprintf(out, "{ error: %q}\n", err.Error())
+			continue
+		}
+		output = bytes.Replace(output, []byte("\n"), []byte(""), -1)
+		if debug {
+			log.Printf("'<<<%s'<<<", output)
+		}
+		fmt.Fprintf(out, "%s\n", output)
+	}
+}
+
+// Main function for the action
+func Main(obj map[string]interface{}) map[string]interface{} {
+	name, ok := obj["name"].(string)
+	if !ok {
+		name = "world"
+	}
+	fmt.Printf("name=%s\n", name)
+	msg := make(map[string]interface{})
+	msg["main-standalone"] = "Hello, " + name + "!"
+	return msg
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index d7cc33f..edeff3b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
 # Licensed to the Apache Software Foundation (ASF) under one or more contributor
 # license agreements; and to You under the Apache License, Version 2.0.
-
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
diff --git a/main/proxy.go b/main/proxy.go
index 0a64e2e..2511ab6 100644
--- a/main/proxy.go
+++ b/main/proxy.go
@@ -17,6 +17,8 @@
 package main
 
 import (
+	"archive/zip"
+	"bytes"
 	"flag"
 	"io/ioutil"
 	"log"
@@ -31,29 +33,37 @@
 // flag to require on-the-fly compilation
 var compile = flag.String("compile", "", "compile, reading in standard input the specified function, and producing the result in stdout")
 
+// fatal if error
+func fatalIf(err error) {
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
 // use the runtime as a compiler "on-the-fly"
 func extractAndCompile(ap *openwhisk.ActionProxy) {
-	// read the std in
+
+	// read the std input
 	in, err := ioutil.ReadAll(os.Stdin)
-	if err != nil {
-		log.Printf(err.Error())
-		return
-	}
+	fatalIf(err)
 
 	// extract and compile it
 	file, err := ap.ExtractAndCompile(&in, *compile)
-	if err != nil {
-		log.Printf(err.Error())
-		return
-	}
+	fatalIf(err)
 
-	// read the file and write it to stdout
-	out, err := ioutil.ReadFile(file)
-	_, err = os.Stdout.Write(out)
-	if err != nil {
-		log.Printf(err.Error())
-		return
-	}
+	// read the file, zip it and write it to stdout
+	buf := new(bytes.Buffer)
+	zwr := zip.NewWriter(buf)
+	zf, err := zwr.Create("exec")
+	fatalIf(err)
+	filedata, err := ioutil.ReadFile(file)
+	fatalIf(err)
+	_, err = zf.Write(filedata)
+	fatalIf(err)
+	fatalIf(zwr.Flush())
+	fatalIf(zwr.Close())
+	_, err = os.Stdout.Write(buf.Bytes())
+	fatalIf(err)
 }
 
 func main() {
diff --git a/openwhisk/_test/build.sh b/openwhisk/_test/build.sh
index db374d8..58f80e8 100755
--- a/openwhisk/_test/build.sh
+++ b/openwhisk/_test/build.sh
@@ -19,50 +19,38 @@
 cd "$(dirname $0)"
 
 function build {
-   if test -e $1
-   then return
-   fi
+   test -e exec && rm exec
    cp $1.src $1.go
-   GOPATH=$PWD go build -a -o $1 $1.go
+   GOPATH=$PWD go build -a -o exec $1.go
    rm $1.go
 }
 
 function build_main {
-   if test -e $1
-   then return
-   fi
+   test -e exec && rm exec
    cp ../../common/gobuild.py.launcher.go $1.go
    cat $1.src >>$1.go
-   go build -a -o $1 $1.go
+   go build -a -o exec $1.go
    rm $1.go
 }
 
-function zipit {
-    if test -e $1
-    then return
-    fi
-    mkdir $$
-    cp $2 $$/$3
-    zip -q -j $1 $$/$3
-    rm -rf $$
-}
-
-build exec
-rm exec.zip
-zip -q -r exec.zip exec etc dir
 
 build hi
-zipit hi.zip hi main
+zip hi.zip exec
+cp exec hi
 
 build_main hello_message
-zipit hello_message.zip hello_message main
-zipit hello_message1.zip hello_message message
+zip hello_message.zip exec
+cp exec hello_message
 
 build_main hello_greeting
-zipit hello_greeting.zip hello_greeting main
-zipit hello_greeting1.zip hello_greeting greeting
+zip hello_greeting.zip exec
+cp exec hello_greeting
 
-rm hello.zip
+test -e hello.zip && rm hello.zip
 cd src
-zip -q -r ../hello.zip main hello
+zip -q -r ../hello.zip main.go hello
 cd ..
+
+build exec
+test -e exec.zip && rm exec.zip
+zip -q -r exec.zip exec etc dir
diff --git a/openwhisk/_test/hi1.src b/openwhisk/_test/error.src
similarity index 89%
rename from openwhisk/_test/hi1.src
rename to openwhisk/_test/error.src
index edb45f0..fd657fc 100644
--- a/openwhisk/_test/hi1.src
+++ b/openwhisk/_test/error.src
@@ -17,9 +17,6 @@
 
 package main
 
-
-func main() {
-	f := bufio.NewWriter(os.Stdout)
-	defer f.Flush()
-	f.Write([]byte("hi\n"))
+func Main() {
+	syntax error
 }
diff --git a/openwhisk/_test/hello1.src b/openwhisk/_test/hello1.src
index e7d0993..9c186b4 100644
--- a/openwhisk/_test/hello1.src
+++ b/openwhisk/_test/hello1.src
@@ -21,7 +21,7 @@
 	"fmt"
 )
 
-func hello(obj map[string]interface{}) map[string]interface{} {
+func Hello(obj map[string]interface{}) map[string]interface{} {
 	name, ok := obj["name"].(string)
 	if !ok {
 		name = "Stranger"
diff --git a/openwhisk/_test/precompile.sh b/openwhisk/_test/precompile.sh
index 9f6697f..bdd23b6 100755
--- a/openwhisk/_test/precompile.sh
+++ b/openwhisk/_test/precompile.sh
@@ -18,7 +18,7 @@
 cd "$(dirname $0)"
 SRC=${1:?source file or dir}
 ID=${2:?target dir}
-TGT=${3:-main}
+TGT=${3:-exec}
 ETC=${4:-}
 rm -Rvf compile/$ID >/dev/null
 mkdir -p compile/$ID/src compile/$ID/bin
diff --git a/openwhisk/_test/src/main b/openwhisk/_test/src/main.go
similarity index 100%
rename from openwhisk/_test/src/main
rename to openwhisk/_test/src/main.go
diff --git a/openwhisk/actionProxy.go b/openwhisk/actionProxy.go
index 738e233..c61c1a8 100644
--- a/openwhisk/actionProxy.go
+++ b/openwhisk/actionProxy.go
@@ -68,7 +68,7 @@
 // the more recently uplodaded
 // action if valid, otherwise remove it
 // and fallback to the previous, if any
-func (ap *ActionProxy) StartLatestAction(main string) error {
+func (ap *ActionProxy) StartLatestAction() error {
 
 	// find the action if any
 	highestDir := highestDir(ap.baseDir)
@@ -82,7 +82,7 @@
 	curExecutor := ap.theExecutor
 
 	// try to launch the action
-	executable := fmt.Sprintf("%s/%d/bin/%s", ap.baseDir, highestDir, main)
+	executable := fmt.Sprintf("%s/%d/bin/exec", ap.baseDir, highestDir)
 	os.Chmod(executable, 0755)
 	newExecutor := NewExecutor(ap.outFile, ap.errFile, executable)
 	Debug("starting %s", executable)
@@ -108,7 +108,6 @@
 }
 
 func (ap *ActionProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	//fmt.Println(r.URL.Path)
 	switch r.URL.Path {
 	case "/init":
 		ap.initHandler(w, r)
diff --git a/openwhisk/actionProxy_test.go b/openwhisk/actionProxy_test.go
index 5f909ec..395e811 100644
--- a/openwhisk/actionProxy_test.go
+++ b/openwhisk/actionProxy_test.go
@@ -50,8 +50,8 @@
 	ap := NewActionProxy("./action/t2", "", logf, logf)
 	// start the action that emits 1
 	buf := []byte("#!/bin/sh\nwhile read a; do echo 1 >&3 ; done\n")
-	ap.ExtractAction(&buf, "main", "bin")
-	ap.StartLatestAction("main")
+	ap.ExtractAction(&buf, "bin")
+	ap.StartLatestAction()
 	ap.theExecutor.io <- []byte("x")
 	res := <-ap.theExecutor.io
 	assert.Equal(t, res, []byte("1\n"))
@@ -64,8 +64,8 @@
 	ap := NewActionProxy("./action/t3", "", logf, logf)
 	// now start an action that terminate immediately
 	buf := []byte("#!/bin/sh\ntrue\n")
-	ap.ExtractAction(&buf, "main", "bin")
-	ap.StartLatestAction("main")
+	ap.ExtractAction(&buf, "bin")
+	ap.StartLatestAction()
 	assert.Nil(t, ap.theExecutor)
 }
 
@@ -75,8 +75,8 @@
 	ap := NewActionProxy("./action/t4", "", logf, logf)
 	// start the action that emits 2
 	buf := []byte("#!/bin/sh\nwhile read a; do echo 2 >&3 ; done\n")
-	ap.ExtractAction(&buf, "main", "bin")
-	ap.StartLatestAction("main")
+	ap.ExtractAction(&buf, "bin")
+	ap.StartLatestAction()
 	ap.theExecutor.io <- []byte("z")
 	assert.Equal(t, <-ap.theExecutor.io, []byte("2\n"))
 	/**/
diff --git a/openwhisk/compiler.go b/openwhisk/compiler.go
index bd6c0d9..a948547 100644
--- a/openwhisk/compiler.go
+++ b/openwhisk/compiler.go
@@ -20,7 +20,6 @@
 import (
 	"fmt"
 	"io/ioutil"
-	"log"
 	"os"
 	"os/exec"
 	"runtime"
@@ -37,18 +36,12 @@
 	return len(buf) > 4 && buf[0] == 0xcf && buf[1] == 0xfa && buf[2] == 0xed && buf[3] == 0xfe
 }
 
-// check if the file is already compiled
-// if the file is a directoy look for a file with the given name
-func isCompiled(fileOrDir string, name string) bool {
-	fi, err := os.Stat(fileOrDir)
+// check if the file exists and it is already compiled
+func isCompiled(file string) bool {
+	_, err := os.Stat(file)
 	if err != nil {
-		log.Print(err)
 		return false
 	}
-	file := fileOrDir
-	if fi.IsDir() {
-		file = fmt.Sprintf("%s/%s", fileOrDir, name)
-	}
 
 	buf, err := ioutil.ReadFile(file)
 	if err != nil {
@@ -76,15 +69,15 @@
 }
 
 // CompileAction will compile an anction in source format invoking a compiler
-func (ap *ActionProxy) CompileAction(main string, src_dir string, bin_dir string) error {
+func (ap *ActionProxy) CompileAction(main string, srcDir string, binDir string) error {
 	if ap.compiler == "" {
 		return fmt.Errorf("No compiler defined")
 	}
 
-	Debug("compiling: %s %s %s %s", ap.compiler, main, src_dir, bin_dir)
+	Debug("compiling: %s %s %s %s", ap.compiler, main, srcDir, binDir)
 
 	var cmd *exec.Cmd
-	cmd = exec.Command(ap.compiler, main, src_dir, bin_dir)
+	cmd = exec.Command(ap.compiler, main, srcDir, binDir)
 	cmd.Env = []string{"PATH=" + os.Getenv("PATH")}
 
 	// gather stdout and stderr
diff --git a/openwhisk/compiler_test.go b/openwhisk/compiler_test.go
index 3fa609e..ca43b2a 100644
--- a/openwhisk/compiler_test.go
+++ b/openwhisk/compiler_test.go
@@ -50,39 +50,33 @@
 )
 
 // compile a main
-func Example() {
-	sys(PREP, "hello.src", "0", "main")
+func Example_compile() {
+	sys(PREP, "hello.src", "0", "exec")
 	ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr)
-	fmt.Println(isCompiled(TMP+"0/src", "main"))
-	fmt.Println(isCompiled(TMP+"0/src/main", "main"))
+	fmt.Println(isCompiled(TMP + "0/src/exec"))
 	ap.CompileAction("main", TMP+"0/src", TMP+"0/bin")
-	sys(CHECK, TMP+"0/bin/main")
-	fmt.Println(isCompiled(TMP+"0/bin", "main"))
-	fmt.Println(isCompiled(TMP+"0/bin/main", "main"))
+	sys(CHECK, TMP+"0/bin/exec")
+	fmt.Println(isCompiled(TMP + "0/bin/exec"))
 	// errors
-	fmt.Println(isCompiled(TMP+"0/bin1/main", "main"))
-	fmt.Println(isCompiled(TMP+"0/bin/main1", "main"))
+	fmt.Println(isCompiled(TMP + "0/bin/exec1"))
 	// Output:
 	// false
-	// false
-	// _test/compile/0/bin/main: application/x-executable
+	// _test/compile/0/bin/exec: application/x-executable
 	// name=Mike
 	// {"message":"Hello, Mike!"}
 	// true
-	// true
-	// false
 	// false
 }
 
 // compile a not-main (hello) function
 func Example_hello() {
 	N := "1"
-	sys(PREP, "hello1.src", N, "hello")
+	sys(PREP, "hello1.src", N, "exec")
 	ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr)
 	ap.CompileAction("hello", TMP+N+"/src", TMP+N+"/bin")
-	sys(CHECK, TMP+N+"/bin/hello")
+	sys(CHECK, TMP+N+"/bin/exec")
 	// Output:
-	// _test/compile/1/bin/hello: application/x-executable
+	// _test/compile/1/bin/exec: application/x-executable
 	// name=Mike
 	// {"hello":"Hello, Mike!"}
 }
@@ -90,12 +84,12 @@
 // compile a function including a package
 func Example_package() {
 	N := "2"
-	sys(PREP, "hello2.src", N, "main", "hello")
+	sys(PREP, "hello2.src", N, "exec", "hello")
 	ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr)
 	ap.CompileAction("main", TMP+N+"/src", TMP+N+"/bin")
-	sys(CHECK, TMP+N+"/bin/main")
+	sys(CHECK, TMP+N+"/bin/exec")
 	// Output:
-	// _test/compile/2/bin/main: application/x-executable
+	// _test/compile/2/bin/exec: application/x-executable
 	// Main
 	// Hello, Mike
 	// {"greetings":"Hello, Mike"}
@@ -103,22 +97,21 @@
 
 func Example_compileError() {
 	N := "6"
-	sys(PREP, "hi1.src", N)
+	sys(PREP, "error.src", N)
 	ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr)
 	err := ap.CompileAction("main", TMP+N+"/src", TMP+N+"/bin")
 	fmt.Printf("%v", removeLineNr(err.Error()))
 	// Unordered output:
-	// ./func_Main_.go::: undefined: bufio
-	// ./func_Main_.go::: undefined: os
+	// ./exec__.go::: syntax error: unexpected error at end of statement
 }
 
 func Example_withMain() {
 	N := "7"
-	sys(PREP, "hi.src", N)
+	sys(PREP, "hi.src", N, "exec")
 	ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr)
 	err := ap.CompileAction("main", TMP+N+"/src", TMP+N+"/bin")
 	fmt.Println(err)
-	sys(TMP + N + "/bin/main")
+	sys(TMP + N + "/bin/exec")
 	// Output:
 	// <nil>
 	// hi
diff --git a/openwhisk/extractor.go b/openwhisk/extractor.go
index 36a6499..70b1520 100644
--- a/openwhisk/extractor.go
+++ b/openwhisk/extractor.go
@@ -103,7 +103,7 @@
 // it handles zip files extracting the content
 // it stores in a new directory under ./action/XXX/suffix where x is incremented every time
 // it returns the file if a file or the directory if it was a zip file
-func (ap *ActionProxy) ExtractAction(buf *[]byte, main string, suffix string) (string, error) {
+func (ap *ActionProxy) ExtractAction(buf *[]byte, suffix string) (string, error) {
 	if buf == nil || len(*buf) == 0 {
 		return "", fmt.Errorf("no file")
 	}
@@ -114,7 +114,7 @@
 	if err != nil {
 		return "", err
 	}
-	file := newDir + "/" + main
+	file := newDir + "/exec"
 	if kind.Extension == "zip" {
 		Debug("Extract Action, assuming a zip")
 		return file, unzip(*buf, newDir)
diff --git a/openwhisk/extractor_test.go b/openwhisk/extractor_test.go
index 6c0b9a1..8e90ed7 100644
--- a/openwhisk/extractor_test.go
+++ b/openwhisk/extractor_test.go
@@ -30,7 +30,7 @@
 	// cleanup
 	assert.Nil(t, os.RemoveAll("./action/x1"))
 	file, _ := ioutil.ReadFile("_test/exec")
-	ap.ExtractAction(&file, "exec", "bin")
+	ap.ExtractAction(&file, "bin")
 	assert.Nil(t, exists("./action/x1", "bin/exec"))
 }
 
@@ -40,7 +40,7 @@
 	assert.Nil(t, os.RemoveAll("./action/x2"))
 	// match  exe
 	file, _ := ioutil.ReadFile("_test/exec")
-	ap.ExtractAction(&file, "exec", "bin")
+	ap.ExtractAction(&file, "bin")
 	assert.Equal(t, detect("./action/x2", "bin/exec"), "elf")
 }
 
@@ -51,7 +51,7 @@
 	assert.Nil(t, os.RemoveAll("./action/x3"))
 	// match  exe
 	file, _ := ioutil.ReadFile("_test/exec.zip")
-	ap.ExtractAction(&file, "exec", "bin")
+	ap.ExtractAction(&file, "bin")
 	assert.Equal(t, detect("./action/x3", "bin/exec"), "elf")
 	assert.Nil(t, exists("./action/x3", "bin/etc"))
 	assert.Nil(t, exists("./action/x3", "bin/dir/etc"))
@@ -61,7 +61,7 @@
 	log, _ := ioutil.TempFile("", "log")
 	ap := NewActionProxy("./action/x4", "", log, log)
 	buf := []byte("#!/bin/sh\necho ok")
-	_, err := ap.ExtractAction(&buf, "exec", "bin")
+	_, err := ap.ExtractAction(&buf, "bin")
 	//fmt.Print(err)
 	assert.Nil(t, err)
 }
diff --git a/openwhisk/initHandler.go b/openwhisk/initHandler.go
index 9d40f53..94454ae 100644
--- a/openwhisk/initHandler.go
+++ b/openwhisk/initHandler.go
@@ -116,7 +116,7 @@
 	}
 
 	// start an action
-	err = ap.StartLatestAction(main)
+	err = ap.StartLatestAction()
 	if err != nil {
 		sendError(w, http.StatusBadRequest, "cannot start action: "+err.Error())
 		return
@@ -134,28 +134,30 @@
 	}
 
 	// extract action
-	file, err := ap.ExtractAction(buf, main, suffix)
+	file, err := ap.ExtractAction(buf, suffix)
 	if err != nil {
 		return "", err
 	}
 	if file == "" {
 		return "", fmt.Errorf("empty filename")
 	}
-	// no compiler, we are done
-	if ap.compiler == "" {
-		return file, nil
-	}
 
 	// some path surgery
 	dir := filepath.Dir(file)
 	parent := filepath.Dir(dir)
 	srcDir := filepath.Join(parent, "src")
 	binDir := filepath.Join(parent, "bin")
-	binFile := filepath.Join(binDir, main)
+	binFile := filepath.Join(binDir, "exec")
 	os.Mkdir(binDir, 0755)
 
 	// if the file is already compiled just move it from src to bin
-	if isCompiled(file, main) {
+	if isCompiled(file) {
+		os.Rename(file, binFile)
+		return binFile, nil
+	}
+
+	// no compiler, move it anyway
+	if ap.compiler == "" {
 		os.Rename(file, binFile)
 		return binFile, nil
 	}
@@ -166,7 +168,7 @@
 	if err != nil {
 		return "", err
 	}
-	if !isCompiled(binFile, main) {
+	if !isCompiled(binFile) {
 		return "", fmt.Errorf("cannot compile")
 	}
 	return binFile, nil
diff --git a/openwhisk/initHandler_test.go b/openwhisk/initHandler_test.go
index be31b1f..803684f 100644
--- a/openwhisk/initHandler_test.go
+++ b/openwhisk/initHandler_test.go
@@ -89,7 +89,6 @@
 	// XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX
 }
 
-/* commented out test for timing problems*/
 func Example_shell_nocompiler() {
 	ts, cur, log := startTestServer("")
 	doRun(ts, "")
@@ -138,24 +137,20 @@
 	ts, cur, log := startTestServer("")
 	doRun(ts, "")
 	doInit(ts, initBinary("_test/hello_greeting.zip", "greeting"))
-	doInit(ts, initBinary("_test/hello_greeting1.zip", "greeting"))
 	doRun(ts, "")
 	stopTestServer(ts, cur, log)
 
 	ts, cur, log = startTestServer("")
 	doInit(ts, initBinary("_test/hello_message.zip", "message"))
-	doInit(ts, initBinary("_test/hello_message1.zip", "message"))
 	doRun(ts, "")
 	stopTestServer(ts, cur, log)
 	// Output:
 	// 500 {"error":"no action defined yet"}
-	// 400 {"error":"cannot start action: command exited"}
 	// 200 {"ok":true}
 	// 200 {"greetings":"Hello, Mike"}
 	// Hello, Mike
 	// XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX
 	// XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX
-	// 400 {"error":"cannot start action: command exited"}
 	// 200 {"ok":true}
 	// 200 {"message":"Hello, Mike!"}
 	// name=Mike
diff --git a/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala
index 72d3b96..bfb31e4 100644
--- a/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala
@@ -109,7 +109,7 @@
 
   override val testEntryPointOtherThanMain = TestConfig(
     """|package main
-       |func niam(args map[string]interface{}) map[string]interface{} {
+       |func Niam(args map[string]interface{}) map[string]interface{} {
        | return args
        |}
     """.stripMargin,
diff --git a/tests/src/test/scala/runtime/actionContainers/ActionLoopContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/ActionLoopContainerTests.scala
index 002bbc8..0e35784 100644
--- a/tests/src/test/scala/runtime/actionContainers/ActionLoopContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopContainerTests.scala
@@ -70,7 +70,7 @@
 
   it should "deploy a shell script" in {
     val script = shCodeHello("main")
-    val mesg = ExeBuilder.mkBase64Src(script, "main")
+    val mesg = ExeBuilder.mkBase64Src(script)
     withActionLoopContainer { c =>
       val payload = initPayload(mesg)
       c.init(payload)._1 should be(200)
@@ -79,10 +79,10 @@
   }
 
   it should "deploy a zip based script" in {
-    val scr = ExeBuilder.mkBase64SrcZip(shCodeHello("main"), "main")
+    val scr = ExeBuilder.mkBase64SrcZip(shCodeHello("exec"))
     withActionLoopContainer { c =>
       c.init(initPayload(scr))._1 should be(200)
-      c.run(helloMsg()) should be(okMsg("main", "Hello, Demo"))
+      c.run(helloMsg()) should be(okMsg("exec", "Hello, Demo"))
     }
   }
 }
diff --git a/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala
index 54857e0..4c1bad7 100644
--- a/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala
@@ -44,7 +44,7 @@
   behavior of image
 
   def helloGo(main: String, pkg: String = "main") = {
-    val func = if (main == "main") "Main" else main
+    val func = main.capitalize
     s"""|package ${pkg}
         |
         |import "fmt"
@@ -63,7 +63,7 @@
   }
 
   private def helloSrc(main: String) = Seq(
-    Seq(s"${main}") -> helloGo(main)
+    Seq(s"${main}.go") -> helloGo(main)
   )
 
   private def helloMsg(name: String = "Demo") =
@@ -80,7 +80,7 @@
   }
 
   it should "accept a binary main" in {
-    val exe = ExeBuilder.mkBase64Exe(goCompiler, helloSrc("main"), "main")
+    val exe = ExeBuilder.mkBase64Zip(goCompiler, helloSrc("main"), "main")
 
     withActionLoopContainer { c =>
       c.init(initPayload(exe))._1 shouldBe (200)
@@ -88,34 +88,9 @@
     }
   }
 
-  //def pr(x: Any) = { println(x) ; x}
-
-  it should "accept a zipped main binary" in {
-    val zip = ExeBuilder.mkBase64Zip(goCompiler, helloSrc("main"), "main")
-    withActionLoopContainer { c =>
-      c.init(initPayload(zip))._1 should be(200)
-      c.run(helloMsg()) should be(okMsg("main-main", "Hello, Demo!"))
-    }
-  }
-
-  it should "accept a binary not-main" in {
-    val exe = ExeBuilder.mkBase64Exe(goCompiler, helloSrc("hello"), "hello")
-    withActionLoopContainer { c =>
-      c.init(initPayload(exe, "hello"))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("main-hello", "Hello, Demo!"))
-    }
-  }
-
-  it should "accept a zipped binary not-main" in {
-    val zip = ExeBuilder.mkBase64Zip(goCompiler, helloSrc("hello"), "hello")
-    withActionLoopContainer { c =>
-      c.init(initPayload(zip, "hello"))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("main-hello", "Hello, Demo!"))
-    }
-  }
 
   it should "accept a src main action " in {
-    var src = ExeBuilder.mkBase64Src(helloSrc("main"), "main")
+    var src = ExeBuilder.mkBase64Src(helloSrc("main"))
     withActionLoopContainer { c =>
       c.init(initPayload(src))._1 shouldBe (200)
       c.run(helloMsg()) should be(okMsg("main-main", "Hello, Demo!"))
@@ -123,7 +98,7 @@
   }
 
   it should "accept a src not-main action " in {
-    var src = ExeBuilder.mkBase64Src(helloSrc("hello"), "hello")
+    var src = ExeBuilder.mkBase64Src(helloSrc("hello"))
     withActionLoopContainer { c =>
       c.init(initPayload(src, "hello"))._1 shouldBe (200)
       c.run(helloMsg()) should be(okMsg("main-hello", "Hello, Demo!"))
@@ -131,7 +106,7 @@
   }
 
   it should "accept a zipped src main action" in {
-    var src = ExeBuilder.mkBase64SrcZip(helloSrc("main"), "main")
+    var src = ExeBuilder.mkBase64SrcZip(helloSrc("main"))
     withActionLoopContainer { c =>
       c.init(initPayload(src))._1 shouldBe (200)
       c.run(helloMsg()) should be(okMsg("main-main", "Hello, Demo!"))
@@ -139,7 +114,7 @@
   }
 
   it should "accept a zipped src not-main action" in {
-    var src = ExeBuilder.mkBase64SrcZip(helloSrc("hello"), "hello")
+    var src = ExeBuilder.mkBase64SrcZip(helloSrc("hello"))
     withActionLoopContainer { c =>
       c.init(initPayload(src, "hello"))._1 shouldBe (200)
       c.run(helloMsg()) should be(okMsg("main-hello", "Hello, Demo!"))
@@ -150,7 +125,7 @@
     var src = ExeBuilder.mkBase64SrcZip(
       Seq(
         Seq("hello", "hello.go") -> helloGo("Hello", "hello"),
-        Seq("main") ->
+        Seq("main.go") ->
           """
           |package main
           |import "hello"
@@ -158,8 +133,7 @@
           | return hello.Hello(args)
           |}
         """.stripMargin
-      ),
-      "main"
+      )
     )
     withActionLoopContainer { c =>
       c.init(initPayload(src))._1 shouldBe (200)
diff --git a/tests/src/test/scala/runtime/actionContainers/GoResourceHelpers.scala b/tests/src/test/scala/runtime/actionContainers/GoResourceHelpers.scala
index 02782a6..0036f99 100644
--- a/tests/src/test/scala/runtime/actionContainers/GoResourceHelpers.scala
+++ b/tests/src/test/scala/runtime/actionContainers/GoResourceHelpers.scala
@@ -154,7 +154,7 @@
     }
 
     // prepare sources, then compile them
-    // return the exe File  and the output dir Path
+    // return the zip File
     private def compile(image: String,
                         sources: Seq[(Seq[String], String)],
                         main: String) = {
@@ -168,7 +168,7 @@
       // DO NOT CREATE IT IN ADVANCE or you will get a permission denied
       val binDir = tmpDirectoryFile("bin")
       binDir.mkdirs()
-      val bin = new File(binDir, main)
+      val zip = new File(binDir, main+".zip")
 
       // command to compile
       val cmd = s"${dockerBin} run -i ${image} -compile ${main}"
@@ -177,38 +177,26 @@
       //println(s"${cmd}\n<${src}\n>${bin}")
 
       import sys.process._
-      (src #> cmd #> bin).!
+      (src #> cmd #> zip).!
 
       // result
-      bin -> binDir.toPath
-
+      zip
     }
 
-    def mkBase64Exe(image: String,
-                    sources: Seq[(Seq[String] /*lines*/, String /*name*/ )],
-                    main: String) = {
-      val (exe, dir) = compile(image, sources, main)
-      //println(s"exe=${exe.getAbsolutePath}")
-      ResourceHelpers.readAsBase64(exe.toPath)
-    }
 
     def mkBase64Zip(image: String,
                     sources: Seq[(Seq[String], String)],
                     main: String) = {
-      val (exe, dir) = compile(image, sources, main)
-      val archive = makeZipFromDir(dir)
-      //println(s"zip=${archive.toFile.getAbsolutePath}")
-      ResourceHelpers.readAsBase64(archive)
+      val zip = compile(image, sources, main)
+      ResourceHelpers.readAsBase64(zip.toPath)
     }
 
-    def mkBase64Src(sources: Seq[(Seq[String], String)], main: String) = {
+    def mkBase64Src(sources: Seq[(Seq[String], String)]) = {
       val (srcDir, srcAbsPaths) = writeSourcesToHomeTmpDirectory(sources)
-      val file = new File(srcDir.toFile, main)
-      //println(file)
-      ResourceHelpers.readAsBase64(file.toPath)
+      ResourceHelpers.readAsBase64(srcAbsPaths.head)
     }
 
-    def mkBase64SrcZip(sources: Seq[(Seq[String], String)], main: String) = {
+    def mkBase64SrcZip(sources: Seq[(Seq[String], String)]) = {
       val (srcDir, srcAbsPaths) = writeSourcesToHomeTmpDirectory(sources)
       val archive = makeZipFromDir(srcDir)
       //println(s"zip=${archive.toFile.getAbsolutePath}")