diff --git a/.gitignore b/.gitignore
index 12b7ab7bc61202ca4833b7900f47d6dc2683d580..b94f87b2685dbf958f71d0b838d04bdd330a5e6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ _dist/
 _proto/*.pb.go
 bin/
 rootfs/tiller
+rootfs/rudder
 vendor/
 *.exe
 .idea/
diff --git a/Makefile b/Makefile
index d9d869a3b073dd960a82bcb66e4781e750adc3a3..dbe8e0334bce7d63827e47e454e94518cda477c2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,10 @@
-DOCKER_REGISTRY ?= gcr.io
-IMAGE_PREFIX    ?= kubernetes-helm
-SHORT_NAME      ?= tiller
-TARGETS         = darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
-DIST_DIRS       = find * -type d -exec
-APP             = helm
+DOCKER_REGISTRY   ?= gcr.io
+IMAGE_PREFIX      ?= kubernetes-helm
+SHORT_NAME        ?= tiller
+SHORT_NAME_RUDDER ?= rudder
+TARGETS           = darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
+DIST_DIRS         = find * -type d -exec
+APP               = helm
 
 # go option
 GO        ?= go
@@ -66,6 +67,19 @@ docker-build: check-docker docker-binary
 	docker build --rm -t ${IMAGE} rootfs
 	docker tag ${IMAGE} ${MUTABLE_IMAGE}
 
+.PHONY: docker-binary-rudder
+docker-binary-rudder: BINDIR = ./rootfs
+docker-binary-rudder: GOFLAGS += -a -installsuffix cgo
+docker-binary-rudder:
+	GOOS=linux GOARCH=amd64 CGO_ENABLED=0 $(GO) build -o $(BINDIR)/rudder $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' k8s.io/helm/cmd/rudder
+
+.PHONY: docker-build-experimental
+docker-build-experimental: check-docker docker-binary docker-binary-rudder
+	docker build --rm -t ${IMAGE} rootfs -f rootfs/Dockerfile.experimental
+	docker tag ${IMAGE} ${MUTABLE_IMAGE}
+	docker build --rm -t ${IMAGE_RUDDER} rootfs -f rootfs/Dockerfile.rudder
+	docker tag ${IMAGE_RUDDER} ${MUTABLE_IMAGE_RUDDER}
+
 .PHONY: test
 test: build
 test: TESTFLAGS += -race -v
diff --git a/_proto/Makefile b/_proto/Makefile
index 078514a9c84217257db52e764103bb080171588f..39f72d441ecad001f6b8917bc8ff943ac5e3843e 100644
--- a/_proto/Makefile
+++ b/_proto/Makefile
@@ -20,6 +20,10 @@ services_ias = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(services_
 services_pbs = $(sort $(wildcard hapi/services/*.proto))
 services_pkg = services
 
+rudder_ias = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(rudder_pkg),$(addprefix M,$(rudder_pbs))))
+rudder_pbs = $(sort $(wildcard hapi/rudder/*.proto))
+rudder_pkg = rudder
+
 version_ias    = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(version_pkg),$(addprefix M,$(version_pbs))))
 version_pbs    = $(sort $(wildcard hapi/version/*.proto))
 version_pkg    = version
@@ -27,7 +31,7 @@ version_pkg    = version
 google_deps	 = Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any
 
 .PHONY: all
-all: chart release services version
+all: chart release services rudder version
 
 .PHONY: chart
 chart:
@@ -41,6 +45,10 @@ release:
 services:
 	PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias),$(release_ias):$(dst) $(services_pbs)
 
+.PHONY: rudder
+rudder:
+	PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(version_ias),$(release_ias):$(dst) $(rudder_pbs)
+
 .PHONY: version
 version:
 	PATH=../bin:$(PATH) protoc --$(target)_out=plugins=$(plugins),$(google_deps):$(dst) $(version_pbs)
diff --git a/_proto/hapi/rudder/rudder.proto b/_proto/hapi/rudder/rudder.proto
new file mode 100644
index 0000000000000000000000000000000000000000..bb724ca45f9136729c4061ab6ace5df48a4b2c2c
--- /dev/null
+++ b/_proto/hapi/rudder/rudder.proto
@@ -0,0 +1,118 @@
+// Copyright 2017 The Kubernetes Authors All rights reserved.
+//
+// Licensed 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.
+
+syntax = "proto3";
+
+package hapi.services.rudder;
+
+import "hapi/release/info.proto";
+import "hapi/release/release.proto";
+
+option go_package = "rudder";
+
+service ReleaseModuleService {
+	rpc Version(VersionReleaseRequest) returns (VersionReleaseResponse)  {
+	}
+
+	// InstallRelease requests installation of a chart as a new release.
+	rpc InstallRelease(InstallReleaseRequest) returns (InstallReleaseResponse) {
+	}
+
+	// DeleteRelease requests deletion of a named release.
+	rpc DeleteRelease(DeleteReleaseRequest) returns (DeleteReleaseResponse) {
+	}
+
+	// RollbackRelease rolls back a release to a previous version.
+	rpc RollbackRelease(RollbackReleaseRequest) returns (RollbackReleaseResponse) {
+	}
+
+	// UpgradeRelease updates release content.
+	rpc UpgradeRelease(UpgradeReleaseRequest) returns (UpgradeReleaseResponse) {
+	}
+
+	// ReleaseStatus retrieves release status.
+	rpc ReleaseStatus(ReleaseStatusRequest) returns (ReleaseStatusResponse) {
+	}
+}
+
+message Result {
+	enum Status {
+		// No status set
+		UNKNOWN = 0;
+		// Operation was successful
+		SUCCESS = 1;
+		// Operation had no results (e.g. upgrade identical, rollback to same, delete non-existent)
+		UNCHANGED = 2;
+		// Operation failed
+		ERROR = 3;
+	}
+	string info = 1;
+	repeated string log = 2;
+}
+
+message VersionReleaseRequest {
+}
+
+message VersionReleaseResponse {
+	string name = 1;     // The canonical name of the release module
+	string version = 2;  // The version of the release module
+}
+
+message InstallReleaseRequest {
+	hapi.release.Release release = 1;
+}
+message InstallReleaseResponse {
+	hapi.release.Release release = 1;
+	Result result = 2;
+}
+
+message DeleteReleaseRequest {
+	hapi.release.Release release = 1;
+}
+message DeleteReleaseResponse {
+	hapi.release.Release release = 1;
+	Result result = 2;
+}
+
+message UpgradeReleaseRequest{
+        hapi.release.Release current = 1;
+        hapi.release.Release target = 2;
+        int64 Timeout = 3;
+        bool Wait = 4;
+        bool Recreate = 5;
+}
+message UpgradeReleaseResponse{
+	hapi.release.Release release = 1;
+	Result result = 2;
+}
+
+message RollbackReleaseRequest{
+        hapi.release.Release current = 1;
+        hapi.release.Release target = 2;
+        int64 Timeout = 3;
+        bool Wait = 4;
+        bool Recreate = 5;
+}
+message RollbackReleaseResponse{
+	hapi.release.Release release = 1;
+	Result result = 2;
+}
+
+message ReleaseStatusRequest{
+        hapi.release.Release release = 1;
+}
+message ReleaseStatusResponse{
+	hapi.release.Release release = 1;
+	hapi.release.Info info = 2;
+}
diff --git a/cmd/rudder/rudder.go b/cmd/rudder/rudder.go
new file mode 100644
index 0000000000000000000000000000000000000000..0a5a97bffdc61a2cc00f767680745736156f50bc
--- /dev/null
+++ b/cmd/rudder/rudder.go
@@ -0,0 +1,138 @@
+/*
+Copyright 2017 The Kubernetes Authors All rights reserved.
+
+Licensed 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 (
+	"bytes"
+	"fmt"
+	"net"
+
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/grpclog"
+	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
+
+	"k8s.io/helm/pkg/kube"
+	rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder"
+	"k8s.io/helm/pkg/rudder"
+	"k8s.io/helm/pkg/tiller"
+	"k8s.io/helm/pkg/version"
+)
+
+var kubeClient *kube.Client
+var clientset internalclientset.Interface
+
+func main() {
+	var err error
+	kubeClient = kube.New(nil)
+	clientset, err = kubeClient.ClientSet()
+	if err != nil {
+		grpclog.Fatalf("Cannot initialize Kubernetes connection: %s", err)
+	}
+
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", rudder.GrpcPort))
+	if err != nil {
+		grpclog.Fatalf("failed to listen: %v", err)
+	}
+	grpcServer := grpc.NewServer()
+	rudderAPI.RegisterReleaseModuleServiceServer(grpcServer, &ReleaseModuleServiceServer{})
+
+	grpclog.Print("Server starting")
+	grpcServer.Serve(lis)
+	grpclog.Print("Server started")
+}
+
+// ReleaseModuleServiceServer provides implementation for rudderAPI.ReleaseModuleServiceServer
+type ReleaseModuleServiceServer struct{}
+
+// Version returns Rudder version based on helm version
+func (r *ReleaseModuleServiceServer) Version(ctx context.Context, in *rudderAPI.VersionReleaseRequest) (*rudderAPI.VersionReleaseResponse, error) {
+	grpclog.Print("version")
+	return &rudderAPI.VersionReleaseResponse{
+		Name:    "helm-rudder-native",
+		Version: version.Version,
+	}, nil
+}
+
+// InstallRelease creates a release using kubeClient.Create
+func (r *ReleaseModuleServiceServer) InstallRelease(ctx context.Context, in *rudderAPI.InstallReleaseRequest) (*rudderAPI.InstallReleaseResponse, error) {
+	grpclog.Print("install")
+	b := bytes.NewBufferString(in.Release.Manifest)
+	err := kubeClient.Create(in.Release.Namespace, b, 500, false)
+	if err != nil {
+		grpclog.Printf("error when creating release: %v", err)
+	}
+	return &rudderAPI.InstallReleaseResponse{}, err
+}
+
+// DeleteRelease deletes a provided release
+func (r *ReleaseModuleServiceServer) DeleteRelease(ctx context.Context, in *rudderAPI.DeleteReleaseRequest) (*rudderAPI.DeleteReleaseResponse, error) {
+	grpclog.Print("delete")
+
+	resp := &rudderAPI.DeleteReleaseResponse{}
+	rel := in.Release
+	vs, err := tiller.GetVersionSet(clientset.Discovery())
+	if err != nil {
+		return resp, fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)
+	}
+
+	kept, errs := tiller.DeleteRelease(rel, vs, kubeClient)
+	rel.Manifest = kept
+
+	allErrors := ""
+	for _, e := range errs {
+		allErrors = allErrors + "\n" + e.Error()
+	}
+
+	if len(allErrors) > 0 {
+		err = fmt.Errorf(allErrors)
+	}
+
+	return &rudderAPI.DeleteReleaseResponse{
+		Release: rel,
+	}, err
+}
+
+// RollbackRelease rolls back the release
+func (r *ReleaseModuleServiceServer) RollbackRelease(ctx context.Context, in *rudderAPI.RollbackReleaseRequest) (*rudderAPI.RollbackReleaseResponse, error) {
+	grpclog.Print("rollback")
+	c := bytes.NewBufferString(in.Current.Manifest)
+	t := bytes.NewBufferString(in.Target.Manifest)
+	err := kubeClient.Update(in.Target.Namespace, c, t, in.Recreate, in.Timeout, in.Wait)
+	return &rudderAPI.RollbackReleaseResponse{}, err
+}
+
+// UpgradeRelease upgrades manifests using kubernetes client
+func (r *ReleaseModuleServiceServer) UpgradeRelease(ctx context.Context, in *rudderAPI.UpgradeReleaseRequest) (*rudderAPI.UpgradeReleaseResponse, error) {
+	grpclog.Print("upgrade")
+	c := bytes.NewBufferString(in.Current.Manifest)
+	t := bytes.NewBufferString(in.Target.Manifest)
+	err := kubeClient.Update(in.Target.Namespace, c, t, in.Recreate, in.Timeout, in.Wait)
+	// upgrade response object should be changed to include status
+	return &rudderAPI.UpgradeReleaseResponse{}, err
+}
+
+func (r *ReleaseModuleServiceServer) ReleaseStatus(ctx context.Context, in *rudderAPI.ReleaseStatusRequest) (*rudderAPI.ReleaseStatusResponse, error) {
+	grpclog.Print("status")
+
+	resp, err := kubeClient.Get(in.Release.Namespace, bytes.NewBufferString(in.Release.Manifest))
+	in.Release.Info.Status.Resources = resp
+	return &rudderAPI.ReleaseStatusResponse{
+		Release: in.Release,
+		Info:    in.Release.Info,
+	}, err
+}
diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go
index 2f193936e906713c861579a14688ab60fd9f6132..e5f3a33f3d21b70ba06640363c591b0756c703d0 100644
--- a/cmd/tiller/tiller.go
+++ b/cmd/tiller/tiller.go
@@ -70,11 +70,12 @@ var rootServer *grpc.Server
 var env = environment.New()
 
 var (
-	grpcAddr      = ":44134"
-	probeAddr     = ":44135"
-	traceAddr     = ":44136"
-	enableTracing = false
-	store         = storageConfigMap
+	grpcAddr             = ":44134"
+	probeAddr            = ":44135"
+	traceAddr            = ":44136"
+	enableTracing        = false
+	store                = storageConfigMap
+	remoteReleaseModules = false
 )
 
 var (
@@ -108,6 +109,7 @@ func main() {
 	p.StringVarP(&grpcAddr, "listen", "l", ":44134", "address:port to listen on")
 	p.StringVar(&store, "storage", storageConfigMap, "storage driver to use. One of 'configmap' or 'memory'")
 	p.BoolVar(&enableTracing, "trace", false, "enable rpc tracing")
+	p.BoolVar(&remoteReleaseModules, "experimental-release", false, "enable experimental release modules")
 
 	p.BoolVar(&tlsEnable, "tls", tlsEnableEnvVarDefault(), "enable TLS")
 	p.BoolVar(&tlsVerify, "tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate")
@@ -173,7 +175,7 @@ func start(c *cobra.Command, args []string) {
 	srvErrCh := make(chan error)
 	probeErrCh := make(chan error)
 	go func() {
-		svc := tiller.NewReleaseServer(env, clientset)
+		svc := tiller.NewReleaseServer(env, clientset, remoteReleaseModules)
 		services.RegisterReleaseServiceServer(rootServer, svc)
 		if err := rootServer.Serve(lstn); err != nil {
 			srvErrCh <- err
diff --git a/pkg/proto/hapi/rudder/rudder.pb.go b/pkg/proto/hapi/rudder/rudder.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..af5577678d668f1736a0c27d326cc3f2fc31aab9
--- /dev/null
+++ b/pkg/proto/hapi/rudder/rudder.pb.go
@@ -0,0 +1,706 @@
+// Code generated by protoc-gen-go.
+// source: hapi/rudder/rudder.proto
+// DO NOT EDIT!
+
+/*
+Package rudder is a generated protocol buffer package.
+
+It is generated from these files:
+	hapi/rudder/rudder.proto
+
+It has these top-level messages:
+	Result
+	VersionReleaseRequest
+	VersionReleaseResponse
+	InstallReleaseRequest
+	InstallReleaseResponse
+	DeleteReleaseRequest
+	DeleteReleaseResponse
+	UpgradeReleaseRequest
+	UpgradeReleaseResponse
+	RollbackReleaseRequest
+	RollbackReleaseResponse
+	ReleaseStatusRequest
+	ReleaseStatusResponse
+*/
+package rudder
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+import hapi_release3 "k8s.io/helm/pkg/proto/hapi/release"
+import hapi_release5 "k8s.io/helm/pkg/proto/hapi/release"
+
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type Result_Status int32
+
+const (
+	// No status set
+	Result_UNKNOWN Result_Status = 0
+	// Operation was successful
+	Result_SUCCESS Result_Status = 1
+	// Operation had no results (e.g. upgrade identical, rollback to same, delete non-existent)
+	Result_UNCHANGED Result_Status = 2
+	// Operation failed
+	Result_ERROR Result_Status = 3
+)
+
+var Result_Status_name = map[int32]string{
+	0: "UNKNOWN",
+	1: "SUCCESS",
+	2: "UNCHANGED",
+	3: "ERROR",
+}
+var Result_Status_value = map[string]int32{
+	"UNKNOWN":   0,
+	"SUCCESS":   1,
+	"UNCHANGED": 2,
+	"ERROR":     3,
+}
+
+func (x Result_Status) String() string {
+	return proto.EnumName(Result_Status_name, int32(x))
+}
+func (Result_Status) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} }
+
+type Result struct {
+	Info string   `protobuf:"bytes,1,opt,name=info" json:"info,omitempty"`
+	Log  []string `protobuf:"bytes,2,rep,name=log" json:"log,omitempty"`
+}
+
+func (m *Result) Reset()                    { *m = Result{} }
+func (m *Result) String() string            { return proto.CompactTextString(m) }
+func (*Result) ProtoMessage()               {}
+func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+func (m *Result) GetInfo() string {
+	if m != nil {
+		return m.Info
+	}
+	return ""
+}
+
+func (m *Result) GetLog() []string {
+	if m != nil {
+		return m.Log
+	}
+	return nil
+}
+
+type VersionReleaseRequest struct {
+}
+
+func (m *VersionReleaseRequest) Reset()                    { *m = VersionReleaseRequest{} }
+func (m *VersionReleaseRequest) String() string            { return proto.CompactTextString(m) }
+func (*VersionReleaseRequest) ProtoMessage()               {}
+func (*VersionReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+type VersionReleaseResponse struct {
+	Name    string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"`
+}
+
+func (m *VersionReleaseResponse) Reset()                    { *m = VersionReleaseResponse{} }
+func (m *VersionReleaseResponse) String() string            { return proto.CompactTextString(m) }
+func (*VersionReleaseResponse) ProtoMessage()               {}
+func (*VersionReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+
+func (m *VersionReleaseResponse) GetName() string {
+	if m != nil {
+		return m.Name
+	}
+	return ""
+}
+
+func (m *VersionReleaseResponse) GetVersion() string {
+	if m != nil {
+		return m.Version
+	}
+	return ""
+}
+
+type InstallReleaseRequest struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+}
+
+func (m *InstallReleaseRequest) Reset()                    { *m = InstallReleaseRequest{} }
+func (m *InstallReleaseRequest) String() string            { return proto.CompactTextString(m) }
+func (*InstallReleaseRequest) ProtoMessage()               {}
+func (*InstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
+
+func (m *InstallReleaseRequest) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+type InstallReleaseResponse struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+	Result  *Result                `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"`
+}
+
+func (m *InstallReleaseResponse) Reset()                    { *m = InstallReleaseResponse{} }
+func (m *InstallReleaseResponse) String() string            { return proto.CompactTextString(m) }
+func (*InstallReleaseResponse) ProtoMessage()               {}
+func (*InstallReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+
+func (m *InstallReleaseResponse) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+func (m *InstallReleaseResponse) GetResult() *Result {
+	if m != nil {
+		return m.Result
+	}
+	return nil
+}
+
+type DeleteReleaseRequest struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+}
+
+func (m *DeleteReleaseRequest) Reset()                    { *m = DeleteReleaseRequest{} }
+func (m *DeleteReleaseRequest) String() string            { return proto.CompactTextString(m) }
+func (*DeleteReleaseRequest) ProtoMessage()               {}
+func (*DeleteReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
+
+func (m *DeleteReleaseRequest) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+type DeleteReleaseResponse struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+	Result  *Result                `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"`
+}
+
+func (m *DeleteReleaseResponse) Reset()                    { *m = DeleteReleaseResponse{} }
+func (m *DeleteReleaseResponse) String() string            { return proto.CompactTextString(m) }
+func (*DeleteReleaseResponse) ProtoMessage()               {}
+func (*DeleteReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
+
+func (m *DeleteReleaseResponse) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+func (m *DeleteReleaseResponse) GetResult() *Result {
+	if m != nil {
+		return m.Result
+	}
+	return nil
+}
+
+type UpgradeReleaseRequest struct {
+	Current  *hapi_release5.Release `protobuf:"bytes,1,opt,name=current" json:"current,omitempty"`
+	Target   *hapi_release5.Release `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"`
+	Timeout  int64                  `protobuf:"varint,3,opt,name=Timeout" json:"Timeout,omitempty"`
+	Wait     bool                   `protobuf:"varint,4,opt,name=Wait" json:"Wait,omitempty"`
+	Recreate bool                   `protobuf:"varint,5,opt,name=Recreate" json:"Recreate,omitempty"`
+}
+
+func (m *UpgradeReleaseRequest) Reset()                    { *m = UpgradeReleaseRequest{} }
+func (m *UpgradeReleaseRequest) String() string            { return proto.CompactTextString(m) }
+func (*UpgradeReleaseRequest) ProtoMessage()               {}
+func (*UpgradeReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
+
+func (m *UpgradeReleaseRequest) GetCurrent() *hapi_release5.Release {
+	if m != nil {
+		return m.Current
+	}
+	return nil
+}
+
+func (m *UpgradeReleaseRequest) GetTarget() *hapi_release5.Release {
+	if m != nil {
+		return m.Target
+	}
+	return nil
+}
+
+func (m *UpgradeReleaseRequest) GetTimeout() int64 {
+	if m != nil {
+		return m.Timeout
+	}
+	return 0
+}
+
+func (m *UpgradeReleaseRequest) GetWait() bool {
+	if m != nil {
+		return m.Wait
+	}
+	return false
+}
+
+func (m *UpgradeReleaseRequest) GetRecreate() bool {
+	if m != nil {
+		return m.Recreate
+	}
+	return false
+}
+
+type UpgradeReleaseResponse struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+	Result  *Result                `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"`
+}
+
+func (m *UpgradeReleaseResponse) Reset()                    { *m = UpgradeReleaseResponse{} }
+func (m *UpgradeReleaseResponse) String() string            { return proto.CompactTextString(m) }
+func (*UpgradeReleaseResponse) ProtoMessage()               {}
+func (*UpgradeReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
+
+func (m *UpgradeReleaseResponse) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+func (m *UpgradeReleaseResponse) GetResult() *Result {
+	if m != nil {
+		return m.Result
+	}
+	return nil
+}
+
+type RollbackReleaseRequest struct {
+	Current  *hapi_release5.Release `protobuf:"bytes,1,opt,name=current" json:"current,omitempty"`
+	Target   *hapi_release5.Release `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"`
+	Timeout  int64                  `protobuf:"varint,3,opt,name=Timeout" json:"Timeout,omitempty"`
+	Wait     bool                   `protobuf:"varint,4,opt,name=Wait" json:"Wait,omitempty"`
+	Recreate bool                   `protobuf:"varint,5,opt,name=Recreate" json:"Recreate,omitempty"`
+}
+
+func (m *RollbackReleaseRequest) Reset()                    { *m = RollbackReleaseRequest{} }
+func (m *RollbackReleaseRequest) String() string            { return proto.CompactTextString(m) }
+func (*RollbackReleaseRequest) ProtoMessage()               {}
+func (*RollbackReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
+
+func (m *RollbackReleaseRequest) GetCurrent() *hapi_release5.Release {
+	if m != nil {
+		return m.Current
+	}
+	return nil
+}
+
+func (m *RollbackReleaseRequest) GetTarget() *hapi_release5.Release {
+	if m != nil {
+		return m.Target
+	}
+	return nil
+}
+
+func (m *RollbackReleaseRequest) GetTimeout() int64 {
+	if m != nil {
+		return m.Timeout
+	}
+	return 0
+}
+
+func (m *RollbackReleaseRequest) GetWait() bool {
+	if m != nil {
+		return m.Wait
+	}
+	return false
+}
+
+func (m *RollbackReleaseRequest) GetRecreate() bool {
+	if m != nil {
+		return m.Recreate
+	}
+	return false
+}
+
+type RollbackReleaseResponse struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+	Result  *Result                `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"`
+}
+
+func (m *RollbackReleaseResponse) Reset()                    { *m = RollbackReleaseResponse{} }
+func (m *RollbackReleaseResponse) String() string            { return proto.CompactTextString(m) }
+func (*RollbackReleaseResponse) ProtoMessage()               {}
+func (*RollbackReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
+
+func (m *RollbackReleaseResponse) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+func (m *RollbackReleaseResponse) GetResult() *Result {
+	if m != nil {
+		return m.Result
+	}
+	return nil
+}
+
+type ReleaseStatusRequest struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+}
+
+func (m *ReleaseStatusRequest) Reset()                    { *m = ReleaseStatusRequest{} }
+func (m *ReleaseStatusRequest) String() string            { return proto.CompactTextString(m) }
+func (*ReleaseStatusRequest) ProtoMessage()               {}
+func (*ReleaseStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
+
+func (m *ReleaseStatusRequest) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+type ReleaseStatusResponse struct {
+	Release *hapi_release5.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
+	Info    *hapi_release3.Info    `protobuf:"bytes,2,opt,name=info" json:"info,omitempty"`
+}
+
+func (m *ReleaseStatusResponse) Reset()                    { *m = ReleaseStatusResponse{} }
+func (m *ReleaseStatusResponse) String() string            { return proto.CompactTextString(m) }
+func (*ReleaseStatusResponse) ProtoMessage()               {}
+func (*ReleaseStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
+
+func (m *ReleaseStatusResponse) GetRelease() *hapi_release5.Release {
+	if m != nil {
+		return m.Release
+	}
+	return nil
+}
+
+func (m *ReleaseStatusResponse) GetInfo() *hapi_release3.Info {
+	if m != nil {
+		return m.Info
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterType((*Result)(nil), "hapi.services.rudder.Result")
+	proto.RegisterType((*VersionReleaseRequest)(nil), "hapi.services.rudder.VersionReleaseRequest")
+	proto.RegisterType((*VersionReleaseResponse)(nil), "hapi.services.rudder.VersionReleaseResponse")
+	proto.RegisterType((*InstallReleaseRequest)(nil), "hapi.services.rudder.InstallReleaseRequest")
+	proto.RegisterType((*InstallReleaseResponse)(nil), "hapi.services.rudder.InstallReleaseResponse")
+	proto.RegisterType((*DeleteReleaseRequest)(nil), "hapi.services.rudder.DeleteReleaseRequest")
+	proto.RegisterType((*DeleteReleaseResponse)(nil), "hapi.services.rudder.DeleteReleaseResponse")
+	proto.RegisterType((*UpgradeReleaseRequest)(nil), "hapi.services.rudder.UpgradeReleaseRequest")
+	proto.RegisterType((*UpgradeReleaseResponse)(nil), "hapi.services.rudder.UpgradeReleaseResponse")
+	proto.RegisterType((*RollbackReleaseRequest)(nil), "hapi.services.rudder.RollbackReleaseRequest")
+	proto.RegisterType((*RollbackReleaseResponse)(nil), "hapi.services.rudder.RollbackReleaseResponse")
+	proto.RegisterType((*ReleaseStatusRequest)(nil), "hapi.services.rudder.ReleaseStatusRequest")
+	proto.RegisterType((*ReleaseStatusResponse)(nil), "hapi.services.rudder.ReleaseStatusResponse")
+	proto.RegisterEnum("hapi.services.rudder.Result_Status", Result_Status_name, Result_Status_value)
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// Client API for ReleaseModuleService service
+
+type ReleaseModuleServiceClient interface {
+	Version(ctx context.Context, in *VersionReleaseRequest, opts ...grpc.CallOption) (*VersionReleaseResponse, error)
+	// InstallRelease requests installation of a chart as a new release.
+	InstallRelease(ctx context.Context, in *InstallReleaseRequest, opts ...grpc.CallOption) (*InstallReleaseResponse, error)
+	// DeleteRelease requests deletion of a named release.
+	DeleteRelease(ctx context.Context, in *DeleteReleaseRequest, opts ...grpc.CallOption) (*DeleteReleaseResponse, error)
+	// RollbackRelease rolls back a release to a previous version.
+	RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error)
+	// UpgradeRelease updates release content.
+	UpgradeRelease(ctx context.Context, in *UpgradeReleaseRequest, opts ...grpc.CallOption) (*UpgradeReleaseResponse, error)
+	// ReleaseStatus retrieves release status.
+	ReleaseStatus(ctx context.Context, in *ReleaseStatusRequest, opts ...grpc.CallOption) (*ReleaseStatusResponse, error)
+}
+
+type releaseModuleServiceClient struct {
+	cc *grpc.ClientConn
+}
+
+func NewReleaseModuleServiceClient(cc *grpc.ClientConn) ReleaseModuleServiceClient {
+	return &releaseModuleServiceClient{cc}
+}
+
+func (c *releaseModuleServiceClient) Version(ctx context.Context, in *VersionReleaseRequest, opts ...grpc.CallOption) (*VersionReleaseResponse, error) {
+	out := new(VersionReleaseResponse)
+	err := grpc.Invoke(ctx, "/hapi.services.rudder.ReleaseModuleService/Version", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *releaseModuleServiceClient) InstallRelease(ctx context.Context, in *InstallReleaseRequest, opts ...grpc.CallOption) (*InstallReleaseResponse, error) {
+	out := new(InstallReleaseResponse)
+	err := grpc.Invoke(ctx, "/hapi.services.rudder.ReleaseModuleService/InstallRelease", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *releaseModuleServiceClient) DeleteRelease(ctx context.Context, in *DeleteReleaseRequest, opts ...grpc.CallOption) (*DeleteReleaseResponse, error) {
+	out := new(DeleteReleaseResponse)
+	err := grpc.Invoke(ctx, "/hapi.services.rudder.ReleaseModuleService/DeleteRelease", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *releaseModuleServiceClient) RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error) {
+	out := new(RollbackReleaseResponse)
+	err := grpc.Invoke(ctx, "/hapi.services.rudder.ReleaseModuleService/RollbackRelease", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *releaseModuleServiceClient) UpgradeRelease(ctx context.Context, in *UpgradeReleaseRequest, opts ...grpc.CallOption) (*UpgradeReleaseResponse, error) {
+	out := new(UpgradeReleaseResponse)
+	err := grpc.Invoke(ctx, "/hapi.services.rudder.ReleaseModuleService/UpgradeRelease", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *releaseModuleServiceClient) ReleaseStatus(ctx context.Context, in *ReleaseStatusRequest, opts ...grpc.CallOption) (*ReleaseStatusResponse, error) {
+	out := new(ReleaseStatusResponse)
+	err := grpc.Invoke(ctx, "/hapi.services.rudder.ReleaseModuleService/ReleaseStatus", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// Server API for ReleaseModuleService service
+
+type ReleaseModuleServiceServer interface {
+	Version(context.Context, *VersionReleaseRequest) (*VersionReleaseResponse, error)
+	// InstallRelease requests installation of a chart as a new release.
+	InstallRelease(context.Context, *InstallReleaseRequest) (*InstallReleaseResponse, error)
+	// DeleteRelease requests deletion of a named release.
+	DeleteRelease(context.Context, *DeleteReleaseRequest) (*DeleteReleaseResponse, error)
+	// RollbackRelease rolls back a release to a previous version.
+	RollbackRelease(context.Context, *RollbackReleaseRequest) (*RollbackReleaseResponse, error)
+	// UpgradeRelease updates release content.
+	UpgradeRelease(context.Context, *UpgradeReleaseRequest) (*UpgradeReleaseResponse, error)
+	// ReleaseStatus retrieves release status.
+	ReleaseStatus(context.Context, *ReleaseStatusRequest) (*ReleaseStatusResponse, error)
+}
+
+func RegisterReleaseModuleServiceServer(s *grpc.Server, srv ReleaseModuleServiceServer) {
+	s.RegisterService(&_ReleaseModuleService_serviceDesc, srv)
+}
+
+func _ReleaseModuleService_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(VersionReleaseRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ReleaseModuleServiceServer).Version(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/hapi.services.rudder.ReleaseModuleService/Version",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ReleaseModuleServiceServer).Version(ctx, req.(*VersionReleaseRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _ReleaseModuleService_InstallRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(InstallReleaseRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ReleaseModuleServiceServer).InstallRelease(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/hapi.services.rudder.ReleaseModuleService/InstallRelease",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ReleaseModuleServiceServer).InstallRelease(ctx, req.(*InstallReleaseRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _ReleaseModuleService_DeleteRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(DeleteReleaseRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ReleaseModuleServiceServer).DeleteRelease(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/hapi.services.rudder.ReleaseModuleService/DeleteRelease",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ReleaseModuleServiceServer).DeleteRelease(ctx, req.(*DeleteReleaseRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _ReleaseModuleService_RollbackRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(RollbackReleaseRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ReleaseModuleServiceServer).RollbackRelease(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/hapi.services.rudder.ReleaseModuleService/RollbackRelease",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ReleaseModuleServiceServer).RollbackRelease(ctx, req.(*RollbackReleaseRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _ReleaseModuleService_UpgradeRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(UpgradeReleaseRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ReleaseModuleServiceServer).UpgradeRelease(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/hapi.services.rudder.ReleaseModuleService/UpgradeRelease",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ReleaseModuleServiceServer).UpgradeRelease(ctx, req.(*UpgradeReleaseRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _ReleaseModuleService_ReleaseStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ReleaseStatusRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ReleaseModuleServiceServer).ReleaseStatus(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/hapi.services.rudder.ReleaseModuleService/ReleaseStatus",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ReleaseModuleServiceServer).ReleaseStatus(ctx, req.(*ReleaseStatusRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _ReleaseModuleService_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "hapi.services.rudder.ReleaseModuleService",
+	HandlerType: (*ReleaseModuleServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Version",
+			Handler:    _ReleaseModuleService_Version_Handler,
+		},
+		{
+			MethodName: "InstallRelease",
+			Handler:    _ReleaseModuleService_InstallRelease_Handler,
+		},
+		{
+			MethodName: "DeleteRelease",
+			Handler:    _ReleaseModuleService_DeleteRelease_Handler,
+		},
+		{
+			MethodName: "RollbackRelease",
+			Handler:    _ReleaseModuleService_RollbackRelease_Handler,
+		},
+		{
+			MethodName: "UpgradeRelease",
+			Handler:    _ReleaseModuleService_UpgradeRelease_Handler,
+		},
+		{
+			MethodName: "ReleaseStatus",
+			Handler:    _ReleaseModuleService_ReleaseStatus_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "hapi/rudder/rudder.proto",
+}
+
+func init() { proto.RegisterFile("hapi/rudder/rudder.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 584 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xd4, 0x56, 0xd1, 0x8e, 0xd2, 0x40,
+	0x14, 0xa5, 0xcb, 0x52, 0xe0, 0x92, 0x55, 0x32, 0xd9, 0x42, 0xd3, 0xf8, 0x40, 0xfa, 0x60, 0x88,
+	0xeb, 0x96, 0x04, 0x7d, 0xf4, 0x45, 0x59, 0xdc, 0xdd, 0x18, 0xd9, 0x64, 0x2a, 0x6e, 0xe2, 0x5b,
+	0x17, 0x2e, 0x58, 0x2d, 0x6d, 0x9d, 0x4e, 0xf7, 0x51, 0xfd, 0x1a, 0xff, 0x43, 0xbf, 0xcc, 0xb4,
+	0xd3, 0x12, 0x5b, 0xa7, 0x11, 0xd7, 0x84, 0xc4, 0xa7, 0xce, 0xf4, 0x1e, 0xee, 0x9c, 0x73, 0x7a,
+	0xe7, 0x04, 0xd0, 0xdf, 0x3b, 0xa1, 0x3b, 0x62, 0xf1, 0x72, 0x89, 0x2c, 0x7b, 0x58, 0x21, 0x0b,
+	0x78, 0x40, 0x8e, 0x93, 0x8a, 0x15, 0x21, 0xbb, 0x75, 0x17, 0x18, 0x59, 0xa2, 0x66, 0xf4, 0x05,
+	0x1e, 0x3d, 0x74, 0x22, 0x1c, 0xb9, 0xfe, 0x2a, 0x10, 0x70, 0xc3, 0x28, 0x14, 0xb2, 0xa7, 0xa8,
+	0x99, 0x1e, 0xa8, 0x14, 0xa3, 0xd8, 0xe3, 0x84, 0xc0, 0x61, 0xf2, 0x1b, 0x5d, 0x19, 0x28, 0xc3,
+	0x36, 0x4d, 0xd7, 0xa4, 0x0b, 0x75, 0x2f, 0x58, 0xeb, 0x07, 0x83, 0xfa, 0xb0, 0x4d, 0x93, 0xa5,
+	0xf9, 0x0c, 0x54, 0x9b, 0x3b, 0x3c, 0x8e, 0x48, 0x07, 0x9a, 0xf3, 0xd9, 0xab, 0xd9, 0xd5, 0xf5,
+	0xac, 0x5b, 0x4b, 0x36, 0xf6, 0x7c, 0x32, 0x99, 0xda, 0x76, 0x57, 0x21, 0x47, 0xd0, 0x9e, 0xcf,
+	0x26, 0x17, 0xcf, 0x67, 0xe7, 0xd3, 0xb3, 0xee, 0x01, 0x69, 0x43, 0x63, 0x4a, 0xe9, 0x15, 0xed,
+	0xd6, 0xcd, 0x3e, 0x68, 0x6f, 0x91, 0x45, 0x6e, 0xe0, 0x53, 0xc1, 0x82, 0xe2, 0xa7, 0x18, 0x23,
+	0x6e, 0xbe, 0x84, 0x5e, 0xb9, 0x10, 0x85, 0x81, 0x1f, 0x61, 0x42, 0xcb, 0x77, 0x36, 0x98, 0xd3,
+	0x4a, 0xd6, 0x44, 0x87, 0xe6, 0xad, 0x40, 0xeb, 0x07, 0xe9, 0xeb, 0x7c, 0x6b, 0x5e, 0x80, 0x76,
+	0xe9, 0x47, 0xdc, 0xf1, 0xbc, 0xe2, 0x01, 0x64, 0x04, 0xcd, 0x4c, 0x78, 0xda, 0xa9, 0x33, 0xd6,
+	0xac, 0xd4, 0xc4, 0xdc, 0x8d, 0x1c, 0x9e, 0xa3, 0xcc, 0x2f, 0xd0, 0x2b, 0x77, 0xca, 0x18, 0xfd,
+	0x6d, 0x2b, 0xf2, 0x14, 0x54, 0x96, 0x7a, 0x9c, 0xb2, 0xed, 0x8c, 0x1f, 0x58, 0xb2, 0xef, 0x67,
+	0x89, 0xef, 0x40, 0x33, 0xac, 0x79, 0x0e, 0xc7, 0x67, 0xe8, 0x21, 0xc7, 0x7f, 0x55, 0xf2, 0x19,
+	0xb4, 0x52, 0xa3, 0xfd, 0x0a, 0xf9, 0xae, 0x80, 0x36, 0x0f, 0xd7, 0xcc, 0x59, 0x4a, 0xa4, 0x2c,
+	0x62, 0xc6, 0xd0, 0xe7, 0x7f, 0x20, 0x90, 0xa1, 0xc8, 0x29, 0xa8, 0xdc, 0x61, 0x6b, 0xcc, 0x09,
+	0x54, 0xe0, 0x33, 0x50, 0x32, 0x27, 0x6f, 0xdc, 0x0d, 0x06, 0x31, 0xd7, 0xeb, 0x03, 0x65, 0x58,
+	0xa7, 0xf9, 0x36, 0x99, 0xaa, 0x6b, 0xc7, 0xe5, 0xfa, 0xe1, 0x40, 0x19, 0xb6, 0x68, 0xba, 0x26,
+	0x06, 0xb4, 0x28, 0x2e, 0x18, 0x3a, 0x1c, 0xf5, 0x46, 0xfa, 0x7e, 0xbb, 0x4f, 0xa6, 0xa1, 0x2c,
+	0x61, 0xbf, 0x26, 0xfe, 0x50, 0xa0, 0x47, 0x03, 0xcf, 0xbb, 0x71, 0x16, 0x1f, 0xff, 0x5b, 0x17,
+	0xbf, 0x2a, 0xd0, 0xff, 0x4d, 0xc4, 0xde, 0x6f, 0x55, 0xd6, 0x49, 0xc4, 0xd8, 0x9d, 0x6f, 0x55,
+	0x08, 0x5a, 0xa9, 0xd1, 0x5d, 0x85, 0x3c, 0xcc, 0x82, 0x57, 0xc8, 0x20, 0x45, 0xf4, 0xa5, 0xbf,
+	0x0a, 0x44, 0x18, 0x8f, 0xbf, 0x35, 0xb6, 0xdc, 0x5f, 0x07, 0xcb, 0xd8, 0x43, 0x5b, 0x48, 0x25,
+	0x2b, 0x68, 0x66, 0xe1, 0x49, 0x4e, 0xe4, 0x26, 0x48, 0x43, 0xd7, 0x78, 0xbc, 0x1b, 0x58, 0xe8,
+	0x32, 0x6b, 0x64, 0x03, 0xf7, 0x8a, 0x91, 0x58, 0x75, 0x9c, 0x34, 0x82, 0xab, 0x8e, 0x93, 0xa7,
+	0xac, 0x59, 0x23, 0x1f, 0xe0, 0xa8, 0x90, 0x5b, 0xe4, 0x91, 0xbc, 0x81, 0x2c, 0x25, 0x8d, 0x93,
+	0x9d, 0xb0, 0xdb, 0xb3, 0x42, 0xb8, 0x5f, 0x1a, 0x4c, 0x52, 0x41, 0x57, 0x7e, 0x09, 0x8d, 0xd3,
+	0x1d, 0xd1, 0xbf, 0x9a, 0x59, 0x4c, 0x94, 0x2a, 0x33, 0xa5, 0xd1, 0x59, 0x65, 0xa6, 0x3c, 0xa4,
+	0x84, 0x99, 0x85, 0x71, 0xad, 0x32, 0x53, 0x76, 0x39, 0xaa, 0xcc, 0x94, 0xce, 0xbf, 0x59, 0x7b,
+	0xd1, 0x7a, 0xa7, 0x0a, 0xc4, 0x8d, 0x9a, 0xfe, 0xc9, 0x78, 0xf2, 0x33, 0x00, 0x00, 0xff, 0xff,
+	0x52, 0x0c, 0xa8, 0x50, 0xcb, 0x08, 0x00, 0x00,
+}
diff --git a/pkg/rudder/client.go b/pkg/rudder/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..219bb010ac65cb88e4b8714f5c951b0699a0c7d7
--- /dev/null
+++ b/pkg/rudder/client.go
@@ -0,0 +1,91 @@
+/*
+Copyright 2017 The Kubernetes Authors All rights reserved.
+
+Licensed 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 rudder // import "k8s.io/helm/pkg/rudder"
+
+import (
+	"fmt"
+
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+
+	rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder"
+)
+
+// GrpcPort specifies port on which rudder will spawn a server
+const (
+	GrpcPort = 10001
+)
+
+var grpcAddr = fmt.Sprintf("127.0.0.1:%d", GrpcPort)
+
+// InstallRelease calls Rudder InstallRelease method which should create provided release
+func InstallRelease(rel *rudderAPI.InstallReleaseRequest) (*rudderAPI.InstallReleaseResponse, error) {
+	//TODO(mkwiek): parametrize this
+	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
+	if err != nil {
+		return nil, err
+	}
+
+	defer conn.Close()
+	client := rudderAPI.NewReleaseModuleServiceClient(conn)
+	return client.InstallRelease(context.Background(), rel)
+}
+
+// UpgradeRelease calls Rudder UpgradeRelease method which should perform update
+func UpgradeRelease(req *rudderAPI.UpgradeReleaseRequest) (*rudderAPI.UpgradeReleaseResponse, error) {
+	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+	client := rudderAPI.NewReleaseModuleServiceClient(conn)
+	return client.UpgradeRelease(context.Background(), req)
+}
+
+// RollbackRelease calls Rudder RollbackRelease method which should perform update
+func RollbackRelease(req *rudderAPI.RollbackReleaseRequest) (*rudderAPI.RollbackReleaseResponse, error) {
+	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+	client := rudderAPI.NewReleaseModuleServiceClient(conn)
+	return client.RollbackRelease(context.Background(), req)
+}
+
+// ReleaseStatus calls Rudder ReleaseStatus method which should perform update
+func ReleaseStatus(req *rudderAPI.ReleaseStatusRequest) (*rudderAPI.ReleaseStatusResponse, error) {
+	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+	client := rudderAPI.NewReleaseModuleServiceClient(conn)
+	return client.ReleaseStatus(context.Background(), req)
+}
+
+// DeleteRelease calls Rudder DeleteRelease method which should uninstall provided release
+func DeleteRelease(rel *rudderAPI.DeleteReleaseRequest) (*rudderAPI.DeleteReleaseResponse, error) {
+	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
+	if err != nil {
+		return nil, err
+	}
+
+	defer conn.Close()
+	client := rudderAPI.NewReleaseModuleServiceClient(conn)
+	return client.DeleteRelease(context.Background(), rel)
+}
diff --git a/pkg/tiller/release_modules.go b/pkg/tiller/release_modules.go
new file mode 100644
index 0000000000000000000000000000000000000000..e13b26de970b0464c50af440576f5157e0ee2d6d
--- /dev/null
+++ b/pkg/tiller/release_modules.go
@@ -0,0 +1,172 @@
+/*
+Copyright 2017 The Kubernetes Authors All rights reserved.
+
+Licensed 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 tiller
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"log"
+	"strings"
+
+	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
+
+	"k8s.io/helm/pkg/chartutil"
+	"k8s.io/helm/pkg/kube"
+	"k8s.io/helm/pkg/proto/hapi/release"
+	rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder"
+	"k8s.io/helm/pkg/proto/hapi/services"
+	relutil "k8s.io/helm/pkg/releaseutil"
+	"k8s.io/helm/pkg/rudder"
+	"k8s.io/helm/pkg/tiller/environment"
+)
+
+// ReleaseModule is an interface that allows ReleaseServer to run operations on release via either local implementation or Rudder service
+type ReleaseModule interface {
+	Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error
+	Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error
+	Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error
+	Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error)
+	Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error)
+}
+
+// LocalReleaseModule is a local implementation of ReleaseModule
+type LocalReleaseModule struct {
+	clientset internalclientset.Interface
+}
+
+// Create creates a release via kubeclient from provided environment
+func (m *LocalReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error {
+	b := bytes.NewBufferString(r.Manifest)
+	return env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait)
+}
+
+// Update performs an update from current to target release
+func (m *LocalReleaseModule) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error {
+	c := bytes.NewBufferString(current.Manifest)
+	t := bytes.NewBufferString(target.Manifest)
+	return env.KubeClient.Update(target.Namespace, c, t, req.Recreate, req.Timeout, req.Wait)
+}
+
+// Rollback performs a rollback from current to target release
+func (m *LocalReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error {
+	c := bytes.NewBufferString(current.Manifest)
+	t := bytes.NewBufferString(target.Manifest)
+	return env.KubeClient.Update(target.Namespace, c, t, req.Recreate, req.Timeout, req.Wait)
+}
+
+// Status returns kubectl-like formatted status of release objects
+func (m *LocalReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) {
+	return env.KubeClient.Get(r.Namespace, bytes.NewBufferString(r.Manifest))
+}
+
+// Delete deletes the release and returns manifests that were kept in the deletion process
+func (m *LocalReleaseModule) Delete(rel *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (kept string, errs []error) {
+	vs, err := GetVersionSet(m.clientset.Discovery())
+	if err != nil {
+		return rel.Manifest, []error{fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)}
+	}
+	return DeleteRelease(rel, vs, env.KubeClient)
+}
+
+// RemoteReleaseModule is a ReleaseModule which calls Rudder service to operate on a release
+type RemoteReleaseModule struct{}
+
+// Create calls rudder.InstallRelease
+func (m *RemoteReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error {
+	request := &rudderAPI.InstallReleaseRequest{Release: r}
+	_, err := rudder.InstallRelease(request)
+	return err
+}
+
+// Update calls rudder.UpgradeRelease
+func (m *RemoteReleaseModule) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error {
+	upgrade := &rudderAPI.UpgradeReleaseRequest{
+		Current:  current,
+		Target:   target,
+		Recreate: req.Recreate,
+		Timeout:  req.Timeout,
+		Wait:     req.Wait,
+	}
+	_, err := rudder.UpgradeRelease(upgrade)
+	return err
+}
+
+// Rollback calls rudder.Rollback
+func (m *RemoteReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error {
+	rollback := &rudderAPI.RollbackReleaseRequest{
+		Current:  current,
+		Target:   target,
+		Recreate: req.Recreate,
+		Timeout:  req.Timeout,
+		Wait:     req.Wait,
+	}
+	_, err := rudder.RollbackRelease(rollback)
+	return err
+}
+
+// Status returns status retrieved from rudder.ReleaseStatus
+func (m *RemoteReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) {
+	statusRequest := &rudderAPI.ReleaseStatusRequest{Release: r}
+	resp, err := rudder.ReleaseStatus(statusRequest)
+	return resp.Info.Status.Resources, err
+}
+
+// Delete calls rudder.DeleteRelease
+func (m *RemoteReleaseModule) Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error) {
+	deleteRequest := &rudderAPI.DeleteReleaseRequest{Release: r}
+	resp, err := rudder.DeleteRelease(deleteRequest)
+	if err != nil {
+		return resp.Release.Manifest, []error{err}
+	}
+	return resp.Release.Manifest, []error{}
+}
+
+// DeleteRelease is a helper that allows Rudder to delete a release without exposing most of Tiller inner functions
+func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient environment.KubeClient) (kept string, errs []error) {
+	manifests := relutil.SplitManifests(rel.Manifest)
+	_, files, err := sortManifests(manifests, vs, UninstallOrder)
+	if err != nil {
+		// We could instead just delete everything in no particular order.
+		// FIXME: One way to delete at this point would be to try a label-based
+		// deletion. The problem with this is that we could get a false positive
+		// and delete something that was not legitimately part of this release.
+		return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)}
+	}
+
+	filesToKeep, filesToDelete := filterManifestsToKeep(files)
+	if len(filesToKeep) > 0 {
+		kept = summarizeKeptManifests(filesToKeep)
+	}
+
+	errs = []error{}
+	for _, file := range filesToDelete {
+		b := bytes.NewBufferString(strings.TrimSpace(file.content))
+		if b.Len() == 0 {
+			continue
+		}
+		if err := kubeClient.Delete(rel.Namespace, b); err != nil {
+			log.Printf("uninstall: Failed deletion of %q: %s", rel.Name, err)
+			if err == kube.ErrNoObjectsVisited {
+				// Rewrite the message from "no objects visited"
+				err = errors.New("object not found, skipping delete")
+			}
+			errs = append(errs, err)
+		}
+	}
+	return kept, errs
+}
diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go
index bd480fb3271ee716e08fd6d379eb72b14b54e98c..adc4ddf3ca538f07165ecdb2503ce87d229e1503 100644
--- a/pkg/tiller/release_server.go
+++ b/pkg/tiller/release_server.go
@@ -33,7 +33,6 @@ import (
 
 	"k8s.io/helm/pkg/chartutil"
 	"k8s.io/helm/pkg/hooks"
-	"k8s.io/helm/pkg/kube"
 	"k8s.io/helm/pkg/proto/hapi/chart"
 	"k8s.io/helm/pkg/proto/hapi/release"
 	"k8s.io/helm/pkg/proto/hapi/services"
@@ -82,15 +81,26 @@ var ValidName = regexp.MustCompile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+
 
 // ReleaseServer implements the server-side gRPC endpoint for the HAPI services.
 type ReleaseServer struct {
+	ReleaseModule
 	env       *environment.Environment
 	clientset internalclientset.Interface
 }
 
 // NewReleaseServer creates a new release server.
-func NewReleaseServer(env *environment.Environment, clientset internalclientset.Interface) *ReleaseServer {
+func NewReleaseServer(env *environment.Environment, clientset internalclientset.Interface, useRemote bool) *ReleaseServer {
+	var releaseModule ReleaseModule
+	if useRemote {
+		releaseModule = &RemoteReleaseModule{}
+	} else {
+		releaseModule = &LocalReleaseModule{
+			clientset: clientset,
+		}
+	}
+
 	return &ReleaseServer{
-		env:       env,
-		clientset: clientset,
+		env:           env,
+		clientset:     clientset,
+		ReleaseModule: releaseModule,
 	}
 }
 
@@ -253,8 +263,7 @@ func (s *ReleaseServer) GetReleaseStatus(c ctx.Context, req *services.GetRelease
 
 	// Ok, we got the status of the release as we had jotted down, now we need to match the
 	// manifest we stashed away with reality from the cluster.
-	kubeCli := s.env.KubeClient
-	resp, err := kubeCli.Get(rel.Namespace, bytes.NewBufferString(rel.Manifest))
+	resp, err := s.ReleaseModule.Status(rel, req, s.env)
 	if sc == release.Status_DELETED || sc == release.Status_FAILED {
 		// Skip errors if this is already deleted or failed.
 		return statusResp, nil
@@ -323,8 +332,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
 			return res, err
 		}
 	}
-
-	if err := s.performKubeUpdate(originalRelease, updatedRelease, req.Recreate, req.Timeout, req.Wait); err != nil {
+	if err := s.ReleaseModule.Update(originalRelease, updatedRelease, req, s.env); err != nil {
 		msg := fmt.Sprintf("Upgrade %q failed: %s", updatedRelease.Name, err)
 		log.Printf("warning: %s", msg)
 		originalRelease.Info.Status.Code = release.Status_SUPERSEDED
@@ -511,7 +519,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
 		}
 	}
 
-	if err := s.performKubeUpdate(currentRelease, targetRelease, req.Recreate, req.Timeout, req.Wait); err != nil {
+	if err := s.ReleaseModule.Rollback(currentRelease, targetRelease, req, s.env); err != nil {
 		msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err)
 		log.Printf("warning: %s", msg)
 		currentRelease.Info.Status.Code = release.Status_SUPERSEDED
@@ -537,13 +545,6 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
 	return res, nil
 }
 
-func (s *ReleaseServer) performKubeUpdate(currentRelease, targetRelease *release.Release, recreate bool, timeout int64, shouldWait bool) error {
-	kubeCli := s.env.KubeClient
-	current := bytes.NewBufferString(currentRelease.Manifest)
-	target := bytes.NewBufferString(targetRelease.Manifest)
-	return kubeCli.Update(targetRelease.Namespace, current, target, recreate, timeout, shouldWait)
-}
-
 // prepareRollback finds the previous release and prepares a new release object with
 //  the previous release's configuration
 func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*release.Release, *release.Release, error) {
@@ -681,7 +682,7 @@ func capabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, e
 	if err != nil {
 		return nil, err
 	}
-	vs, err := getVersionSet(disc)
+	vs, err := GetVersionSet(disc)
 	if err != nil {
 		return nil, fmt.Errorf("Could not get apiVersions from Kubernetes: %s", err)
 	}
@@ -769,7 +770,8 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
 	return rel, err
 }
 
-func getVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet, error) {
+// GetVersionSet retrieves a set of available k8s API versions
+func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet, error) {
 	groups, err := client.ServerGroups()
 	if err != nil {
 		return chartutil.DefaultVersionSet, err
@@ -892,8 +894,12 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
 		// update new release with next revision number
 		// so as to append to the old release's history
 		r.Version = old.Version + 1
-
-		if err := s.performKubeUpdate(old, r, false, req.Timeout, req.Wait); err != nil {
+		updateReq := &services.UpdateReleaseRequest{
+			Wait:     req.Wait,
+			Recreate: false,
+			Timeout:  req.Timeout,
+		}
+		if err := s.ReleaseModule.Update(old, r, updateReq, s.env); err != nil {
 			msg := fmt.Sprintf("Release replace %q failed: %s", r.Name, err)
 			log.Printf("warning: %s", msg)
 			old.Info.Status.Code = release.Status_SUPERSEDED
@@ -907,8 +913,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
 	default:
 		// nothing to replace, create as normal
 		// regular manifests
-		b := bytes.NewBufferString(r.Manifest)
-		if err := s.env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait); err != nil {
+		if err := s.ReleaseModule.Create(r, req, s.env); err != nil {
 			msg := fmt.Sprintf("Release %q failed: %s", r.Name, err)
 			log.Printf("warning: %s", msg)
 			r.Info.Status.Code = release.Status_FAILED
@@ -1047,47 +1052,19 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
 		}
 	}
 
-	vs, err := getVersionSet(s.clientset.Discovery())
-	if err != nil {
-		return nil, fmt.Errorf("Could not get apiVersions from Kubernetes: %s", err)
-	}
-
 	// From here on out, the release is currently considered to be in Status_DELETING
 	// state.
 	if err := s.env.Releases.Update(rel); err != nil {
 		log.Printf("uninstall: Failed to store updated release: %s", err)
 	}
 
-	manifests := relutil.SplitManifests(rel.Manifest)
-	_, files, err := sortManifests(manifests, vs, UninstallOrder)
-	if err != nil {
-		// We could instead just delete everything in no particular order.
-		// FIXME: One way to delete at this point would be to try a label-based
-		// deletion. The problem with this is that we could get a false positive
-		// and delete something that was not legitimately part of this release.
-		return nil, fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)
-	}
+	kept, errs := s.ReleaseModule.Delete(rel, req, s.env)
+	res.Info = kept
 
-	filesToKeep, filesToDelete := filterManifestsToKeep(files)
-	if len(filesToKeep) > 0 {
-		res.Info = summarizeKeptManifests(filesToKeep)
-	}
-
-	// Collect the errors, and return them later.
-	es := []string{}
-	for _, file := range filesToDelete {
-		b := bytes.NewBufferString(strings.TrimSpace(file.content))
-		if b.Len() == 0 {
-			continue
-		}
-		if err := s.env.KubeClient.Delete(rel.Namespace, b); err != nil {
-			log.Printf("uninstall: Failed deletion of %q: %s", req.Name, err)
-			if err == kube.ErrNoObjectsVisited {
-				// Rewrite the message from "no objects visited"
-				err = errors.New("object not found, skipping delete")
-			}
-			es = append(es, err.Error())
-		}
+	es := make([]string, 0, len(errs))
+	for _, e := range errs {
+		log.Printf("error: %v", e)
+		es = append(es, e.Error())
 	}
 
 	if !req.DisableHooks {
diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go
index 596f0803b0a0c9dd2e6cd8ec86e35a8f4e36a3b9..fd09fa47b56cbe4b5b0d7aab84538c5a5f547ae2 100644
--- a/pkg/tiller/release_server_test.go
+++ b/pkg/tiller/release_server_test.go
@@ -98,9 +98,13 @@ data:
 `
 
 func rsFixture() *ReleaseServer {
+	clientset := fake.NewSimpleClientset()
 	return &ReleaseServer{
+		ReleaseModule: &LocalReleaseModule{
+			clientset: clientset,
+		},
 		env:       MockEnvironment(),
-		clientset: fake.NewSimpleClientset(),
+		clientset: clientset,
 	}
 }
 
@@ -206,7 +210,7 @@ func TestValidName(t *testing.T) {
 
 func TestGetVersionSet(t *testing.T) {
 	rs := rsFixture()
-	vs, err := getVersionSet(rs.clientset.Discovery())
+	vs, err := GetVersionSet(rs.clientset.Discovery())
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/rootfs/Dockerfile.experimental b/rootfs/Dockerfile.experimental
new file mode 100644
index 0000000000000000000000000000000000000000..8f3bce3c02e40907dd134b6a6dfb1889914949ce
--- /dev/null
+++ b/rootfs/Dockerfile.experimental
@@ -0,0 +1,24 @@
+# Copyright 2017 The Kubernetes Authors.
+#
+# Licensed 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.
+
+FROM alpine:3.3
+
+ENV HOME /tmp
+
+COPY tiller /tiller
+
+EXPOSE 44134
+
+CMD ["/tiller", "--experimental-release"]
+
diff --git a/rootfs/Dockerfile.rudder b/rootfs/Dockerfile.rudder
new file mode 100644
index 0000000000000000000000000000000000000000..7821096c5685f346acf252177e702c5742983e95
--- /dev/null
+++ b/rootfs/Dockerfile.rudder
@@ -0,0 +1,23 @@
+# Copyright 2017 The Kubernetes Authors.
+#
+# Licensed 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.
+
+FROM alpine:3.3
+
+ENV HOME /tmp
+
+COPY rudder /rudder
+
+EXPOSE 10001
+
+CMD ["/rudder"]
diff --git a/versioning.mk b/versioning.mk
index 83921f04d2341289fde7cb5326ded065f9a839fb..2333530d93f8cea5a355edda08e9ab13a5593013 100644
--- a/versioning.mk
+++ b/versioning.mk
@@ -22,12 +22,13 @@ endif
 ifneq ($(GIT_TAG),)
 	LDFLAGS += -X k8s.io/helm/pkg/version.BuildMetadata=
 endif
-
 LDFLAGS += -X k8s.io/helm/pkg/version.GitCommit=${GIT_COMMIT}
 LDFLAGS += -X k8s.io/helm/pkg/version.GitTreeState=${GIT_DIRTY}
 
-IMAGE         := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${DOCKER_VERSION}
-MUTABLE_IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION}
+IMAGE                := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${DOCKER_VERSION}
+IMAGE_RUDDER         := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME_RUDDER}:${DOCKER_VERSION}
+MUTABLE_IMAGE        := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION}
+MUTABLE_IMAGE_RUDDER := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME_RUDDER}:${DOCKER_VERSION}
 
 DOCKER_PUSH = docker push
 ifeq ($(DOCKER_REGISTRY),gcr.io)