diff --git a/cfg.c b/cfg.c
index b1c67cbb..577f2d12 100644
--- a/cfg.c
+++ b/cfg.c
@@ -81,7 +81,7 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
 	size_t		 len;
 	struct cmd_list	*cmdlist;
 	struct cmd_ctx	 ctx;
-	int		 retval;
+	enum cmd_retval	 retval;
 
 	if ((f = fopen(path, "rb")) == NULL) {
 		cfg_add_cause(causes, "%s: %s", path, strerror(errno));
@@ -90,7 +90,7 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
 	n = 0;
 
 	line = NULL;
-	retval = 0;
+	retval = CMD_RETURN_NORMAL;
 	while ((buf = fgetln(f, &len))) {
 		if (buf[len - 1] == '\n')
 			len--;
@@ -145,8 +145,18 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
 		ctx.info = cfg_print;
 
 		cfg_cause = NULL;
-		if (cmd_list_exec(cmdlist, &ctx) == 1)
-			retval = 1;
+		switch (cmd_list_exec(cmdlist, &ctx)) {
+		case CMD_RETURN_YIELD:
+			if (retval != CMD_RETURN_ATTACH)
+				retval = CMD_RETURN_YIELD;
+			break;
+		case CMD_RETURN_ATTACH:
+			retval = CMD_RETURN_ATTACH;
+			break;
+		case CMD_RETURN_ERROR:
+		case CMD_RETURN_NORMAL:
+			break;
+		}
 		cmd_list_free(cmdlist);
 		if (cfg_cause != NULL) {
 			cfg_add_cause(
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index d8e1ccc3..18a20244 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -26,7 +26,7 @@
  * Attach existing session to the current terminal.
  */
 
-int	cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_attach_session_entry = {
 	"attach-session", "attach",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_attach_session_entry = {
 	cmd_attach_session_exec
 };
 
-int
+enum cmd_retval
 cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -50,14 +50,14 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (RB_EMPTY(&sessions)) {
 		ctx->error(ctx, "no sessions");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if ((s = cmd_find_session(ctx, args_get(args, 't'), 1)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (ctx->cmdclient == NULL && ctx->curclient == NULL)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	if (ctx->cmdclient == NULL) {
 		if (args_has(self->args, 'd')) {
@@ -84,7 +84,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 		if (server_client_open(ctx->cmdclient, s, &cause) != 0) {
 			ctx->error(ctx, "open terminal failed: %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 
 		if (args_has(self->args, 'r'))
@@ -107,5 +107,5 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 	recalculate_sizes();
 	server_update_socket();
 
-	return (1);	/* 1 means don't tell command client to exit */
+	return (CMD_RETURN_ATTACH);
 }
diff --git a/cmd-bind-key.c b/cmd-bind-key.c
index 5e864960..28e94e26 100644
--- a/cmd-bind-key.c
+++ b/cmd-bind-key.c
@@ -27,10 +27,10 @@
  * Bind a key to a command, this recurses through cmd_*.
  */
 
-int	cmd_bind_key_check(struct args *);
-int	cmd_bind_key_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_bind_key_check(struct args *);
+enum cmd_retval	 cmd_bind_key_exec(struct cmd *, struct cmd_ctx *);
 
-int	cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int);
+enum cmd_retval	 cmd_bind_key_table(struct cmd *, struct cmd_ctx *, int);
 
 const struct cmd_entry cmd_bind_key_entry = {
 	"bind-key", "bind",
@@ -42,20 +42,20 @@ const struct cmd_entry cmd_bind_key_entry = {
 	cmd_bind_key_exec
 };
 
-int
+enum cmd_retval
 cmd_bind_key_check(struct args *args)
 {
 	if (args_has(args, 't')) {
 		if (args->argc != 2)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	} else {
 		if (args->argc < 2)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	}
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
-int
+enum cmd_retval
 cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -66,7 +66,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx)
 	key = key_string_lookup_string(args->argv[0]);
 	if (key == KEYC_NONE) {
 		ctx->error(ctx, "unknown key: %s", args->argv[0]);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (args_has(args, 't'))
@@ -76,16 +76,16 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (cmdlist == NULL) {
 		ctx->error(ctx, "%s", cause);
 		free(cause);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (!args_has(args, 'n'))
 	    key |= KEYC_PREFIX;
 	key_bindings_add(key, args_has(args, 'r'), cmdlist);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
-int
+enum cmd_retval
 cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 {
 	struct args			*args = self->args;
@@ -97,25 +97,25 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 	tablename = args_get(args, 't');
 	if ((mtab = mode_key_findtable(tablename)) == NULL) {
 		ctx->error(ctx, "unknown key table: %s", tablename);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	cmd = mode_key_fromstring(mtab->cmdstr, args->argv[1]);
 	if (cmd == MODEKEY_NONE) {
 		ctx->error(ctx, "unknown command: %s", args->argv[1]);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	mtmp.key = key;
 	mtmp.mode = !!args_has(args, 'c');
 	if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
 		mbind->cmd = cmd;
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 	mbind = xmalloc(sizeof *mbind);
 	mbind->key = mtmp.key;
 	mbind->mode = mtmp.mode;
 	mbind->cmd = cmd;
 	RB_INSERT(mode_key_tree, mtab->tree, mbind);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-break-pane.c b/cmd-break-pane.c
index 58ffdba6..bf5f276c 100644
--- a/cmd-break-pane.c
+++ b/cmd-break-pane.c
@@ -26,7 +26,7 @@
  * Break pane off into a window.
  */
 
-int	cmd_break_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_break_pane_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_break_pane_entry = {
 	"break-pane", "breakp",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_break_pane_entry = {
 	cmd_break_pane_exec
 };
 
-int
+enum cmd_retval
 cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -55,11 +55,11 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	char			*cp;
 
 	if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (window_count_panes(wl->window) == 1) {
 		ctx->error(ctx, "can't break with only one pane");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	w = wl->window;
@@ -110,5 +110,5 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 		format_free(ft);
 	}
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index 2dc516ee..a94c7177 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -27,7 +27,7 @@
  * Write the entire contents of a pane to a buffer.
  */
 
-int	cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_capture_pane_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_capture_pane_entry = {
 	"capture-pane", "capturep",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_capture_pane_entry = {
 	cmd_capture_pane_exec
 };
 
-int
+enum cmd_retval
 cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -52,7 +52,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	size_t         		 len, linelen;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	s = &wp->base;
 	gd = s->grid;
 
@@ -103,7 +103,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (!args_has(args, 'b')) {
 		paste_add(&global_buffers, buf, len, limit);
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
@@ -111,14 +111,14 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 		ctx->error(ctx, "buffer %s", cause);
 		free(buf);
 		free(cause);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (paste_replace(&global_buffers, buffer, buf, len) != 0) {
 		ctx->error(ctx, "no buffer %d", buffer);
 		free(buf);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index d08c2342..446edfeb 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -27,7 +27,7 @@
  * Enter choice mode to choose a buffer.
  */
 
-int	cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_choose_buffer_exec(struct cmd *, struct cmd_ctx *);
 
 void	cmd_choose_buffer_callback(struct window_choose_data *);
 void	cmd_choose_buffer_free(struct window_choose_data *);
@@ -42,7 +42,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
 	cmd_choose_buffer_exec
 };
 
-int
+enum cmd_retval
 cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -55,20 +55,20 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (ctx->curclient == NULL) {
 		ctx->error(ctx, "must be run interactively");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if ((template = args_get(args, 'F')) == NULL)
 		template = DEFAULT_BUFFER_LIST_TEMPLATE;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (paste_get_top(&global_buffers) == NULL)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	if (args->argc != 0)
 		action = xstrdup(args->argv[0]);
@@ -96,7 +96,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 	window_choose_ready(wl->window->active,
 	    0, cmd_choose_buffer_callback, cmd_choose_buffer_free);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 void
diff --git a/cmd-choose-client.c b/cmd-choose-client.c
index 92e70d00..0462e6a1 100644
--- a/cmd-choose-client.c
+++ b/cmd-choose-client.c
@@ -27,7 +27,7 @@
  * Enter choice mode to choose a client.
  */
 
-int	cmd_choose_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_choose_client_exec(struct cmd *, struct cmd_ctx *);
 
 void	cmd_choose_client_callback(struct window_choose_data *);
 void	cmd_choose_client_free(struct window_choose_data *);
@@ -47,7 +47,7 @@ struct cmd_choose_client_data {
 	char   		*template;
 };
 
-int
+enum cmd_retval
 cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -60,14 +60,14 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (ctx->curclient == NULL) {
 		ctx->error(ctx, "must be run interactively");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	if ((template = args_get(args, 'F')) == NULL)
 		template = DEFAULT_CLIENT_TEMPLATE;
@@ -104,7 +104,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 	window_choose_ready(wl->window->active,
 	    cur, cmd_choose_client_callback, cmd_choose_client_free);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 void
diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c
index e83a425d..0a5cd86a 100644
--- a/cmd-choose-tree.c
+++ b/cmd-choose-tree.c
@@ -70,7 +70,7 @@ const struct cmd_entry cmd_choose_window_entry = {
 	cmd_choose_tree_exec
 };
 
-int
+enum cmd_retval
 cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -89,17 +89,17 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (ctx->curclient == NULL) {
 		ctx->error(ctx, "must be run interactively");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	s = ctx->curclient->session;
 	tty = &ctx->curclient->tty;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	/* Sort out which command this is. */
 	wflag = sflag = 0;
@@ -221,7 +221,7 @@ windows_only:
 	window_choose_ready(wl->window->active, cur_win,
 		cmd_choose_tree_callback, cmd_choose_tree_free);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 void
@@ -248,4 +248,3 @@ cmd_choose_tree_free(struct window_choose_data *cdata)
 	free(cdata);
 
 }
-
diff --git a/cmd-clear-history.c b/cmd-clear-history.c
index cb00db90..27f73dbb 100644
--- a/cmd-clear-history.c
+++ b/cmd-clear-history.c
@@ -24,7 +24,7 @@
  * Clear pane history.
  */
 
-int	cmd_clear_history_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_clear_history_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_clear_history_entry = {
 	"clear-history", "clearhist",
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_clear_history_entry = {
 	cmd_clear_history_exec
 };
 
-int
+enum cmd_retval
 cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -44,11 +44,11 @@ cmd_clear_history_exec(struct cmd *self, struct cmd_ctx *ctx)
 	struct grid		*gd;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	gd = wp->base.grid;
 
 	grid_move_lines(gd, 0, gd->hsize, gd->sy);
 	gd->hsize = 0;
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c
index 49e78042..139e7157 100644
--- a/cmd-clock-mode.c
+++ b/cmd-clock-mode.c
@@ -24,7 +24,7 @@
  * Enter clock mode.
  */
 
-int	cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_clock_mode_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_clock_mode_entry = {
 	"clock-mode", NULL,
@@ -36,16 +36,16 @@ const struct cmd_entry cmd_clock_mode_entry = {
 	cmd_clock_mode_exec
 };
 
-int
+enum cmd_retval
 cmd_clock_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
 	struct window_pane	*wp;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	window_pane_set_mode(wp, &window_clock_mode);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index bb94fb1f..ea380353 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -31,7 +31,7 @@
 
 void	cmd_command_prompt_key_binding(struct cmd *, int);
 int	cmd_command_prompt_check(struct args *);
-int	cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
 
 int	cmd_command_prompt_callback(void *, const char *);
 void	cmd_command_prompt_free(void *);
@@ -84,7 +84,7 @@ cmd_command_prompt_key_binding(struct cmd *self, int key)
 	}
 }
 
-int
+enum cmd_retval
 cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -95,10 +95,10 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
 	size_t				 n;
 
 	if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (c->prompt_string != NULL)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	cdata = xmalloc(sizeof *cdata);
 	cdata->c = c;
@@ -141,7 +141,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
 	    cmd_command_prompt_free, cdata, 0);
 	free(prompt);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 int
diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c
index ea7eab4f..329027cc 100644
--- a/cmd-confirm-before.c
+++ b/cmd-confirm-before.c
@@ -26,11 +26,11 @@
  * Asks for confirmation before executing a command.
  */
 
-void	cmd_confirm_before_key_binding(struct cmd *, int);
-int	cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_confirm_before_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *);
 
-int	cmd_confirm_before_callback(void *, const char *);
-void	cmd_confirm_before_free(void *);
+int		 cmd_confirm_before_callback(void *, const char *);
+void		 cmd_confirm_before_free(void *);
 
 const struct cmd_entry cmd_confirm_before_entry = {
 	"confirm-before", "confirm",
@@ -65,7 +65,7 @@ cmd_confirm_before_key_binding(struct cmd *self, int key)
 	}
 }
 
-int
+enum cmd_retval
 cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -76,11 +76,11 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (ctx->curclient == NULL) {
 		ctx->error(ctx, "must be run interactively");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if ((prompt = args_get(args, 'p')) != NULL)
 		xasprintf(&new_prompt, "%s ", prompt);
@@ -99,7 +99,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmd_ctx *ctx)
 	    PROMPT_SINGLE);
 
 	free(new_prompt);
-	return (1);
+	return (CMD_RETURN_YIELD);
 }
 
 int
diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c
index 2028a21a..8a5b5fc4 100644
--- a/cmd-copy-mode.c
+++ b/cmd-copy-mode.c
@@ -24,8 +24,8 @@
  * Enter copy mode.
  */
 
-void	cmd_copy_mode_key_binding(struct cmd *, int);
-int	cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_copy_mode_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_copy_mode_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_copy_mode_entry = {
 	"copy-mode", NULL,
@@ -45,20 +45,20 @@ cmd_copy_mode_key_binding(struct cmd *self, int key)
 		args_set(self->args, 'u', NULL);
 }
 
-int
+enum cmd_retval
 cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
 	struct window_pane	*wp;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (window_pane_set_mode(wp, &window_copy_mode) != 0)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	window_copy_init_from_pane(wp);
 	if (wp->mode == &window_copy_mode && args_has(self->args, 'u'))
 		window_copy_pageup(wp);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c
index 36c5ae0c..f9d2587c 100644
--- a/cmd-delete-buffer.c
+++ b/cmd-delete-buffer.c
@@ -26,7 +26,7 @@
  * Delete a paste buffer.
  */
 
-int	cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_delete_buffer_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_delete_buffer_entry = {
 	"delete-buffer", "deleteb",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
 	cmd_delete_buffer_exec
 };
 
-int
+enum cmd_retval
 cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -47,20 +47,20 @@ cmd_delete_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (!args_has(args, 'b')) {
 		paste_free_top(&global_buffers);
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
 	if (cause != NULL) {
 		ctx->error(ctx, "buffer %s", cause);
 		free(cause);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (paste_free_index(&global_buffers, buffer) != 0) {
 		ctx->error(ctx, "no buffer %d", buffer);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-detach-client.c b/cmd-detach-client.c
index ed38f53d..f75b37a3 100644
--- a/cmd-detach-client.c
+++ b/cmd-detach-client.c
@@ -24,7 +24,7 @@
  * Detach a client.
  */
 
-int	cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_detach_client_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_detach_client_entry = {
 	"detach-client", "detach",
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_detach_client_entry = {
 	cmd_detach_client_exec
 };
 
-int
+enum cmd_retval
 cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -53,7 +53,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (args_has(args, 's')) {
 		s = cmd_find_session(ctx, args_get(args, 's'), 0);
 		if (s == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 
 		for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
 			c = ARRAY_ITEM(&clients, i);
@@ -63,7 +63,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 	} else {
 		c = cmd_find_client(ctx, args_get(args, 't'));
 		if (c == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 
 		if (args_has(args, 'a')) {
 			for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@@ -76,5 +76,5 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 			server_write_client(c, msgtype, NULL, 0);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-display-message.c b/cmd-display-message.c
index 41242cb9..dba5bdfd 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -27,7 +27,7 @@
  * Displays a message in the status line.
  */
 
-int	cmd_display_message_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_display_message_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_display_message_entry = {
 	"display-message", "display",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_display_message_entry = {
 	cmd_display_message_exec
 };
 
-int
+enum cmd_retval
 cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -55,21 +55,21 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
 	size_t			 len;
 
 	if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args_has(args, 't')) {
 		wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp);
 		if (wl == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	} else {
 		wl = cmd_find_pane(ctx, NULL, &s, &wp);
 		if (wl == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	}
 
 	if (args_has(args, 'F') && args->argc != 0) {
 		ctx->error(ctx, "only one of -F or argument must be given");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	template = args_get(args, 'F');
@@ -96,5 +96,5 @@ cmd_display_message_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	free(msg);
 	format_free(ft);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-display-panes.c b/cmd-display-panes.c
index ac94d4e0..2745ac59 100644
--- a/cmd-display-panes.c
+++ b/cmd-display-panes.c
@@ -24,7 +24,7 @@
  * Display panes on a client.
  */
 
-int	cmd_display_panes_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_display_panes_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_display_panes_entry = {
 	"display-panes", "displayp",
@@ -36,16 +36,16 @@ const struct cmd_entry cmd_display_panes_entry = {
 	cmd_display_panes_exec
 };
 
-int
+enum cmd_retval
 cmd_display_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
 	struct client	*c;
 
 	if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	server_set_identify(c);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-find-window.c b/cmd-find-window.c
index 33187068..b51475bd 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -28,7 +28,7 @@
  * Find window containing text.
  */
 
-int	cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
 
 u_int	cmd_find_window_match_flags(struct args *);
 void	cmd_find_window_callback(struct window_choose_data *);
@@ -74,7 +74,7 @@ cmd_find_window_match_flags(struct args *args)
 	return (match_flags);
 }
 
-int
+enum cmd_retval
 cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -90,12 +90,12 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (ctx->curclient == NULL) {
 		ctx->error(ctx, "must be run interactively");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	s = ctx->curclient->session;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if ((template = args_get(args, 'F')) == NULL)
 		template = DEFAULT_FIND_WINDOW_TEMPLATE;
@@ -150,7 +150,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		ctx->error(ctx, "no windows matching: %s", str);
 		ARRAY_FREE(&list_idx);
 		ARRAY_FREE(&list_ctx);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (ARRAY_LENGTH(&list_idx) == 1) {
@@ -189,7 +189,7 @@ out:
 	ARRAY_FREE(&list_idx);
 	ARRAY_FREE(&list_ctx);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 void
diff --git a/cmd-has-session.c b/cmd-has-session.c
index e8af47fb..9f19c4db 100644
--- a/cmd-has-session.c
+++ b/cmd-has-session.c
@@ -24,7 +24,7 @@
  * Cause client to report an error and exit with 1 if session doesn't exist.
  */
 
-int	cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_has_session_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_has_session_entry = {
 	"has-session", "has",
@@ -36,13 +36,13 @@ const struct cmd_entry cmd_has_session_entry = {
 	cmd_has_session_exec
 };
 
-int
+enum cmd_retval
 cmd_has_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
 
 	if (cmd_find_session(ctx, args_get(args, 't'), 0) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 9123f4f3..37474475 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -29,7 +29,7 @@
  * Executes a tmux command if a shell command returns true or false.
  */
 
-int	cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
 
 void	cmd_if_shell_callback(struct job *);
 void	cmd_if_shell_free(void *);
@@ -50,7 +50,7 @@ struct cmd_if_shell_data {
 	struct cmd_ctx	 ctx;
 };
 
-int
+enum cmd_retval
 cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -72,7 +72,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata);
 
-	return (1);	/* don't let client exit */
+	return (CMD_RETURN_YIELD);	/* don't let client exit */
 }
 
 void
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index f223d72b..a2e7a2dc 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -28,10 +28,10 @@
  * Join or move a pane into another (like split/swap/kill).
  */
 
-void	cmd_join_pane_key_binding(struct cmd *, int);
-int	cmd_join_pane_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_join_pane_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_join_pane_exec(struct cmd *, struct cmd_ctx *);
 
-int	join_pane(struct cmd *, struct cmd_ctx *, int);
+enum cmd_retval	 join_pane(struct cmd *, struct cmd_ctx *, int);
 
 const struct cmd_entry cmd_join_pane_entry = {
 	"join-pane", "joinp",
@@ -67,13 +67,13 @@ cmd_join_pane_key_binding(struct cmd *self, int key)
 	}
 }
 
-int
+enum cmd_retval
 cmd_join_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	return (join_pane(self, ctx, self->entry == &cmd_join_pane_entry));
 }
 
-int
+enum cmd_retval
 join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
 {
 	struct args		*args = self->args;
@@ -88,22 +88,22 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
 
 	dst_wl = cmd_find_pane(ctx, args_get(args, 't'), &dst_s, &dst_wp);
 	if (dst_wl == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	dst_w = dst_wl->window;
 	dst_idx = dst_wl->idx;
 
 	src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
 	if (src_wl == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	src_w = src_wl->window;
 
 	if (not_same_window && src_w == dst_w) {
 		ctx->error(ctx, "can't join a pane to its own window");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	if (!not_same_window && src_wp == dst_wp) {
 		ctx->error(ctx, "source and target panes must be different");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	type = LAYOUT_TOPBOTTOM;
@@ -116,14 +116,14 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
 		if (cause != NULL) {
 			ctx->error(ctx, "size %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	} else if (args_has(args, 'p')) {
 		percentage = args_strtonum(args, 'p', 0, 100, &cause);
 		if (cause != NULL) {
 			ctx->error(ctx, "percentage %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		if (type == LAYOUT_TOPBOTTOM)
 			size = (dst_wp->sy * percentage) / 100;
@@ -133,7 +133,7 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
 	lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'));
 	if (lc == NULL) {
 		ctx->error(ctx, "create pane failed: pane too small");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	layout_close_pane(src_wp);
@@ -167,5 +167,5 @@ join_pane(struct cmd *self, struct cmd_ctx *ctx, int not_same_window)
 		server_status_session(dst_s);
 
 	notify_window_layout_changed(dst_w);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c
index 893fb933..5d2cb573 100644
--- a/cmd-kill-pane.c
+++ b/cmd-kill-pane.c
@@ -26,7 +26,7 @@
  * Kill pane.
  */
 
-int	cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_kill_pane_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_kill_pane_entry = {
 	"kill-pane", "killp",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_kill_pane_entry = {
 	cmd_kill_pane_exec
 };
 
-int
+enum cmd_retval
 cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -46,13 +46,13 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	struct window_pane	*loopwp, *nextwp, *wp;
 
 	if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (window_count_panes(wl->window) == 1) {
 		/* Only one pane, kill the window. */
 		server_kill_window(wl->window);
 		recalculate_sizes();
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	if (args_has(self->args, 'a')) {
@@ -71,5 +71,5 @@ cmd_kill_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	}
 	server_redraw_window(wl->window);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-kill-server.c b/cmd-kill-server.c
index 8805b3ad..6eb39c41 100644
--- a/cmd-kill-server.c
+++ b/cmd-kill-server.c
@@ -27,7 +27,7 @@
  * Kill the server and do nothing else.
  */
 
-int	cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_kill_server_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_kill_server_entry = {
 	"kill-server", NULL,
@@ -40,10 +40,10 @@ const struct cmd_entry cmd_kill_server_entry = {
 };
 
 /* ARGSUSED */
-int
+enum cmd_retval
 cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
 {
 	kill(getpid(), SIGTERM);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-kill-session.c b/cmd-kill-session.c
index 0ce65e6d..145f77e9 100644
--- a/cmd-kill-session.c
+++ b/cmd-kill-session.c
@@ -27,7 +27,7 @@
  * Note this deliberately has no alias to make it hard to hit by accident.
  */
 
-int	cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_kill_session_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_kill_session_entry = {
 	"kill-session", NULL,
@@ -39,14 +39,14 @@ const struct cmd_entry cmd_kill_session_entry = {
 	cmd_kill_session_exec
 };
 
-int
+enum cmd_retval
 cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
 	struct session	*s, *s2, *s3;
 
 	if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args_has(args, 'a')) {
 		RB_FOREACH_SAFE(s2, sessions, &sessions, s3) {
@@ -59,5 +59,5 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 		server_destroy_session(s);
 		session_destroy(s);
 	}
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-kill-window.c b/cmd-kill-window.c
index ec2b1895..88f8dd54 100644
--- a/cmd-kill-window.c
+++ b/cmd-kill-window.c
@@ -24,7 +24,7 @@
  * Destroy window.
  */
 
-int	cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_kill_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_kill_window_entry = {
 	"kill-window", "killw",
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_kill_window_entry = {
 	cmd_kill_window_exec
 };
 
-int
+enum cmd_retval
 cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -44,7 +44,7 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	struct session	*s;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args_has(args, 'a')) {
 		RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
@@ -55,5 +55,5 @@ cmd_kill_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		server_kill_window(wl->window);
 
 	recalculate_sizes();
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-link-window.c b/cmd-link-window.c
index 8caff1fd..0e9c55ef 100644
--- a/cmd-link-window.c
+++ b/cmd-link-window.c
@@ -26,7 +26,7 @@
  * Link a window into another session.
  */
 
-int	cmd_link_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_link_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_link_window_entry = {
 	"link-window", "linkw",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_link_window_entry = {
 	cmd_link_window_exec
 };
 
-int
+enum cmd_retval
 cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -48,18 +48,18 @@ cmd_link_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	int		 idx, kflag, dflag;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	kflag = args_has(self->args, 'k');
 	dflag = args_has(self->args, 'd');
 	if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
 		ctx->error(ctx, "can't link window: %s", cause);
 		free(cause);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	recalculate_sizes();
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c
index 9f1041c5..d0a66ff9 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -27,7 +27,7 @@
  * List paste buffers.
  */
 
-int	cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_buffers_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_list_buffers_entry = {
 	"list-buffers", "lsb",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_list_buffers_entry = {
 };
 
 /* ARGSUSED */
-int
+enum cmd_retval
 cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -66,5 +66,5 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 		format_free(ft);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-list-clients.c b/cmd-list-clients.c
index f6a562c8..da646ecc 100644
--- a/cmd-list-clients.c
+++ b/cmd-list-clients.c
@@ -41,7 +41,7 @@ const struct cmd_entry cmd_list_clients_entry = {
 };
 
 /* ARGSUSED */
-int
+enum cmd_retval
 cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args 		*args = self->args;
@@ -55,7 +55,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (args_has(args, 't')) {
 		s = cmd_find_session(ctx, args_get(args, 't'), 0);
 		if (s == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	} else
 		s = NULL;
 
@@ -82,5 +82,5 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
 		format_free(ft);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-list-commands.c b/cmd-list-commands.c
index bf7b0cec..68e0e80d 100644
--- a/cmd-list-commands.c
+++ b/cmd-list-commands.c
@@ -24,7 +24,7 @@
  * List all commands with usages.
  */
 
-int	cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_commands_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_list_commands_entry = {
 	"list-commands", "lscm",
@@ -37,7 +37,7 @@ const struct cmd_entry cmd_list_commands_entry = {
 };
 
 /* ARGSUSED */
-int
+enum cmd_retval
 cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 {
 	const struct cmd_entry 	      **entryp;
@@ -45,5 +45,5 @@ cmd_list_commands_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 	for (entryp = cmd_table; *entryp != NULL; entryp++)
 		ctx->print(ctx, "%s %s", (*entryp)->name, (*entryp)->usage);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-list-keys.c b/cmd-list-keys.c
index 40543c9f..afd5b4a3 100644
--- a/cmd-list-keys.c
+++ b/cmd-list-keys.c
@@ -26,9 +26,8 @@
  * List key bindings.
  */
 
-int	cmd_list_keys_exec(struct cmd *, struct cmd_ctx *);
-
-int	cmd_list_keys_table(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_keys_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_keys_table(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_list_keys_entry = {
 	"list-keys", "lsk",
@@ -40,7 +39,7 @@ const struct cmd_entry cmd_list_keys_entry = {
 	cmd_list_keys_exec
 };
 
-int
+enum cmd_retval
 cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -95,7 +94,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
 		ctx->print(ctx, "bind-key %s", tmp);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 int
@@ -111,7 +110,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
 	tablename = args_get(args, 't');
 	if ((mtab = mode_key_findtable(tablename)) == NULL) {
 		ctx->error(ctx, "unknown key table: %s", tablename);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	width = 0;
@@ -145,5 +144,5 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
 		}
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-list-panes.c b/cmd-list-panes.c
index 9ef6cfaf..0934645f 100644
--- a/cmd-list-panes.c
+++ b/cmd-list-panes.c
@@ -27,7 +27,7 @@
  * List panes on given window.
  */
 
-int	cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
 
 void	cmd_list_panes_server(struct cmd *, struct cmd_ctx *);
 void	cmd_list_panes_session(
@@ -45,7 +45,7 @@ const struct cmd_entry cmd_list_panes_entry = {
 	cmd_list_panes_exec
 };
 
-int
+enum cmd_retval
 cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -57,16 +57,16 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
 	else if (args_has(args, 's')) {
 		s = cmd_find_session(ctx, args_get(args, 't'), 0);
 		if (s == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		cmd_list_panes_session(self, s, ctx, 1);
 	} else {
 		wl = cmd_find_window(ctx, args_get(args, 't'), &s);
 		if (wl == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		cmd_list_panes_window(self, s, wl, ctx, 0);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 void
diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c
index 92566fac..2b14c25e 100644
--- a/cmd-list-sessions.c
+++ b/cmd-list-sessions.c
@@ -28,7 +28,7 @@
  * List all sessions.
  */
 
-int	cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_list_sessions_entry = {
 	"list-sessions", "ls",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_list_sessions_entry = {
 	cmd_list_sessions_exec
 };
 
-int
+enum cmd_retval
 cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -67,5 +67,5 @@ cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx)
 		n++;
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-list-windows.c b/cmd-list-windows.c
index 32297138..cdebd360 100644
--- a/cmd-list-windows.c
+++ b/cmd-list-windows.c
@@ -27,7 +27,7 @@
  * List windows on given session.
  */
 
-int	cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
 
 void	cmd_list_windows_server(struct cmd *, struct cmd_ctx *);
 void	cmd_list_windows_session(
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_list_windows_entry = {
 	cmd_list_windows_exec
 };
 
-int
+enum cmd_retval
 cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -54,11 +54,11 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
 	else {
 		s = cmd_find_session(ctx, args_get(args, 't'), 0);
 		if (s == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		cmd_list_windows_session(self, s, ctx, 0);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 void
diff --git a/cmd-list.c b/cmd-list.c
index e4f824b4..0557000e 100644
--- a/cmd-list.c
+++ b/cmd-list.c
@@ -79,12 +79,13 @@ bad:
 	return (NULL);
 }
 
-int
+enum cmd_retval
 cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
 {
 	struct client	*c = ctx->curclient;
 	struct cmd	*cmd;
-	int		 n, retval, guards;
+	enum cmd_retval	 retval;
+	int		 guards, n;
 
 	guards = 0;
 	if (c != NULL && c->session != NULL)
@@ -98,21 +99,17 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
 		if (guards)
 			ctx->print(ctx, "%%end");
 
-		/* Return of -1 is an error. */
-		if (n == -1)
-			return (-1);
-
-		/*
-		 * A 1 return value means the command client is being attached
-		 * (sent MSG_READY).
-		 */
-		if (n == 1) {
-			retval = 1;
+		switch (n)
+		{
+		case CMD_RETURN_ERROR:
+			return (CMD_RETURN_ERROR);
+		case CMD_RETURN_ATTACH:
+			/* Client is being attached (send MSG_READY). */
+			retval = CMD_RETURN_ATTACH;
 
 			/*
-			 * The command client has been attached, so mangle the
-			 * context to treat any following commands as if they
-			 * were called from inside.
+			 * Mangle the context to treat any following commands
+			 * as if they were called from inside.
 			 */
 			if (ctx->curclient == NULL) {
 				ctx->curclient = ctx->cmdclient;
@@ -122,6 +119,13 @@ cmd_list_exec(struct cmd_list *cmdlist, struct cmd_ctx *ctx)
 				ctx->print = key_bindings_print;
 				ctx->info = key_bindings_info;
 			}
+			break;
+		case CMD_RETURN_YIELD:
+			if (retval == CMD_RETURN_NORMAL)
+				retval = CMD_RETURN_YIELD;
+			break;
+		case CMD_RETURN_NORMAL:
+			break;
 		}
 	}
 	return (retval);
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 4b877404..aaf23d99 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -30,8 +30,8 @@
  * Loads a paste buffer from a file.
  */
 
-int	cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
-void	cmd_load_buffer_callback(struct client *, int, void *);
+enum cmd_retval	 cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_load_buffer_callback(struct client *, int, void *);
 
 const struct cmd_entry cmd_load_buffer_entry = {
 	"load-buffer", "loadb",
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_load_buffer_entry = {
 	cmd_load_buffer_exec
 };
 
-int
+enum cmd_retval
 cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -63,7 +63,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 		if (cause != NULL) {
 			ctx->error(ctx, "buffer %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -77,9 +77,9 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 		if (error != 0) {
 			ctx->error(ctx, "%s: %s", path, cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
-		return (1);
+		return (CMD_RETURN_YIELD);
 	}
 
 	if (c != NULL)
@@ -97,7 +97,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 	}
 	if ((f = fopen(path, "rb")) == NULL) {
 		ctx->error(ctx, "%s: %s", path, strerror(errno));
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	pdata = NULL;
@@ -123,21 +123,21 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 	limit = options_get_number(&global_options, "buffer-limit");
 	if (buffer == -1) {
 		paste_add(&global_buffers, pdata, psize, limit);
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 	if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
 		ctx->error(ctx, "no buffer %d", buffer);
 		free(pdata);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 
 error:
 	free(pdata);
 	if (f != NULL)
 		fclose(f);
-	return (-1);
+	return (CMD_RETURN_ERROR);
 }
 
 void
diff --git a/cmd-lock-server.c b/cmd-lock-server.c
index e625797d..9d650275 100644
--- a/cmd-lock-server.c
+++ b/cmd-lock-server.c
@@ -28,7 +28,7 @@
  * Lock commands.
  */
 
-int	cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_lock_server_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_lock_server_entry = {
 	"lock-server", "lock",
@@ -61,7 +61,7 @@ const struct cmd_entry cmd_lock_client_entry = {
 };
 
 /* ARGSUSED */
-int
+enum cmd_retval
 cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -72,14 +72,14 @@ cmd_lock_server_exec(struct cmd *self, unused struct cmd_ctx *ctx)
 		server_lock();
 	else if (self->entry == &cmd_lock_session_entry) {
 		if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		server_lock_session(s);
 	} else {
 		if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		server_lock_client(c);
 	}
 	recalculate_sizes();
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-move-window.c b/cmd-move-window.c
index 28cec4cd..8bd9ffee 100644
--- a/cmd-move-window.c
+++ b/cmd-move-window.c
@@ -26,7 +26,7 @@
  * Move a window.
  */
 
-int	cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_move_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_move_window_entry = {
 	"move-window", "movew",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_move_window_entry = {
 	cmd_move_window_exec
 };
 
-int
+enum cmd_retval
 cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -49,28 +49,28 @@ cmd_move_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (args_has(args, 'r')) {
 		if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 
 		session_renumber_windows(s);
 		recalculate_sizes();
 
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 's'), &src)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	if ((idx = cmd_find_index(ctx, args_get(args, 't'), &dst)) == -2)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	kflag = args_has(self->args, 'k');
 	dflag = args_has(self->args, 'd');
 	if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) {
 		ctx->error(ctx, "can't move window: %s", cause);
 		free(cause);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	server_unlink_window(src, wl);
 	recalculate_sizes();
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-new-session.c b/cmd-new-session.c
index 2e0df33d..8477d9b2 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -30,8 +30,8 @@
  * Create a new session and attach to the current terminal unless -d is given.
  */
 
-int	cmd_new_session_check(struct args *);
-int	cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_new_session_check(struct args *);
+enum cmd_retval	 cmd_new_session_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_new_session_entry = {
 	"new-session", "new",
@@ -44,15 +44,15 @@ const struct cmd_entry cmd_new_session_entry = {
 	cmd_new_session_exec
 };
 
-int
+enum cmd_retval
 cmd_new_session_check(struct args *args)
 {
 	if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n')))
-		return (-1);
-	return (0);
+		return (CMD_RETURN_ERROR);
+	return (CMD_RETURN_NORMAL);
 }
 
-int
+enum cmd_retval
 cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -71,11 +71,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (newname != NULL) {
 		if (!session_check_name(newname)) {
 			ctx->error(ctx, "bad session name: %s", newname);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		if (session_find(newname) != NULL) {
 			ctx->error(ctx, "duplicate session: %s", newname);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -83,7 +83,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (target != NULL) {
 		groupwith = cmd_find_session(ctx, target, 0);
 		if (groupwith == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	} else
 		groupwith = NULL;
 
@@ -131,7 +131,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 		if (server_client_open(ctx->cmdclient, NULL, &cause) != 0) {
 			ctx->error(ctx, "open terminal failed: %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -163,7 +163,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 			    args_get(args, 'x'), 1, USHRT_MAX, &errstr);
 			if (errstr != NULL) {
 				ctx->error(ctx, "width %s", errstr);
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			}
 		}
 		if (args_has(args, 'y')) {
@@ -171,7 +171,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 			    args_get(args, 'y'), 1, USHRT_MAX, &errstr);
 			if (errstr != NULL) {
 				ctx->error(ctx, "height %s", errstr);
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			}
 		}
 	}
@@ -202,7 +202,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (s == NULL) {
 		ctx->error(ctx, "create session failed: %s", cause);
 		free(cause);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	environ_free(&env);
 
@@ -269,5 +269,5 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 		ARRAY_FREE(&cfg_causes);
 	}
 
-	return (!detached);	/* 1 means don't tell command client to exit */
+	return (detached ? CMD_RETURN_NORMAL : CMD_RETURN_ATTACH);
 }
diff --git a/cmd-new-window.c b/cmd-new-window.c
index af5ac544..95ad5988 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_new_window_entry = {
 	cmd_new_window_exec
 };
 
-int
+enum cmd_retval
 cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -56,7 +56,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (args_has(args, 'a')) {
 		wl = cmd_find_window(ctx, args_get(args, 't'), &s);
 		if (wl == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		idx = wl->idx + 1;
 
 		/* Find the next free index. */
@@ -66,7 +66,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		}
 		if (last == INT_MAX) {
 			ctx->error(ctx, "no free window indexes");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 
 		/* Move everything from last - 1 to idx up a bit. */
@@ -77,7 +77,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		}
 	} else {
 		if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	}
 	detached = args_has(args, 'd');
 
@@ -113,7 +113,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (wl == NULL) {
 		ctx->error(ctx, "create window failed: %s", cause);
 		free(cause);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	if (!detached) {
 		session_select(s, wl->idx);
@@ -139,5 +139,5 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		format_free(ft);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index c75fa9cf..ff92783f 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -27,7 +27,7 @@
  * Paste paste buffer if present.
  */
 
-int	cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
 
 void	cmd_paste_buffer_filter(struct window_pane *,
 	    const char *, size_t, const char *, int bracket);
@@ -42,7 +42,7 @@ const struct cmd_entry cmd_paste_buffer_entry = {
 	cmd_paste_buffer_exec
 };
 
-int
+enum cmd_retval
 cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -55,7 +55,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 	int			 pflag;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (!args_has(args, 'b'))
 		buffer = -1;
@@ -64,7 +64,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 		if (cause != NULL) {
 			ctx->error(ctx, "buffer %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -74,7 +74,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 		pb = paste_get_index(&global_buffers, buffer);
 		if (pb == NULL) {
 			ctx->error(ctx, "no buffer %d", buffer);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -99,7 +99,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 			paste_free_index(&global_buffers, buffer);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 /* Add bytes to a buffer and filter '\n' according to separator. */
diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c
index 5c8b6a0c..d2d85003 100644
--- a/cmd-pipe-pane.c
+++ b/cmd-pipe-pane.c
@@ -31,7 +31,7 @@
  * Open pipe to redirect pane output. If already open, close first.
  */
 
-int	cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *);
 
 void	cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
 
@@ -45,7 +45,7 @@ const struct cmd_entry cmd_pipe_pane_entry = {
 	cmd_pipe_pane_exec
 };
 
-int
+enum cmd_retval
 cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -55,7 +55,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	int			 old_fd, pipe_fd[2], null_fd;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	c = cmd_find_client(ctx, NULL);
 
 	/* Destroy the old pipe. */
@@ -68,7 +68,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	/* If no pipe command, that is enough. */
 	if (args->argc == 0 || *args->argv[0] == '\0')
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	/*
 	 * With -o, only open the new pipe if there was no previous one. This
@@ -77,19 +77,19 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	 *	bind ^p pipep -o 'cat >>~/output'
 	 */
 	if (args_has(self->args, 'o') && old_fd != -1)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	/* Open the new pipe. */
 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) {
 		ctx->error(ctx, "socketpair error: %s", strerror(errno));
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	/* Fork the child. */
 	switch (fork()) {
 	case -1:
 		ctx->error(ctx, "fork error: %s", strerror(errno));
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	case 0:
 		/* Child process. */
 		close(pipe_fd[0]);
@@ -126,7 +126,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 		bufferevent_enable(wp->pipe_event, EV_WRITE);
 
 		setblocking(wp->pipe_fd, 0);
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 }
 
diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c
index cf3692e1..52518122 100644
--- a/cmd-refresh-client.c
+++ b/cmd-refresh-client.c
@@ -24,7 +24,7 @@
  * Refresh client.
  */
 
-int	cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_refresh_client_entry = {
 	"refresh-client", "refresh",
@@ -36,14 +36,14 @@ const struct cmd_entry cmd_refresh_client_entry = {
 	cmd_refresh_client_exec
 };
 
-int
+enum cmd_retval
 cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
 	struct client	*c;
 
 	if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args_has(args, 'S')) {
 		status_update_jobs(c);
@@ -51,5 +51,5 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 	} else
 		server_redraw_client(c);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-rename-session.c b/cmd-rename-session.c
index cb81f913..74443bc2 100644
--- a/cmd-rename-session.c
+++ b/cmd-rename-session.c
@@ -26,7 +26,7 @@
  * Change session name.
  */
 
-int	cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_rename_session_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_rename_session_entry = {
 	"rename-session", "rename",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_rename_session_entry = {
 	cmd_rename_session_exec
 };
 
-int
+enum cmd_retval
 cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -48,15 +48,15 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 	newname = args->argv[0];
 	if (!session_check_name(newname)) {
 		ctx->error(ctx, "bad session name: %s", newname);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	if (session_find(newname) != NULL) {
 		ctx->error(ctx, "duplicate session: %s", newname);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	RB_REMOVE(sessions, &sessions, s);
 	free(s->name);
@@ -66,5 +66,5 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
 	server_status_session(s);
 	notify_session_renamed(s);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-rename-window.c b/cmd-rename-window.c
index 08f97f99..e42dd52f 100644
--- a/cmd-rename-window.c
+++ b/cmd-rename-window.c
@@ -26,7 +26,7 @@
  * Rename a window.
  */
 
-int	cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_rename_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_rename_window_entry = {
 	"rename-window", "renamew",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_rename_window_entry = {
 	cmd_rename_window_exec
 };
 
-int
+enum cmd_retval
 cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -46,12 +46,12 @@ cmd_rename_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	struct winlink	*wl;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	window_set_name(wl->window, args->argv[0]);
 	options_set_number(&wl->window->options, "automatic-rename", 0);
 
 	server_status_window(wl->window);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c
index d39bbb70..19ff0e9d 100644
--- a/cmd-resize-pane.c
+++ b/cmd-resize-pane.c
@@ -26,8 +26,8 @@
  * Increase or decrease pane size.
  */
 
-void	cmd_resize_pane_key_binding(struct cmd *, int);
-int	cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_resize_pane_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_resize_pane_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_resize_pane_entry = {
 	"resize-pane", "resizep",
@@ -81,7 +81,7 @@ cmd_resize_pane_key_binding(struct cmd *self, int key)
 	}
 }
 
-int
+enum cmd_retval
 cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -91,7 +91,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	u_int			 adjust;
 
 	if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args->argc == 0)
 		adjust = 1;
@@ -99,7 +99,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 		adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
 		if (errstr != NULL) {
 			ctx->error(ctx, "adjustment %s", errstr);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -114,5 +114,5 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 		layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust);
 	server_redraw_window(wl->window);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c
index 37c221af..cf3d9303 100644
--- a/cmd-respawn-pane.c
+++ b/cmd-respawn-pane.c
@@ -28,7 +28,7 @@
  * Respawn a pane (restart the command). Kill existing if -k given.
  */
 
-int	cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_respawn_pane_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_respawn_pane_entry = {
 	"respawn-pane", "respawnp",
@@ -40,7 +40,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
 	cmd_respawn_pane_exec
 };
 
-int
+enum cmd_retval
 cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -54,7 +54,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	u_int			 idx;
 
 	if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	w = wl->window;
 
 	if (!args_has(self->args, 'k') && wp->fd != -1) {
@@ -62,7 +62,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 			fatalx("index not found");
 		ctx->error(ctx, "pane still active: %s:%u.%u",
 		    s->name, wl->idx, idx);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	environ_init(&env);
@@ -82,11 +82,11 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 		ctx->error(ctx, "respawn pane failed: %s", cause);
 		free(cause);
 		environ_free(&env);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	wp->flags |= PANE_REDRAW;
 	server_status_window(w);
 
 	environ_free(&env);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c
index dea29cac..46d6b0d0 100644
--- a/cmd-respawn-window.c
+++ b/cmd-respawn-window.c
@@ -27,7 +27,7 @@
  * Respawn a window (restart the command). Kill existing if -k given.
  */
 
-int	cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_respawn_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_respawn_window_entry = {
 	"respawn-window", "respawnw",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_respawn_window_entry = {
 	cmd_respawn_window_exec
 };
 
-int
+enum cmd_retval
 cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -52,7 +52,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	char		 	*cause;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	w = wl->window;
 
 	if (!args_has(self->args, 'k')) {
@@ -61,7 +61,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 				continue;
 			ctx->error(ctx,
 			    "window still active: %s:%d", s->name, wl->idx);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -85,7 +85,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		free(cause);
 		environ_free(&env);
 		server_destroy_pane(wp);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	layout_init(w);
 	window_pane_reset_mode(wp);
@@ -97,5 +97,5 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	server_redraw_window(w);
 
 	environ_free(&env);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c
index 6de06a9c..74f4c066 100644
--- a/cmd-rotate-window.c
+++ b/cmd-rotate-window.c
@@ -24,8 +24,8 @@
  * Rotate the panes in a window.
  */
 
-void	cmd_rotate_window_key_binding(struct cmd *, int);
-int	cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_rotate_window_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_rotate_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_rotate_window_entry = {
 	"rotate-window", "rotatew",
@@ -45,7 +45,7 @@ cmd_rotate_window_key_binding(struct cmd *self, int key)
 		args_set(self->args, 'D', NULL);
 }
 
-int
+enum cmd_retval
 cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -56,7 +56,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	u_int			 sx, sy, xoff, yoff;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	w = wl->window;
 
 	if (args_has(self->args, 'D')) {
@@ -115,5 +115,5 @@ cmd_rotate_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		server_redraw_window(w);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index 53db61c3..130a5411 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -29,10 +29,9 @@
  * Runs a command without a window.
  */
 
-int	cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
-
-void	cmd_run_shell_callback(struct job *);
-void	cmd_run_shell_free(void *);
+enum cmd_retval	 cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_run_shell_callback(struct job *);
+void		 cmd_run_shell_free(void *);
 
 const struct cmd_entry cmd_run_shell_entry = {
 	"run-shell", "run",
@@ -49,7 +48,7 @@ struct cmd_run_shell_data {
 	struct cmd_ctx	 ctx;
 };
 
-int
+enum cmd_retval
 cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args			*args = self->args;
@@ -67,7 +66,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata);
 
-	return (1);	/* don't let client exit */
+	return (CMD_RETURN_YIELD);	/* don't let client exit */
 }
 
 void
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 7139d4e8..638c5742 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -29,7 +29,7 @@
  * Saves a paste buffer to a file.
  */
 
-int	cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_save_buffer_entry = {
 	"save-buffer", "saveb",
@@ -41,7 +41,7 @@ const struct cmd_entry cmd_save_buffer_entry = {
 	cmd_save_buffer_exec
 };
 
-int
+enum cmd_retval
 cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -57,20 +57,20 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (!args_has(args, 'b')) {
 		if ((pb = paste_get_top(&global_buffers)) == NULL) {
 			ctx->error(ctx, "no buffers");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	} else {
 		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
 		if (cause != NULL) {
 			ctx->error(ctx, "buffer %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 
 		pb = paste_get_index(&global_buffers, buffer);
 		if (pb == NULL) {
 			ctx->error(ctx, "no buffer %d", buffer);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -78,7 +78,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (strcmp(path, "-") == 0) {
 		if (c == NULL) {
 			ctx->error(ctx, "%s: can't write to stdout", path);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		evbuffer_add(c->stdout_data, pb->data, pb->size);
 		server_push_stdout(c);
@@ -105,15 +105,15 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 		umask(mask);
 		if (f == NULL) {
 			ctx->error(ctx, "%s: %s", path, strerror(errno));
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
 			ctx->error(ctx, "%s: fwrite error", path);
 			fclose(f);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		fclose(f);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-select-layout.c b/cmd-select-layout.c
index fe728980..5b234abf 100644
--- a/cmd-select-layout.c
+++ b/cmd-select-layout.c
@@ -24,8 +24,8 @@
  * Switch window to selected layout.
  */
 
-void	cmd_select_layout_key_binding(struct cmd *, int);
-int	cmd_select_layout_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_select_layout_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_select_layout_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_select_layout_entry = {
 	"select-layout", "selectl",
@@ -90,7 +90,7 @@ cmd_select_layout_key_binding(struct cmd *self, int key)
 	}
 }
 
-int
+enum cmd_retval
 cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -100,7 +100,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
 	int		 next, previous, layout;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	w = wl->window;
 
 	next = self->entry == &cmd_next_layout_entry;
@@ -114,13 +114,13 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (args_has(self->args, 'U')) {
 		if ((layoutname = layout_list_redo(w)) == NULL) {
 			ctx->info(ctx, "no more layout history");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		goto set_layout;
 	} else if (args_has(self->args, 'u')) {
 		if ((layoutname = layout_list_undo(w)) == NULL) {
 			ctx->info(ctx, "no more layout history");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		goto set_layout;
 	}
@@ -132,7 +132,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
 			layout = layout_set_previous(wl->window);
 		server_redraw_window(wl->window);
 		ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	if (args->argc == 0)
@@ -143,19 +143,19 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx)
 		layout = layout_set_select(wl->window, layout);
 		server_redraw_window(wl->window);
 		ctx->info(ctx, "arranging in: %s", layout_set_name(layout));
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	if (args->argc == 0)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	layoutname = args->argv[0];
 
 set_layout:
 	if (layout_parse(wl->window, layoutname) == -1) {
 		ctx->error(ctx, "can't set layout: %s", layoutname);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	server_redraw_window(wl->window);
 	ctx->info(ctx, "arranging in: %s", layoutname);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index ae8fd4a0..8ebae5fb 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -24,8 +24,8 @@
  * Select pane.
  */
 
-void	cmd_select_pane_key_binding(struct cmd *, int);
-int	cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_select_pane_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_select_pane_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_select_pane_entry = {
 	"select-pane", "selectp",
@@ -63,7 +63,7 @@ cmd_select_pane_key_binding(struct cmd *self, int key)
 		args_set(self->args, 't', ":.+");
 }
 
-int
+enum cmd_retval
 cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -73,26 +73,26 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
 		wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
 		if (wl == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 
 		if (wl->window->last == NULL) {
 			ctx->error(ctx, "no last pane");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 
 		window_set_active_pane(wl->window, wl->window->last);
 		server_status_window(wl->window);
 		server_redraw_window_borders(wl->window);
 
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	if ((wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (!window_pane_visible(wp)) {
 		ctx->error(ctx, "pane not visible");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (args_has(self->args, 'L'))
@@ -105,12 +105,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 		wp = window_pane_find_down(wp);
 	if (wp == NULL) {
 		ctx->error(ctx, "pane not found");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	window_set_active_pane(wl->window, wp);
 	server_status_window(wl->window);
 	server_redraw_window_borders(wl->window);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-select-window.c b/cmd-select-window.c
index ab071093..5d87e59a 100644
--- a/cmd-select-window.c
+++ b/cmd-select-window.c
@@ -26,8 +26,8 @@
  * Select window by index.
  */
 
-void	cmd_select_window_key_binding(struct cmd *, int);
-int	cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_select_window_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_select_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_select_window_entry = {
 	"select-window", "selectw",
@@ -83,7 +83,7 @@ cmd_select_window_key_binding(struct cmd *self, int key)
 		args_set(self->args, 'a', NULL);
 }
 
-int
+enum cmd_retval
 cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -104,23 +104,23 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (next || previous || last) {
 		s = cmd_find_session(ctx, args_get(args, 't'), 0);
 		if (s == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 
 		activity = args_has(self->args, 'a');
 		if (next) {
 			if (session_next(s, activity) != 0) {
 				ctx->error(ctx, "no next window");
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			}
 		} else if (previous) {
 			if (session_previous(s, activity) != 0) {
 				ctx->error(ctx, "no previous window");
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			}
 		} else {
 			if (session_last(s) != 0) {
 				ctx->error(ctx, "no last window");
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			}
 		}
 
@@ -128,12 +128,12 @@ cmd_select_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	} else {
 		wl = cmd_find_window(ctx, args_get(args, 't'), &s);
 		if (wl == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 
 		if (session_select(s, wl->idx) == 0)
 			server_redraw_session(s);
 	}
 	recalculate_sizes();
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-send-keys.c b/cmd-send-keys.c
index 79a21647..ec1007b1 100644
--- a/cmd-send-keys.c
+++ b/cmd-send-keys.c
@@ -27,7 +27,7 @@
  * Send keys to client.
  */
 
-int	cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_send_keys_entry = {
 	"send-keys", "send",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_send_keys_entry = {
 	cmd_send_keys_exec
 };
 
-int
+enum cmd_retval
 cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -50,7 +50,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
 	int			 i, key;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args_has(args, 'R')) {
 		ictx = &wp->ictx;
@@ -80,5 +80,5 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
 		}
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-send-prefix.c b/cmd-send-prefix.c
index 99aa1bac..5dded955 100644
--- a/cmd-send-prefix.c
+++ b/cmd-send-prefix.c
@@ -24,7 +24,7 @@
  * Send prefix key as a key.
  */
 
-int	cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_send_prefix_entry = {
 	"send-prefix", NULL,
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_send_prefix_entry = {
 	cmd_send_prefix_exec
 };
 
-int
+enum cmd_retval
 cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -45,7 +45,7 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
 	int			 key;
 
 	if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args_has(args, '2'))
 		key = options_get_number(&s->options, "prefix2");
@@ -53,5 +53,5 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
 		key = options_get_number(&s->options, "prefix");
 	window_pane_key(wp, s, key);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-server-info.c b/cmd-server-info.c
index 44c6375a..e2e33646 100644
--- a/cmd-server-info.c
+++ b/cmd-server-info.c
@@ -30,7 +30,7 @@
  * Show various information about server.
  */
 
-int	cmd_server_info_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_server_info_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_server_info_entry = {
 	"server-info", "info",
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_server_info_entry = {
 };
 
 /* ARGSUSED */
-int
+enum cmd_retval
 cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct tty_term				*term;
@@ -179,5 +179,5 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 		    job->cmd, job->fd, job->pid, job->status);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index 73507403..1eeaead5 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -27,7 +27,7 @@
  * Add or set a paste buffer.
  */
 
-int	cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_set_buffer_entry = {
 	"set-buffer", "setb",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_set_buffer_entry = {
 	cmd_set_buffer_exec
 };
 
-int
+enum cmd_retval
 cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -55,7 +55,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (!args_has(args, 'b')) {
 		paste_add(&global_buffers, pdata, psize, limit);
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
@@ -63,14 +63,14 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 		ctx->error(ctx, "buffer %s", cause);
 		free(cause);
 		free(pdata);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
 		ctx->error(ctx, "no buffer %d", buffer);
 		free(pdata);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-set-environment.c b/cmd-set-environment.c
index 05b26034..95336269 100644
--- a/cmd-set-environment.c
+++ b/cmd-set-environment.c
@@ -27,7 +27,7 @@
  * Set an environment variable.
  */
 
-int	cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_set_environment_entry = {
 	"set-environment", "setenv",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_set_environment_entry = {
 	cmd_set_environment_exec
 };
 
-int
+enum cmd_retval
 cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -50,11 +50,11 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
 	name = args->argv[0];
 	if (*name == '\0') {
 		ctx->error(ctx, "empty variable name");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	if (strchr(name, '=') != NULL) {
 		ctx->error(ctx, "variable name contains =");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (args->argc < 1)
@@ -66,29 +66,29 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
 		env = &global_environ;
 	else {
 		if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		env = &s->environ;
 	}
 
 	if (args_has(self->args, 'u')) {
 		if (value != NULL) {
 			ctx->error(ctx, "can't specify a value with -u");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		environ_unset(env, name);
 	} else if (args_has(self->args, 'r')) {
 		if (value != NULL) {
 			ctx->error(ctx, "can't specify a value with -r");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		environ_set(env, name, NULL);
 	} else {
 		if (value == NULL) {
 			ctx->error(ctx, "no value specified");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		environ_set(env, name, value);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-set-option.c b/cmd-set-option.c
index 1d37bfeb..ca99a977 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -27,7 +27,7 @@
  * Set an option.
  */
 
-int	cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_set_option_exec(struct cmd *, struct cmd_ctx *);
 
 int	cmd_set_option_unset(struct cmd *, struct cmd_ctx *,
 	    const struct options_table_entry *, struct options *,
@@ -78,7 +78,7 @@ const struct cmd_entry cmd_set_window_option_entry = {
 	cmd_set_option_exec
 };
 
-int
+enum cmd_retval
 cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args				*args = self->args;
@@ -95,7 +95,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
 	optstr = args->argv[0];
 	if (*optstr == '\0') {
 		ctx->error(ctx, "invalid option");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	if (args->argc < 2)
 		valstr = NULL;
@@ -106,11 +106,11 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
 	table = oe = NULL;
 	if (options_table_find(optstr, &table, &oe) != 0) {
 		ctx->error(ctx, "ambiguous option: %s", optstr);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 	if (oe == NULL) {
 		ctx->error(ctx, "unknown option: %s", optstr);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	/* Work out the tree from the table. */
@@ -122,7 +122,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
 		else {
 			wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
 			if (wl == NULL)
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			oo = &wl->window->options;
 		}
 	} else if (table == session_options_table) {
@@ -131,21 +131,21 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
 		else {
 			s = cmd_find_session(ctx, args_get(args, 't'), 0);
 			if (s == NULL)
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			oo = &s->options;
 		}
 	} else {
 		ctx->error(ctx, "unknown table");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	/* Unset or set the option. */
 	if (args_has(args, 'u')) {
 		if (cmd_set_option_unset(self, ctx, oe, oo, valstr) != 0)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	} else {
 		if (cmd_set_option_set(self, ctx, oe, oo, valstr) != 0)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 	}
 
 	/* Start or stop timers when automatic-rename changed. */
@@ -168,7 +168,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
 			server_redraw_client(c);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
 /* Unset an option. */
diff --git a/cmd-show-buffer.c b/cmd-show-buffer.c
index ba11e4d2..b345ebc1 100644
--- a/cmd-show-buffer.c
+++ b/cmd-show-buffer.c
@@ -26,7 +26,7 @@
  * Show a paste buffer.
  */
 
-int	cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_show_buffer_entry = {
 	"show-buffer", "showb",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_show_buffer_entry = {
 	cmd_show_buffer_exec
 };
 
-int
+enum cmd_retval
 cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -50,25 +50,25 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 	u_int			 width;
 
 	if ((s = cmd_find_session(ctx, NULL, 0)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (!args_has(args, 'b')) {
 		if ((pb = paste_get_top(&global_buffers)) == NULL) {
 			ctx->error(ctx, "no buffers");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	} else {
 		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
 		if (cause != NULL) {
 			ctx->error(ctx, "buffer %s", cause);
 			free(cause);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 
 		pb = paste_get_index(&global_buffers, buffer);
 		if (pb == NULL) {
 			ctx->error(ctx, "no buffer %d", buffer);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	}
 
@@ -107,5 +107,5 @@ cmd_show_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	free(in);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-show-environment.c b/cmd-show-environment.c
index 1eb8fc31..679d5d4a 100644
--- a/cmd-show-environment.c
+++ b/cmd-show-environment.c
@@ -27,7 +27,7 @@
  * Show environment.
  */
 
-int	cmd_show_environment_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_show_environment_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_show_environment_entry = {
 	"show-environment", "showenv",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_environment_entry = {
 	cmd_show_environment_exec
 };
 
-int
+enum cmd_retval
 cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -51,7 +51,7 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
 		env = &global_environ;
 	else {
 		if ((s = cmd_find_session(ctx, args_get(args, 't'), 0)) == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		env = &s->environ;
 	}
 
@@ -59,13 +59,13 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
 		envent = environ_find(env, args->argv[0]);
 		if (envent == NULL) {
 			ctx->error(ctx, "unknown variable: %s", args->argv[0]);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		if (envent->value != NULL)
 			ctx->print(ctx, "%s=%s", envent->name, envent->value);
 		else
 			ctx->print(ctx, "-%s", envent->name);
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	RB_FOREACH(envent, environ, env) {
@@ -75,5 +75,5 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
 			ctx->print(ctx, "-%s", envent->name);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-show-messages.c b/cmd-show-messages.c
index c41d99e3..d8c18519 100644
--- a/cmd-show-messages.c
+++ b/cmd-show-messages.c
@@ -27,7 +27,7 @@
  * Show client message log.
  */
 
-int	cmd_show_messages_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_show_messages_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_show_messages_entry = {
 	"show-messages", "showmsgs",
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_messages_entry = {
 	cmd_show_messages_exec
 };
 
-int
+enum cmd_retval
 cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -49,7 +49,7 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
 	u_int			 i;
 
 	if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
 		msg = &ARRAY_ITEM(&c->message_log, i);
@@ -60,5 +60,5 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx)
 		ctx->print(ctx, "%s %s", tim, msg->msg);
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-show-options.c b/cmd-show-options.c
index 3abb5643..d37b791e 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -27,7 +27,7 @@
  * Show options.
  */
 
-int	cmd_show_options_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_show_options_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_show_options_entry = {
 	"show-options", "show",
@@ -49,7 +49,7 @@ const struct cmd_entry cmd_show_window_options_entry = {
 	cmd_show_options_exec
 };
 
-int
+enum cmd_retval
 cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args				*args = self->args;
@@ -71,7 +71,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
 		else {
 			wl = cmd_find_window(ctx, args_get(args, 't'), NULL);
 			if (wl == NULL)
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			oo = &wl->window->options;
 		}
 	} else {
@@ -81,7 +81,7 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
 		else {
 			s = cmd_find_session(ctx, args_get(args, 't'), 0);
 			if (s == NULL)
-				return (-1);
+				return (CMD_RETURN_ERROR);
 			oo = &s->options;
 		}
 	}
@@ -90,14 +90,14 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
 		table = oe = NULL;
 		if (options_table_find(args->argv[0], &table, &oe) != 0) {
 			ctx->error(ctx, "ambiguous option: %s", args->argv[0]);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		if (oe == NULL) {
 			ctx->error(ctx, "unknown option: %s", args->argv[0]);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 		if ((o = options_find1(oo, oe->name)) == NULL)
-			return (0);
+			return (CMD_RETURN_NORMAL);
 		optval = options_table_print_entry(oe, o);
 		ctx->print(ctx, "%s %s", oe->name, optval);
 	} else {
@@ -109,5 +109,5 @@ cmd_show_options_exec(struct cmd *self, struct cmd_ctx *ctx)
 		}
 	}
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-source-file.c b/cmd-source-file.c
index 6ba55b09..12ed3de2 100644
--- a/cmd-source-file.c
+++ b/cmd-source-file.c
@@ -26,7 +26,7 @@
  * Sources a configuration file.
  */
 
-int	cmd_source_file_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_source_file_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_source_file_entry = {
 	"source-file", "source",
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_source_file_entry = {
 	cmd_source_file_exec
 };
 
-int
+enum cmd_retval
 cmd_source_file_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
diff --git a/cmd-split-window.c b/cmd-split-window.c
index 9a94d984..b49800e7 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -27,8 +27,8 @@
  * Split a window (add a new pane).
  */
 
-void	cmd_split_window_key_binding(struct cmd *, int);
-int	cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_split_window_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_split_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_split_window_entry = {
 	"split-window", "splitw",
@@ -49,7 +49,7 @@ cmd_split_window_key_binding(struct cmd *self, int key)
 		args_set(self->args, 'h', NULL);
 }
 
-int
+enum cmd_retval
 cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -70,7 +70,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	char			*cp;
 
 	if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	w = wl->window;
 
 	environ_init(&env);
@@ -155,7 +155,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 		format_free(ft);
 	}
 	notify_window_layout_changed(w);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 
 error:
 	environ_free(&env);
@@ -163,5 +163,5 @@ error:
 		window_remove_pane(w, new_wp);
 	ctx->error(ctx, "create pane failed: %s", cause);
 	free(cause);
-	return (-1);
+	return (CMD_RETURN_ERROR);
 }
diff --git a/cmd-start-server.c b/cmd-start-server.c
index f88d697d..7da13375 100644
--- a/cmd-start-server.c
+++ b/cmd-start-server.c
@@ -24,7 +24,7 @@
  * Start the server and do nothing else.
  */
 
-int	cmd_start_server_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_start_server_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_start_server_entry = {
 	"start-server", "start",
@@ -37,8 +37,8 @@ const struct cmd_entry cmd_start_server_entry = {
 };
 
 /* ARGSUSED */
-int
+enum cmd_retval
 cmd_start_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
 {
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c
index 558451ed..95278f98 100644
--- a/cmd-suspend-client.c
+++ b/cmd-suspend-client.c
@@ -27,7 +27,7 @@
  * Suspend client with SIGTSTP.
  */
 
-int	cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_suspend_client_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_suspend_client_entry = {
 	"suspend-client", "suspendc",
@@ -39,18 +39,18 @@ const struct cmd_entry cmd_suspend_client_entry = {
 	cmd_suspend_client_exec
 };
 
-int
+enum cmd_retval
 cmd_suspend_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
 	struct client	*c;
 
 	if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	tty_stop_tty(&c->tty);
 	c->flags |= CLIENT_SUSPENDED;
 	server_write_client(c, MSG_SUSPEND, NULL, 0);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index 5cac373c..42fe2fcb 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -26,8 +26,8 @@
  * Swap two panes.
  */
 
-void	cmd_swap_pane_key_binding(struct cmd *, int);
-int	cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_swap_pane_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_swap_pane_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_swap_pane_entry = {
 	"swap-pane", "swapp",
@@ -49,7 +49,7 @@ cmd_swap_pane_key_binding(struct cmd *self, int key)
 		args_set(self->args, 'D', NULL);
 }
 
-int
+enum cmd_retval
 cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -61,7 +61,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	dst_wl = cmd_find_pane(ctx, args_get(args, 't'), NULL, &dst_wp);
 	if (dst_wl == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	dst_w = dst_wl->window;
 
 	if (!args_has(args, 's')) {
@@ -75,16 +75,16 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 			if (src_wp == NULL)
 				src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
 		} else
-			return (0);
+			return (CMD_RETURN_NORMAL);
 	} else {
 		src_wl = cmd_find_pane(ctx, args_get(args, 's'), NULL, &src_wp);
 		if (src_wl == NULL)
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		src_w = src_wl->window;
 	}
 
 	if (src_wp == dst_wp)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
 	TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
@@ -138,5 +138,5 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
 	server_redraw_window(src_w);
 	server_redraw_window(dst_w);
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-swap-window.c b/cmd-swap-window.c
index 8fbda355..4c955402 100644
--- a/cmd-swap-window.c
+++ b/cmd-swap-window.c
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_swap_window_entry = {
 	cmd_swap_window_exec
 };
 
-int
+enum cmd_retval
 cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -50,21 +50,21 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	target_src = args_get(args, 's');
 	if ((wl_src = cmd_find_window(ctx, target_src, &src)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	target_dst = args_get(args, 't');
 	if ((wl_dst = cmd_find_window(ctx, target_dst, &dst)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	sg_src = session_group_find(src);
 	sg_dst = session_group_find(dst);
 	if (src != dst &&
 	    sg_src != NULL && sg_dst != NULL && sg_src == sg_dst) {
 		ctx->error(ctx, "can't move window, sessions are grouped");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (wl_dst->window == wl_src->window)
-		return (0);
+		return (CMD_RETURN_NORMAL);
 
 	w = wl_dst->window;
 	wl_dst->window = wl_src->window;
@@ -83,5 +83,5 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	}
 	recalculate_sizes();
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-switch-client.c b/cmd-switch-client.c
index 656bf06b..1ca0c41d 100644
--- a/cmd-switch-client.c
+++ b/cmd-switch-client.c
@@ -27,8 +27,8 @@
  * Switch client to a different session.
  */
 
-void	cmd_switch_client_key_binding(struct cmd *, int);
-int	cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
+void		 cmd_switch_client_key_binding(struct cmd *, int);
+enum cmd_retval	 cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_switch_client_entry = {
 	"switch-client", "switchc",
@@ -57,7 +57,7 @@ cmd_switch_client_key_binding(struct cmd *self, int key)
 	}
 }
 
-int
+enum cmd_retval
 cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args	*args = self->args;
@@ -65,7 +65,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 	struct session	*s;
 
 	if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (args_has(args, 'r')) {
 		if (c->flags & CLIENT_READONLY) {
@@ -81,24 +81,24 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 	if (args_has(args, 'n')) {
 		if ((s = session_next_session(c->session)) == NULL) {
 			ctx->error(ctx, "can't find next session");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	} else if (args_has(args, 'p')) {
 		if ((s = session_previous_session(c->session)) == NULL) {
 			ctx->error(ctx, "can't find previous session");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	} else if (args_has(args, 'l')) {
 		if (c->last_session != NULL && session_alive(c->last_session))
 			s = c->last_session;
 		if (s == NULL) {
 			ctx->error(ctx, "can't find last session");
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	} else
 		s = cmd_find_session(ctx, args_get(args, 't'), 0);
 	if (s == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 
 	if (c->session != NULL)
 		c->last_session = c->session;
@@ -110,5 +110,5 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
 	server_redraw_client(c);
 	s->curw->flags &= ~WINLINK_ALERTFLAGS;
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c
index d5937118..261ded40 100644
--- a/cmd-unbind-key.c
+++ b/cmd-unbind-key.c
@@ -26,10 +26,9 @@
  * Unbind key from command.
  */
 
-int	cmd_unbind_key_check(struct args *);
-int	cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *);
-
-int	cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int);
+enum cmd_retval	 cmd_unbind_key_check(struct args *);
+enum cmd_retval	 cmd_unbind_key_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_unbind_key_table(struct cmd *, struct cmd_ctx *, int);
 
 const struct cmd_entry cmd_unbind_key_entry = {
 	"unbind-key", "unbind",
@@ -41,17 +40,17 @@ const struct cmd_entry cmd_unbind_key_entry = {
 	cmd_unbind_key_exec
 };
 
-int
+enum cmd_retval
 cmd_unbind_key_check(struct args *args)
 {
 	if (args_has(args, 'a') && args->argc != 0)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	if (!args_has(args, 'a') && args->argc != 1)
-		return (-1);
-	return (0);
+		return (CMD_RETURN_ERROR);
+	return (CMD_RETURN_NORMAL);
 }
 
-int
+enum cmd_retval
 cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -62,7 +61,7 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
 		key = key_string_lookup_string(args->argv[0]);
 		if (key == KEYC_NONE) {
 			ctx->error(ctx, "unknown key: %s", args->argv[0]);
-			return (-1);
+			return (CMD_RETURN_ERROR);
 		}
 	} else
 		key = KEYC_NONE;
@@ -75,16 +74,16 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
 			bd = RB_ROOT(&key_bindings);
 			key_bindings_remove(bd->key);
 		}
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	if (!args_has(args, 'n'))
 		key |= KEYC_PREFIX;
 	key_bindings_remove(key);
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
 
-int
+enum cmd_retval
 cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 {
 	struct args			*args = self->args;
@@ -95,7 +94,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 	tablename = args_get(args, 't');
 	if ((mtab = mode_key_findtable(tablename)) == NULL) {
 		ctx->error(ctx, "unknown key table: %s", tablename);
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	if (key == KEYC_NONE) {
@@ -104,7 +103,7 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 			RB_REMOVE(mode_key_tree, mtab->tree, mbind);
 			free(mbind);
 		}
-		return (0);
+		return (CMD_RETURN_NORMAL);
 	}
 
 	mtmp.key = key;
@@ -113,5 +112,5 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
 		RB_REMOVE(mode_key_tree, mtab->tree, mbind);
 		free(mbind);
 	}
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c
index bd0ff104..19731ba5 100644
--- a/cmd-unlink-window.c
+++ b/cmd-unlink-window.c
@@ -24,7 +24,7 @@
  * Unlink a window, unless it would be destroyed by doing so (only one link).
  */
 
-int	cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_unlink_window_exec(struct cmd *, struct cmd_ctx *);
 
 const struct cmd_entry cmd_unlink_window_entry = {
 	"unlink-window", "unlinkw",
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_unlink_window_entry = {
 	cmd_unlink_window_exec
 };
 
-int
+enum cmd_retval
 cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
 	struct args		*args = self->args;
@@ -47,7 +47,7 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 	u_int			 references;
 
 	if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL)
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	w = wl->window;
 
 	sg = session_group_find(s);
@@ -60,11 +60,11 @@ cmd_unlink_window_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	if (!args_has(self->args, 'k') && w->references == references) {
 		ctx->error(ctx, "window is only linked to one session");
-		return (-1);
+		return (CMD_RETURN_ERROR);
 	}
 
 	server_unlink_window(s, wl);
 	recalculate_sizes();
 
-	return (0);
+	return (CMD_RETURN_NORMAL);
 }
diff --git a/cmd.c b/cmd.c
index f32dc67e..24136429 100644
--- a/cmd.c
+++ b/cmd.c
@@ -279,7 +279,7 @@ usage:
 	return (NULL);
 }
 
-int
+enum cmd_retval
 cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
 {
 	return (cmd->entry->exec(cmd, ctx));
diff --git a/server-client.c b/server-client.c
index e2a5b957..1f407e4f 100644
--- a/server-client.c
+++ b/server-client.c
@@ -867,8 +867,16 @@ server_client_msg_command(struct client *c, struct msg_command_data *data)
 	}
 	cmd_free_argv(argc, argv);
 
-	if (cmd_list_exec(cmdlist, &ctx) != 1)
+	switch (cmd_list_exec(cmdlist, &ctx))
+	{
+	case CMD_RETURN_ERROR:
+	case CMD_RETURN_NORMAL:
 		c->flags |= CLIENT_EXIT;
+		break;
+	case CMD_RETURN_ATTACH:
+	case CMD_RETURN_YIELD:
+		break;
+	}
 	cmd_list_free(cmdlist);
 	return;
 
diff --git a/tmux.h b/tmux.h
index b6da693e..49f053f3 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1327,6 +1327,13 @@ struct cmd_list {
 	TAILQ_HEAD(, cmd) 	 list;
 };
 
+enum cmd_retval {
+	CMD_RETURN_ERROR = -1,
+	CMD_RETURN_NORMAL = 0,
+	CMD_RETURN_YIELD,
+	CMD_RETURN_ATTACH
+};
+
 struct cmd_entry {
 	const char	*name;
 	const char	*alias;
@@ -1345,7 +1352,7 @@ struct cmd_entry {
 
 	void		 (*key_binding)(struct cmd *, int);
 	int		 (*check)(struct args *);
-	int		 (*exec)(struct cmd *, struct cmd_ctx *);
+	enum cmd_retval	 (*exec)(struct cmd *, struct cmd_ctx *);
 };
 
 /* Key binding. */
@@ -1637,7 +1644,7 @@ int		 cmd_unpack_argv(char *, size_t, int, char ***);
 char	       **cmd_copy_argv(int, char *const *);
 void		 cmd_free_argv(int, char **);
 struct cmd	*cmd_parse(int, char **, char **);
-int		 cmd_exec(struct cmd *, struct cmd_ctx *);
+enum cmd_retval	 cmd_exec(struct cmd *, struct cmd_ctx *);
 void		 cmd_free(struct cmd *);
 size_t		 cmd_print(struct cmd *, char *, size_t);
 struct session	*cmd_current_session(struct cmd_ctx *, int);
@@ -1741,7 +1748,7 @@ extern const struct cmd_entry cmd_up_pane_entry;
 
 /* cmd-list.c */
 struct cmd_list	*cmd_list_parse(int, char **, char **);
-int		 cmd_list_exec(struct cmd_list *, struct cmd_ctx *);
+enum cmd_retval	 cmd_list_exec(struct cmd_list *, struct cmd_ctx *);
 void		 cmd_list_free(struct cmd_list *);
 size_t		 cmd_list_print(struct cmd_list *, char *, size_t);