mikemccracken: A couple minor comments:

I think maybe the model name should include 'conjure-up' also, so when you conjure-up and use a preexisting controller, you still know that the model came from conjure-up.

It might also be nice to include cloud type in the controller name, like 'conjure-up-aws'. 

Also I don't think we need more than 3-4 digits of random UUID string. You get 8 from the code you wrote, maybe just truncate it? Someone's going to end up typing the whole thing and get mad..
battlemidget: @mikemccracken updated based on your suggestions
battlemidget: @mikemccracken should be ready for review and merge, test deploys reflects both the updated controller and models
diff --git a/README.md b/README.md
index f2f872f..7521e7c 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,15 @@ $ sudo apt update
 $ sudo apt install conjure-up
 ```
 
+## alternate (soon to be recommended)
+
+We will be switching over to a snap based installation in the very near future.
+Please help us test this out by installing via `snap` command:
+
+```
+$ sudo snap install conjure-up --classic --edge
+```
+
 # how to use
 
 ## Run the installer interactively
diff --git a/conjureup/controllers/controllerpicker/gui.py b/conjureup/controllers/controllerpicker/gui.py
index 3ace007..0469bd5 100644
--- a/conjureup/controllers/controllerpicker/gui.py
+++ b/conjureup/controllers/controllerpicker/gui.py
@@ -1,6 +1,4 @@
-import petname
-
-from conjureup import async, controllers, juju
+from conjureup import async, controllers, juju, utils
 from conjureup.app_config import app
 from conjureup.telemetry import track_exception, track_screen
 from conjureup.ui.views.ControllerListView import ControllerListView
@@ -23,7 +21,9 @@ class ControllerPicker:
             return controllers.use('clouds').render()
 
         app.current_controller = controller
-        app.current_model = petname.Name()
+        app.current_model = "conjure-up-{}-{}".format(
+            app.env['CONJURE_UP_SPELL'],
+            utils.gen_hash())
         async.submit(self.__add_model,
                      self.__handle_exception,
                      queue_name=juju.JUJU_ASYNC_QUEUE)
diff --git a/conjureup/controllers/newcloud/gui.py b/conjureup/controllers/newcloud/gui.py
index 17b0fcf..ab118c3 100644
--- a/conjureup/controllers/newcloud/gui.py
+++ b/conjureup/controllers/newcloud/gui.py
@@ -4,8 +4,6 @@ import os.path as path
 from functools import partial
 from subprocess import check_output
 
-import petname
-
 from conjureup import async, controllers, juju, utils
 from conjureup.api.models import model_info
 from conjureup.app_config import app
@@ -57,6 +55,7 @@ class NewCloudController:
         future = juju.bootstrap_async(
             controller=app.current_controller,
             cloud=cloud,
+            model=app.current_model,
             credential=credential,
             exc_cb=self.__handle_exception)
         app.bootstrap.running = future
@@ -136,10 +135,14 @@ class NewCloudController:
         track_screen("Cloud Creation")
 
         if app.current_controller is None:
-            app.current_controller = petname.Name()
+            app.current_controller = "conjure-up-{}-{}".format(
+                app.current_cloud,
+                utils.gen_hash())
 
         if app.current_model is None:
-            app.current_model = 'conjure-up'
+            app.current_model = "conjure-up-{}-{}".format(
+                app.env['CONJURE_UP_SPELL'],
+                utils.gen_hash())
 
         # LXD is a special case as we want to make sure a bridge
         # is configured. If not we'll bring up a new view to allow
diff --git a/conjureup/controllers/newcloud/tui.py b/conjureup/controllers/newcloud/tui.py
index fb0f3c9..540a7c7 100644
--- a/conjureup/controllers/newcloud/tui.py
+++ b/conjureup/controllers/newcloud/tui.py
@@ -3,8 +3,6 @@ import os
 import sys
 from subprocess import PIPE
 
-import petname
-
 from conjureup import controllers, juju, utils
 from conjureup.api.models import model_info
 from conjureup.app_config import app
@@ -45,12 +43,15 @@ class NewCloudController:
         return controllers.use('deploy').render()
 
     def render(self):
-
         if app.current_controller is None:
-            app.current_controller = petname.Name()
+            app.current_controller = "conjure-up-{}-{}".format(
+                app.current_cloud,
+                utils.gen_hash())
 
         if app.current_model is None:
-            app.current_model = 'conjure-up'
+            app.current_model = "conjure-up-{}-{}".format(
+                app.env['CONJURE_UP_SPELL'],
+                utils.gen_hash())
 
         if app.current_cloud != 'localhost':
             if not common.try_get_creds(app.current_cloud):
@@ -72,6 +73,7 @@ class NewCloudController:
         utils.info("Bootstrapping Juju controller")
         p = juju.bootstrap(controller=app.current_controller,
                            cloud=app.current_cloud,
+                           model=app.current_model,
                            credential=common.try_get_creds(app.current_cloud))
         if p.returncode != 0:
             pathbase = os.path.join(
diff --git a/conjureup/juju.py b/conjureup/juju.py
index 784ef24..8fbd18f 100644
--- a/conjureup/juju.py
+++ b/conjureup/juju.py
@@ -139,7 +139,8 @@ def login(force=False):
     this.IS_AUTHENTICATED = True  # noqa
 
 
-def bootstrap(controller, cloud, series="xenial", credential=None):
+def bootstrap(controller, cloud, model='conjure-up', series="xenial",
+              credential=None):
     """ Performs juju bootstrap
 
     If not LXD pass along the newly defined credentials
@@ -155,7 +156,7 @@ def bootstrap(controller, cloud, series="xenial", credential=None):
           "--config image-stream=daily ".format(
               cloud, controller)
     cmd += "--config enable-os-upgrade=false "
-    cmd += "--default-model conjure-up "
+    cmd += "--default-model {} ".format(model)
     if app.argv.http_proxy:
         cmd += "--config http-proxy={} ".format(app.argv.http_proxy)
     if app.argv.https_proxy:
@@ -204,12 +205,14 @@ def bootstrap(controller, cloud, series="xenial", credential=None):
         raise e
 
 
-def bootstrap_async(controller, cloud, credential=None, exc_cb=None):
+def bootstrap_async(controller, cloud, model='conjure-up', credential=None,
+                    exc_cb=None):
     """ Performs a bootstrap asynchronously
     """
     return async.submit(partial(bootstrap,
                                 controller=controller,
                                 cloud=cloud,
+                                model=model,
                                 credential=credential), exc_cb,
                         queue_name=JUJU_ASYNC_QUEUE)
 
diff --git a/conjureup/ui/views/bootstrapwait.py b/conjureup/ui/views/bootstrapwait.py
index 15a9d7f..f6277ff 100644
--- a/conjureup/ui/views/bootstrapwait.py
+++ b/conjureup/ui/views/bootstrapwait.py
@@ -33,7 +33,7 @@ class BootstrapWaitView(WidgetWrap):
             sanitize = "".join(ch for ch
                                in t if unicodedata.category(ch)[0] != "C")
             if sanitize.endswith("%"):
-                new_out.append(sanitize.split("%")[0])
+                new_out.append("{}%".format(sanitize.split("%")[0]))
             else:
                 new_out.append(sanitize)
         if len(new_out) >= 10:
@@ -66,7 +66,7 @@ class BootstrapWaitView(WidgetWrap):
         text = [Padding.line_break(""),
                 self.message,
                 Padding.line_break(""),
-                self.output,
+                Padding.center_90(self.output),
                 Padding.line_break("")]
 
         _boxes = []
diff --git a/conjureup/utils.py b/conjureup/utils.py
index 2197707..df24e3a 100644
--- a/conjureup/utils.py
+++ b/conjureup/utils.py
@@ -4,6 +4,7 @@ import errno
 import os
 import pty
 import shutil
+import uuid
 from subprocess import (
     DEVNULL,
     PIPE,
@@ -355,3 +356,9 @@ def get_options_whitelist(service_name):
     svc_opts_whitelist = options_whitelist.get(service_name, [])
 
     return svc_opts_whitelist
+
+
+def gen_hash():
+    """ generates a UUID
+    """
+    return str(uuid.uuid4()).split('-')[0][:3]

conjure-up uses petname for model name
conjure-up apparently uses single-word petnames for Juju models it
creates, e.g.:
```
| james@malefic:~$ juju models
| Controller: lxd
|
| Model Cloud/Region Status Machines Cores Access Last connection
| controller localhost/localhost available 1 - admin just now
| default localhost/localhost available 0 - admin 2017-01-02
| dane* localhost/localhost available 4 - admin 6 minutes ago
|
| james@malefic:~$
```
A bare pet name is pretty confusing and would only get more so if you
conjured up multiple spells. At a minimum, I think the spell should
be indicated in some way in the model name (perhaps combined with a
petname, if you need to avoid clashes). It might also be useful to
indicate in some way that this is a conjure-up model?
diff --git a/test/test_controllers_newcloud_tui.py b/test/test_controllers_newcloud_tui.py
index f570b25..941177f 100644
--- a/test/test_controllers_newcloud_tui.py
+++ b/test/test_controllers_newcloud_tui.py
@@ -63,11 +63,13 @@ class NewCloudTUIRenderTestCase(unittest.TestCase):
         self.mock_common.try_get_creds.return_value = True
         self.mock_app.current_controller = sentinel.controllername
         self.mock_app.current_cloud = sentinel.cloudname
+        self.mock_app.current_model = sentinel.modelname
         self.mock_juju.bootstrap.return_value.returncode = 0
         self.controller.render()
         self.mock_juju.bootstrap.assert_called_once_with(
             controller=sentinel.controllername,
             cloud=sentinel.cloudname,
+            model=sentinel.modelname,
             credential=True)
 
         self.controller.do_post_bootstrap.assert_called_once_with()

pip install -e .
parse_log_pytest
requirements.txt
nose tox pytest
apt-get update apt-get install -y gcc
3.5
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
charset-normalizer==2.0.12
-e git+https://github.com/conjure-up/conjure-up.git@fd4ccd29a9b6198364738f3ff9e8f8ab63fa0344#egg=conjure_up
distlib==0.3.9
filelock==3.4.1
idna==3.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
Jinja2==3.0.3
juju-wait==2.8.4
MarkupSafe==2.0.1
nose==1.3.7
oauthlib==3.2.2
packaging==21.3
petname==2.6
platformdirs==2.4.0
pluggy==1.0.0
prettytable==2.5.0
progressbar2==3.55.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
python-utils==3.5.2
PyYAML==6.0.1
q==2.7
requests==2.27.1
requests-oauthlib==2.0.0
requests-unixsocket==0.3.0
six==1.17.0
termcolor==1.1.0
toml==0.10.2
tomli==1.2.3
tox==3.28.0
typing_extensions==4.1.1
urllib3==1.26.20
urwid==2.1.2
virtualenv==20.17.1
wcwidth==0.2.13
ws4py==0.3.4
zipp==3.6.0

name: conjure-up
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - distlib==0.3.9
      - filelock==3.4.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - jinja2==3.0.3
      - juju-wait==2.8.4
      - markupsafe==2.0.1
      - nose==1.3.7
      - oauthlib==3.2.2
      - packaging==21.3
      - petname==2.6
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - prettytable==2.5.0
      - progressbar2==3.55.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - python-utils==3.5.2
      - pyyaml==6.0.1
      - q==2.7
      - requests==2.27.1
      - requests-oauthlib==2.0.0
      - requests-unixsocket==0.3.0
      - six==1.17.0
      - termcolor==1.1.0
      - toml==0.10.2
      - tomli==1.2.3
      - tox==3.28.0
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - urwid==2.1.2
      - virtualenv==20.17.1
      - wcwidth==0.2.13
      - ws4py==0.3.4
      - zipp==3.6.0
prefix: /opt/conda/envs/conjure-up

test/test_controllers_newcloud_tui.py::NewCloudTUIRenderTestCase::test_render
test/test_controllers_newcloud_tui.py::NewCloudTUIRenderTestCase::test_render_non_localhost_no_creds test/test_controllers_newcloud_tui.py::NewCloudTUIRenderTestCase::test_render_non_localhost_with_creds test/test_controllers_newcloud_tui.py::NewCloudTUIFinishTestCase::test_finish
conjureup/utils.py conjureup/juju.py README.md conjureup/ui/views/bootstrapwait.py conjureup/controllers/newcloud/gui.py conjureup/controllers/newcloud/tui.py conjureup/controllers/controllerpicker/gui.py
conjureup/utils.py conjureup/juju.py README.md conjureup/ui/views/bootstrapwait.py conjureup/controllers/newcloud/gui.py conjureup/controllers/newcloud/tui.py conjureup/controllers/controllerpicker/gui.py