diff --git a/src/ClaudeDo.Ui/Services/PtyTerminalSession.cs b/src/ClaudeDo.Ui/Services/PtyTerminalSession.cs
index 29b2d920..1be2a2cd 100644
--- a/src/ClaudeDo.Ui/Services/PtyTerminalSession.cs
+++ b/src/ClaudeDo.Ui/Services/PtyTerminalSession.cs
@@ -46,6 +46,13 @@ public sealed class PtyTerminalSession : IDisposable
control.StartingDirectory = descriptor.Cwd;
await control.LaunchProcess();
+
+ // Permanent reparent mode: TerminalView.OnDetachedFromLogicalTree kills the child
+ // process unless BeginReparent() suppressed it, and Mission Control detaches pane
+ // views routinely (overview-grid rebuilds on pane add/remove, focus-mode tab
+ // switches). ClaudeDo owns teardown explicitly instead — ConPtyPaneViewModel.Dispose
+ // calls Kill() when a pane closes — so EndReparent is deliberately never called.
+ control.BeginReparent();
IsRunning = true;
}
diff --git a/src/ClaudeDo.Ui/Views/MissionControl/ConPtyPaneHost.cs b/src/ClaudeDo.Ui/Views/MissionControl/ConPtyPaneHost.cs
new file mode 100644
index 00000000..10854650
--- /dev/null
+++ b/src/ClaudeDo.Ui/Views/MissionControl/ConPtyPaneHost.cs
@@ -0,0 +1,48 @@
+using System.Runtime.CompilerServices;
+using Avalonia.Controls;
+using ClaudeDo.Ui.ViewModels.MissionControl;
+
+namespace ClaudeDo.Ui.Views.MissionControl;
+
+///
+/// Hosts the single long-lived of a .
+/// The Mission Control layouts recreate their DataTemplate content freely (the overview grid is
+/// rebuilt from scratch on every pane/column change, focus-mode tabs re-present on selection), but
+/// the running PTY session is bound to the original TerminalControl — a freshly instantiated view
+/// would render a dead, empty terminal. This host therefore reparents the pane's one real view
+/// instead of letting the template create a new one. Safe while the session runs because
+/// puts the control in permanent reparent mode
+/// (detach never kills the child process).
+///
+public sealed class ConPtyPaneHost : Decorator
+{
+ // Keyed weakly so a closed pane's view dies with its view model.
+ private static readonly ConditionalWeakTable Views = new();
+
+ public ConPtyPaneHost()
+ {
+ DataContextChanged += (_, _) => Reclaim();
+ AttachedToVisualTree += (_, _) => Reclaim();
+ }
+
+ /// Takes ownership of the pane's cached view, stealing it from whichever host showed
+ /// it last — but only while effectively visible, so the hidden layout (overview grid vs. focus
+ /// tabs) never yanks the view away from the visible one.
+ public void Reclaim()
+ {
+ var vm = DataContext as ConPtyPaneViewModel;
+
+ // A recycled host now bound to a different pane must not keep showing the old view.
+ // The cached views carry their own local DataContext, so this check can't be fooled
+ // by DataContext inheritance.
+ if (Child is ConPtyPaneView stale && !ReferenceEquals(stale.DataContext, vm))
+ Child = null;
+
+ if (vm is null || !IsEffectivelyVisible) return;
+
+ var view = Views.GetValue(vm, static key => new ConPtyPaneView { DataContext = key });
+ if (ReferenceEquals(Child, view)) return;
+ if (view.Parent is ConPtyPaneHost previous) previous.Child = null;
+ Child = view;
+ }
+}
diff --git a/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml b/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml
index 02ae99f5..26aa73bb 100644
--- a/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml
+++ b/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml
@@ -8,8 +8,11 @@
x:DataType="vm:MissionControlViewModel"
x:Class="ClaudeDo.Ui.Views.MissionControl.MissionControlView">
+
-
+
diff --git a/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml.cs b/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml.cs
index 2f544297..67197117 100644
--- a/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml.cs
+++ b/src/ClaudeDo.Ui/Views/MissionControl/MissionControlView.axaml.cs
@@ -1,11 +1,13 @@
using System;
using System.Collections.Specialized;
using System.ComponentModel;
+using System.Linq;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform.Storage;
+using Avalonia.VisualTree;
using ClaudeDo.Ui.ViewModels;
namespace ClaudeDo.Ui.Views.MissionControl;
@@ -73,6 +75,18 @@ public partial class MissionControlView : UserControl
RebuildOverviewGrid();
else if (e.PropertyName == nameof(MissionControlViewModel.HasQueued))
UpdateQueueColumn();
+ else if (e.PropertyName == nameof(MissionControlViewModel.IsFocusMode))
+ // The now-visible layout's hosts must re-steal their pane views from the hidden
+ // one (see ConPtyPaneHost) — posted so it runs after the visibility change and
+ // the TabControl's content presenter have gone through a layout pass.
+ Avalonia.Threading.Dispatcher.UIThread.Post(ReclaimVisiblePaneHosts,
+ Avalonia.Threading.DispatcherPriority.Loaded);
+ }
+
+ private void ReclaimVisiblePaneHosts()
+ {
+ foreach (var host in this.GetVisualDescendants().OfType())
+ host.Reclaim();
}
// The queue column is Pixel-widthed (so the splitter can drag it) — when nothing is