Detailed changes
  
  
    
    @@ -581,11 +581,13 @@ impl Item for AgentDiffPane {
         _workspace_id: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| Self::new(self.thread.clone(), self.workspace.clone(), window, cx)))
+        Task::ready(Some(cx.new(|cx| {
+            Self::new(self.thread.clone(), self.workspace.clone(), window, cx)
+        })))
     }
 
     fn is_dirty(&self, cx: &App) -> bool {
  
  
  
    
    @@ -776,26 +776,30 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T
         .unwrap();
 
     // Clients A and B follow each other in split panes
-    workspace_a.update_in(cx_a, |workspace, window, cx| {
-        workspace.split_and_clone(
-            workspace.active_pane().clone(),
-            SplitDirection::Right,
-            window,
-            cx,
-        );
-    });
+    workspace_a
+        .update_in(cx_a, |workspace, window, cx| {
+            workspace.split_and_clone(
+                workspace.active_pane().clone(),
+                SplitDirection::Right,
+                window,
+                cx,
+            )
+        })
+        .await;
     workspace_a.update_in(cx_a, |workspace, window, cx| {
         workspace.follow(client_b.peer_id().unwrap(), window, cx)
     });
     executor.run_until_parked();
-    workspace_b.update_in(cx_b, |workspace, window, cx| {
-        workspace.split_and_clone(
-            workspace.active_pane().clone(),
-            SplitDirection::Right,
-            window,
-            cx,
-        );
-    });
+    workspace_b
+        .update_in(cx_b, |workspace, window, cx| {
+            workspace.split_and_clone(
+                workspace.active_pane().clone(),
+                SplitDirection::Right,
+                window,
+                cx,
+            )
+        })
+        .await;
     workspace_b.update_in(cx_b, |workspace, window, cx| {
         workspace.follow(client_a.peer_id().unwrap(), window, cx)
     });
@@ -1369,9 +1373,11 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont
     );
 
     // When client B activates a different pane, it continues following client A in the original pane.
-    workspace_b.update_in(cx_b, |workspace, window, cx| {
-        workspace.split_and_clone(pane_b.clone(), SplitDirection::Right, window, cx)
-    });
+    workspace_b
+        .update_in(cx_b, |workspace, window, cx| {
+            workspace.split_and_clone(pane_b.clone(), SplitDirection::Right, window, cx)
+        })
+        .await;
     assert_eq!(
         workspace_b.update(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
         Some(leader_id.into())
  
  
  
    
    @@ -6748,7 +6748,7 @@ async fn test_preview_tabs(cx: &mut TestAppContext) {
     pane.update(cx, |pane, cx| {
         pane.split(workspace::SplitDirection::Right, cx);
     });
-
+    cx.run_until_parked();
     let right_pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
 
     pane.update(cx, |pane, cx| {
  
  
  
    
    @@ -498,8 +498,8 @@ impl Item for ChannelView {
         _: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>> {
-        Some(cx.new(|cx| {
+    ) -> Task<Option<Entity<Self>>> {
+        Task::ready(Some(cx.new(|cx| {
             Self::new(
                 self.project.clone(),
                 self.workspace.clone(),
@@ -508,7 +508,7 @@ impl Item for ChannelView {
                 window,
                 cx,
             )
-        }))
+        })))
     }
 
     fn navigate(
  
  
  
    
    @@ -693,11 +693,11 @@ impl Item for BufferDiagnosticsEditor {
         _workspace_id: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| {
+        Task::ready(Some(cx.new(|cx| {
             BufferDiagnosticsEditor::new(
                 self.project_path.clone(),
                 self.project.clone(),
@@ -706,7 +706,7 @@ impl Item for BufferDiagnosticsEditor {
                 window,
                 cx,
             )
-        }))
+        })))
     }
 
     fn deactivated(&mut self, window: &mut Window, cx: &mut Context<Self>) {
  
  
  
    
    @@ -732,11 +732,11 @@ impl Item for ProjectDiagnosticsEditor {
         _workspace_id: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| {
+        Task::ready(Some(cx.new(|cx| {
             ProjectDiagnosticsEditor::new(
                 self.include_warnings,
                 self.project.clone(),
@@ -744,7 +744,7 @@ impl Item for ProjectDiagnosticsEditor {
                 window,
                 cx,
             )
-        }))
+        })))
     }
 
     fn is_dirty(&self, cx: &App) -> bool {
  
  
  
    
    @@ -762,11 +762,11 @@ impl Item for Editor {
         _workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Editor>>
+    ) -> Task<Option<Entity<Editor>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| self.clone(window, cx)))
+        Task::ready(Some(cx.new(|cx| self.clone(window, cx))))
     }
 
     fn set_nav_history(
  
  
  
    
    @@ -4,8 +4,8 @@ use editor::{Editor, EditorEvent, MultiBuffer, SelectionEffects, multibuffer_con
 use git::repository::{CommitDetails, CommitDiff, RepoPath};
 use gpui::{
     Action, AnyElement, AnyView, App, AppContext as _, AsyncApp, AsyncWindowContext, Context,
-    Entity, EventEmitter, FocusHandle, Focusable, IntoElement, PromptLevel, Render, WeakEntity,
-    Window, actions,
+    Entity, EventEmitter, FocusHandle, Focusable, IntoElement, PromptLevel, Render, Task,
+    WeakEntity, Window, actions,
 };
 use language::{
     Anchor, Buffer, Capability, DiskState, File, LanguageRegistry, LineEnding, OffsetRangeExt as _,
@@ -561,11 +561,11 @@ impl Item for CommitView {
         _workspace_id: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| {
+        Task::ready(Some(cx.new(|cx| {
             let editor = cx.new(|cx| {
                 self.editor
                     .update(cx, |editor, cx| editor.clone(window, cx))
@@ -577,7 +577,7 @@ impl Item for CommitView {
                 commit: self.commit.clone(),
                 stash: self.stash,
             }
-        }))
+        })))
     }
 }
 
  
  
  
    
    @@ -625,12 +625,16 @@ impl Item for ProjectDiff {
         _workspace_id: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        let workspace = self.workspace.upgrade()?;
-        Some(cx.new(|cx| ProjectDiff::new(self.project.clone(), workspace, window, cx)))
+        let Some(workspace) = self.workspace.upgrade() else {
+            return Task::ready(None);
+        };
+        Task::ready(Some(cx.new(|cx| {
+            ProjectDiff::new(self.project.clone(), workspace, window, cx)
+        })))
     }
 
     fn is_dirty(&self, cx: &App) -> bool {
  
  
  
    
    @@ -176,15 +176,15 @@ impl Item for ImageView {
         _workspace_id: Option<WorkspaceId>,
         _: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| Self {
+        Task::ready(Some(cx.new(|cx| Self {
             image_item: self.image_item.clone(),
             project: self.project.clone(),
             focus_handle: cx.focus_handle(),
-        }))
+        })))
     }
 
     fn has_deleted_file(&self, cx: &App) -> bool {
  
  
  
    
    @@ -1,6 +1,7 @@
 use gpui::{
     Action, App, AppContext as _, Entity, EventEmitter, FocusHandle, Focusable,
-    KeyBindingContextPredicate, KeyContext, Keystroke, MouseButton, Render, Subscription, actions,
+    KeyBindingContextPredicate, KeyContext, Keystroke, MouseButton, Render, Subscription, Task,
+    actions,
 };
 use itertools::Itertools;
 use serde_json::json;
@@ -157,11 +158,11 @@ impl Item for KeyContextView {
         _workspace_id: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| KeyContextView::new(window, cx)))
+        Task::ready(Some(cx.new(|cx| KeyContextView::new(window, cx))))
     }
 }
 
  
  
  
    
    @@ -3,7 +3,7 @@ use copilot::Copilot;
 use editor::{Editor, EditorEvent, actions::MoveToEnd, scroll::Autoscroll};
 use gpui::{
     AnyView, App, Context, Corner, Entity, EventEmitter, FocusHandle, Focusable, IntoElement,
-    ParentElement, Render, Styled, Subscription, WeakEntity, Window, actions, div,
+    ParentElement, Render, Styled, Subscription, Task, WeakEntity, Window, actions, div,
 };
 use itertools::Itertools;
 use language::{LanguageServerId, language_settings::SoftWrap};
@@ -763,11 +763,11 @@ impl Item for LspLogView {
         _workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| {
+        Task::ready(Some(cx.new(|cx| {
             let mut new_view = Self::new(self.project.clone(), self.log_store.clone(), window, cx);
             if let Some(server_id) = self.current_server_id {
                 match self.active_entry_kind {
@@ -778,7 +778,7 @@ impl Item for LspLogView {
                 }
             }
             new_view
-        }))
+        })))
     }
 }
 
  
  
  
    
    @@ -3,7 +3,7 @@ use editor::{Anchor, Editor, ExcerptId, SelectionEffects, scroll::Autoscroll};
 use gpui::{
     App, AppContext as _, Context, Div, Entity, EntityId, EventEmitter, FocusHandle, Focusable,
     Hsla, InteractiveElement, IntoElement, MouseButton, MouseDownEvent, MouseMoveEvent,
-    ParentElement, Render, ScrollStrategy, SharedString, Styled, UniformListScrollHandle,
+    ParentElement, Render, ScrollStrategy, SharedString, Styled, Task, UniformListScrollHandle,
     WeakEntity, Window, actions, div, rems, uniform_list,
 };
 use language::{Buffer, OwnedSyntaxLayer};
@@ -573,17 +573,17 @@ impl Item for SyntaxTreeView {
         _: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| {
+        Task::ready(Some(cx.new(|cx| {
             let mut clone = Self::new(self.workspace_handle.clone(), None, window, cx);
             if let Some(editor) = &self.editor {
                 clone.set_editor(editor.editor.clone(), window, cx)
             }
             clone
-        }))
+        })))
     }
 }
 
  
  
  
    
    @@ -385,14 +385,14 @@ impl Item for Onboarding {
         _workspace_id: Option<WorkspaceId>,
         _: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>> {
-        Some(cx.new(|cx| Onboarding {
+    ) -> Task<Option<Entity<Self>>> {
+        Task::ready(Some(cx.new(|cx| Onboarding {
             workspace: self.workspace.clone(),
             user_store: self.user_store.clone(),
             scroll_handle: ScrollHandle::new(),
             focus_handle: cx.focus_handle(),
             _settings_subscription: cx.observe_global::<SettingsStore>(move |_, cx| cx.notify()),
-        }))
+        })))
     }
 
     fn to_item_events(event: &Self::Event, mut f: impl FnMut(workspace::item::ItemEvent)) {
  
  
  
    
    @@ -144,141 +144,146 @@ impl Project {
             .await
             .unwrap_or_default();
 
-            project.update(cx, move |this, cx| {
-                let format_to_run = || {
-                    if let Some(command) = &spawn_task.command {
-                        let mut command: Option<Cow<str>> = shell_kind.try_quote(command);
-                        if let Some(command) = &mut command
-                            && command.starts_with('"')
-                            && let Some(prefix) = shell_kind.command_prefix()
-                        {
-                            *command = Cow::Owned(format!("{prefix}{command}"));
-                        }
+            let builder = project
+                .update(cx, move |_, cx| {
+                    let format_to_run = || {
+                        if let Some(command) = &spawn_task.command {
+                            let mut command: Option<Cow<str>> = shell_kind.try_quote(command);
+                            if let Some(command) = &mut command
+                                && command.starts_with('"')
+                                && let Some(prefix) = shell_kind.command_prefix()
+                            {
+                                *command = Cow::Owned(format!("{prefix}{command}"));
+                            }
 
-                        let args = spawn_task
-                            .args
-                            .iter()
-                            .filter_map(|arg| shell_kind.try_quote(&arg));
+                            let args = spawn_task
+                                .args
+                                .iter()
+                                .filter_map(|arg| shell_kind.try_quote(&arg));
 
-                        command.into_iter().chain(args).join(" ")
-                    } else {
-                        // todo: this breaks for remotes to windows
-                        format!("exec {shell} -l")
-                    }
-                };
-
-                let (shell, env) = {
-                    env.extend(spawn_task.env);
-                    match remote_client {
-                        Some(remote_client) => match activation_script.clone() {
-                            activation_script if !activation_script.is_empty() => {
-                                let activation_script = activation_script.join("; ");
-                                let to_run = format_to_run();
-                                let args =
-                                    vec!["-c".to_owned(), format!("{activation_script}; {to_run}")];
-                                create_remote_shell(
-                                    Some((
-                                        &remote_client
-                                            .read(cx)
-                                            .shell()
-                                            .unwrap_or_else(get_default_system_shell),
-                                        &args,
-                                    )),
+                            command.into_iter().chain(args).join(" ")
+                        } else {
+                            // todo: this breaks for remotes to windows
+                            format!("exec {shell} -l")
+                        }
+                    };
+
+                    let (shell, env) = {
+                        env.extend(spawn_task.env);
+                        match remote_client {
+                            Some(remote_client) => match activation_script.clone() {
+                                activation_script if !activation_script.is_empty() => {
+                                    let activation_script = activation_script.join("; ");
+                                    let to_run = format_to_run();
+                                    let args = vec![
+                                        "-c".to_owned(),
+                                        format!("{activation_script}; {to_run}"),
+                                    ];
+                                    create_remote_shell(
+                                        Some((
+                                            &remote_client
+                                                .read(cx)
+                                                .shell()
+                                                .unwrap_or_else(get_default_system_shell),
+                                            &args,
+                                        )),
+                                        env,
+                                        path,
+                                        remote_client,
+                                        cx,
+                                    )?
+                                }
+                                _ => create_remote_shell(
+                                    spawn_task
+                                        .command
+                                        .as_ref()
+                                        .map(|command| (command, &spawn_task.args)),
                                     env,
                                     path,
                                     remote_client,
                                     cx,
-                                )?
-                            }
-                            _ => create_remote_shell(
-                                spawn_task
-                                    .command
-                                    .as_ref()
-                                    .map(|command| (command, &spawn_task.args)),
-                                env,
-                                path,
-                                remote_client,
-                                cx,
-                            )?,
-                        },
-                        None => match activation_script.clone() {
-                            activation_script if !activation_script.is_empty() => {
-                                let separator = shell_kind.sequential_commands_separator();
-                                let activation_script =
-                                    activation_script.join(&format!("{separator} "));
-                                let to_run = format_to_run();
-
-                                let mut arg = format!("{activation_script}{separator} {to_run}");
-                                if shell_kind == ShellKind::Cmd {
-                                    // We need to put the entire command in quotes since otherwise CMD tries to execute them
-                                    // as separate commands rather than chaining one after another.
-                                    arg = format!("\"{arg}\"");
-                                }
+                                )?,
+                            },
+                            None => match activation_script.clone() {
+                                activation_script if !activation_script.is_empty() => {
+                                    let separator = shell_kind.sequential_commands_separator();
+                                    let activation_script =
+                                        activation_script.join(&format!("{separator} "));
+                                    let to_run = format_to_run();
+
+                                    let mut arg =
+                                        format!("{activation_script}{separator} {to_run}");
+                                    if shell_kind == ShellKind::Cmd {
+                                        // We need to put the entire command in quotes since otherwise CMD tries to execute them
+                                        // as separate commands rather than chaining one after another.
+                                        arg = format!("\"{arg}\"");
+                                    }
 
-                                let args = shell_kind.args_for_shell(false, arg);
+                                    let args = shell_kind.args_for_shell(false, arg);
 
-                                (
-                                    Shell::WithArguments {
-                                        program: shell,
-                                        args,
-                                        title_override: None,
+                                    (
+                                        Shell::WithArguments {
+                                            program: shell,
+                                            args,
+                                            title_override: None,
+                                        },
+                                        env,
+                                    )
+                                }
+                                _ => (
+                                    if let Some(program) = spawn_task.command {
+                                        Shell::WithArguments {
+                                            program,
+                                            args: spawn_task.args,
+                                            title_override: None,
+                                        }
+                                    } else {
+                                        Shell::System
                                     },
                                     env,
-                                )
-                            }
-                            _ => (
-                                if let Some(program) = spawn_task.command {
-                                    Shell::WithArguments {
-                                        program,
-                                        args: spawn_task.args,
-                                        title_override: None,
-                                    }
-                                } else {
-                                    Shell::System
-                                },
-                                env,
-                            ),
-                        },
-                    }
-                };
-                TerminalBuilder::new(
-                    local_path.map(|path| path.to_path_buf()),
-                    task_state,
-                    shell,
-                    env,
-                    settings.cursor_shape,
-                    settings.alternate_scroll,
-                    settings.max_scroll_history_lines,
-                    is_via_remote,
-                    cx.entity_id().as_u64(),
-                    Some(completion_tx),
-                    cx,
-                    activation_script,
-                )
-                .map(|builder| {
-                    let terminal_handle = cx.new(|cx| builder.subscribe(cx));
-
-                    this.terminals
-                        .local_handles
-                        .push(terminal_handle.downgrade());
-
-                    let id = terminal_handle.entity_id();
-                    cx.observe_release(&terminal_handle, move |project, _terminal, cx| {
-                        let handles = &mut project.terminals.local_handles;
-
-                        if let Some(index) = handles
-                            .iter()
-                            .position(|terminal| terminal.entity_id() == id)
-                        {
-                            handles.remove(index);
-                            cx.notify();
+                                ),
+                            },
                         }
-                    })
-                    .detach();
+                    };
+                    anyhow::Ok(TerminalBuilder::new(
+                        local_path.map(|path| path.to_path_buf()),
+                        task_state,
+                        shell,
+                        env,
+                        settings.cursor_shape,
+                        settings.alternate_scroll,
+                        settings.max_scroll_history_lines,
+                        is_via_remote,
+                        cx.entity_id().as_u64(),
+                        Some(completion_tx),
+                        cx,
+                        activation_script,
+                    ))
+                })??
+                .await?;
+            project.update(cx, move |this, cx| {
+                let terminal_handle = cx.new(|cx| builder.subscribe(cx));
+
+                this.terminals
+                    .local_handles
+                    .push(terminal_handle.downgrade());
+
+                let id = terminal_handle.entity_id();
+                cx.observe_release(&terminal_handle, move |project, _terminal, cx| {
+                    let handles = &mut project.terminals.local_handles;
 
-                    terminal_handle
+                    if let Some(index) = handles
+                        .iter()
+                        .position(|terminal| terminal.entity_id() == id)
+                    {
+                        handles.remove(index);
+                        cx.notify();
+                    }
                 })
-            })?
+                .detach();
+
+                terminal_handle
+            })
         })
     }
 
@@ -364,53 +369,55 @@ impl Project {
             })
             .await
             .unwrap_or_default();
-            project.update(cx, move |this, cx| {
-                let (shell, env) = {
-                    match remote_client {
-                        Some(remote_client) => {
-                            create_remote_shell(None, env, path, remote_client, cx)?
-                        }
-                        None => (settings.shell, env),
-                    }
-                };
-                TerminalBuilder::new(
-                    local_path.map(|path| path.to_path_buf()),
-                    None,
-                    shell,
-                    env,
-                    settings.cursor_shape,
-                    settings.alternate_scroll,
-                    settings.max_scroll_history_lines,
-                    is_via_remote,
-                    cx.entity_id().as_u64(),
-                    None,
-                    cx,
-                    activation_script,
-                )
-                .map(|builder| {
-                    let terminal_handle = cx.new(|cx| builder.subscribe(cx));
-
-                    this.terminals
-                        .local_handles
-                        .push(terminal_handle.downgrade());
-
-                    let id = terminal_handle.entity_id();
-                    cx.observe_release(&terminal_handle, move |project, _terminal, cx| {
-                        let handles = &mut project.terminals.local_handles;
-
-                        if let Some(index) = handles
-                            .iter()
-                            .position(|terminal| terminal.entity_id() == id)
-                        {
-                            handles.remove(index);
-                            cx.notify();
+            let builder = project
+                .update(cx, move |_, cx| {
+                    let (shell, env) = {
+                        match remote_client {
+                            Some(remote_client) => {
+                                create_remote_shell(None, env, path, remote_client, cx)?
+                            }
+                            None => (settings.shell, env),
                         }
-                    })
-                    .detach();
+                    };
+                    anyhow::Ok(TerminalBuilder::new(
+                        local_path.map(|path| path.to_path_buf()),
+                        None,
+                        shell,
+                        env,
+                        settings.cursor_shape,
+                        settings.alternate_scroll,
+                        settings.max_scroll_history_lines,
+                        is_via_remote,
+                        cx.entity_id().as_u64(),
+                        None,
+                        cx,
+                        activation_script,
+                    ))
+                })??
+                .await?;
+            project.update(cx, move |this, cx| {
+                let terminal_handle = cx.new(|cx| builder.subscribe(cx));
+
+                this.terminals
+                    .local_handles
+                    .push(terminal_handle.downgrade());
+
+                let id = terminal_handle.entity_id();
+                cx.observe_release(&terminal_handle, move |project, _terminal, cx| {
+                    let handles = &mut project.terminals.local_handles;
 
-                    terminal_handle
+                    if let Some(index) = handles
+                        .iter()
+                        .position(|terminal| terminal.entity_id() == id)
+                    {
+                        handles.remove(index);
+                        cx.notify();
+                    }
                 })
-            })?
+                .detach();
+
+                terminal_handle
+            })
         })
     }
 
@@ -419,20 +426,21 @@ impl Project {
         terminal: &Entity<Terminal>,
         cx: &mut Context<'_, Project>,
         cwd: Option<PathBuf>,
-    ) -> Result<Entity<Terminal>> {
+    ) -> Task<Result<Entity<Terminal>>> {
         let local_path = if self.is_via_remote_server() {
             None
         } else {
             cwd
         };
 
-        terminal
-            .read(cx)
-            .clone_builder(cx, local_path)
-            .map(|builder| {
-                let terminal_handle = cx.new(|cx| builder.subscribe(cx));
+        let builder = terminal.read(cx).clone_builder(cx, local_path);
+        cx.spawn(async |project, cx| {
+            let terminal = builder.await?;
+            project.update(cx, |project, cx| {
+                let terminal_handle = cx.new(|cx| terminal.subscribe(cx));
 
-                self.terminals
+                project
+                    .terminals
                     .local_handles
                     .push(terminal_handle.downgrade());
 
@@ -452,6 +460,7 @@ impl Project {
 
                 terminal_handle
             })
+        })
     }
 
     pub fn terminal_settings<'a>(
  
  
  
    
    @@ -709,11 +709,13 @@ impl Item for NotebookEditor {
         _workspace_id: Option<workspace::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| Self::new(self.project.clone(), self.notebook_item.clone(), window, cx)))
+        Task::ready(Some(cx.new(|cx| {
+            Self::new(self.project.clone(), self.notebook_item.clone(), window, cx)
+        })))
     }
 
     fn buffer_kind(&self, _: &App) -> workspace::item::ItemBufferKind {
  
  
  
    
    @@ -572,12 +572,14 @@ impl Item for ProjectSearchView {
         _workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
         let model = self.entity.update(cx, |model, cx| model.clone(cx));
-        Some(cx.new(|cx| Self::new(self.workspace.clone(), model, window, cx, None)))
+        Task::ready(Some(cx.new(|cx| {
+            Self::new(self.workspace.clone(), model, window, cx, None)
+        })))
     }
 
     fn added_to_workspace(
@@ -3694,6 +3696,7 @@ pub mod tests {
                 )
             })
             .unwrap()
+            .await
             .unwrap();
         assert_eq!(cx.update(|cx| second_pane.read(cx).items_len()), 1);
 
@@ -3889,6 +3892,7 @@ pub mod tests {
                 )
             })
             .unwrap()
+            .await
             .unwrap();
         assert_eq!(cx.update(|cx| second_pane.read(cx).items_len()), 1);
         assert!(
  
  
  
    
    @@ -423,232 +423,233 @@ impl TerminalBuilder {
         completion_tx: Option<Sender<Option<ExitStatus>>>,
         cx: &App,
         activation_script: Vec<String>,
-    ) -> Result<TerminalBuilder> {
-        // If the parent environment doesn't have a locale set
-        // (As is the case when launched from a .app on MacOS),
-        // and the Project doesn't have a locale set, then
-        // set a fallback for our child environment to use.
-        if std::env::var("LANG").is_err() {
-            env.entry("LANG".to_string())
-                .or_insert_with(|| "en_US.UTF-8".to_string());
-        }
-
-        env.insert("ZED_TERM".to_string(), "true".to_string());
-        env.insert("TERM_PROGRAM".to_string(), "zed".to_string());
-        env.insert("TERM".to_string(), "xterm-256color".to_string());
-        env.insert("COLORTERM".to_string(), "truecolor".to_string());
-        env.insert(
-            "TERM_PROGRAM_VERSION".to_string(),
-            release_channel::AppVersion::global(cx).to_string(),
-        );
-
-        #[derive(Default)]
-        struct ShellParams {
-            program: String,
-            args: Option<Vec<String>>,
-            title_override: Option<SharedString>,
-        }
-
-        impl ShellParams {
-            fn new(
+    ) -> Task<Result<TerminalBuilder>> {
+        let version = release_channel::AppVersion::global(cx);
+        cx.background_spawn(async move {
+            // If the parent environment doesn't have a locale set
+            // (As is the case when launched from a .app on MacOS),
+            // and the Project doesn't have a locale set, then
+            // set a fallback for our child environment to use.
+            if std::env::var("LANG").is_err() {
+                env.entry("LANG".to_string())
+                    .or_insert_with(|| "en_US.UTF-8".to_string());
+            }
+
+            env.insert("ZED_TERM".to_string(), "true".to_string());
+            env.insert("TERM_PROGRAM".to_string(), "zed".to_string());
+            env.insert("TERM".to_string(), "xterm-256color".to_string());
+            env.insert("COLORTERM".to_string(), "truecolor".to_string());
+            env.insert("TERM_PROGRAM_VERSION".to_string(), version.to_string());
+
+            #[derive(Default)]
+            struct ShellParams {
                 program: String,
                 args: Option<Vec<String>>,
                 title_override: Option<SharedString>,
-            ) -> Self {
-                log::info!("Using {program} as shell");
-                Self {
-                    program,
-                    args,
-                    title_override,
-                }
             }
-        }
 
-        let shell_params = match shell.clone() {
-            Shell::System => {
-                if cfg!(windows) {
-                    Some(ShellParams::new(
-                        util::shell::get_windows_system_shell(),
-                        None,
-                        None,
-                    ))
-                } else {
-                    None
+            impl ShellParams {
+                fn new(
+                    program: String,
+                    args: Option<Vec<String>>,
+                    title_override: Option<SharedString>,
+                ) -> Self {
+                    log::info!("Using {program} as shell");
+                    Self {
+                        program,
+                        args,
+                        title_override,
+                    }
                 }
             }
-            Shell::Program(program) => Some(ShellParams::new(program, None, None)),
-            Shell::WithArguments {
-                program,
-                args,
-                title_override,
-            } => Some(ShellParams::new(program, Some(args), title_override)),
-        };
-        let terminal_title_override = shell_params.as_ref().and_then(|e| e.title_override.clone());
 
-        #[cfg(windows)]
-        let shell_program = shell_params.as_ref().map(|params| {
-            use util::ResultExt;
+            let shell_params = match shell.clone() {
+                Shell::System => {
+                    if cfg!(windows) {
+                        Some(ShellParams::new(
+                            util::shell::get_windows_system_shell(),
+                            None,
+                            None,
+                        ))
+                    } else {
+                        None
+                    }
+                }
+                Shell::Program(program) => Some(ShellParams::new(program, None, None)),
+                Shell::WithArguments {
+                    program,
+                    args,
+                    title_override,
+                } => Some(ShellParams::new(program, Some(args), title_override)),
+            };
+            let terminal_title_override =
+                shell_params.as_ref().and_then(|e| e.title_override.clone());
 
-            Self::resolve_path(¶ms.program)
-                .log_err()
-                .unwrap_or(params.program.clone())
-        });
+            #[cfg(windows)]
+            let shell_program = shell_params.as_ref().map(|params| {
+                use util::ResultExt;
 
-        // Note: when remoting, this shell_kind will scrutinize `ssh` or
-        // `wsl.exe` as a shell and fall back to posix or powershell based on
-        // the compilation target. This is fine right now due to the restricted
-        // way we use the return value, but would become incorrect if we
-        // supported remoting into windows.
-        let shell_kind = shell.shell_kind(cfg!(windows));
-
-        let pty_options = {
-            let alac_shell = shell_params.as_ref().map(|params| {
-                alacritty_terminal::tty::Shell::new(
-                    params.program.clone(),
-                    params.args.clone().unwrap_or_default(),
-                )
+                Self::resolve_path(¶ms.program)
+                    .log_err()
+                    .unwrap_or(params.program.clone())
             });
 
-            alacritty_terminal::tty::Options {
-                shell: alac_shell,
-                working_directory: working_directory.clone(),
-                drain_on_exit: true,
-                env: env.clone().into_iter().collect(),
-                // We do not want to escape arguments if we are using CMD as our shell.
-                // If we do we end up with too many quotes/escaped quotes for CMD to handle.
-                #[cfg(windows)]
-                escape_args: shell_kind != util::shell::ShellKind::Cmd,
-            }
-        };
-
-        let default_cursor_style = AlacCursorStyle::from(cursor_shape);
-        let scrolling_history = if task.is_some() {
-            // Tasks like `cargo build --all` may produce a lot of output, ergo allow maximum scrolling.
-            // After the task finishes, we do not allow appending to that terminal, so small tasks output should not
-            // cause excessive memory usage over time.
-            MAX_SCROLL_HISTORY_LINES
-        } else {
-            max_scroll_history_lines
-                .unwrap_or(DEFAULT_SCROLL_HISTORY_LINES)
-                .min(MAX_SCROLL_HISTORY_LINES)
-        };
-        let config = Config {
-            scrolling_history,
-            default_cursor_style,
-            ..Config::default()
-        };
+            // Note: when remoting, this shell_kind will scrutinize `ssh` or
+            // `wsl.exe` as a shell and fall back to posix or powershell based on
+            // the compilation target. This is fine right now due to the restricted
+            // way we use the return value, but would become incorrect if we
+            // supported remoting into windows.
+            let shell_kind = shell.shell_kind(cfg!(windows));
+
+            let pty_options = {
+                let alac_shell = shell_params.as_ref().map(|params| {
+                    alacritty_terminal::tty::Shell::new(
+                        params.program.clone(),
+                        params.args.clone().unwrap_or_default(),
+                    )
+                });
 
-        //Spawn a task so the Alacritty EventLoop can communicate with us
-        //TODO: Remove with a bounded sender which can be dispatched on &self
-        let (events_tx, events_rx) = unbounded();
-        //Set up the terminal...
-        let mut term = Term::new(
-            config.clone(),
-            &TerminalBounds::default(),
-            ZedListener(events_tx.clone()),
-        );
+                alacritty_terminal::tty::Options {
+                    shell: alac_shell,
+                    working_directory: working_directory.clone(),
+                    drain_on_exit: true,
+                    env: env.clone().into_iter().collect(),
+                    // We do not want to escape arguments if we are using CMD as our shell.
+                    // If we do we end up with too many quotes/escaped quotes for CMD to handle.
+                    #[cfg(windows)]
+                    escape_args: shell_kind != util::shell::ShellKind::Cmd,
+                }
+            };
 
-        //Alacritty defaults to alternate scrolling being on, so we just need to turn it off.
-        if let AlternateScroll::Off = alternate_scroll {
-            term.unset_private_mode(PrivateMode::Named(NamedPrivateMode::AlternateScroll));
-        }
+            let default_cursor_style = AlacCursorStyle::from(cursor_shape);
+            let scrolling_history = if task.is_some() {
+                // Tasks like `cargo build --all` may produce a lot of output, ergo allow maximum scrolling.
+                // After the task finishes, we do not allow appending to that terminal, so small tasks output should not
+                // cause excessive memory usage over time.
+                MAX_SCROLL_HISTORY_LINES
+            } else {
+                max_scroll_history_lines
+                    .unwrap_or(DEFAULT_SCROLL_HISTORY_LINES)
+                    .min(MAX_SCROLL_HISTORY_LINES)
+            };
+            let config = Config {
+                scrolling_history,
+                default_cursor_style,
+                ..Config::default()
+            };
 
-        let term = Arc::new(FairMutex::new(term));
+            //Spawn a task so the Alacritty EventLoop can communicate with us
+            //TODO: Remove with a bounded sender which can be dispatched on &self
+            let (events_tx, events_rx) = unbounded();
+            //Set up the terminal...
+            let mut term = Term::new(
+                config.clone(),
+                &TerminalBounds::default(),
+                ZedListener(events_tx.clone()),
+            );
 
-        //Setup the pty...
-        let pty = match tty::new(&pty_options, TerminalBounds::default().into(), window_id) {
-            Ok(pty) => pty,
-            Err(error) => {
-                bail!(TerminalError {
-                    directory: working_directory,
-                    program: shell_params.as_ref().map(|params| params.program.clone()),
-                    args: shell_params.as_ref().and_then(|params| params.args.clone()),
-                    title_override: terminal_title_override,
-                    source: error,
-                });
+            //Alacritty defaults to alternate scrolling being on, so we just need to turn it off.
+            if let AlternateScroll::Off = alternate_scroll {
+                term.unset_private_mode(PrivateMode::Named(NamedPrivateMode::AlternateScroll));
             }
-        };
 
-        let pty_info = PtyProcessInfo::new(&pty);
+            let term = Arc::new(FairMutex::new(term));
 
-        //And connect them together
-        let event_loop = EventLoop::new(
-            term.clone(),
-            ZedListener(events_tx),
-            pty,
-            pty_options.drain_on_exit,
-            false,
-        )
-        .context("failed to create event loop")?;
+            //Setup the pty...
+            let pty = match tty::new(&pty_options, TerminalBounds::default().into(), window_id) {
+                Ok(pty) => pty,
+                Err(error) => {
+                    bail!(TerminalError {
+                        directory: working_directory,
+                        program: shell_params.as_ref().map(|params| params.program.clone()),
+                        args: shell_params.as_ref().and_then(|params| params.args.clone()),
+                        title_override: terminal_title_override,
+                        source: error,
+                    });
+                }
+            };
 
-        //Kick things off
-        let pty_tx = event_loop.channel();
-        let _io_thread = event_loop.spawn(); // DANGER
+            let pty_info = PtyProcessInfo::new(&pty);
 
-        let no_task = task.is_none();
+            //And connect them together
+            let event_loop = EventLoop::new(
+                term.clone(),
+                ZedListener(events_tx),
+                pty,
+                pty_options.drain_on_exit,
+                false,
+            )
+            .context("failed to create event loop")?;
 
-        let terminal = Terminal {
-            task,
-            terminal_type: TerminalType::Pty {
-                pty_tx: Notifier(pty_tx),
-                info: pty_info,
-            },
-            completion_tx,
-            term,
-            term_config: config,
-            title_override: terminal_title_override,
-            events: VecDeque::with_capacity(10), //Should never get this high.
-            last_content: Default::default(),
-            last_mouse: None,
-            matches: Vec::new(),
-            selection_head: None,
-            breadcrumb_text: String::new(),
-            scroll_px: px(0.),
-            next_link_id: 0,
-            selection_phase: SelectionPhase::Ended,
-            hyperlink_regex_searches: RegexSearches::new(),
-            vi_mode_enabled: false,
-            is_ssh_terminal,
-            last_mouse_move_time: Instant::now(),
-            last_hyperlink_search_position: None,
-            #[cfg(windows)]
-            shell_program,
-            activation_script: activation_script.clone(),
-            template: CopyTemplate {
-                shell,
-                env,
-                cursor_shape,
-                alternate_scroll,
-                max_scroll_history_lines,
-                window_id,
-            },
-            child_exited: None,
-        };
+            //Kick things off
+            let pty_tx = event_loop.channel();
+            let _io_thread = event_loop.spawn(); // DANGER
+
+            let no_task = task.is_none();
 
-        if !activation_script.is_empty() && no_task {
-            for activation_script in activation_script {
-                terminal.write_to_pty(activation_script.into_bytes());
+            let terminal = Terminal {
+                task,
+                terminal_type: TerminalType::Pty {
+                    pty_tx: Notifier(pty_tx),
+                    info: pty_info,
+                },
+                completion_tx,
+                term,
+                term_config: config,
+                title_override: terminal_title_override,
+                events: VecDeque::with_capacity(10), //Should never get this high.
+                last_content: Default::default(),
+                last_mouse: None,
+                matches: Vec::new(),
+                selection_head: None,
+                breadcrumb_text: String::new(),
+                scroll_px: px(0.),
+                next_link_id: 0,
+                selection_phase: SelectionPhase::Ended,
+                hyperlink_regex_searches: RegexSearches::new(),
+                vi_mode_enabled: false,
+                is_ssh_terminal,
+                last_mouse_move_time: Instant::now(),
+                last_hyperlink_search_position: None,
+                #[cfg(windows)]
+                shell_program,
+                activation_script: activation_script.clone(),
+                template: CopyTemplate {
+                    shell,
+                    env,
+                    cursor_shape,
+                    alternate_scroll,
+                    max_scroll_history_lines,
+                    window_id,
+                },
+                child_exited: None,
+            };
+
+            if !activation_script.is_empty() && no_task {
+                for activation_script in activation_script {
+                    terminal.write_to_pty(activation_script.into_bytes());
+                    // Simulate enter key press
+                    // NOTE(PowerShell): using `\r\n` will put PowerShell in a continuation mode (infamous >> character)
+                    // and generally mess up the rendering.
+                    terminal.write_to_pty(b"\x0d");
+                }
+                // In order to clear the screen at this point, we have two options:
+                // 1. We can send a shell-specific command such as "clear" or "cls"
+                // 2. We can "echo" a marker message that we will then catch when handling a Wakeup event
+                //    and clear the screen using `terminal.clear()` method
+                // We cannot issue a `terminal.clear()` command at this point as alacritty is evented
+                // and while we have sent the activation script to the pty, it will be executed asynchronously.
+                // Therefore, we somehow need to wait for the activation script to finish executing before we
+                // can proceed with clearing the screen.
+                terminal.write_to_pty(shell_kind.clear_screen_command().as_bytes());
                 // Simulate enter key press
-                // NOTE(PowerShell): using `\r\n` will put PowerShell in a continuation mode (infamous >> character)
-                // and generally mess up the rendering.
                 terminal.write_to_pty(b"\x0d");
             }
-            // In order to clear the screen at this point, we have two options:
-            // 1. We can send a shell-specific command such as "clear" or "cls"
-            // 2. We can "echo" a marker message that we will then catch when handling a Wakeup event
-            //    and clear the screen using `terminal.clear()` method
-            // We cannot issue a `terminal.clear()` command at this point as alacritty is evented
-            // and while we have sent the activation script to the pty, it will be executed asynchronously.
-            // Therefore, we somehow need to wait for the activation script to finish executing before we
-            // can proceed with clearing the screen.
-            terminal.write_to_pty(shell_kind.clear_screen_command().as_bytes());
-            // Simulate enter key press
-            terminal.write_to_pty(b"\x0d");
-        }
 
-        Ok(TerminalBuilder {
-            terminal,
-            events_rx,
+            Ok(TerminalBuilder {
+                terminal,
+                events_rx,
+            })
         })
     }
 
@@ -2153,7 +2154,7 @@ impl Terminal {
         self.vi_mode_enabled
     }
 
-    pub fn clone_builder(&self, cx: &App, cwd: Option<PathBuf>) -> Result<TerminalBuilder> {
+    pub fn clone_builder(&self, cx: &App, cwd: Option<PathBuf>) -> Task<Result<TerminalBuilder>> {
         let working_directory = self.working_directory().or_else(|| cwd);
         TerminalBuilder::new(
             working_directory,
@@ -2389,28 +2390,30 @@ mod tests {
         let (completion_tx, completion_rx) = smol::channel::unbounded();
         let (program, args) = ShellBuilder::new(&Shell::System, false)
             .build(Some("echo".to_owned()), &["hello".to_owned()]);
-        let terminal = cx.new(|cx| {
-            TerminalBuilder::new(
-                None,
-                None,
-                task::Shell::WithArguments {
-                    program,
-                    args,
-                    title_override: None,
-                },
-                HashMap::default(),
-                CursorShape::default(),
-                AlternateScroll::On,
-                None,
-                false,
-                0,
-                Some(completion_tx),
-                cx,
-                vec![],
-            )
-            .unwrap()
-            .subscribe(cx)
-        });
+        let builder = cx
+            .update(|cx| {
+                TerminalBuilder::new(
+                    None,
+                    None,
+                    task::Shell::WithArguments {
+                        program,
+                        args,
+                        title_override: None,
+                    },
+                    HashMap::default(),
+                    CursorShape::default(),
+                    AlternateScroll::On,
+                    None,
+                    false,
+                    0,
+                    Some(completion_tx),
+                    cx,
+                    vec![],
+                )
+            })
+            .await
+            .unwrap();
+        let terminal = cx.new(|cx| builder.subscribe(cx));
         assert_eq!(
             completion_rx.recv().await.unwrap(),
             Some(ExitStatus::default())
@@ -2439,25 +2442,27 @@ mod tests {
         cx.executor().allow_parking();
 
         let (completion_tx, completion_rx) = smol::channel::unbounded();
+        let builder = cx
+            .update(|cx| {
+                TerminalBuilder::new(
+                    None,
+                    None,
+                    task::Shell::System,
+                    HashMap::default(),
+                    CursorShape::default(),
+                    AlternateScroll::On,
+                    None,
+                    false,
+                    0,
+                    Some(completion_tx),
+                    cx,
+                    Vec::new(),
+                )
+            })
+            .await
+            .unwrap();
         // Build an empty command, which will result in a tty shell spawned.
-        let terminal = cx.new(|cx| {
-            TerminalBuilder::new(
-                None,
-                None,
-                task::Shell::System,
-                HashMap::default(),
-                CursorShape::default(),
-                AlternateScroll::On,
-                None,
-                false,
-                0,
-                Some(completion_tx),
-                cx,
-                Vec::new(),
-            )
-            .unwrap()
-            .subscribe(cx)
-        });
+        let terminal = cx.new(|cx| builder.subscribe(cx));
 
         let (event_tx, event_rx) = smol::channel::unbounded::<Event>();
         cx.update(|cx| {
@@ -2508,28 +2513,30 @@ mod tests {
         let (completion_tx, completion_rx) = smol::channel::unbounded();
         let (program, args) = ShellBuilder::new(&Shell::System, false)
             .build(Some("asdasdasdasd".to_owned()), &["@@@@@".to_owned()]);
-        let terminal = cx.new(|cx| {
-            TerminalBuilder::new(
-                None,
-                None,
-                task::Shell::WithArguments {
-                    program,
-                    args,
-                    title_override: None,
-                },
-                HashMap::default(),
-                CursorShape::default(),
-                AlternateScroll::On,
-                None,
-                false,
-                0,
-                Some(completion_tx),
-                cx,
-                Vec::new(),
-            )
-            .unwrap()
-            .subscribe(cx)
-        });
+        let builder = cx
+            .update(|cx| {
+                TerminalBuilder::new(
+                    None,
+                    None,
+                    task::Shell::WithArguments {
+                        program,
+                        args,
+                        title_override: None,
+                    },
+                    HashMap::default(),
+                    CursorShape::default(),
+                    AlternateScroll::On,
+                    None,
+                    false,
+                    0,
+                    Some(completion_tx),
+                    cx,
+                    Vec::new(),
+                )
+            })
+            .await
+            .unwrap();
+        let terminal = cx.new(|cx| builder.subscribe(cx));
 
         let (event_tx, event_rx) = smol::channel::unbounded::<Event>();
         cx.update(|cx| {
  
  
  
    
    @@ -214,14 +214,6 @@ async fn deserialize_pane_group(
         }
         SerializedPaneGroup::Pane(serialized_pane) => {
             let active = serialized_pane.active;
-            let new_items = deserialize_terminal_views(
-                workspace_id,
-                project.clone(),
-                workspace.clone(),
-                serialized_pane.children.as_slice(),
-                cx,
-            )
-            .await;
 
             let pane = panel
                 .update_in(cx, |terminal_panel, window, cx| {
@@ -236,56 +228,71 @@ async fn deserialize_pane_group(
                 .log_err()?;
             let active_item = serialized_pane.active_item;
             let pinned_count = serialized_pane.pinned_count;
-            let terminal = pane
-                .update_in(cx, |pane, window, cx| {
-                    populate_pane_items(pane, new_items, active_item, window, cx);
-                    pane.set_pinned_count(pinned_count);
+            let new_items = deserialize_terminal_views(
+                workspace_id,
+                project.clone(),
+                workspace.clone(),
+                serialized_pane.children.as_slice(),
+                cx,
+            );
+            cx.spawn({
+                let pane = pane.downgrade();
+                async move |cx| {
+                    let new_items = new_items.await;
+
+                    let items = pane.update_in(cx, |pane, window, cx| {
+                        populate_pane_items(pane, new_items, active_item, window, cx);
+                        pane.set_pinned_count(pinned_count);
+                        pane.items_len()
+                    });
                     // Avoid blank panes in splits
-                    if pane.items_len() == 0 {
+                    if items.is_ok_and(|items| items == 0) {
                         let working_directory = workspace
                             .update(cx, |workspace, cx| default_working_directory(workspace, cx))
                             .ok()
                             .flatten();
-                        let terminal = project.update(cx, |project, cx| {
-                            project.create_terminal_shell(working_directory, cx)
-                        });
-                        Some(Some(terminal))
-                    } else {
-                        Some(None)
+                        let Some(terminal) = project
+                            .update(cx, |project, cx| {
+                                project.create_terminal_shell(working_directory, cx)
+                            })
+                            .log_err()
+                        else {
+                            return;
+                        };
+
+                        let terminal = terminal.await.log_err();
+                        pane.update_in(cx, |pane, window, cx| {
+                            if let Some(terminal) = terminal {
+                                let terminal_view = Box::new(cx.new(|cx| {
+                                    TerminalView::new(
+                                        terminal,
+                                        workspace.clone(),
+                                        Some(workspace_id),
+                                        project.downgrade(),
+                                        window,
+                                        cx,
+                                    )
+                                }));
+                                pane.add_item(terminal_view, true, false, None, window, cx);
+                            }
+                        })
+                        .ok();
                     }
-                })
-                .ok()
-                .flatten()?;
-            if let Some(terminal) = terminal {
-                let terminal = terminal.await.ok()?;
-                pane.update_in(cx, |pane, window, cx| {
-                    let terminal_view = Box::new(cx.new(|cx| {
-                        TerminalView::new(
-                            terminal,
-                            workspace.clone(),
-                            Some(workspace_id),
-                            project.downgrade(),
-                            window,
-                            cx,
-                        )
-                    }));
-                    pane.add_item(terminal_view, true, false, None, window, cx);
-                })
-                .ok()?;
-            }
+                }
+            })
+            .detach();
             Some((Member::Pane(pane.clone()), active.then_some(pane)))
         }
     }
 }
 
-async fn deserialize_terminal_views(
+fn deserialize_terminal_views(
     workspace_id: WorkspaceId,
     project: Entity<Project>,
     workspace: WeakEntity<Workspace>,
     item_ids: &[u64],
     cx: &mut AsyncWindowContext,
-) -> Vec<Entity<TerminalView>> {
-    let mut items = Vec::with_capacity(item_ids.len());
+) -> impl Future<Output = Vec<Entity<TerminalView>>> + use<> {
     let mut deserialized_items = item_ids
         .iter()
         .map(|item_id| {
@@ -302,12 +309,15 @@ async fn deserialize_terminal_views(
             .unwrap_or_else(|e| Task::ready(Err(e.context("no window present"))))
         })
         .collect::<FuturesUnordered<_>>();
-    while let Some(item) = deserialized_items.next().await {
-        if let Some(item) = item.log_err() {
-            items.push(item);
+    async move {
+        let mut items = Vec::with_capacity(deserialized_items.len());
+        while let Some(item) = deserialized_items.next().await {
+            if let Some(item) = item.log_err() {
+                items.push(item);
+            }
         }
+        items
     }
-    items
 }
 
 #[derive(Debug, Serialize, Deserialize)]
  
  
  
    
    @@ -462,11 +462,11 @@ impl TerminalPanel {
         cx.spawn_in(window, async move |panel, cx| {
             let terminal = project
                 .update(cx, |project, cx| match terminal_view {
-                    Some(view) => Task::ready(project.clone_terminal(
+                    Some(view) => project.clone_terminal(
                         &view.read(cx).terminal.clone(),
                         cx,
                         working_directory,
-                    )),
+                    ),
                     None => project.create_terminal_shell(working_directory, cx),
                 })
                 .ok()?
  
  
  
    
    @@ -1220,28 +1220,31 @@ impl Item for TerminalView {
         workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>> {
-        let terminal = self
-            .project
-            .update(cx, |project, cx| {
-                let cwd = project
-                    .active_project_directory(cx)
-                    .map(|it| it.to_path_buf());
-                project.clone_terminal(self.terminal(), cx, cwd)
+    ) -> Task<Option<Entity<Self>>> {
+        let Ok(terminal) = self.project.update(cx, |project, cx| {
+            let cwd = project
+                .active_project_directory(cx)
+                .map(|it| it.to_path_buf());
+            project.clone_terminal(self.terminal(), cx, cwd)
+        }) else {
+            return Task::ready(None);
+        };
+        cx.spawn_in(window, async move |this, cx| {
+            let terminal = terminal.await.log_err()?;
+            this.update_in(cx, |this, window, cx| {
+                cx.new(|cx| {
+                    TerminalView::new(
+                        terminal,
+                        this.workspace.clone(),
+                        workspace_id,
+                        this.project.clone(),
+                        window,
+                        cx,
+                    )
+                })
             })
-            .ok()?
-            .log_err()?;
-
-        Some(cx.new(|cx| {
-            TerminalView::new(
-                terminal,
-                self.workspace.clone(),
-                workspace_id,
-                self.project.clone(),
-                window,
-                cx,
-            )
-        }))
+            .ok()
+        })
     }
 
     fn is_dirty(&self, cx: &gpui::App) -> bool {
  
  
  
    
    @@ -11,8 +11,9 @@ use anyhow::Result;
 use client::{Client, proto};
 use futures::{StreamExt, channel::mpsc};
 use gpui::{
-    Action, AnyElement, AnyView, App, Context, Entity, EntityId, EventEmitter, FocusHandle,
-    Focusable, Font, HighlightStyle, Pixels, Point, Render, SharedString, Task, WeakEntity, Window,
+    Action, AnyElement, AnyView, App, AppContext, Context, Entity, EntityId, EventEmitter,
+    FocusHandle, Focusable, Font, HighlightStyle, Pixels, Point, Render, SharedString, Task,
+    WeakEntity, Window,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 pub use settings::{
@@ -217,11 +218,11 @@ pub trait Item: Focusable + EventEmitter<Self::Event> + Render + Sized {
         _workspace_id: Option<WorkspaceId>,
         _window: &mut Window,
         _: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        None
+        Task::ready(None)
     }
     fn is_dirty(&self, _: &App) -> bool {
         false
@@ -422,7 +423,7 @@ pub trait ItemHandle: 'static + Send {
         workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut App,
-    ) -> Option<Box<dyn ItemHandle>>;
+    ) -> Task<Option<Box<dyn ItemHandle>>>;
     fn added_to_pane(
         &self,
         workspace: &mut Workspace,
@@ -635,9 +636,12 @@ impl<T: Item> ItemHandle for Entity<T> {
         workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut App,
-    ) -> Option<Box<dyn ItemHandle>> {
-        self.update(cx, |item, cx| item.clone_on_split(workspace_id, window, cx))
-            .map(|handle| Box::new(handle) as Box<dyn ItemHandle>)
+    ) -> Task<Option<Box<dyn ItemHandle>>> {
+        let task = self.update(cx, |item, cx| item.clone_on_split(workspace_id, window, cx));
+        cx.background_spawn(async move {
+            task.await
+                .map(|handle| Box::new(handle) as Box<dyn ItemHandle>)
+        })
     }
 
     fn added_to_pane(
@@ -1504,11 +1508,11 @@ pub mod test {
             _workspace_id: Option<WorkspaceId>,
             _: &mut Window,
             cx: &mut Context<Self>,
-        ) -> Option<Entity<Self>>
+        ) -> Task<Option<Entity<Self>>>
         where
             Self: Sized,
         {
-            Some(cx.new(|cx| Self {
+            Task::ready(Some(cx.new(|cx| Self {
                 state: self.state.clone(),
                 label: self.label.clone(),
                 save_count: self.save_count,
@@ -1525,7 +1529,7 @@ pub mod test {
                 workspace_id: self.workspace_id,
                 focus_handle: cx.focus_handle(),
                 serialize: None,
-            }))
+            })))
         }
 
         fn is_dirty(&self, _: &App) -> bool {
  
  
  
    
    @@ -3295,11 +3295,18 @@ impl Pane {
                         else {
                             return;
                         };
-                        if let Some(item) = item.clone_on_split(database_id, window, cx) {
-                            to_pane.update(cx, |pane, cx| {
-                                pane.add_item(item, true, true, None, window, cx);
-                            })
-                        }
+                        let task = item.clone_on_split(database_id, window, cx);
+                        let to_pane = to_pane.downgrade();
+                        cx.spawn_in(window, async move |_, cx| {
+                            if let Some(item) = task.await {
+                                to_pane
+                                    .update_in(cx, |pane, window, cx| {
+                                        pane.add_item(item, true, true, None, window, cx)
+                                    })
+                                    .ok();
+                            }
+                        })
+                        .detach();
                     } else {
                         move_item(&from_pane, &to_pane, item_id, ix, true, window, cx);
                     }
  
  
  
    
    @@ -6,7 +6,7 @@ use call::{RemoteVideoTrack, RemoteVideoTrackView, Room};
 use client::{User, proto::PeerId};
 use gpui::{
     AppContext as _, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
-    ParentElement, Render, SharedString, Styled, div,
+    ParentElement, Render, SharedString, Styled, Task, div,
 };
 use std::sync::Arc;
 use ui::{Icon, IconName, prelude::*};
@@ -114,14 +114,14 @@ impl Item for SharedScreen {
         _workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>> {
-        Some(cx.new(|cx| Self {
+    ) -> Task<Option<Entity<Self>>> {
+        Task::ready(Some(cx.new(|cx| Self {
             view: self.view.update(cx, |view, cx| view.clone(window, cx)),
             peer_id: self.peer_id,
             user: self.user.clone(),
             nav_history: Default::default(),
             focus: cx.focus_handle(),
-        }))
+        })))
     }
 
     fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
  
  
  
    
    @@ -1,5 +1,7 @@
 #![allow(unused, dead_code)]
-use gpui::{AnyElement, App, Entity, EventEmitter, FocusHandle, Focusable, Hsla, actions, hsla};
+use gpui::{
+    AnyElement, App, Entity, EventEmitter, FocusHandle, Focusable, Hsla, Task, actions, hsla,
+};
 use strum::IntoEnumIterator;
 use theme::all_theme_colors;
 use ui::{
@@ -100,11 +102,11 @@ impl Item for ThemePreview {
         _workspace_id: Option<crate::WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Self>>
+    ) -> Task<Option<Entity<Self>>>
     where
         Self: Sized,
     {
-        Some(cx.new(|cx| Self::new(window, cx)))
+        Task::ready(Some(cx.new(|cx| Self::new(window, cx))))
     }
 }
 
  
  
  
    
    @@ -3630,7 +3630,8 @@ impl Workspace {
         if let Some(pane) = panes.get(action.0).map(|p| (*p).clone()) {
             window.focus(&pane.focus_handle(cx));
         } else {
-            self.split_and_clone(self.active_pane.clone(), SplitDirection::Right, window, cx);
+            self.split_and_clone(self.active_pane.clone(), SplitDirection::Right, window, cx)
+                .detach();
         }
     }
 
@@ -3997,7 +3998,8 @@ impl Workspace {
                 clone_active_item,
             } => {
                 if *clone_active_item {
-                    self.split_and_clone(pane.clone(), *direction, window, cx);
+                    self.split_and_clone(pane.clone(), *direction, window, cx)
+                        .detach();
                 } else {
                     self.split_and_move(pane.clone(), *direction, window, cx);
                 }
@@ -4138,21 +4140,27 @@ impl Workspace {
         direction: SplitDirection,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<Entity<Pane>> {
-        let item = pane.read(cx).active_item()?;
-        let maybe_pane_handle =
-            if let Some(clone) = item.clone_on_split(self.database_id(), window, cx) {
-                let new_pane = self.add_pane(window, cx);
-                new_pane.update(cx, |pane, cx| {
-                    pane.add_item(clone, true, true, None, window, cx)
-                });
-                self.center.split(&pane, &new_pane, direction).unwrap();
-                cx.notify();
-                Some(new_pane)
+    ) -> Task<Option<Entity<Pane>>> {
+        let Some(item) = pane.read(cx).active_item() else {
+            return Task::ready(None);
+        };
+        let task = item.clone_on_split(self.database_id(), window, cx);
+        cx.spawn_in(window, async move |this, cx| {
+            if let Some(clone) = task.await {
+                this.update_in(cx, |this, window, cx| {
+                    let new_pane = this.add_pane(window, cx);
+                    new_pane.update(cx, |pane, cx| {
+                        pane.add_item(clone, true, true, None, window, cx)
+                    });
+                    this.center.split(&pane, &new_pane, direction).unwrap();
+                    cx.notify();
+                    new_pane
+                })
+                .ok()
             } else {
                 None
-            };
-        maybe_pane_handle
+            }
+        })
     }
 
     pub fn join_all_panes(&mut self, window: &mut Window, cx: &mut Context<Self>) {
@@ -8177,19 +8185,27 @@ pub fn clone_active_item(
     let Some(active_item) = source.read(cx).active_item() else {
         return;
     };
-    destination.update(cx, |target_pane, cx| {
-        let Some(clone) = active_item.clone_on_split(workspace_id, window, cx) else {
-            return;
-        };
-        target_pane.add_item(
-            clone,
-            focus_destination,
-            focus_destination,
-            Some(target_pane.items_len()),
-            window,
-            cx,
-        );
-    });
+    let destination = destination.downgrade();
+    let task = active_item.clone_on_split(workspace_id, window, cx);
+    window
+        .spawn(cx, async move |cx| {
+            let Some(clone) = task.await else {
+                return;
+            };
+            destination
+                .update_in(cx, |target_pane, window, cx| {
+                    target_pane.add_item(
+                        clone,
+                        focus_destination,
+                        focus_destination,
+                        Some(target_pane.items_len()),
+                        window,
+                        cx,
+                    );
+                })
+                .log_err();
+        })
+        .detach();
 }
 
 #[derive(Debug)]
@@ -8696,25 +8712,24 @@ mod tests {
                 cx,
             );
 
-            let right_pane = workspace
-                .split_and_clone(left_pane.clone(), SplitDirection::Right, window, cx)
-                .unwrap();
+            let right_pane =
+                workspace.split_and_clone(left_pane.clone(), SplitDirection::Right, window, cx);
 
-            right_pane.update(cx, |pane, cx| {
-                pane.add_item(
-                    single_entry_items[1].boxed_clone(),
-                    true,
-                    true,
-                    None,
-                    window,
-                    cx,
-                );
-                pane.add_item(Box::new(item_3_4.clone()), true, true, None, window, cx);
+            let boxed_clone = single_entry_items[1].boxed_clone();
+            let right_pane = window.spawn(cx, async move |cx| {
+                right_pane.await.inspect(|right_pane| {
+                    right_pane
+                        .update_in(cx, |pane, window, cx| {
+                            pane.add_item(boxed_clone, true, true, None, window, cx);
+                            pane.add_item(Box::new(item_3_4.clone()), true, true, None, window, cx);
+                        })
+                        .unwrap();
+                })
             });
 
             (left_pane, right_pane)
         });
-
+        let right_pane = right_pane.await.unwrap();
         cx.focus(&right_pane);
 
         let mut close = right_pane.update_in(cx, |pane, window, cx| {
@@ -10531,7 +10546,10 @@ mod tests {
                 window,
                 cx,
             );
+        });
+        cx.run_until_parked();
 
+        workspace.update(cx, |workspace, cx| {
             assert_eq!(workspace.panes.len(), 3, "Two new panes were created");
             for pane in workspace.panes() {
                 assert_eq!(
  
  
  
    
    @@ -2836,14 +2836,16 @@ mod tests {
         });
 
         // Split the pane with the first entry, then open the second entry again.
-        window
+        let (task1, task2) = window
             .update(cx, |w, window, cx| {
-                w.split_and_clone(w.active_pane().clone(), SplitDirection::Right, window, cx);
-                w.open_path(file2.clone(), None, true, window, cx)
+                (
+                    w.split_and_clone(w.active_pane().clone(), SplitDirection::Right, window, cx),
+                    w.open_path(file2.clone(), None, true, window, cx),
+                )
             })
-            .unwrap()
-            .await
             .unwrap();
+        task1.await.unwrap();
+        task2.await.unwrap();
 
         window
             .read_with(cx, |w, cx| {
@@ -3466,7 +3468,13 @@ mod tests {
                     SplitDirection::Right,
                     window,
                     cx,
-                );
+                )
+            })
+            .unwrap()
+            .await
+            .unwrap();
+        window
+            .update(cx, |workspace, window, cx| {
                 workspace.open_path(
                     (worktree.read(cx).id(), rel_path("the-new-name.rs")),
                     None,
  
  
  
    
    @@ -721,7 +721,7 @@ impl Item for ComponentPreview {
         _workspace_id: Option<WorkspaceId>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<gpui::Entity<Self>>
+    ) -> Task<Option<gpui::Entity<Self>>>
     where
         Self: Sized,
     {
@@ -743,13 +743,13 @@ impl Item for ComponentPreview {
             cx,
         );
 
-        match self_result {
+        Task::ready(match self_result {
             Ok(preview) => Some(cx.new(|_cx| preview)),
             Err(e) => {
                 log::error!("Failed to clone component preview: {}", e);
                 None
             }
-        }
+        })
     }
 
     fn to_item_events(event: &Self::Event, mut f: impl FnMut(workspace::item::ItemEvent)) {