diff --git a/TODO b/TODO
index 9d87db7d573bc49c63dcbf36b2786d3f33d6d641..33132311fe6d4510b82660757a12470a48de3635 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,3 @@
-- more colors
-- "shc CONTAINER start" vs. "shc CONTAINER shell"
-
 Albireo cleanup:
 - prerouting rule
 - containers
diff --git a/shipcat/main.py b/shipcat/main.py
index 9d17d343bef0bb82efc8652526746e6caa3ef8f2..fa7f0187bb4bf5a00a6e0c213b36e09eac070f75 100755
--- a/shipcat/main.py
+++ b/shipcat/main.py
@@ -11,13 +11,13 @@ import sys
 from typing import List, Optional
 
 from shipcat.config import GlobalConfig, ContainerConfig, ConfigError
-from shipcat.util import die, verbose, set_verbose, run_command
+from shipcat.util import die, progress, verbose, set_verbose, run_command
 
 
 config: GlobalConfig
 
 
-def progress(msg: str) -> None:
+def trace(msg: str) -> None:
     print(msg, file=sys.stderr, end="", flush=True)
 
 
@@ -107,68 +107,68 @@ def cmd_init(args: argparse.Namespace) -> None:
     name = args.name
     cc = setup_container(args, True)
 
-    progress(f'User {cc.user_name}: ')
+    trace(f'User {cc.user_name}: ')
     try:
         pwd = getpwnam(cc.user_name)
-        progress('already exists\n')
+        trace('already exists\n')
     except KeyError:
-        progress('creating\n')
+        trace('creating\n')
         run_command(
             ['adduser', '--system', '--group', '--gecos', f'Container {name}', '--disabled-password', cc.user_name]
         )
         pwd = getpwnam(cc.user_name)
     uid = pwd.pw_uid
 
-    progress('Subuid range: ')
+    trace('Subuid range: ')
     subuids = SubIds('/etc/subuid')
     sur = subuids.find_range(uid, cc.user_name, 65536)
     if sur is not None:
-        progress('already exists\n')
+        trace('already exists\n')
     else:
-        progress('allocating\n')
+        trace('allocating\n')
         sur = subuids.alloc_range(cc.user_name, 65536)
         run_command(
             ['usermod', '--add-subuids', f'{sur.first}-{sur.first + sur.count - 1}', cc.user_name]
         )
 
-    progress('Subgid range: ')
+    trace('Subgid range: ')
     subgids = SubIds('/etc/subgid')
     sgr = subgids.find_range(uid, cc.user_name, 65536)
     if sgr is not None:
-        progress('already exists\n')
+        trace('already exists\n')
     else:
-        progress('allocating\n')
+        trace('allocating\n')
         sgr = subgids.alloc_range(cc.user_name, 65536)
         run_command(
             ['usermod', '--add-subgids', f'{sgr.first}-{sgr.first + sgr.count - 1}', cc.user_name]
         )
 
-    progress(f'Using user {cc.user_name}, uid {uid}, subuids {sur.first}+{sur.count}, subgids {sgr.first}+{sgr.count}\n')
+    trace(f'Using user {cc.user_name}, uid {uid}, subuids {sur.first}+{sur.count}, subgids {sgr.first}+{sgr.count}\n')
 
     root_path = cc.root_path
-    progress(f'Container directory {root_path}: ')
+    trace(f'Container directory {root_path}: ')
     if root_path.is_dir():
-        progress('already exists\n')
+        trace('already exists\n')
     else:
         root_path.mkdir(mode=0o750, exist_ok=True)
         os.chown(root_path, 0, sgr.first)
-        progress('created\n')
+        trace('created\n')
 
     data_path = cc.data_path
-    progress(f'Data directory {data_path}: ')
+    trace(f'Data directory {data_path}: ')
     if data_path.is_dir():
-        progress('already exists\n')
+        trace('already exists\n')
     else:
         data_path.mkdir(mode=0o755, exist_ok=True)
         os.chown(data_path, sur.first, sgr.first)
-        progress('created\n')
+        trace('created\n')
 
-    progress('IP address: ')
+    trace('IP address: ')
     try:
         ip = socket.gethostbyname(name)
     except OSError as e:
         die(str(e))
-    progress(f'{ip}\n')
+    trace(f'{ip}\n')
 
 
 def service_action(cc: ContainerConfig, action: str) -> None:
@@ -177,16 +177,23 @@ def service_action(cc: ContainerConfig, action: str) -> None:
     )
 
 
-def cmd_create(args: argparse.Namespace) -> None:
+def cmd_update(args: argparse.Namespace) -> None:
     cc = setup_container(args, False)
 
+    progress('Pulling new image')
     run_command(
         ['podman', 'pull', cc.image]
     )
 
+    progress('Stopping container')
     service_action(cc, 'stop')
+
+    progress('Creating container')
     create_container(cc)
 
+    progress('Starting container')
+    service_action(cc, 'start')
+
 
 def create_container(cc: ContainerConfig) -> None:
     ip = socket.gethostbyname(cc.name)
@@ -343,9 +350,6 @@ def main() -> None:
     parser.add_argument('--verbose', '-v', default=False, action='store_true', help='be chatty and explain what is going on')
     subparsers = parser.add_subparsers(help='action to perform', dest='action', required=True, metavar='ACTION')
 
-    create_parser = subparsers.add_parser('create', help='create a container from an image', description='Create a container from an image.')
-    create_parser.add_argument('name', help='name of the container')
-
     create_parser = subparsers.add_parser('disable', help='disable automatic startup of a container', description='Disable automatic startup of a container.')
     create_parser.add_argument('name', help='name of the container')
 
@@ -385,10 +389,12 @@ def main() -> None:
     stop_parser = subparsers.add_parser('stop', help='stop a container', description='Stop a container')
     stop_parser.add_argument('name', help='name of the container')
 
+    update_parser = subparsers.add_parser('update', help='update a container from an image', description='Update a container from an image and start it.')
+    update_parser.add_argument('name', help='name of the container')
+
     args = parser.parse_args()
 
     actions = {
-        'create': cmd_create,
         'disable': cmd_disable,
         'enable': cmd_enable,
         'exec': cmd_exec,
@@ -399,6 +405,7 @@ def main() -> None:
         'start': cmd_start,
         'status': cmd_status,
         'stop': cmd_stop,
+        'update': cmd_update,
     }
 
     global config