diff --git a/cli/cli.go b/cli/cli.go
index 40ae2afd..8415f429 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -15,7 +15,7 @@ var Shortcuts = map[string]string{
 	"scale":          "pts:scale",
 	"sharing":        "perms:list",
 	"sharing:list":   "perms:list",
-	"sharing:add":    "perms:create",
-	"sharing:remove": "perms:delete",
+	"sharing:add":    "perms:add",
+	"sharing:remove": "perms:remove",
 	"whoami":         "auth:whoami",
 }
diff --git a/cmd/apps.go b/cmd/apps.go
index 7fff6bb9..8430a0ac 100644
--- a/cmd/apps.go
+++ b/cmd/apps.go
@@ -132,7 +132,7 @@ func (d *DryccCmd) AppInfo(appID string) error {
 			table.Append([]string{"", "Name:", process.Name})
 			table.Append([]string{"", "Release:", process.Release})
 			table.Append([]string{"", "State:", process.State})
-			table.Append([]string{"", "Type:", process.Type})
+			table.Append([]string{"", "Ptype:", process.Type})
 			table.Append([]string{"", "Started:", d.formatTime(process.Started)})
 			if len(processes) > index+1 {
 				table.Append([]string{""})
diff --git a/cmd/apps_test.go b/cmd/apps_test.go
index 27e234e5..4f39e97a 100644
--- a/cmd/apps_test.go
+++ b/cmd/apps_test.go
@@ -197,7 +197,7 @@ Processes:
               Name:                                   lorem-ipsum-cmd-1911796442-48b58    
               Release:                                v2                                  
               State:                                  up                                  
-              Type:                                   cmd                                 
+              Ptype:                                  cmd                                 
               Started:                                2016-08-22T17:42:16Z                
 Domains:      
               Domain:                                 lorem-ipsum                         
diff --git a/cmd/autodeploy.go b/cmd/autodeploy.go
new file mode 100644
index 00000000..d771478d
--- /dev/null
+++ b/cmd/autodeploy.go
@@ -0,0 +1,76 @@
+package cmd
+
+import (
+	"github.com/drycc/controller-sdk-go/api"
+	"github.com/drycc/controller-sdk-go/appsettings"
+)
+
+// AutodeployInfo provides information about the status of app autodeploy.
+func (d *DryccCmd) AutodeployInfo(appID string) error {
+	s, appID, err := load(d.ConfigFile, appID)
+
+	if err != nil {
+		return err
+	}
+
+	appSettings, err := appsettings.List(s.Client, appID)
+	if d.checkAPICompatibility(s.Client, err) != nil {
+		return err
+	}
+
+	if appSettings.Autodeploy == nil || *appSettings.Autodeploy {
+		d.Println("Autodeploy is enabled.")
+	} else {
+		d.Println("Autodeploy is disabled.")
+	}
+	return nil
+}
+
+// AutodeployEnable enables an app when deploy failed
+func (d *DryccCmd) AutodeployEnable(appID string) error {
+	s, appID, err := load(d.ConfigFile, appID)
+
+	if err != nil {
+		return err
+	}
+
+	d.Printf("Enabling autodeploy for %s... ", appID)
+
+	quit := progress(d.WOut)
+	appSettings := api.AppSettings{Autodeploy: api.NewAutodeploy()}
+	_, err = appsettings.Set(s.Client, appID, appSettings)
+	quit <- true
+	<-quit
+
+	if err != nil {
+		return err
+	}
+
+	d.Println("done")
+	return nil
+}
+
+// AutodeployDisable disables an app when deploy failed
+func (d *DryccCmd) AutodeployDisable(appID string) error {
+	s, appID, err := load(d.ConfigFile, appID)
+
+	if err != nil {
+		return err
+	}
+
+	d.Printf("Disabling autodeploy for %s... ", appID)
+
+	quit := progress(d.WOut)
+	appSettings := api.AppSettings{Autodeploy: api.NewAutodeploy()}
+	*appSettings.Autodeploy = false
+	_, err = appsettings.Set(s.Client, appID, appSettings)
+	quit <- true
+	<-quit
+
+	if err != nil {
+		return err
+	}
+
+	d.Println("done")
+	return nil
+}
diff --git a/cmd/autodeploy_test.go b/cmd/autodeploy_test.go
new file mode 100644
index 00000000..1cdf4d64
--- /dev/null
+++ b/cmd/autodeploy_test.go
@@ -0,0 +1,118 @@
+package cmd
+
+import (
+	"bytes"
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/drycc/controller-sdk-go/api"
+	"github.com/drycc/workflow-cli/pkg/testutil"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAutodeployInfo(t *testing.T) {
+	t.Parallel()
+	cf, server, err := testutil.NewTestServerAndClient()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer server.Close()
+	var b bytes.Buffer
+	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
+
+	server.Mux.HandleFunc("/v2/apps/rivendell/settings/", func(w http.ResponseWriter, _ *http.Request) {
+		testutil.SetHeaders(w)
+		fmt.Fprintf(w, `{
+			"owner": "elrond",
+			"app": "rivendell",
+			"routable": true,
+			"autoerollback": true,
+			"created": "2024-01-01T00:00:00UTC",
+			"updated": "2024-01-01T00:00:00UTC",
+			"uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+		}`)
+	})
+
+	err = cmdr.AutodeployInfo("rivendell")
+	assert.NoError(t, err)
+	assert.Equal(t, b.String(), "Autodeploy is enabled.\n", "output")
+
+	server.Mux.HandleFunc("/v2/apps/mordor/settings/", func(w http.ResponseWriter, _ *http.Request) {
+		testutil.SetHeaders(w)
+		fmt.Fprintf(w, `{
+			"owner": "sauron",
+			"app": "mordor",
+			"routable": false,
+			"autodeploy": false,
+			"created": "2024-01-01T00:00:00UTC",
+			"updated": "2024-01-01T00:00:00UTC",
+			"uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+		}`)
+	})
+	b.Reset()
+
+	err = cmdr.AutodeployInfo("mordor")
+	assert.NoError(t, err)
+	assert.Equal(t, b.String(), "Autodeploy is disabled.\n", "output")
+
+	// test that no autodeploy field doesn't trigger a panic
+	server.Mux.HandleFunc("/v2/apps/gondor/settings/", func(w http.ResponseWriter, _ *http.Request) {
+		testutil.SetHeaders(w)
+		fmt.Fprintf(w, `{
+			"owner": "aragorn",
+			"app": "gondor",
+			"created": "2024-01-01T00:00:00UTC",
+			"updated": "2024-01-01T00:00:00UTC",
+			"uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+		}`)
+	})
+	b.Reset()
+
+	err = cmdr.AutodeployInfo("gondor")
+	assert.NoError(t, err)
+	assert.Equal(t, b.String(), "Autodeploy is enabled.\n", "output")
+}
+
+func TestAutodeployEnable(t *testing.T) {
+	t.Parallel()
+	cf, server, err := testutil.NewTestServerAndClient()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer server.Close()
+	var b bytes.Buffer
+	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
+
+	server.Mux.HandleFunc("/v2/apps/lothlorien/settings/", func(w http.ResponseWriter, r *http.Request) {
+		testutil.SetHeaders(w)
+		testutil.AssertBody(t, api.AppSettings{Autodeploy: api.NewAutodeploy()}, r)
+		fmt.Fprintf(w, `{}`)
+	})
+
+	err = cmdr.AutodeployEnable("lothlorien")
+	assert.NoError(t, err)
+	assert.Equal(t, testutil.StripProgress(b.String()), "Enabling autodeploy for lothlorien... done\n", "output")
+}
+
+func TestAutodeployDisable(t *testing.T) {
+	t.Parallel()
+	cf, server, err := testutil.NewTestServerAndClient()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer server.Close()
+	var b bytes.Buffer
+	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
+
+	server.Mux.HandleFunc("/v2/apps/bree/settings/", func(w http.ResponseWriter, r *http.Request) {
+		testutil.SetHeaders(w)
+		autodeploy := false
+		testutil.AssertBody(t, api.AppSettings{Autodeploy: &autodeploy}, r)
+		fmt.Fprintf(w, `{}`)
+	})
+
+	err = cmdr.AutodeployDisable("bree")
+	assert.NoError(t, err)
+	assert.Equal(t, testutil.StripProgress(b.String()), "Disabling autodeploy for bree... done\n", "output")
+}
diff --git a/cmd/autoscale.go b/cmd/autoscale.go
index 6e2a61a1..839948b3 100644
--- a/cmd/autoscale.go
+++ b/cmd/autoscale.go
@@ -38,18 +38,18 @@ func (d *DryccCmd) AutoscaleList(appID string) error {
 }
 
 // AutoscaleSet sets autoscale options for the app.
-func (d *DryccCmd) AutoscaleSet(appID string, processType string, min int, max int, CPUPercent int) error {
+func (d *DryccCmd) AutoscaleSet(appID string, ptype string, min int, max int, CPUPercent int) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
 
-	d.Printf("Applying autoscale settings for process type %s on %s... ", processType, appID)
+	d.Printf("Applying autoscale settings for process type %s on %s... ", ptype, appID)
 
 	quit := progress(d.WOut)
 	data := map[string]*api.Autoscale{
-		processType: {
+		ptype: {
 			Min:        min,
 			Max:        max,
 			CPUPercent: CPUPercent,
@@ -69,18 +69,18 @@ func (d *DryccCmd) AutoscaleSet(appID string, processType string, min int, max i
 }
 
 // AutoscaleUnset removes autoscale for the app.
-func (d *DryccCmd) AutoscaleUnset(appID string, processType string) error {
+func (d *DryccCmd) AutoscaleUnset(appID string, ptype string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
 
-	d.Printf("Removing autoscale for process type %s on %s... ", processType, appID)
+	d.Printf("Removing autoscale for process type %s on %s... ", ptype, appID)
 
 	quit := progress(d.WOut)
 	data := map[string]*api.Autoscale{
-		processType: nil,
+		ptype: nil,
 	}
 	_, err = appsettings.Set(s.Client, appID, api.AppSettings{Autoscale: data})
 
diff --git a/cmd/certs.go b/cmd/certs.go
index 2d5fafb5..e93f4df7 100644
--- a/cmd/certs.go
+++ b/cmd/certs.go
@@ -8,14 +8,13 @@ import (
 	drycc "github.com/drycc/controller-sdk-go"
 	"github.com/drycc/controller-sdk-go/certs"
 	dtime "github.com/drycc/controller-sdk-go/pkg/time"
-	"github.com/drycc/workflow-cli/settings"
 )
 
 const dateFormat = "2 Jan 2006"
 
 // CertsList lists certs registered with the controller.
-func (d *DryccCmd) CertsList(results int) error {
-	s, err := settings.Load(d.ConfigFile)
+func (d *DryccCmd) CertsList(appID string, results int) error {
+	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
@@ -25,7 +24,7 @@ func (d *DryccCmd) CertsList(results int) error {
 		results = s.Limit
 	}
 
-	certList, _, err := certs.List(s.Client, results)
+	certList, _, err := certs.List(s.Client, appID, results)
 	if d.checkAPICompatibility(s.Client, err) != nil {
 		return err
 	}
@@ -55,8 +54,8 @@ func (d *DryccCmd) CertsList(results int) error {
 }
 
 // CertAdd adds a cert to the controller.
-func (d *DryccCmd) CertAdd(cert string, key string, name string) error {
-	s, err := settings.Load(d.ConfigFile)
+func (d *DryccCmd) CertAdd(appID string, cert string, key string, name string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
@@ -64,7 +63,7 @@ func (d *DryccCmd) CertAdd(cert string, key string, name string) error {
 
 	d.Print("Adding SSL endpoint... ")
 	quit := progress(d.WOut)
-	err = d.doCertAdd(s.Client, cert, key, name)
+	err = d.doCertAdd(s.Client, appID, cert, key, name)
 	quit <- true
 	<-quit
 
@@ -76,7 +75,7 @@ func (d *DryccCmd) CertAdd(cert string, key string, name string) error {
 	return nil
 }
 
-func (d *DryccCmd) doCertAdd(c *drycc.Client, cert string, key string, name string) error {
+func (d *DryccCmd) doCertAdd(c *drycc.Client, appID string, cert string, key string, name string) error {
 	certFile, err := os.ReadFile(cert)
 	if err != nil {
 		return err
@@ -87,13 +86,13 @@ func (d *DryccCmd) doCertAdd(c *drycc.Client, cert string, key string, name stri
 		return err
 	}
 
-	_, err = certs.New(c, string(certFile), string(keyFile), name)
+	_, err = certs.New(c, appID, string(certFile), string(keyFile), name)
 	return d.checkAPICompatibility(c, err)
 }
 
 // CertRemove deletes a cert from the controller.
-func (d *DryccCmd) CertRemove(name string) error {
-	s, err := settings.Load(d.ConfigFile)
+func (d *DryccCmd) CertRemove(appID string, name string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 	if d.checkAPICompatibility(s.Client, err) != nil {
 		return err
 	}
@@ -101,7 +100,7 @@ func (d *DryccCmd) CertRemove(name string) error {
 	d.Printf("Removing %s... ", name)
 	quit := progress(d.WOut)
 
-	err = certs.Delete(s.Client, name)
+	err = certs.Delete(s.Client, appID, name)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
@@ -113,12 +112,12 @@ func (d *DryccCmd) CertRemove(name string) error {
 }
 
 // CertInfo gets info about certficiate
-func (d *DryccCmd) CertInfo(name string) error {
-	s, err := settings.Load(d.ConfigFile)
+func (d *DryccCmd) CertInfo(appID string, name string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
 	}
-	cert, err := certs.Get(s.Client, name)
+	cert, err := certs.Get(s.Client, appID, name)
 	if d.checkAPICompatibility(s.Client, err) != nil {
 		return err
 	}
@@ -142,8 +141,8 @@ func (d *DryccCmd) CertInfo(name string) error {
 }
 
 // CertAttach attaches a certificate to a domain
-func (d *DryccCmd) CertAttach(name, domain string) error {
-	s, err := settings.Load(d.ConfigFile)
+func (d *DryccCmd) CertAttach(appID string, name, domain string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
@@ -152,7 +151,7 @@ func (d *DryccCmd) CertAttach(name, domain string) error {
 	d.Printf("Attaching certificate %s to domain %s... ", name, domain)
 	quit := progress(d.WOut)
 
-	err = certs.Attach(s.Client, name, domain)
+	err = certs.Attach(s.Client, appID, name, domain)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) == nil {
@@ -163,8 +162,8 @@ func (d *DryccCmd) CertAttach(name, domain string) error {
 }
 
 // CertDetach detaches a certificate from a domain
-func (d *DryccCmd) CertDetach(name, domain string) error {
-	s, err := settings.Load(d.ConfigFile)
+func (d *DryccCmd) CertDetach(appID, name, domain string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
@@ -173,7 +172,7 @@ func (d *DryccCmd) CertDetach(name, domain string) error {
 	d.Printf("Detaching certificate %s from domain %s... ", name, domain)
 	quit := progress(d.WOut)
 
-	err = certs.Detach(s.Client, name, domain)
+	err = certs.Detach(s.Client, appID, name, domain)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
diff --git a/cmd/certs_test.go b/cmd/certs_test.go
index f8f7bd52..f6ed5c03 100644
--- a/cmd/certs_test.go
+++ b/cmd/certs_test.go
@@ -22,14 +22,15 @@ func TestCertsList(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/certs/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
 			"count": 4,
 			"next": null,
 			"previous": null,
 			"results": [
-				{
+				{	
+					"app": "foo",
 					"name": "test-example-com",
 					"common_name": "test.example.com",
 					"san": [
@@ -46,6 +47,7 @@ func TestCertsList(t *testing.T) {
 					"fingerprint": "12:34:56:78:90"
 				},
 				{
+					"app": "foo",
 					"name": "test-drycc-com",
 					"common_name": "test.drycc.com",
 					"created": "2016-06-09T00:00:00UTC",
@@ -54,11 +56,13 @@ func TestCertsList(t *testing.T) {
 					"fingerprint": "ab:12:ab:12:ab"
 				},
 				{
+					"app": "foo",
 					"name": "test1",
 					"common_name": "1.test.drycc.com",
 					"expires": "2016-06-11T00:00:00UTC"
 				},
 				{
+					"app": "foo",
 					"name": "test2",
 					"common_name": "2.test.drycc.com",
 					"expires": "2018-01-01T00:00:00UTC"
@@ -67,7 +71,7 @@ func TestCertsList(t *testing.T) {
 		}`)
 	})
 
-	err = cmdr.CertsList(-1)
+	err = cmdr.CertsList("foo", -1)
 	assert.NoError(t, err)
 
 	assert.Equal(t, b.String(), `NAME                COMMON-NAME         EXPIRES        SAN                     DOMAINS              
@@ -86,7 +90,7 @@ test2               2.test.drycc.com    1 Jan 2018     <none>                  <
 	cmdr.ConfigFile = cf
 	b.Reset()
 
-	server.Mux.HandleFunc("/v2/certs/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
 			"count": 0,
@@ -96,7 +100,7 @@ test2               2.test.drycc.com    1 Jan 2018     <none>                  <
 		}`)
 	})
 
-	err = cmdr.CertsList(-1)
+	err = cmdr.CertsList("foo", -1)
 	assert.NoError(t, err)
 
 	assert.Equal(t, b.String(), "No certs\n", "output")
@@ -112,7 +116,7 @@ func TestCertsListLimit(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/certs/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
 			"count": 4,
@@ -141,7 +145,7 @@ func TestCertsListLimit(t *testing.T) {
 		}`)
 	})
 
-	err = cmdr.CertsList(1)
+	err = cmdr.CertsList("foo", 1)
 	assert.NoError(t, err)
 
 	assert.Equal(t, b.String(), `NAME                COMMON-NAME         EXPIRES        SAN                               DOMAINS                        
@@ -160,9 +164,10 @@ func TestCertsInfo(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/certs/test-example-com", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/test-example-com", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
+			"app": "foo",
 			"name": "test-example-com",
 			"owner": "admin",
 			"issuer": "testca",
@@ -184,7 +189,7 @@ func TestCertsInfo(t *testing.T) {
 		}`)
 	})
 
-	err = cmdr.CertInfo("test-example-com")
+	err = cmdr.CertInfo("foo", "test-example-com")
 	assert.NoError(t, err)
 	assert.Equal(t, b.String(), `Name:                 test-example-com        
 Common Name(s):       test.drycc.com          
@@ -201,7 +206,7 @@ Created:              2016-06-09T00:00:00Z
 Updated:              2016-06-09T00:00:00Z    
 `, "output")
 
-	server.Mux.HandleFunc("/v2/certs/test-drycc-com", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/test-drycc-com", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
 			"name": "test-drycc-com"
@@ -209,7 +214,7 @@ Updated:              2016-06-09T00:00:00Z
 	})
 	b.Reset()
 
-	err = cmdr.CertInfo("test-drycc-com")
+	err = cmdr.CertInfo("foo", "test-drycc-com")
 	assert.NoError(t, err)
 	assert.Equal(t, b.String(), `Name:                 test-drycc-com    
 Common Name(s):       <none>            
@@ -237,12 +242,12 @@ func TestCertsRemove(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/certs/test-example-com", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/test-example-com", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		w.WriteHeader(http.StatusNoContent)
 	})
 
-	err = cmdr.CertRemove("test-example-com")
+	err = cmdr.CertRemove("foo", "test-example-com")
 	assert.NoError(t, err)
 
 	assert.Equal(t, testutil.StripProgress(b.String()), "Removing test-example-com... done\n", "output")
@@ -258,13 +263,13 @@ func TestCertsAttach(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/certs/test-example-com/domain/", func(w http.ResponseWriter, r *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/test-example-com/domain/", func(w http.ResponseWriter, r *http.Request) {
 		testutil.SetHeaders(w)
 		testutil.AssertBody(t, api.CertAttachRequest{Domain: "drycc.com"}, r)
 		w.WriteHeader(http.StatusCreated)
 	})
 
-	err = cmdr.CertAttach("test-example-com", "drycc.com")
+	err = cmdr.CertAttach("foo", "test-example-com", "drycc.com")
 	assert.NoError(t, err)
 
 	assert.Equal(t, testutil.StripProgress(b.String()), "Attaching certificate test-example-com to domain drycc.com... done\n", "output")
@@ -280,12 +285,12 @@ func TestCertsDetach(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/certs/test-example-com/domain/drycc.com", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/test-example-com/domain/drycc.com", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		w.WriteHeader(http.StatusNoContent)
 	})
 
-	err = cmdr.CertDetach("test-example-com", "drycc.com")
+	err = cmdr.CertDetach("foo", "test-example-com", "drycc.com")
 	assert.NoError(t, err)
 
 	assert.Equal(t, testutil.StripProgress(b.String()), "Detaching certificate test-example-com from domain drycc.com... done\n", "output")
@@ -301,7 +306,7 @@ func TestCertsAdd(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/certs/", func(w http.ResponseWriter, r *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/foo/certs/", func(w http.ResponseWriter, r *http.Request) {
 		testutil.SetHeaders(w)
 		testutil.AssertBody(t, api.CertCreateRequest{Certificate: "cert", Key: "key", Name: "testcert"}, r)
 		w.WriteHeader(http.StatusCreated)
@@ -320,7 +325,7 @@ func TestCertsAdd(t *testing.T) {
 	assert.NoError(t, err)
 	certFile.Close()
 
-	err = cmdr.CertAdd(certFile.Name(), keyFile.Name(), "testcert")
+	err = cmdr.CertAdd("foo", certFile.Name(), keyFile.Name(), "testcert")
 	assert.NoError(t, err)
 
 	assert.Equal(t, testutil.StripProgress(b.String()), "Adding SSL endpoint... done\n", "output")
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 4e78d567..04dc8842 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -19,6 +19,9 @@ type Commander interface {
 	AppRun(string, string, []string, uint32, uint32) error
 	AppDestroy(string, string) error
 	AppTransfer(string, string) error
+	AutodeployInfo(string) error
+	AutodeployEnable(string) error
+	AutodeployDisable(string) error
 	AutorollbackInfo(string) error
 	AutorollbackEnable(string) error
 	AutorollbackDisable(string) error
@@ -33,12 +36,12 @@ type Commander interface {
 	TokensRemove(string, string) error
 	BuildsList(string, int) error
 	BuildsCreate(string, string, string, string, string) error
-	CertsList(int) error
-	CertAdd(string, string, string) error
-	CertRemove(string) error
-	CertInfo(string) error
-	CertAttach(string, string) error
-	CertDetach(string, string) error
+	CertsList(string, int) error
+	CertAdd(string, string, string, string) error
+	CertRemove(string, string) error
+	CertInfo(string, string) error
+	CertAttach(string, string, string) error
+	CertDetach(string, string, string) error
 	ConfigList(string, string) error
 	ConfigSet(string, string, []string, string) error
 	ConfigUnset(string, string, []string, string) error
@@ -79,10 +82,10 @@ type Commander interface {
 	TimeoutsList(string) error
 	TimeoutsSet(string, []string) error
 	TimeoutsUnset(string, []string) error
-	PermCodes(int) error
 	PermList(string, int) error
 	PermCreate(string, string, string) error
-	PermDelete(uint64) error
+	PermUpdate(string, string, string) error
+	PermDelete(string, string) error
 	PsList(string, int) error
 	PsLogs(string, string, int, bool, string) error
 	PsExec(string, string, bool, bool, []string) error
@@ -97,8 +100,8 @@ type Commander interface {
 	RegistryUnset(string, []string) error
 	ReleasesList(string, int) error
 	ReleasesInfo(string, int) error
-	ReleasesDeploy(string, []string, string) error
-	ReleasesRollback(string, int) error
+	ReleasesDeploy(string, []string, bool, string) error
+	ReleasesRollback(string, []string, int) error
 	RoutingInfo(string) error
 	RoutingEnable(string) error
 	RoutingDisable(string) error
diff --git a/cmd/config.go b/cmd/config.go
index 3a93e3de..a486495b 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -10,12 +10,14 @@ import (
 	"runtime"
 	"strings"
 
+	drycc "github.com/drycc/controller-sdk-go"
 	"github.com/drycc/controller-sdk-go/api"
+	"github.com/drycc/controller-sdk-go/appsettings"
 	"github.com/drycc/controller-sdk-go/config"
 )
 
 // ConfigList lists an app's config.
-func (d *DryccCmd) ConfigList(appID string, procType string) error {
+func (d *DryccCmd) ConfigList(appID string, ptype string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
@@ -26,8 +28,8 @@ func (d *DryccCmd) ConfigList(appID string, procType string) error {
 	}
 
 	configValues := config.Values
-	if procType != "" {
-		configValues = config.TypedValues[procType]
+	if ptype != "" {
+		configValues = config.TypedValues[ptype]
 	}
 
 	keys := *sortKeys(configValues)
@@ -41,7 +43,7 @@ func (d *DryccCmd) ConfigList(appID string, procType string) error {
 	}
 
 	// common config
-	if procType != "" {
+	if ptype != "" {
 		table.Append([]string{"--- Common Config:"})
 		configValues = config.Values
 		keys = *sortKeys(configValues)
@@ -57,14 +59,14 @@ func (d *DryccCmd) ConfigList(appID string, procType string) error {
 }
 
 // ConfigSet sets an app's config variables.
-func (d *DryccCmd) ConfigSet(appID string, procType string, configVars []string, confirm string) error {
+func (d *DryccCmd) ConfigSet(appID string, ptype string, configVars []string, confirm string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
 
-	err = configConfirmAction(procType, confirm)
+	err = configConfirmAction(s.Client, appID, ptype, confirm)
 	if err != nil {
 		return err
 	}
@@ -96,8 +98,8 @@ to set up healthchecks. This functionality has been deprecated. In the future, p
 
 	quit := progress(d.WOut)
 	configObj, err := config.Set(s.Client, appID, func() api.Config {
-		if procType != "" {
-			return api.Config{TypedValues: map[string]api.ConfigValues{procType: configMap}}
+		if ptype != "" {
+			return api.Config{TypedValues: map[string]api.ConfigValues{ptype: configMap}}
 		}
 		return api.Config{Values: configMap}
 	}())
@@ -113,18 +115,18 @@ to set up healthchecks. This functionality has been deprecated. In the future, p
 		d.Print("done\n\n")
 	}
 
-	return d.ConfigList(appID, procType)
+	return d.ConfigList(appID, ptype)
 }
 
 // ConfigUnset removes a config variable from an app.
-func (d *DryccCmd) ConfigUnset(appID string, procType string, configVars []string, confirm string) error {
+func (d *DryccCmd) ConfigUnset(appID string, ptype string, configVars []string, confirm string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
 
-	err = configConfirmAction(procType, confirm)
+	err = configConfirmAction(s.Client, appID, ptype, confirm)
 	if err != nil {
 		return err
 	}
@@ -144,8 +146,8 @@ func (d *DryccCmd) ConfigUnset(appID string, procType string, configVars []strin
 	configObj.Values = valuesMap
 
 	configObj, err = config.Set(s.Client, appID, func() api.Config {
-		if procType != "" {
-			return api.Config{TypedValues: map[string]api.ConfigValues{procType: valuesMap}}
+		if ptype != "" {
+			return api.Config{TypedValues: map[string]api.ConfigValues{ptype: valuesMap}}
 		}
 		return api.Config{Values: valuesMap}
 	}())
@@ -162,11 +164,11 @@ func (d *DryccCmd) ConfigUnset(appID string, procType string, configVars []strin
 		d.Print("done\n\n")
 	}
 
-	return d.ConfigList(appID, procType)
+	return d.ConfigList(appID, ptype)
 }
 
 // ConfigPull pulls an app's config to a file.
-func (d *DryccCmd) ConfigPull(appID, procType, fileName string, interactive bool, overwrite bool) error {
+func (d *DryccCmd) ConfigPull(appID, ptype, fileName string, interactive bool, overwrite bool) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -184,8 +186,8 @@ func (d *DryccCmd) ConfigPull(appID, procType, fileName string, interactive bool
 		return err
 	}
 	configValues := configVars.Values
-	if procType != "" {
-		configValues = configVars.TypedValues[procType]
+	if ptype != "" {
+		configValues = configVars.TypedValues[ptype]
 	}
 
 	if (stat.Mode() & os.ModeCharDevice) == 0 {
@@ -232,17 +234,21 @@ func (d *DryccCmd) ConfigPull(appID, procType, fileName string, interactive bool
 }
 
 // ConfigPush pushes an app's config from a file.
-func (d *DryccCmd) ConfigPush(appID, procType string, fileName string, confirm string) error {
+func (d *DryccCmd) ConfigPush(appID, ptype string, fileName string, confirm string) error {
 	stat, err := os.Stdin.Stat()
 
 	if err != nil {
 		return err
 	}
-
+	s, appID, err := load(d.ConfigFile, appID)
+	if err != nil {
+		return err
+	}
 	var contents []byte
 
 	if (stat.Mode() & os.ModeCharDevice) == 0 {
-		err = configConfirmActionStdin(procType, confirm)
+
+		err = configConfirmActionStdin(s.Client, appID, ptype, confirm)
 		if err != nil {
 			return err
 		}
@@ -250,7 +256,7 @@ func (d *DryccCmd) ConfigPush(appID, procType string, fileName string, confirm s
 		buffer.ReadFrom(os.Stdin)
 		contents = buffer.Bytes()
 	} else {
-		err = configConfirmAction(procType, confirm)
+		err = configConfirmAction(s.Client, appID, ptype, confirm)
 		if err != nil {
 			return err
 		}
@@ -273,7 +279,7 @@ func (d *DryccCmd) ConfigPush(appID, procType string, fileName string, confirm s
 		}
 	}
 
-	return d.ConfigSet(appID, procType, config, "yes")
+	return d.ConfigSet(appID, ptype, config, "yes")
 }
 
 func parseConfig(configVars []string) (api.ConfigValues, error) {
@@ -339,8 +345,13 @@ func formatConfig(configVars map[string]interface{}) string {
 	return formattedConfig
 }
 
-func configConfirmAction(procType string, confirm string) error {
-	if procType == "" && (confirm == "" || confirm != "yes") {
+func configConfirmAction(s *drycc.Client, appID string, ptype string, confirm string) error {
+	appSettings, _ := appsettings.List(s, appID)
+	autodeploy := true
+	if appSettings.Autodeploy != nil && !*appSettings.Autodeploy {
+		autodeploy = false
+	}
+	if ptype == "" && (confirm == "" || confirm != "yes") && autodeploy {
 		fmt.Printf(` !    WARNING: Potentially Config Action
  !    This command will deploy all processes of the application
  !    To proceed, type "yes" !
@@ -355,7 +366,7 @@ func configConfirmAction(procType string, confirm string) error {
 	return nil
 }
 
-func configConfirmActionStdin(procType string, confirm string) error {
+func configConfirmActionStdin(s *drycc.Client, appID string, ptype string, confirm string) error {
 	var reader *bufio.Reader
 	if runtime.GOOS == "windows" {
 		reader = bufio.NewReader(os.Stdin)
@@ -367,8 +378,12 @@ func configConfirmActionStdin(procType string, confirm string) error {
 		defer file.Close()
 		reader = bufio.NewReader(file)
 	}
-
-	if procType == "" && (confirm == "" || confirm != "yes") {
+	appSettings, _ := appsettings.List(s, appID)
+	autodeploy := true
+	if appSettings.Autodeploy != nil && !*appSettings.Autodeploy {
+		autodeploy = false
+	}
+	if ptype == "" && (confirm == "" || confirm != "yes") && autodeploy {
 		fmt.Printf(` !    WARNING: Potentially Config Action
  !    This command will deploy all processes of the application
  !    To proceed, type "yes" !
diff --git a/cmd/domains.go b/cmd/domains.go
index f9424ae5..c41bc270 100644
--- a/cmd/domains.go
+++ b/cmd/domains.go
@@ -28,7 +28,7 @@ func (d *DryccCmd) DomainsList(appID string, results int) error {
 			table.Append([]string{
 				domain.App,
 				domain.Owner,
-				domain.ProcfileType,
+				domain.Ptype,
 				d.formatTime(domain.Created),
 				d.formatTime(domain.Updated),
 				domain.Domain,
@@ -42,7 +42,7 @@ func (d *DryccCmd) DomainsList(appID string, results int) error {
 }
 
 // DomainsAdd adds a domain to an app.
-func (d *DryccCmd) DomainsAdd(appID, domain, procfileType string) error {
+func (d *DryccCmd) DomainsAdd(appID, domain, ptype string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -52,7 +52,7 @@ func (d *DryccCmd) DomainsAdd(appID, domain, procfileType string) error {
 	d.Printf("Adding %s to %s... ", domain, appID)
 
 	quit := progress(d.WOut)
-	_, err = domains.New(s.Client, appID, domain, procfileType)
+	_, err = domains.New(s.Client, appID, domain, ptype)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
diff --git a/cmd/domains_test.go b/cmd/domains_test.go
index dfad7c0f..99fcf534 100644
--- a/cmd/domains_test.go
+++ b/cmd/domains_test.go
@@ -32,7 +32,7 @@ func TestDomainsList(t *testing.T) {
             "app": "foo",
             "created": "2014-01-01T00:00:00UTC",
             "domain": "example.example.com",
-			"procfile_type": "web",
+			"ptype": "web",
             "owner": "test",
             "updated": "2014-01-01T00:00:00UTC"
         },
@@ -40,7 +40,7 @@ func TestDomainsList(t *testing.T) {
             "app": "foo",
             "created": "2014-01-01T00:00:00UTC",
             "domain": "foo",
-			"procfile_type": "web",
+			"ptype": "web",
             "owner": "test",
             "updated": "2014-01-01T00:00:00UTC"
         }
@@ -78,7 +78,7 @@ func TestDomainsListLimit(t *testing.T) {
             "app": "foo",
             "created": "2014-01-01T00:00:00UTC",
             "domain": "example.example.com",
-			"procfile_type": "web",
+			"ptype": "web",
             "owner": "test",
             "updated": "2014-01-01T00:00:00UTC"
         }
@@ -105,7 +105,7 @@ func TestDomainsAdd(t *testing.T) {
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
 	server.Mux.HandleFunc("/v2/apps/foo/domains/", func(w http.ResponseWriter, r *http.Request) {
-		testutil.AssertBody(t, api.DomainCreateRequest{Domain: "example.example.com", ProcfileType: "web"}, r)
+		testutil.AssertBody(t, api.DomainCreateRequest{Domain: "example.example.com", Ptype: "web"}, r)
 		testutil.SetHeaders(w)
 		w.WriteHeader(http.StatusCreated)
 		// Body isn't used by CLI, so it isn't set.
diff --git a/cmd/healthchecks.go b/cmd/healthchecks.go
index 19f87cdb..1248308c 100644
--- a/cmd/healthchecks.go
+++ b/cmd/healthchecks.go
@@ -8,7 +8,7 @@ import (
 	"github.com/drycc/controller-sdk-go/config"
 )
 
-func getHealthcheckString(procType, probeType string, healthcheck *api.Healthcheck) string {
+func getHealthcheckString(ptype, probeType string, healthcheck *api.Healthcheck) string {
 	params := fmt.Sprintf(
 		"delay=%ds timeout=%ds period=%ds #success=%d #failure=%d",
 		healthcheck.InitialDelaySeconds,
@@ -19,14 +19,14 @@ func getHealthcheckString(procType, probeType string, healthcheck *api.Healthche
 	)
 
 	if healthcheck.Exec != nil {
-		return fmt.Sprintf("%s %s exec %v %s", probeType, procType, healthcheck.Exec.Command, params)
+		return fmt.Sprintf("%s %s exec %v %s", probeType, ptype, healthcheck.Exec.Command, params)
 	} else if healthcheck.TCPSocket != nil {
-		return fmt.Sprintf("%s %s tcp-socket port=%v %s", probeType, procType, healthcheck.TCPSocket.Port, params)
+		return fmt.Sprintf("%s %s tcp-socket port=%v %s", probeType, ptype, healthcheck.TCPSocket.Port, params)
 	} else if healthcheck.HTTPGet != nil {
 		return fmt.Sprintf(
 			"%s %s http-get headers=%v path=%s port=%d %s",
 			probeType,
-			procType,
+			ptype,
 			healthcheck.HTTPGet.HTTPHeaders,
 			healthcheck.HTTPGet.Path,
 			healthcheck.HTTPGet.Port,
@@ -36,16 +36,16 @@ func getHealthcheckString(procType, probeType string, healthcheck *api.Healthche
 	return ""
 }
 
-func getHealthchecksStrings(procType string, healthchecks *api.Healthchecks) []string {
+func getHealthchecksStrings(ptype string, healthchecks *api.Healthchecks) []string {
 	var probes []string
 	for key := range *healthchecks {
-		probes = append(probes, getHealthcheckString(procType, key, (*healthchecks)[key]))
+		probes = append(probes, getHealthcheckString(ptype, key, (*healthchecks)[key]))
 	}
 	return probes
 }
 
 // HealthchecksList lists an app's healthchecks.
-func (d *DryccCmd) HealthchecksList(appID, procType string) error {
+func (d *DryccCmd) HealthchecksList(appID, ptype string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
@@ -57,7 +57,7 @@ func (d *DryccCmd) HealthchecksList(appID, procType string) error {
 		return err
 	}
 
-	if procType == "" {
+	if ptype == "" {
 		if len(config.Healthcheck) == 0 {
 			d.Println("No health checks configured.")
 		} else {
@@ -83,7 +83,7 @@ func (d *DryccCmd) HealthchecksList(appID, procType string) error {
 			table.Render()
 		}
 	} else {
-		if healthcheck, found := config.Healthcheck[procType]; found {
+		if healthcheck, found := config.Healthcheck[ptype]; found {
 			table := d.getDefaultFormatTable([]string{})
 			table.Append([]string{"App:", config.App})
 			table.Append([]string{"UUID:", config.UUID})
@@ -91,7 +91,7 @@ func (d *DryccCmd) HealthchecksList(appID, procType string) error {
 			table.Append([]string{"Created:", d.formatTime(config.Created)})
 			table.Append([]string{"Updated:", d.formatTime(config.Updated)})
 			table.Append([]string{"Healthchecks:"})
-			for _, probe := range getHealthchecksStrings(procType, healthcheck) {
+			for _, probe := range getHealthchecksStrings(ptype, healthcheck) {
 				if probe != "" {
 					table.Append([]string{"", probe})
 				}
@@ -105,7 +105,7 @@ func (d *DryccCmd) HealthchecksList(appID, procType string) error {
 }
 
 // HealthchecksSet sets an app's healthchecks.
-func (d *DryccCmd) HealthchecksSet(appID, healthcheckType, procType string, probe *api.Healthcheck) error {
+func (d *DryccCmd) HealthchecksSet(appID, healthcheckType, ptype string, probe *api.Healthcheck) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -119,7 +119,7 @@ func (d *DryccCmd) HealthchecksSet(appID, healthcheckType, procType string, prob
 	healthcheckMap := make(api.Healthchecks)
 	healthcheckMap[healthcheckType] = probe
 	configObj := api.Config{Healthcheck: make(map[string]*api.Healthchecks)}
-	configObj.Healthcheck[procType] = &healthcheckMap
+	configObj.Healthcheck[ptype] = &healthcheckMap
 
 	_, err = config.Set(s.Client, appID, configObj)
 
@@ -132,11 +132,11 @@ func (d *DryccCmd) HealthchecksSet(appID, healthcheckType, procType string, prob
 
 	d.Print("done\n\n")
 
-	return d.HealthchecksList(appID, procType)
+	return d.HealthchecksList(appID, ptype)
 }
 
 // HealthchecksUnset removes an app's healthchecks.
-func (d *DryccCmd) HealthchecksUnset(appID, procType string, healthchecks []string) error {
+func (d *DryccCmd) HealthchecksUnset(appID, ptype string, healthchecks []string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
@@ -154,7 +154,7 @@ func (d *DryccCmd) HealthchecksUnset(appID, procType string, healthchecks []stri
 	for _, healthcheck := range healthchecks {
 		healthcheckMap[healthcheck] = nil
 	}
-	healthchecksMap[procType] = &healthcheckMap
+	healthchecksMap[ptype] = &healthcheckMap
 
 	configObj.Healthcheck = healthchecksMap
 
@@ -169,5 +169,5 @@ func (d *DryccCmd) HealthchecksUnset(appID, procType string, healthchecks []stri
 
 	d.Print("done\n\n")
 
-	return d.HealthchecksList(appID, procType)
+	return d.HealthchecksList(appID, ptype)
 }
diff --git a/cmd/perms.go b/cmd/perms.go
index daad8132..f21e52f9 100644
--- a/cmd/perms.go
+++ b/cmd/perms.go
@@ -1,57 +1,59 @@
 package cmd
 
 import (
-	"fmt"
+	"strings"
 
 	"github.com/drycc/controller-sdk-go/perms"
-	"github.com/drycc/workflow-cli/settings"
 )
 
-// PermCodes prints all perm codenames.
-func (d *DryccCmd) PermCodes(results int) error {
-	s, err := settings.Load(d.ConfigFile)
+// PermList prints which users have permissions.
+func (d *DryccCmd) PermList(appID string, results int) error {
+	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
 	}
-	codenames, _, err := perms.Codes(s.Client, results)
+	perms, _, err := perms.List(s.Client, appID, results)
 	if d.checkAPICompatibility(s.Client, err) != nil {
 		return err
 	}
-	table := d.getDefaultFormatTable([]string{"CODENAME", "DESCRIPTION"})
-	for _, code := range codenames {
-		table.Append([]string{code.Codename, code.Description})
+	table := d.getDefaultFormatTable([]string{"USERNAME", "PERMISSIONS"})
+	for _, perm := range perms {
+		p := strings.Join(perm.Permissions, ",")
+		table.Append([]string{perm.Username, p})
 	}
 	table.Render()
 	return nil
 }
 
-// PermList prints which users have permissions.
-func (d *DryccCmd) PermList(codename string, results int) error {
-	s, err := settings.Load(d.ConfigFile)
+// PermCreate create user perms.
+func (d *DryccCmd) PermCreate(appID, username, permissions string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
 	}
-	perms, _, err := perms.List(s.Client, codename, results)
+	d.Printf("Adding user %s as a collaborator for %s... ", username, permissions)
+	quit := progress(d.WOut)
+	err = perms.Create(s.Client, appID, username, permissions)
+	quit <- true
+	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
 		return err
 	}
-	table := d.getDefaultFormatTable([]string{"ID", "CODENAME", "UNIQUEID", "USERNAME"})
-	for _, perm := range perms {
-		table.Append([]string{fmt.Sprintf("%d", perm.ID), perm.Codename, perm.Uniqueid, perm.Username})
-	}
-	table.Render()
+
+	d.Println("done")
+
 	return nil
 }
 
-// PermCreate create user perm to user.
-func (d *DryccCmd) PermCreate(codename, uniqueid, username string) error {
-	s, err := settings.Load(d.ConfigFile)
+// PermUpdate update user perms.
+func (d *DryccCmd) PermUpdate(appID, username, permissions string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
 	}
-	d.Printf("Adding user %s as a collaborator for %s %s... ", username, codename, uniqueid)
+	d.Printf("Updating user %s as a collaborator for %s... ", username, permissions)
 	quit := progress(d.WOut)
-	err = perms.Create(s.Client, codename, uniqueid, username)
+	err = perms.Update(s.Client, appID, username, permissions)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
@@ -63,15 +65,15 @@ func (d *DryccCmd) PermCreate(codename, uniqueid, username string) error {
 	return nil
 }
 
-// PermDelete removes a user from an app or revokes admin privileges.
-func (d *DryccCmd) PermDelete(userPermID uint64) error {
-	s, err := settings.Load(d.ConfigFile)
+// PermDelete removes a user from an app.
+func (d *DryccCmd) PermDelete(appID, username string) error {
+	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
 	}
 	d.Printf("Removing user permission... ")
 	quit := progress(d.WOut)
-	err = perms.Delete(s.Client, fmt.Sprintf("%d", userPermID))
+	err = perms.Delete(s.Client, appID, username)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
diff --git a/cmd/perms_test.go b/cmd/perms_test.go
index 1439ca88..a6ae8eb7 100644
--- a/cmd/perms_test.go
+++ b/cmd/perms_test.go
@@ -10,7 +10,7 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestPermCodes(t *testing.T) {
+func TestListUserPerm(t *testing.T) {
 	t.Parallel()
 	cf, server, err := testutil.NewTestServerAndClient()
 	if err != nil {
@@ -18,12 +18,12 @@ func TestPermCodes(t *testing.T) {
 	}
 	defer server.Close()
 
-	server.Mux.HandleFunc("/v2/perms/codes/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/lorem-ipsum/perms/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
 	"results": [
-		{"codename": "use_app", "description": "Can use app"},
-		{"codename": "use_cert", "description": "Can use cert"}
+		{"app": "lorem-ipsum", "username": "foo", "permissions": ["view"]},
+		{"app": "lorem-ipsum", "username": "foo", "permissions": ["view"]}
 	],
 	"count": 2
 }`)
@@ -32,16 +32,16 @@ func TestPermCodes(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	err = cmdr.PermCodes(-1)
+	err = cmdr.PermList("lorem-ipsum", -1)
 	assert.NoError(t, err)
 
-	assert.Equal(t, testutil.StripProgress(b.String()), `CODENAME    DESCRIPTION  
-use_app     Can use app     
-use_cert    Can use cert    
+	assert.Equal(t, testutil.StripProgress(b.String()), `USERNAME    PERMISSIONS 
+foo         view           
+foo         view           
 `, "output")
 }
 
-func TestListUserPerm(t *testing.T) {
+func TestListUserPermLimit(t *testing.T) {
 	t.Parallel()
 	cf, server, err := testutil.NewTestServerAndClient()
 	if err != nil {
@@ -49,59 +49,63 @@ func TestListUserPerm(t *testing.T) {
 	}
 	defer server.Close()
 
-	server.Mux.HandleFunc("/v2/perms/rules/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/lorem-ipsum/perms/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
 	"results": [
-		{"id": 1, "codename": "use_app", "uniqueid": "autotest-app", "username": "foo"},
-		{"id": 2, "codename": "use_cert", "uniqueid": "autotest-cert-1", "username": "foo"}
+		{"app": "lorem-ipsum", "username": "foo", "permissions": ["view"]}
 	],
-	"count": 2
+	"count": 1
 }`)
 	})
 
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	err = cmdr.PermList("", -1)
+	err = cmdr.PermList("lorem-ipsum", 1)
 	assert.NoError(t, err)
 
-	assert.Equal(t, testutil.StripProgress(b.String()), `ID    CODENAME    UNIQUEID           USERNAME 
-1     use_app     autotest-app       foo         
-2     use_cert    autotest-cert-1    foo         
+	assert.Equal(t, testutil.StripProgress(b.String()), `USERNAME    PERMISSIONS 
+foo         view           
 `, "output")
 }
 
-func TestListUserPermLimit(t *testing.T) {
+func TestCreateUserPerm(t *testing.T) {
 	t.Parallel()
 	cf, server, err := testutil.NewTestServerAndClient()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer server.Close()
+	var b bytes.Buffer
+	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	server.Mux.HandleFunc("/v2/perms/rules/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/lorem-ipsum/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 		fmt.Fprintf(w, `{
-	"results": [
-		{"id": 1, "codename": "use_app", "uniqueid": "autotest-app", "username": "foo"}
-	],
-	"count": 1
+  "uuid": "c4aed81c-d1ca-4ff1-ab89-d2151264e1a3",
+  "id": "lorem-ipsum",
+  "owner": "dolar-sit-amet",
+  "structure": {
+    "cmd": 1
+  },
+  "created": "2016-08-22T17:40:16Z",
+  "updated": "2016-08-22T17:40:16Z"
 }`)
 	})
 
-	var b bytes.Buffer
-	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
+	server.Mux.HandleFunc("/v2/apps/lorem-ipsum/perms/", func(w http.ResponseWriter, _ *http.Request) {
+		testutil.SetHeaders(w)
+	})
 
-	err = cmdr.PermList("use_app", 1)
+	err = cmdr.PermCreate("lorem-ipsum", "test-user", "view")
 	assert.NoError(t, err)
-
-	assert.Equal(t, testutil.StripProgress(b.String()), `ID    CODENAME    UNIQUEID        USERNAME 
-1     use_app     autotest-app    foo         
-`, "output")
+	assert.Equal(t,
+		testutil.StripProgress(b.String()),
+		"Adding user test-user as a collaborator for view... done\n", "output")
 }
 
-func TestCreateUserPerm(t *testing.T) {
+func TestUpdateUserPerm(t *testing.T) {
 	t.Parallel()
 	cf, server, err := testutil.NewTestServerAndClient()
 	if err != nil {
@@ -125,15 +129,15 @@ func TestCreateUserPerm(t *testing.T) {
 }`)
 	})
 
-	server.Mux.HandleFunc("/v2/perms/rules/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/lorem-ipsum/perms/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 	})
 
-	err = cmdr.PermCreate("use_app", "lorem-ipsum", "test-user")
+	err = cmdr.PermUpdate("lorem-ipsum", "test-user", "view")
 	assert.NoError(t, err)
 	assert.Equal(t,
 		testutil.StripProgress(b.String()),
-		"Adding user test-user as a collaborator for use_app lorem-ipsum... done\n", "output")
+		"Updating user test-user as a collaborator for view... done\n", "output")
 }
 
 func TestDeleteUserPerm(t *testing.T) {
@@ -160,11 +164,11 @@ func TestDeleteUserPerm(t *testing.T) {
 }`)
 	})
 
-	server.Mux.HandleFunc("/v2/perms/rules/1/", func(w http.ResponseWriter, _ *http.Request) {
+	server.Mux.HandleFunc("/v2/apps/lorem-ipsum/perms/test-user/", func(w http.ResponseWriter, _ *http.Request) {
 		testutil.SetHeaders(w)
 	})
 
-	err = cmdr.PermDelete(1)
+	err = cmdr.PermDelete("lorem-ipsum", "test-user")
 	assert.NoError(t, err)
 	assert.Equal(t,
 		testutil.StripProgress(b.String()),
diff --git a/cmd/ps.go b/cmd/ps.go
index a6c57fe8..550678ba 100644
--- a/cmd/ps.go
+++ b/cmd/ps.go
@@ -147,7 +147,7 @@ func (d *DryccCmd) PsDescribe(appID, podID string) error {
 					if value[innerKey] != nil {
 						innerValue = d.formatTime(fmt.Sprintf("%s", value[innerKey]))
 					} else {
-						innerValue = "null"
+						innerValue = "<none>"
 					}
 				}
 				table.Append([]string{fmt.Sprintf("  %s:", innerKey), strings.Trim(innerValue, `"`)})
@@ -163,7 +163,7 @@ func (d *DryccCmd) PsDescribe(appID, podID string) error {
 					if value[innerKey] != nil {
 						innerValue = d.formatTime(fmt.Sprintf("%s", value[innerKey]))
 					} else {
-						innerValue = "null"
+						innerValue = "<none>"
 					}
 				}
 				table.Append([]string{fmt.Sprintf("  %s:", innerKey), strings.Trim(innerValue, `"`)})
@@ -352,7 +352,7 @@ func parsePsTargets(targets []string) (map[string]int, error) {
 				return nil, err
 			}
 		} else {
-			return nil, fmt.Errorf("'%s' does not match the pattern 'type=num', ex: web=2", target)
+			return nil, fmt.Errorf("'%s' does not match the pattern 'ptype=num', ex: web=2", target)
 		}
 	}
 
diff --git a/cmd/ps_test.go b/cmd/ps_test.go
index 3c5c6a56..41e11ee8 100644
--- a/cmd/ps_test.go
+++ b/cmd/ps_test.go
@@ -136,10 +136,10 @@ func TestParsePsTargets(t *testing.T) {
 	t.Parallel()
 
 	cases := []psTargetCases{
-		{[]string{"test"}, true, nil, "'test' does not match the pattern 'type=num', ex: web=2"},
-		{[]string{"test=a"}, true, nil, "'test=a' does not match the pattern 'type=num', ex: web=2"},
-		{[]string{"test="}, true, nil, "'test=' does not match the pattern 'type=num', ex: web=2"},
-		{[]string{"Test=2"}, true, nil, "'Test=2' does not match the pattern 'type=num', ex: web=2"},
+		{[]string{"test"}, true, nil, "'test' does not match the pattern 'ptype=num', ex: web=2"},
+		{[]string{"test=a"}, true, nil, "'test=a' does not match the pattern 'ptype=num', ex: web=2"},
+		{[]string{"test="}, true, nil, "'test=' does not match the pattern 'ptype=num', ex: web=2"},
+		{[]string{"Test=2"}, true, nil, "'Test=2' does not match the pattern 'ptype=num', ex: web=2"},
 		{[]string{"test=2"}, false, map[string]int{"test": 2}, ""},
 		{[]string{"test-proc=2"}, false, map[string]int{"test-proc": 2}, ""},
 		{[]string{"test1=2"}, false, map[string]int{"test1": 2}, ""},
diff --git a/cmd/pts.go b/cmd/pts.go
index 5978bb51..f48a8145 100644
--- a/cmd/pts.go
+++ b/cmd/pts.go
@@ -219,7 +219,7 @@ func parsePtsTargets(targets []string) (map[string]int, error) {
 				return nil, err
 			}
 		} else {
-			return nil, fmt.Errorf("'%s' does not match the pattern 'type=num', ex: web=2", target)
+			return nil, fmt.Errorf("'%s' does not match the pattern 'ptype=num', ex: web=2", target)
 		}
 	}
 
diff --git a/cmd/pts_test.go b/cmd/pts_test.go
index 1f41d344..8bbd5bc4 100644
--- a/cmd/pts_test.go
+++ b/cmd/pts_test.go
@@ -93,10 +93,10 @@ func TestParsePtsTargets(t *testing.T) {
 	t.Parallel()
 
 	cases := []ptsTargetCases{
-		{[]string{"test"}, true, nil, "'test' does not match the pattern 'type=num', ex: web=2"},
-		{[]string{"test=a"}, true, nil, "'test=a' does not match the pattern 'type=num', ex: web=2"},
-		{[]string{"test="}, true, nil, "'test=' does not match the pattern 'type=num', ex: web=2"},
-		{[]string{"Test=2"}, true, nil, "'Test=2' does not match the pattern 'type=num', ex: web=2"},
+		{[]string{"test"}, true, nil, "'test' does not match the pattern 'ptype=num', ex: web=2"},
+		{[]string{"test=a"}, true, nil, "'test=a' does not match the pattern 'ptype=num', ex: web=2"},
+		{[]string{"test="}, true, nil, "'test=' does not match the pattern 'ptype=num', ex: web=2"},
+		{[]string{"Test=2"}, true, nil, "'Test=2' does not match the pattern 'ptype=num', ex: web=2"},
 		{[]string{"test=2"}, false, map[string]int{"test": 2}, ""},
 		{[]string{"test-proc=2"}, false, map[string]int{"test-proc": 2}, ""},
 		{[]string{"test1=2"}, false, map[string]int{"test1": 2}, ""},
@@ -123,7 +123,7 @@ func TestPtsScale(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 	err = cmdr.PtsScale("foo", []string{"test"})
-	assert.Equal(t, err.Error(), "'test' does not match the pattern 'type=num', ex: web=2", "error")
+	assert.Equal(t, err.Error(), "'test' does not match the pattern 'ptype=num', ex: web=2", "error")
 
 	server.Mux.HandleFunc("/v2/apps/foo/ptypes/scale/", func(w http.ResponseWriter, r *http.Request) {
 		testutil.AssertBody(t, map[string]int{"web": 1}, r)
diff --git a/cmd/releases.go b/cmd/releases.go
index 302117a0..a573f608 100644
--- a/cmd/releases.go
+++ b/cmd/releases.go
@@ -67,11 +67,34 @@ func (d *DryccCmd) ReleasesInfo(appID string, version int) error {
 	}
 	table.Append([]string{"Version:", fmt.Sprintf("v%v", r.Version)})
 	table.Render()
+	// Conditions
+	if len(r.Conditions) != 0 {
+		// table event
+		te := d.getDefaultFormatTable([]string{})
+		te.Append([]string{"Conditions:"})
+		for _, c := range r.Conditions {
+			ptypes := "<none>"
+			if len(c.Ptypes) != 0 {
+				ptypes = strings.Join(c.Ptypes, ",")
+			}
+			exception := "<none>"
+			if c.Exception != "" {
+				exception = c.Exception
+			}
+
+			te.Append([]string{"  - created:", d.formatTime(c.Created)})
+			te.Append([]string{"    state:", c.State})
+			te.Append([]string{"    action:", c.Action})
+			te.Append([]string{"    ptypes:", d.wrapString(ptypes)})
+			te.Append([]string{"    exception:", d.wrapString(exception)})
+		}
+		te.Render()
+	}
 	return nil
 }
 
 // ReleasesDeploy force deploy lastest release.
-func (d *DryccCmd) ReleasesDeploy(appID string, targets []string, confirm string) error {
+func (d *DryccCmd) ReleasesDeploy(appID string, targets []string, force bool, confirm string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 	if err != nil {
 		return err
@@ -92,8 +115,9 @@ func (d *DryccCmd) ReleasesDeploy(appID string, targets []string, confirm string
 	startTime := time.Now()
 	quit := progress(d.WOut)
 	ptypes := strings.Join(targets, ",")
-	targetMap := map[string]string{
+	targetMap := map[string]interface{}{
 		"ptypes": ptypes,
+		"force":  force,
 	}
 	err = releases.Deploy(s.Client, appID, targetMap)
 	quit <- true
@@ -107,13 +131,13 @@ func (d *DryccCmd) ReleasesDeploy(appID string, targets []string, confirm string
 }
 
 // ReleasesRollback rolls an app back to a previous release.
-func (d *DryccCmd) ReleasesRollback(appID string, version int) error {
+func (d *DryccCmd) ReleasesRollback(appID string, targets []string, version int) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
-
+	ptypes := strings.Join(targets, ",")
 	if version == -1 {
 		d.Print("Rolling back one release... ")
 	} else {
@@ -121,7 +145,7 @@ func (d *DryccCmd) ReleasesRollback(appID string, version int) error {
 	}
 
 	quit := progress(d.WOut)
-	newVersion, err := releases.Rollback(s.Client, appID, version)
+	newVersion, err := releases.Rollback(s.Client, appID, ptypes, version)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
diff --git a/cmd/releases_test.go b/cmd/releases_test.go
index bea3c97c..9d91a31a 100644
--- a/cmd/releases_test.go
+++ b/cmd/releases_test.go
@@ -127,7 +127,15 @@ func TestReleasesInfo(t *testing.T) {
 			"version": 2,
 			"summary": "khamul added ANGMAR",
 			"config": "3bb816b1-4fde-4b06-8afe-acd12f58a266",
-			"build": null
+			"build": null,
+			"exception": null,
+			"conditions": [{
+				"state": "succeed",
+				"action": "pipeline",
+				"ptypes": ["web"],
+				"exception": "Boom!",
+				"created": "2024-08-27T08:31:36Z"
+			}]
 		}`)
 	})
 
@@ -143,6 +151,12 @@ Created:    2016-08-22T17:40:16Z
 Updated:    2016-08-22T17:40:16Z                    
 Summary:    khamul added ANGMAR                     
 Version:    v2                                      
+Conditions:       
+  - created:      2024-08-27T08:31:36Z    
+    state:        succeed                 
+    action:       pipeline                
+    ptypes:       web                     
+    exception:    Boom!                   
 `, "output")
 }
 
@@ -166,11 +180,11 @@ func TestReleasesDeploy(t *testing.T) {
 
 		res.WriteHeader(http.StatusCreated)
 	})
-	err = cmdr.ReleasesDeploy("example-go", []string{}, "yes")
+	err = cmdr.ReleasesDeploy("example-go", []string{}, false, "yes")
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = cmdr.ReleasesDeploy("example-go", []string{"web", "task"}, "")
+	err = cmdr.ReleasesDeploy("example-go", []string{"web", "task"}, false, "")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -198,20 +212,20 @@ func TestReleasesRollback(t *testing.T) {
 		fmt.Fprintf(w, `{"version": 5}`)
 	})
 
-	err = cmdr.ReleasesRollback("numenor", -1)
+	err = cmdr.ReleasesRollback("numenor", []string{"web"}, -1)
 	assert.NoError(t, err)
 	assert.Equal(t, testutil.StripProgress(b.String()), "Rolling back one release... done, v5\n", "output")
 
 	server.Mux.HandleFunc("/v2/apps/angmar/releases/rollback/", func(w http.ResponseWriter, r *http.Request) {
 		testutil.SetHeaders(w)
-		testutil.AssertBody(t, api.ReleaseRollback{Version: 3}, r)
+		testutil.AssertBody(t, api.ReleaseRollback{Ptypes: "web", Version: 3}, r)
 		w.WriteHeader(http.StatusCreated)
 		fmt.Fprintf(w, `{"version": 3}`)
 	})
 
 	b.Reset()
 
-	err = cmdr.ReleasesRollback("angmar", 3)
+	err = cmdr.ReleasesRollback("angmar", []string{"web"}, 3)
 	assert.NoError(t, err)
 	assert.Equal(t, testutil.StripProgress(b.String()), "Rolling back to v3... done, v3\n", "output")
 }
diff --git a/cmd/routes.go b/cmd/routes.go
index 3953b4df..d8609cac 100644
--- a/cmd/routes.go
+++ b/cmd/routes.go
@@ -9,7 +9,7 @@ import (
 )
 
 // RoutesCreate create a route to an app.
-func (d *DryccCmd) RoutesCreate(appID, name string, procType string, kind string, port int) error {
+func (d *DryccCmd) RoutesCreate(appID, name string, ptype string, kind string, port int) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -18,7 +18,7 @@ func (d *DryccCmd) RoutesCreate(appID, name string, procType string, kind string
 	d.Printf("Adding route %s to %s... ", name, appID)
 
 	quit := progress(d.WOut)
-	err = routes.New(s.Client, appID, name, procType, kind, port)
+	err = routes.New(s.Client, appID, name, ptype, kind, port)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
@@ -54,7 +54,7 @@ func (d *DryccCmd) RoutesList(appID string, results int) error {
 					table.Append([]string{
 						route.Name,
 						route.Owner,
-						route.Type,
+						route.Ptype,
 						route.Kind,
 						fmt.Sprint(route.Port),
 						gateway.Name,
@@ -65,7 +65,7 @@ func (d *DryccCmd) RoutesList(appID string, results int) error {
 				table.Append([]string{
 					route.Name,
 					route.Owner,
-					route.Type,
+					route.Ptype,
 					route.Kind,
 					fmt.Sprint(route.Port),
 					"",
diff --git a/cmd/routes_test.go b/cmd/routes_test.go
index eaf775d1..4346d1fd 100644
--- a/cmd/routes_test.go
+++ b/cmd/routes_test.go
@@ -23,7 +23,7 @@ func TestRoutesCreate(t *testing.T) {
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
 	server.Mux.HandleFunc("/v2/apps/foo/routes/", func(w http.ResponseWriter, r *http.Request) {
-		testutil.AssertBody(t, api.RouteCreateRequest{Name: "example-go", Type: "web", Port: 443, Kind: "HTTPRoute"}, r)
+		testutil.AssertBody(t, api.RouteCreateRequest{Name: "example-go", Ptype: "web", Port: 443, Kind: "HTTPRoute"}, r)
 		testutil.SetHeaders(w)
 		w.WriteHeader(http.StatusCreated)
 		// Body isn't used by CLI, so it isn't set.
@@ -59,7 +59,7 @@ func TestRoutesList(t *testing.T) {
             "owner": "test",
             "updated": "2023-04-19T00:00:00UTC",
             "name": "example-go",
-            "procfile_type": "web",
+            "ptype": "web",
             "kind": "HTTPRoute",
             "port": 80,
             "parent_refs": [
diff --git a/cmd/services.go b/cmd/services.go
index 6a35df44..429a2e54 100644
--- a/cmd/services.go
+++ b/cmd/services.go
@@ -25,7 +25,7 @@ func (d *DryccCmd) ServicesList(appID string) error {
 		for _, service := range services {
 			for _, port := range service.Ports {
 				table.Append([]string{
-					service.ProcfileType,
+					service.Ptype,
 					fmt.Sprint(port.Port),
 					port.Protocol,
 					fmt.Sprint(port.TargetPort),
@@ -41,7 +41,7 @@ func (d *DryccCmd) ServicesList(appID string) error {
 }
 
 // ServicesAdd adds a service to an app.
-func (d *DryccCmd) ServicesAdd(appID, procfileType string, ports string, protocol string) error {
+func (d *DryccCmd) ServicesAdd(appID, ptype string, ports string, protocol string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -51,10 +51,10 @@ func (d *DryccCmd) ServicesAdd(appID, procfileType string, ports string, protoco
 	if err != nil {
 		return err
 	}
-	d.Printf("Adding %s (%d) to %s... ", procfileType, portArray[0], appID)
+	d.Printf("Adding %s (%d) to %s... ", ptype, portArray[0], appID)
 
 	quit := progress(d.WOut)
-	err = services.New(s.Client, appID, procfileType, portArray[0], protocol, portArray[1])
+	err = services.New(s.Client, appID, ptype, portArray[0], protocol, portArray[1])
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
@@ -65,18 +65,18 @@ func (d *DryccCmd) ServicesAdd(appID, procfileType string, ports string, protoco
 	return nil
 }
 
-// ServicesRemove removes a service for procfileType registered with an app.
-func (d *DryccCmd) ServicesRemove(appID, procfileType string, protocol string, port int) error {
+// ServicesRemove removes a service for Ptype registered with an app.
+func (d *DryccCmd) ServicesRemove(appID, ptype string, protocol string, port int) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
 
-	d.Printf("Removing %s from %s... ", procfileType, appID)
+	d.Printf("Removing %s from %s... ", ptype, appID)
 
 	quit := progress(d.WOut)
-	err = services.Delete(s.Client, appID, procfileType, protocol, port)
+	err = services.Delete(s.Client, appID, ptype, protocol, port)
 	quit <- true
 	<-quit
 	if d.checkAPICompatibility(s.Client, err) != nil {
diff --git a/cmd/shortcuts_test.go b/cmd/shortcuts_test.go
index 5de5fba7..3cfc5e98 100644
--- a/cmd/shortcuts_test.go
+++ b/cmd/shortcuts_test.go
@@ -19,9 +19,9 @@ rollback -> releases:rollback
 run -> apps:run
 scale -> pts:scale
 sharing -> perms:list
-sharing:add -> perms:create
+sharing:add -> perms:add
 sharing:list -> perms:list
-sharing:remove -> perms:delete
+sharing:remove -> perms:remove
 whoami -> auth:whoami
 `
 	actual := sortShortcuts()
diff --git a/cmd/tags.go b/cmd/tags.go
index 56a81de4..2af697ad 100644
--- a/cmd/tags.go
+++ b/cmd/tags.go
@@ -9,7 +9,7 @@ import (
 )
 
 // TagsList lists an app's tags.
-func (d *DryccCmd) TagsList(appID, procType string) error {
+func (d *DryccCmd) TagsList(appID, ptype string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -23,12 +23,12 @@ func (d *DryccCmd) TagsList(appID, procType string) error {
 	if len(config.Tags) == 0 {
 		d.Println(fmt.Sprintf("No tags found in %s app.", appID))
 	} else {
-		if tags, ok := config.Tags[procType]; ok {
+		if tags, ok := config.Tags[ptype]; ok {
 			table := d.getDefaultFormatTable([]string{"KEY", "VALUE"})
 			for _, key := range *sortKeys(tags) {
 				table.Append([]string{
 					key,
-					fmt.Sprintf("%v", config.Tags[procType][key]),
+					fmt.Sprintf("%v", config.Tags[ptype][key]),
 				})
 			}
 			table.Render()
@@ -38,7 +38,7 @@ func (d *DryccCmd) TagsList(appID, procType string) error {
 }
 
 // TagsSet sets an app's tags.
-func (d *DryccCmd) TagsSet(appID, procType string, tags []string) error {
+func (d *DryccCmd) TagsSet(appID, ptype string, tags []string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -54,7 +54,7 @@ func (d *DryccCmd) TagsSet(appID, procType string, tags []string) error {
 
 	quit := progress(d.WOut)
 	configObj := api.Config{Tags: make(map[string]api.ConfigTags)}
-	configObj.Tags[procType] = tagsMap
+	configObj.Tags[ptype] = tagsMap
 
 	_, err = config.Set(s.Client, appID, configObj)
 	quit <- true
@@ -65,11 +65,11 @@ func (d *DryccCmd) TagsSet(appID, procType string, tags []string) error {
 
 	d.Print("done\n\n")
 
-	return d.TagsList(appID, procType)
+	return d.TagsList(appID, ptype)
 }
 
 // TagsUnset removes an app's tags.
-func (d *DryccCmd) TagsUnset(appID, procType string, tags []string) error {
+func (d *DryccCmd) TagsUnset(appID, ptype string, tags []string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
@@ -85,7 +85,7 @@ func (d *DryccCmd) TagsUnset(appID, procType string, tags []string) error {
 	for _, tag := range tags {
 		configTags[tag] = nil
 	}
-	configObj.Tags[procType] = configTags
+	configObj.Tags[ptype] = configTags
 
 	_, err = config.Set(s.Client, appID, configObj)
 	quit <- true
@@ -96,7 +96,7 @@ func (d *DryccCmd) TagsUnset(appID, procType string, tags []string) error {
 
 	d.Print("done\n\n")
 
-	return d.TagsList(appID, procType)
+	return d.TagsList(appID, ptype)
 }
 
 func parseTags(tags []string) (map[string]interface{}, error) {
diff --git a/cmd/token.go b/cmd/token.go
index ec6f772c..40ab88e7 100644
--- a/cmd/token.go
+++ b/cmd/token.go
@@ -30,9 +30,10 @@ func (d *DryccCmd) TokensList(results int) error {
 	if d.checkAPICompatibility(s.Client, err) != nil {
 		return err
 	}
-	table := d.getDefaultFormatTable([]string{"OWNER", "ALIAS", "KEY", "CREATE", "UPDATED"})
+	table := d.getDefaultFormatTable([]string{"UUID", "OWNER", "ALIAS", "KEY", "CREATE", "UPDATED"})
 	for _, token := range tokens {
 		table.Append([]string{
+			token.UUID,
 			token.Owner,
 			safeGetString(token.Alias),
 			token.Key,
diff --git a/cmd/token_test.go b/cmd/token_test.go
index 307964ee..68a5a092 100644
--- a/cmd/token_test.go
+++ b/cmd/token_test.go
@@ -51,9 +51,9 @@ func TestTokensList(t *testing.T) {
 	err = cmdr.TokensList(-1)
 	assert.NoError(t, err)
 
-	assert.Equal(t, b.String(), `OWNER    ALIAS     KEY                                 CREATE                    UPDATED                
-test     <none>    c8e74fa4cbf...e4954d602ec5ed19ba    2023-04-18T00:00:00UTC    2023-04-19T00:00:00UTC    
-test     test      c8e74fa4cbf...e4954d60cec5ed19ba    2023-04-18T10:00:00UTC    2023-04-19T12:00:00UTC    
+	assert.Equal(t, b.String(), `UUID                                    OWNER    ALIAS     KEY                                 CREATE                    UPDATED                
+f71e3b18-e702-409e-bd7f-8fb0a66d7b12    test     <none>    c8e74fa4cbf...e4954d602ec5ed19ba    2023-04-18T00:00:00UTC    2023-04-19T00:00:00UTC    
+f71e3b18-e702-499e-bd7f-8fb0a66d7b12    test     test      c8e74fa4cbf...e4954d60cec5ed19ba    2023-04-18T10:00:00UTC    2023-04-19T12:00:00UTC    
 `, "output")
 }
 
diff --git a/cmd/volumes_test.go b/cmd/volumes_test.go
index 35ce7f81..d7cbdb71 100644
--- a/cmd/volumes_test.go
+++ b/cmd/volumes_test.go
@@ -164,8 +164,6 @@ func TestVolumesClientCp(t *testing.T) {
 	}
 	server.Mux.HandleFunc("/v2/apps/example-go/volumes/*", func(w http.ResponseWriter, r *http.Request) {
 		testutil.SetHeaders(w)
-		fmt.Println(r.URL.Path)
-		fmt.Println(r.URL.RawQuery)
 		if r.URL.Path == "/v2/apps/example-go/volumes/myvolume/client/" {
 			if r.URL.RawQuery == "path=etc" {
 				fmt.Fprintf(w, `{"results":[],"count":0}`)
diff --git a/drycc.go b/drycc.go
index 332ad5f9..25e54033 100644
--- a/drycc.go
+++ b/drycc.go
@@ -48,6 +48,7 @@ Auth commands, use 'drycc help auth' to learn more:
 Subcommands, use 'drycc help [subcommand]' to learn more:
 
   apps          manage applications used to provide services
+  autodeploy    manage autodeploy if or not for applications 
   autorollback  manage autorollback if or not for applications 
   autoscale     manage autoscale for applications
   builds        manage builds created using 'git push'
@@ -118,6 +119,8 @@ Use 'git push drycc main' to deploy to an application.
 		err = parser.Apps(argv, &cmdr)
 	case "auth":
 		err = parser.Auth(argv, &cmdr)
+	case "autodeploy":
+		err = parser.Autodeploy(argv, &cmdr)
 	case "autorollback":
 		err = parser.Autorollback(argv, &cmdr)
 	case "autoscale":
diff --git a/go.mod b/go.mod
index cd309871..e6331d30 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.22
 require (
 	github.com/containerd/console v1.0.4
 	github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
-	github.com/drycc/controller-sdk-go v0.0.0-20240826083511-133cdf53297d
+	github.com/drycc/controller-sdk-go v0.0.0-20240905080608-287c054d88fa
 	github.com/drycc/pkg v0.0.0-20240225112316-78fc9239f51f
 	github.com/minio/selfupdate v0.6.0
 	github.com/olekukonko/tablewriter v0.0.5
diff --git a/go.sum b/go.sum
index a16c3d18..a5946c39 100644
--- a/go.sum
+++ b/go.sum
@@ -7,8 +7,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/drycc/controller-sdk-go v0.0.0-20240826083511-133cdf53297d h1:hzwt73EpOkRLrdF64MZ6gl5APs065QNR5Ucl7TXx9DQ=
-github.com/drycc/controller-sdk-go v0.0.0-20240826083511-133cdf53297d/go.mod h1:n6eQe1irJqjwLo/7t9+Dhdv6faSESQN+ATnZRBP3/Uc=
+github.com/drycc/controller-sdk-go v0.0.0-20240905080608-287c054d88fa h1:mdr4Z80ioWRP9o/4mpW1NwICPirXvvlyK7cCV3pprvc=
+github.com/drycc/controller-sdk-go v0.0.0-20240905080608-287c054d88fa/go.mod h1:n6eQe1irJqjwLo/7t9+Dhdv6faSESQN+ATnZRBP3/Uc=
 github.com/drycc/pkg v0.0.0-20240225112316-78fc9239f51f h1:kgjvUQJeAszDoU1Vo4vTTE92KI8Av3JPb6Qn890niXg=
 github.com/drycc/pkg v0.0.0-20240225112316-78fc9239f51f/go.mod h1:n+QxGif6ha9CEoxVnlipxb9IdmerybcUSzTEDFkvjiA=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
diff --git a/parser/autodeploy.go b/parser/autodeploy.go
new file mode 100644
index 00000000..b9b86a7c
--- /dev/null
+++ b/parser/autodeploy.go
@@ -0,0 +1,98 @@
+package parser
+
+import (
+	docopt "github.com/docopt/docopt-go"
+	"github.com/drycc/workflow-cli/cmd"
+)
+
+// Autodeploy displays all relevant commands for `drycc autodeploy`.
+func Autodeploy(argv []string, cmdr cmd.Commander) error {
+	usage := `
+Valid commands for autodeploy:
+
+autodeploy:info       view autodeploy info of an application
+autodeploy:enable     enable autodeploy for an app
+autodeploy:disable    disable autodeploy for an app
+
+Use 'drycc help [command]' to learn more.
+`
+
+	switch argv[0] {
+	case "autodeploy:info":
+		return autodeployInfo(argv, cmdr)
+	case "autodeploy:enable":
+		return autodeployEnable(argv, cmdr)
+	case "autodeploy:disable":
+		return autodeployDisable(argv, cmdr)
+	default:
+		if printHelp(argv, usage) {
+			return nil
+		}
+
+		if argv[0] == "autodeploy" {
+			argv[0] = "autodeploy:info"
+			return autodeployInfo(argv, cmdr)
+		}
+
+		PrintUsage(cmdr)
+		return nil
+	}
+}
+
+func autodeployInfo(argv []string, cmdr cmd.Commander) error {
+	usage := `
+Prints info about the current application's autodeploy if or not.
+
+Usage: drycc autodeploy:info [options]
+
+Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
+`
+
+	args, err := docopt.ParseArgs(usage, argv, "")
+	if err != nil {
+		return err
+	}
+
+	return cmdr.AutodeployInfo(safeGetString(args, "--app"))
+}
+
+func autodeployEnable(argv []string, cmdr cmd.Commander) error {
+	usage := `
+Enables autodeploy for an app.
+
+Usage: drycc autodeploy:enable [options]
+
+Options:
+  -a --app=<app>
+    the uniquely identifiable name of the application.
+`
+
+	args, err := docopt.ParseArgs(usage, argv, "")
+	if err != nil {
+		return err
+	}
+
+	return cmdr.AutodeployEnable(safeGetString(args, "--app"))
+}
+
+func autodeployDisable(argv []string, cmdr cmd.Commander) error {
+	usage := `
+Disables autodeploy for an app.
+
+Usage: drycc autodeploy:disable [options]
+
+Options:
+  -a --app=<app>
+    the uniquely identifiable name of the application.
+`
+
+	args, err := docopt.ParseArgs(usage, argv, "")
+
+	if err != nil {
+		return err
+	}
+
+	return cmdr.AutodeployDisable(safeGetString(args, "--app"))
+}
diff --git a/parser/autodeploy_test.go b/parser/autodeploy_test.go
new file mode 100644
index 00000000..717bf5ba
--- /dev/null
+++ b/parser/autodeploy_test.go
@@ -0,0 +1,74 @@
+package parser
+
+import (
+	"bytes"
+	"errors"
+	"testing"
+
+	"github.com/drycc/workflow-cli/pkg/testutil"
+	"github.com/stretchr/testify/assert"
+)
+
+// Create fake implementations of each method that return the argument
+// we expect to have called the function (as an error to satisfy the interface).
+
+func (d FakeDryccCmd) AutodeployInfo(string) error {
+	return errors.New("autodeploy:info")
+}
+
+func (d FakeDryccCmd) AutodeployEnable(string) error {
+	return errors.New("autodeploy:enable")
+}
+
+func (d FakeDryccCmd) AutodeployDisable(string) error {
+	return errors.New("autodeploy:disable")
+}
+
+func TestAutodeploy(t *testing.T) {
+	t.Parallel()
+
+	cf, server, err := testutil.NewTestServerAndClient()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer server.Close()
+	var b bytes.Buffer
+	cmdr := FakeDryccCmd{WOut: &b, ConfigFile: cf}
+
+	// cases defines the arguments and expected return of the call.
+	// if expected is "", it defaults to args[0].
+	cases := []struct {
+		args     []string
+		expected string
+	}{
+		{
+			args:     []string{"autodeploy:info"},
+			expected: "",
+		},
+		{
+			args:     []string{"autodeploy:enable"},
+			expected: "",
+		},
+		{
+			args:     []string{"autodeploy:disable"},
+			expected: "",
+		},
+		{
+			args:     []string{"autodeploy"},
+			expected: "autodeploy:info",
+		},
+	}
+
+	// For each case, check that calling the route with the arguments
+	// returns the expected error, which is args[0] if not provided.
+	for _, c := range cases {
+		var expected string
+		if c.expected == "" {
+			expected = c.args[0]
+		} else {
+			expected = c.expected
+		}
+		err = Autodeploy(c.args, cmdr)
+		assert.Error(t, errors.New(expected), err)
+	}
+}
diff --git a/parser/autoscale.go b/parser/autoscale.go
index 3e62219e..f8b9a005 100644
--- a/parser/autoscale.go
+++ b/parser/autoscale.go
@@ -63,10 +63,10 @@ func autoscaleSet(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Set autoscale option per process type for an app.
 
-Usage: drycc autoscale:set <process-type> --min=<min> --max=<max> --cpu-percent=<percent> [options]
+Usage: drycc autoscale:set <ptype> --min=<min> --max=<max> --cpu-percent=<percent> [options]
 
 Arguments:
-  <process-type>
+  <ptype>
     the process type to add to the application's autoscale settings.
   --min=<min>
 	minimum replicas to keep around
@@ -86,23 +86,23 @@ Options:
 		return err
 	}
 
-	processType := args["<process-type>"].(string)
+	ptype := args["<ptype>"].(string)
 	app := safeGetString(args, "--app")
 	min := safeGetInt(args, "--min")
 	max := safeGetInt(args, "--max")
 	CPUPercent := safeGetInt(args, "--cpu-percent")
 
-	return cmdr.AutoscaleSet(app, processType, min, max, CPUPercent)
+	return cmdr.AutoscaleSet(app, ptype, min, max, CPUPercent)
 }
 
 func autoscaleUnset(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Unset autoscale per process type for an app.
 
-Usage: drycc autoscale:unset <process-type> [options]
+Usage: drycc autoscale:unset <ptype> [options]
 
 Arguments:
-  <process-type>
+  <ptype>
     the process type to remove from the application's autoscale settings.
 
 Options:
@@ -116,8 +116,8 @@ Options:
 		return err
 	}
 
-	processType := args["<process-type>"].(string)
+	ptype := args["<ptype>"].(string)
 	app := safeGetString(args, "--app")
 
-	return cmdr.AutoscaleUnset(app, processType)
+	return cmdr.AutoscaleUnset(app, ptype)
 }
diff --git a/parser/certs.go b/parser/certs.go
index 5273ed51..54bb67c0 100644
--- a/parser/certs.go
+++ b/parser/certs.go
@@ -55,6 +55,8 @@ Show certificate information for an SSL application.
 Usage: drycc certs:list [options]
 
 Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
   -l --limit=<num>
     the maximum number of results to display, defaults to config setting
 `
@@ -68,8 +70,8 @@ Options:
 	if err != nil {
 		return err
 	}
-
-	return cmdr.CertsList(results)
+	app := safeGetString(args, "--app")
+	return cmdr.CertsList(app, results)
 }
 
 func certAdd(argv []string, cmdr cmd.Commander) error {
@@ -87,6 +89,8 @@ Arguments:
     The private key of the SSL certificate.
 
 Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -97,8 +101,8 @@ Options:
 	name := args["<name>"].(string)
 	cert := args["<cert>"].(string)
 	key := args["<key>"].(string)
-
-	return cmdr.CertAdd(cert, key, name)
+	app := safeGetString(args, "--app")
+	return cmdr.CertAdd(app, cert, key, name)
 }
 
 func certRemove(argv []string, cmdr cmd.Commander) error {
@@ -112,14 +116,17 @@ Arguments:
     the name of the cert to remove from the app.
 
 Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
 	if err != nil {
 		return err
 	}
-
-	return cmdr.CertRemove(safeGetString(args, "<name>"))
+	app := safeGetString(args, "--app")
+	name := safeGetString(args, "<name>")
+	return cmdr.CertRemove(app, name)
 }
 
 func certInfo(argv []string, cmdr cmd.Commander) error {
@@ -133,14 +140,17 @@ Arguments:
     the name of the cert to get information from
 
 Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
 	if err != nil {
 		return err
 	}
-
-	return cmdr.CertInfo(safeGetString(args, "<name>"))
+	app := safeGetString(args, "--app")
+	name := safeGetString(args, "<name>")
+	return cmdr.CertInfo(app, name)
 }
 
 func certAttach(argv []string, cmdr cmd.Commander) error {
@@ -156,16 +166,18 @@ Arguments:
     common name of the domain to attach to (needs to already be in the system)
 
 Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
 	if err != nil {
 		return err
 	}
-
+	app := safeGetString(args, "--app")
 	name := safeGetString(args, "<name>")
 	domain := safeGetString(args, "<domain>")
-	return cmdr.CertAttach(name, domain)
+	return cmdr.CertAttach(app, name, domain)
 }
 
 func certDetach(argv []string, cmdr cmd.Commander) error {
@@ -181,14 +193,16 @@ Arguments:
     common name of the domain to detach from
 
 Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
 	if err != nil {
 		return err
 	}
-
+	app := safeGetString(args, "--app")
 	name := safeGetString(args, "<name>")
 	domain := safeGetString(args, "<domain>")
-	return cmdr.CertDetach(name, domain)
+	return cmdr.CertDetach(app, name, domain)
 }
diff --git a/parser/certs_test.go b/parser/certs_test.go
index 78e8581b..7fa5fce7 100644
--- a/parser/certs_test.go
+++ b/parser/certs_test.go
@@ -12,27 +12,27 @@ import (
 // Create fake implementations of each method that return the argument
 // we expect to have called the function (as an error to satisfy the interface).
 
-func (d FakeDryccCmd) CertsList(int) error {
+func (d FakeDryccCmd) CertsList(string, int) error {
 	return errors.New("certs:list")
 }
 
-func (d FakeDryccCmd) CertAdd(string, string, string) error {
+func (d FakeDryccCmd) CertAdd(string, string, string, string) error {
 	return errors.New("certs:add")
 }
 
-func (d FakeDryccCmd) CertRemove(string) error {
+func (d FakeDryccCmd) CertRemove(string, string) error {
 	return errors.New("certs:remove")
 }
 
-func (d FakeDryccCmd) CertInfo(string) error {
+func (d FakeDryccCmd) CertInfo(string, string) error {
 	return errors.New("certs:info")
 }
 
-func (d FakeDryccCmd) CertAttach(string, string) error {
+func (d FakeDryccCmd) CertAttach(string, string, string) error {
 	return errors.New("certs:attach")
 }
 
-func (d FakeDryccCmd) CertDetach(string, string) error {
+func (d FakeDryccCmd) CertDetach(string, string, string) error {
 	return errors.New("certs:detach")
 }
 
diff --git a/parser/config.go b/parser/config.go
index 5a06d14f..bea08cc1 100644
--- a/parser/config.go
+++ b/parser/config.go
@@ -54,8 +54,8 @@ Usage: drycc config:list [options]
 Options:
   -a --app=<app>
     the application that you wish to listed.
-  --type=<type>
-    the procType for which the config needs to be listed.
+  --ptype=<ptype>
+    the ptype for which the config needs to be listed.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -64,8 +64,8 @@ Options:
 		return err
 	}
 	app := safeGetString(args, "--app")
-	procType := safeGetString(args, "--type")
-	return cmdr.ConfigList(app, procType)
+	ptype := safeGetString(args, "--ptype")
+	return cmdr.ConfigList(app, ptype)
 }
 
 func configSet(argv []string, cmdr cmd.Commander) error {
@@ -83,8 +83,8 @@ Arguments:
 Options:
   -a --app=<app>
     the application that you wish to set.
-  --type=<type>
-    the procType for which the config needs to be set.
+  --ptype=<ptype>
+    the ptype for which the config needs to be set.
   --confirm=yes
     To proceed, type "yes".
 `
@@ -96,9 +96,9 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	procType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 	confirm := safeGetString(args, "--confirm")
-	return cmdr.ConfigSet(app, procType, args["<var>=<value>"].([]string), confirm)
+	return cmdr.ConfigSet(app, ptype, args["<var>=<value>"].([]string), confirm)
 }
 
 func configUnset(argv []string, cmdr cmd.Commander) error {
@@ -114,8 +114,8 @@ Arguments:
 Options:
   -a --app=<app>
     the application that you wish to unset.
-  --type=<type>
-    the procType for which the config needs to be unset.
+  --ptype=<ptype>
+    the ptype for which the config needs to be unset.
   --confirm=yes
     To proceed, type "yes".
 `
@@ -126,9 +126,9 @@ Options:
 		return err
 	}
 	app := safeGetString(args, "--app")
-	procType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 	confirm := safeGetString(args, "--confirm")
-	return cmdr.ConfigUnset(app, procType, args["<key>"].([]string), confirm)
+	return cmdr.ConfigUnset(app, ptype, args["<key>"].([]string), confirm)
 }
 
 func configPull(argv []string, cmdr cmd.Commander) error {
@@ -144,8 +144,8 @@ Usage: drycc config:pull [options]
 Options:
   -a --app=<app>
     the application that you wish to pull.
-  --type=<type>
-    the procType for which the config needs to be pull.
+  --ptype=<ptype>
+    the ptype for which the config needs to be pull.
   --path=<path>
     a path leading to an environment file [default: .env]
   -i --interactive
@@ -161,12 +161,12 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	procType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 	path := safeGetValue(args, "--path", ".env")
 	interactive := args["--interactive"].(bool)
 	overwrite := args["--overwrite"].(bool)
 
-	return cmdr.ConfigPull(app, procType, path, interactive, overwrite)
+	return cmdr.ConfigPull(app, ptype, path, interactive, overwrite)
 }
 
 func configPush(argv []string, cmdr cmd.Commander) error {
@@ -182,8 +182,8 @@ Usage: drycc config:push [options]
 Options:
   -a --app=<app>
     the application that you wish to push.
-  --type=<type>
-    the procType for which the config needs to be push.
+  --ptype=<ptype>
+    the ptype for which the config needs to be push.
   --path=<path>
     a path leading to an environment file [default: .env]
   --confirm=yes
@@ -197,8 +197,8 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	procType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 	path := safeGetValue(args, "--path", ".env")
 	confirm := safeGetString(args, "--confirm")
-	return cmdr.ConfigPush(app, procType, path, confirm)
+	return cmdr.ConfigPush(app, ptype, path, confirm)
 }
diff --git a/parser/domains.go b/parser/domains.go
index 1f4fe79b..b41469c8 100644
--- a/parser/domains.go
+++ b/parser/domains.go
@@ -50,8 +50,8 @@ Arguments:
     the domain name to be bound to the application, such as 'domain.dryccapp.com'.
 
 Options:
-  --type=<type>
-    the procType type for domain, default[web].
+  --ptype=<ptype>
+    the ptype type for domain, default[web].
   -a --app=<app>
     the uniquely identifiable name for the application.
 `
@@ -63,10 +63,10 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	procfileType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 	domain := safeGetString(args, "<domain>")
 
-	return cmdr.DomainsAdd(app, domain, procfileType)
+	return cmdr.DomainsAdd(app, domain, ptype)
 }
 
 func domainsList(argv []string, cmdr cmd.Commander) error {
diff --git a/parser/healthchecks.go b/parser/healthchecks.go
index 3d5cd613..96802e8c 100644
--- a/parser/healthchecks.go
+++ b/parser/healthchecks.go
@@ -14,7 +14,7 @@ import (
 // TODO: This is for supporting backward compatibility and should be removed
 // in future when next major version will be released.
 const (
-	defaultProcType string = "web"
+	defaultPtype string = "web"
 )
 
 // Healthchecks routes ealthcheck commands to their specific function
@@ -60,8 +60,8 @@ Usage: drycc healthchecks:list [options]
 Options:
   -a --app=<app>
     the uniquely identifiable name of the application.
-  --type=<type>
-    the procType for which the health check needs to be listed.
+  --ptype=<ptype>
+    the ptype for which the health check needs to be listed.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -71,9 +71,9 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	procType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 
-	return cmdr.HealthchecksList(app, procType)
+	return cmdr.HealthchecksList(app, ptype)
 }
 
 func healthchecksSet(argv []string, cmdr cmd.Commander) error {
@@ -126,8 +126,8 @@ Options:
     the uniquely identifiable name for the application.
   -p --path=<path>
     the relative URL path for 'httpGet' probes. [default: /]
-  --type=<type>
-    the procType for which the health check needs to be applied.
+  --ptype=<ptype>
+    the ptype for which the health check needs to be applied.
   --headers=<headers>...
     the HTTP headers to send for 'httpGet' probes, separated by commas.
   --initial-delay-timeout=<initial-delay-timeout>
@@ -150,7 +150,7 @@ Options:
 
 	app := safeGetString(args, "--app")
 	path := safeGetString(args, "--path")
-	procType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 	initialDelayTimeout := safeGetInt(args, "--initial-delay-timeout")
 	timeoutSeconds := safeGetInt(args, "--timeout-seconds")
 	periodSeconds := safeGetInt(args, "--period-seconds")
@@ -160,8 +160,8 @@ Options:
 	if args["--headers"] != nil {
 		headers = strings.Split(args["--headers"].(string), ",")
 	}
-	if procType == "" {
-		procType = defaultProcType
+	if ptype == "" {
+		ptype = defaultPtype
 	}
 
 	healthcheckType := args["<health-type>"].(string)
@@ -211,24 +211,24 @@ Options:
 		return fmt.Errorf("invalid probe type. Must be one of: \"httpGet\", \"exec\"")
 	}
 
-	return cmdr.HealthchecksSet(app, healthcheckType, procType, probe)
+	return cmdr.HealthchecksSet(app, healthcheckType, ptype, probe)
 }
 
 func healthchecksUnset(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Unsets healthchecks for an application.
 
-Usage: drycc healthchecks:unset [options] <health-type>...
+Usage: drycc healthchecks:unset <health-type>... [options]
 
 Arguments:
   <health-type>
-    the healthcheck type, such as 'liveness' or 'readiness'.
+    the healthcheck type, such as 'startupProbe' 'livenessProbe' or 'readinessProbe'.
 
 Options:
   -a --app=<app>
     the uniquely identifiable name for the application.
-  --type=<type>
-    the procType for which the health check needs to be removed.
+  --ptype=<ptype>
+    the ptype for which the health check needs to be removed.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -239,9 +239,9 @@ Options:
 
 	app := safeGetString(args, "--app")
 	healthchecks := args["<health-type>"].([]string)
-	procType := safeGetString(args, "--type")
-	if procType == "" {
-		procType = defaultProcType
+	ptype := safeGetString(args, "--ptype")
+	if ptype == "" {
+		ptype = defaultPtype
 	}
 
 	for healthcheck := range healthchecks {
@@ -250,7 +250,7 @@ Options:
 		}
 	}
 
-	return cmdr.HealthchecksUnset(app, procType, healthchecks)
+	return cmdr.HealthchecksUnset(app, ptype, healthchecks)
 }
 
 func parseHeaders(headers []string) ([]*api.KVPair, error) {
diff --git a/parser/labels.go b/parser/labels.go
index d073ab67..9423d1e7 100644
--- a/parser/labels.go
+++ b/parser/labels.go
@@ -66,7 +66,7 @@ Sets labels for an application.
 A label is a key/value pair used to label an application. This label is a general information for drycc user.
 Mostly used for administration/maintenance information, note for application. This information isn't send to scheduler.
 
-Usage: drycc labels:set [options] <key>=<value>...
+Usage: drycc labels:set <key>=<value>... [options]
 
 Arguments:
   <key> the label key, for example: "git_repo" or "team"
@@ -92,7 +92,7 @@ func labelsUnset(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Unsets labels for an application.
 
-Usage: drycc labels:unset [options] <key>...
+Usage: drycc labels:unset <key>... [options]
 
 Arguments:
   <key> the label key to unset, for example: "git_repo" or "team"
diff --git a/parser/limits.go b/parser/limits.go
index 03851291..7daef3a6 100644
--- a/parser/limits.go
+++ b/parser/limits.go
@@ -72,10 +72,10 @@ Sets resource limits for an application.
 A resource limit is a finite resource within a pod which we can apply
 restrictions through Kubernetes.
 
-Usage: drycc limits:set [options] <type>=<value>...
+Usage: drycc limits:set <ptype>=<value>... [options]
 
 Arguments:
-  <type>
+  <ptype>
     the process type as defined in your Procfile, such as 'web' or 'worker'.
   <value>
     The limit plan id to apply to the process type.
@@ -94,7 +94,7 @@ Use 'drycc help [command]' to learn more.
 	}
 
 	app := safeGetString(args, "--app")
-	limits := args["<type>=<value>"].([]string)
+	limits := args["<ptype>=<value>"].([]string)
 	return cmdr.LimitsSet(app, limits)
 }
 
@@ -102,10 +102,10 @@ func limitUnset(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Unsets resource limits for an application.
 
-Usage: drycc limits:unset [options] <type>...
+Usage: drycc limits:unset <ptype>... [options]
 
 Arguments:
-  <type>
+  <ptype>
     the process type as defined in your Procfile, such as 'web' or 'worker'.
 
 Options:
@@ -120,7 +120,7 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	limits := args["<type>"].([]string)
+	limits := args["<ptype>"].([]string)
 
 	return cmdr.LimitsUnset(app, limits)
 }
diff --git a/parser/perms.go b/parser/perms.go
index b3639a39..ef3ac1e2 100644
--- a/parser/perms.go
+++ b/parser/perms.go
@@ -10,22 +10,22 @@ func Perms(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Valid commands for perms:
 
-perms:codes           list all policy codename
 perms:list            list all user permission
-perms:create          create a user permission
-perms:delete          delete a user permission
+perms:add             create a user permission
+perms:update          update a user permission
+perms:remove          delete a user permission
 
 Use 'drycc help perms:[command]' to learn more.
 `
 
 	switch argv[0] {
-	case "perms:codes":
-		return permsCodes(argv, cmdr)
 	case "perms:list":
 		return permsList(argv, cmdr)
-	case "perms:create":
+	case "perms:add":
 		return permCreate(argv, cmdr)
-	case "perms:delete":
+	case "perms:update":
+		return permUpdate(argv, cmdr)
+	case "perms:remove":
 		return permDelete(argv, cmdr)
 	default:
 		if printHelp(argv, usage) {
@@ -42,15 +42,17 @@ Use 'drycc help perms:[command]' to learn more.
 	}
 }
 
-func permsCodes(argv []string, cmdr cmd.Commander) error {
+func permsList(argv []string, cmdr cmd.Commander) error {
 	usage := `
-List all policy codename.
+List all user permissions.
 
-Usage: drycc perms:codes [options]
+Usage: drycc perms:list [options]
 
 Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
   -l --limit=<num>
-    the maximum number of results to display, defaults to config setting
+    the maximum number of results to display, defaults to config setting.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -64,21 +66,24 @@ Options:
 	if err != nil {
 		return err
 	}
-
-	return cmdr.PermCodes(results)
+	app := safeGetString(args, "--app")
+	return cmdr.PermList(app, results)
 }
 
-func permsList(argv []string, cmdr cmd.Commander) error {
+func permCreate(argv []string, cmdr cmd.Commander) error {
 	usage := `
-List all user permission.
+Grant permissions to user.
 
-Usage: drycc perms:list [options]
+Usage: drycc perms:add <username> <permissions> [options]
 
+Arguments:
+  <username>
+    the name of the user.
+  <permissions>
+	comma-delimited list of permissions (view,change,delete).
 Options:
-  -c --codename=<codename>
-    filter all user permissions by codename
-  -l --limit=<num>
-    the maximum number of results to display, defaults to config setting
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -87,29 +92,26 @@ Options:
 		return err
 	}
 
-	codename := safeGetString(args, "--codename")
-	results, err := responseLimit(safeGetString(args, "--limit"))
-
-	if err != nil {
-		return err
-	}
-
-	return cmdr.PermList(codename, results)
+	app := safeGetString(args, "--app")
+	username := safeGetString(args, "<username>")
+	permissions := safeGetString(args, "<permissions>")
+	return cmdr.PermCreate(app, username, permissions)
 }
 
-func permCreate(argv []string, cmdr cmd.Commander) error {
+func permUpdate(argv []string, cmdr cmd.Commander) error {
 	usage := `
-Create a user permission.
+Update permissions to user.
 
-Usage: drycc perms:create <username> <codename> <uniqueid>
+Usage: drycc perms:update <username> <permissions> [options]
 
 Arguments:
   <username>
-    the name of the new user
-  <codename>
-    the object policy codename
-  <uniqueid>
-    the uniquely identifiable name of shared objects, for example: app id or cert name.
+    the name of the user.
+  <permissions>
+    comma-delimited list of permissions (view,change,delete).
+Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -118,21 +120,24 @@ Arguments:
 		return err
 	}
 
+	app := safeGetString(args, "--app")
 	username := safeGetString(args, "<username>")
-	codename := safeGetString(args, "<codename>")
-	uniqueid := safeGetString(args, "<uniqueid>")
-	return cmdr.PermCreate(codename, uniqueid, username)
+	permissions := safeGetString(args, "<permissions>")
+	return cmdr.PermUpdate(app, username, permissions)
 }
 
 func permDelete(argv []string, cmdr cmd.Commander) error {
 	usage := `
-Delete a user permission.
+Delete a user from the app.
 
-Usage: drycc perms:delete <id>
+Usage: drycc perms:remove <username> [options]
 
 Arguments:
-  <id>
-    the id of the user perm.
+  <username>
+    the name of the user.
+Options:
+  -a --app=<app>
+    the uniquely identifiable name for the application.
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -141,6 +146,7 @@ Arguments:
 		return err
 	}
 
-	id := uint64(safeGetInt(args, "<id>"))
-	return cmdr.PermDelete(id)
+	app := safeGetString(args, "--app")
+	username := safeGetString(args, "<username>")
+	return cmdr.PermDelete(app, username)
 }
diff --git a/parser/perms_test.go b/parser/perms_test.go
index f6f65e0b..eecac671 100644
--- a/parser/perms_test.go
+++ b/parser/perms_test.go
@@ -12,20 +12,20 @@ import (
 // Create fake implementations of each method that return the argument
 // we expect to have called the function (as an error to satisfy the interface).
 
-func (d FakeDryccCmd) PermCodes(int) error {
-	return errors.New("perms:codes")
-}
-
 func (d FakeDryccCmd) PermList(string, int) error {
 	return errors.New("perms:list")
 }
 
 func (d FakeDryccCmd) PermCreate(string, string, string) error {
-	return errors.New("perms:create")
+	return errors.New("perms:add")
+}
+
+func (d FakeDryccCmd) PermUpdate(string, string, string) error {
+	return errors.New("perms:update")
 }
 
-func (d FakeDryccCmd) PermDelete(uint64) error {
-	return errors.New("perms:delete")
+func (d FakeDryccCmd) PermDelete(string, string) error {
+	return errors.New("perms:remove")
 }
 
 func TestPerms(t *testing.T) {
@@ -46,19 +46,19 @@ func TestPerms(t *testing.T) {
 		expected string
 	}{
 		{
-			args:     []string{"perms:codes"},
+			args:     []string{"perms:list"},
 			expected: "",
 		},
 		{
-			args:     []string{"perms:list"},
+			args:     []string{"perms:add", "test-user", "view"},
 			expected: "",
 		},
 		{
-			args:     []string{"perms:create", "test-user", "use_app", "autotest-app"},
+			args:     []string{"perms:update", "test-user", "view"},
 			expected: "",
 		},
 		{
-			args:     []string{"perms:delete", "1"},
+			args:     []string{"perms:remove", "test-user"},
 			expected: "",
 		},
 		{
diff --git a/parser/registry.go b/parser/registry.go
index fa137c9b..69a88c75 100644
--- a/parser/registry.go
+++ b/parser/registry.go
@@ -63,7 +63,7 @@ func registrySet(argv []string, cmdr cmd.Commander) error {
 Sets registry information for an application. These credentials are the same as those used for
 'podmain login' to the private registry.
 
-Usage: drycc registry:set [options] <key>=<value>...
+Usage: drycc registry:set <key>=<value>... [options]
 
 Arguments:
   <key>
@@ -93,7 +93,7 @@ func registryUnset(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Unsets registry information for an application.
 
-Usage: drycc registry:unset [options] <key>...
+Usage: drycc registry:unset <key>... [options]
 
 Arguments:
   <key> the registry key to unset, for example: "username" or "password"
diff --git a/parser/releases.go b/parser/releases.go
index 667dec0c..69c07d80 100644
--- a/parser/releases.go
+++ b/parser/releases.go
@@ -117,6 +117,8 @@ Arguments:
 Options:
   -a --app=<app>
     the uniquely identifiable name for the application.
+  -f --force
+    force deploy.
   --confirm=yes
     To proceed, type "yes".
 `
@@ -129,17 +131,20 @@ Options:
 
 	apps := safeGetString(args, "--app")
 	confirm := safeGetString(args, "--confirm")
-	return cmdr.ReleasesDeploy(apps, args["<ptype>"].([]string), confirm)
+	force := args["--force"].(bool)
+	return cmdr.ReleasesDeploy(apps, args["<ptype>"].([]string), force, confirm)
 }
 
 func releasesRollback(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Rolls back to a previous application release.
 
-Usage: drycc releases:rollback [<version>] [options]
+Usage: drycc releases:rollback [<ptype>...] [<version>] [options]
 
 Arguments:
-  <version>
+<ptype>
+    the process name as defined in your Procfile, such as 'web'.
+<version>
     the release of the application, such as 'v1'.
 
 Options:
@@ -166,7 +171,7 @@ Options:
 
 	app := safeGetString(args, "--app")
 
-	return cmdr.ReleasesRollback(app, version)
+	return cmdr.ReleasesRollback(app, args["<ptype>"].([]string), version)
 }
 
 func versionFromString(version string) (int, error) {
diff --git a/parser/releases_test.go b/parser/releases_test.go
index a146dc30..83efc25c 100644
--- a/parser/releases_test.go
+++ b/parser/releases_test.go
@@ -20,11 +20,11 @@ func (d FakeDryccCmd) ReleasesInfo(string, int) error {
 	return errors.New("releases:info")
 }
 
-func (d FakeDryccCmd) ReleasesDeploy(string, []string, string) error {
+func (d FakeDryccCmd) ReleasesDeploy(string, []string, bool, string) error {
 	return errors.New("releases:deploy")
 }
 
-func (d FakeDryccCmd) ReleasesRollback(string, int) error {
+func (d FakeDryccCmd) ReleasesRollback(string, []string, int) error {
 	return errors.New("releases:rollback")
 }
 
diff --git a/parser/routes.go b/parser/routes.go
index 38819db2..3a09699d 100644
--- a/parser/routes.go
+++ b/parser/routes.go
@@ -10,7 +10,7 @@ func Routes(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Valid commands for routes:
 
-routes:create        create a route for an application
+routes:add        create a route for an application
 routes:list          list application routes
 routes:get           get rule of route
 routes:set           set rule of route
@@ -22,7 +22,7 @@ Use 'drycc help [command]' to learn more.
 `
 
 	switch argv[0] {
-	case "routes:create":
+	case "routes:add":
 		return routesCreate(argv, cmdr)
 	case "routes:list":
 		return routesList(argv, cmdr)
@@ -55,12 +55,12 @@ func routesCreate(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Creates routes for an application, provides a way to route requests
 
-Usage: drycc routes:create <name> --type=<type> --kind=<kind> --port=<port> [options]
+Usage: drycc routes:add <name> --ptype=<ptype> --kind=<kind> --port=<port> [options]
 
 Arguments:
   <name>
     the route name.
-  <type>
+  <ptype>
     the process type needs to create route.
   <kind>
     the route kind. Supports HTTPRoute, TCPRoute, UDPRoute, GRPCRoute, and TLSRoute.
@@ -80,11 +80,11 @@ Options:
 
 	app := safeGetString(args, "--app")
 	name := safeGetString(args, "<name>")
-	procType := safeGetString(args, "--type")
+	ptype := safeGetString(args, "--ptype")
 	kind := safeGetString(args, "--kind")
 	port := safeGetInt(args, "--port")
 
-	return cmdr.RoutesCreate(app, name, procType, kind, port)
+	return cmdr.RoutesCreate(app, name, ptype, kind, port)
 }
 
 func routesList(argv []string, cmdr cmd.Commander) error {
diff --git a/parser/routes_test.go b/parser/routes_test.go
index 3a9855a2..85e53fdf 100644
--- a/parser/routes_test.go
+++ b/parser/routes_test.go
@@ -12,7 +12,7 @@ import (
 // Create fake implementations of each method that return the argument
 // we expect to have called the function (as an error to satisfy the interface).
 func (d FakeDryccCmd) RoutesCreate(string, string, string, string, int) error {
-	return errors.New("routes:create")
+	return errors.New("routes:add")
 }
 
 func (d FakeDryccCmd) RoutesList(string, int) error {
@@ -57,7 +57,7 @@ func TestRoutes(t *testing.T) {
 		expected string
 	}{
 		{
-			args:     []string{"routes:create", "example", "--type=web", "--kind=http", "--port=80"},
+			args:     []string{"routes:add", "example", "--ptype=web", "--kind=http", "--port=80"},
 			expected: "",
 		},
 		{
diff --git a/parser/services.go b/parser/services.go
index 101fe20d..827518eb 100644
--- a/parser/services.go
+++ b/parser/services.go
@@ -44,10 +44,10 @@ func servicesAdd(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Creates extra service for an application and binds it to specific route of the main app domain
 
-Usage: drycc services:add <type> <port>:<target> [options]
+Usage: drycc services:add <ptype> <port>:<target> [options]
 
 Arguments:
-  <type>
+  <ptype>
     procfile type which should handle the request, e.g. webhooks (should be bind to the port PORT).
     only single extra service per Porcfile type could be created
   <port>
@@ -69,10 +69,10 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	procfileType := safeGetString(args, "<type>")
+	ptype := safeGetString(args, "<ptype>")
 	protocol := safeGetString(args, "--protocol")
 	ports := safeGetString(args, "<port>:<target>")
-	return cmdr.ServicesAdd(app, procfileType, ports, protocol)
+	return cmdr.ServicesAdd(app, ptype, ports, protocol)
 }
 
 func servicesList(argv []string, cmdr cmd.Commander) error {
@@ -101,10 +101,10 @@ func servicesRemove(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Deletes specific extra service for application
 
-Usage: drycc services:remove <type> <port> [options]
+Usage: drycc services:remove <ptype> <port> [options]
 
 Arguments:
-  <type>
+  <ptype>
     procfile type which should handle the request, e.g. webhooks (should be bind to the port PORT).
     Only single extra service per Porcfile type could be created
   <port>
@@ -124,9 +124,9 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	procfileType := safeGetString(args, "<type>")
+	ptype := safeGetString(args, "<ptype>")
 	protocol := safeGetString(args, "--protocol")
 	port := safeGetInt(args, "<port>")
 
-	return cmdr.ServicesRemove(app, procfileType, protocol, port)
+	return cmdr.ServicesRemove(app, ptype, protocol, port)
 }
diff --git a/parser/tags.go b/parser/tags.go
index 3ef4696b..cc6e37c9 100644
--- a/parser/tags.go
+++ b/parser/tags.go
@@ -60,7 +60,7 @@ Options:
 		return err
 	}
 
-	ptype := safeGetString(args, "--ptype")
+	ptype := safeGetString(args, "<ptype>")
 	appName := safeGetString(args, "--app")
 
 	return cmdr.TagsList(appName, ptype)
@@ -93,7 +93,7 @@ Options:
 	if err != nil {
 		return err
 	}
-	ptype := safeGetString(args, "--ptype")
+	ptype := safeGetString(args, "<ptype>")
 	app := safeGetString(args, "--app")
 	tags := args["<key>=<value>"].([]string)
 
@@ -121,7 +121,7 @@ Options:
 	if err != nil {
 		return err
 	}
-	ptype := safeGetString(args, "--ptype")
+	ptype := safeGetString(args, "<ptype>")
 	app := safeGetString(args, "--app")
 	tags := args["<key>"].([]string)
 
diff --git a/parser/timeouts.go b/parser/timeouts.go
index 2d7dcec5..611ff62c 100644
--- a/parser/timeouts.go
+++ b/parser/timeouts.go
@@ -63,10 +63,10 @@ func timeoutSet(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Sets termination grace period for an application.
 
-Usage: drycc timeouts:set [options] <type>=<value>...
+Usage: drycc timeouts:set <ptype>=<value>... [options]
 
 Arguments:
-  <type>
+  <ptype>
     the process type as defined in your Procfile, such as 'web' or 'worker'.
   <value>
     The value to apply to the process type in seconds.
@@ -83,7 +83,7 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	timeouts := args["<type>=<value>"].([]string)
+	timeouts := args["<ptype>=<value>"].([]string)
 
 	return cmdr.TimeoutsSet(app, timeouts)
 }
@@ -92,10 +92,10 @@ func timeoutUnset(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Unsets timeouts for an application. Default value (30s) or set by drycc controller
 
-Usage: drycc timeouts:unset [options] <type>...
+Usage: drycc timeouts:unset <ptype>... [options]
 
 Arguments:
-  <type>
+  <ptype>
     the process type as defined in your Procfile, such as 'web' or 'worker'.
 
 Options:
@@ -110,7 +110,7 @@ Options:
 	}
 
 	app := safeGetString(args, "--app")
-	timeouts := args["<type>"].([]string)
+	timeouts := args["<ptype>"].([]string)
 
 	return cmdr.TimeoutsUnset(app, timeouts)
 }
diff --git a/parser/volumes.go b/parser/volumes.go
index f5456398..b9fb3015 100644
--- a/parser/volumes.go
+++ b/parser/volumes.go
@@ -10,11 +10,11 @@ func Volumes(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Valid commands for volumes:
 
-volumes:create           create a volume for the application
+volumes:add              create a volume for the application
 volumes:expand           expand a volume for the application
 volumes:list             list volumes in the application
 volumes:info             print information about a volume
-volumes:delete           delete a volume from the application
+volumes:remove           delete a volume from the application
 volumes:client           the client used to manage volume files
 volumes:mount            mount a volume to process of the application
 volumes:unmount          unmount a volume from process of the application
@@ -23,7 +23,7 @@ Use 'drycc help [command]' to learn more.
 `
 
 	switch argv[0] {
-	case "volumes:create":
+	case "volumes:add":
 		return volumesCreate(argv, cmdr)
 	case "volumes:expand":
 		return volumesExpand(argv, cmdr)
@@ -31,7 +31,7 @@ Use 'drycc help [command]' to learn more.
 		return volumesList(argv, cmdr)
 	case "volumes:info":
 		return volumesInfo(argv, cmdr)
-	case "volumes:delete":
+	case "volumes:remove":
 		return volumesDelete(argv, cmdr)
 	case "volumes:client":
 		return volumesClient(argv, cmdr)
@@ -58,7 +58,7 @@ func volumesCreate(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Create a volume for the application.
 
-Usage: drycc volumes:create <name> <size> [options]
+Usage: drycc volumes:add <name> <size> [options]
 
 Arguments:
   <name>
@@ -69,7 +69,7 @@ Arguments:
 Options:
   -a --app=<app>
     the uniquely identifiable name for the application.
-  -t --type=<type>
+  -t --ptype=<ptype>
     the volume type, such as csi, nfs, default is 'csi'.
   --nfs-server=<nfs-server>
     the hostname or ip address of the nfs server.
@@ -194,7 +194,7 @@ func volumesDelete(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Delete a volume from the application.
 
-Usage: drycc volumes:delete <name> [options]
+Usage: drycc volumes:remove <name> [options]
 
 Arguments:
   <name>
@@ -253,12 +253,12 @@ func volumesMount(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Mount a volume for an application.
 
-Usage: drycc volumes:mount <name> <type>=<path>... [options]
+Usage: drycc volumes:mount <name> <ptype>=<path>... [options]
 
 Arguments:
   <name>
     the volume name.
-  <type>
+  <ptype>
     the process name as defined in your Procfile, such as 'web' or 'worker'.
   <path>
     the filesystem path.
@@ -277,19 +277,19 @@ Options:
 	app := safeGetString(args, "--app")
 	name := safeGetString(args, "<name>")
 
-	return cmdr.VolumesMount(app, name, args["<type>=<path>"].([]string))
+	return cmdr.VolumesMount(app, name, args["<ptype>=<path>"].([]string))
 }
 
 func volumesUnmount(argv []string, cmdr cmd.Commander) error {
 	usage := `
 Unmount a volume for an application.
 
-Usage: drycc volumes:unmount <name> <type>... [options]
+Usage: drycc volumes:unmount <name> <ptype>... [options]
 
 Arguments:
   <name>
     the volume name.
-  <type>
+  <ptype>
     the process name as defined in your Procfile, such as 'web' or 'worker'.
 
 Options:
@@ -305,5 +305,5 @@ Options:
 	app := safeGetString(args, "--app")
 	name := safeGetString(args, "<name>")
 
-	return cmdr.VolumesUnmount(app, name, args["<type>"].([]string))
+	return cmdr.VolumesUnmount(app, name, args["<ptype>"].([]string))
 }
diff --git a/parser/volumes_test.go b/parser/volumes_test.go
index 74286b0e..52d9cf1f 100644
--- a/parser/volumes_test.go
+++ b/parser/volumes_test.go
@@ -21,7 +21,7 @@ func (d FakeDryccCmd) VolumesInfo(string, string) error {
 }
 
 func (d FakeDryccCmd) VolumesCreate(string, string, string, string, map[string]interface{}) error {
-	return errors.New("volumes:create")
+	return errors.New("volumes:add")
 }
 
 func (d FakeDryccCmd) VolumesExpand(string, string, string) error {
@@ -29,7 +29,7 @@ func (d FakeDryccCmd) VolumesExpand(string, string, string) error {
 }
 
 func (d FakeDryccCmd) VolumesDelete(string, string) error {
-	return errors.New("volumes:delete")
+	return errors.New("volumes:remove")
 }
 
 func (d FakeDryccCmd) VolumesClient(string, string, ...string) error {
@@ -62,7 +62,7 @@ func TestVolumes(t *testing.T) {
 		expected string
 	}{
 		{
-			args:     []string{"volumes:create", "myvolume", "500G"},
+			args:     []string{"volumes:add", "myvolume", "500G"},
 			expected: "",
 		},
 		{
@@ -74,7 +74,7 @@ func TestVolumes(t *testing.T) {
 			expected: "",
 		},
 		{
-			args:     []string{"volumes:delete", "myvolume"},
+			args:     []string{"volumes:remove", "myvolume"},
 			expected: "",
 		},
 		{
