diff --git a/src/ClaudeDo.Ui/Design/IslandStyles.axaml b/src/ClaudeDo.Ui/Design/IslandStyles.axaml
index ab1ae34..76cc491 100644
--- a/src/ClaudeDo.Ui/Design/IslandStyles.axaml
+++ b/src/ClaudeDo.Ui/Design/IslandStyles.axaml
@@ -85,6 +85,9 @@
M13 4 H20 V11 H18 V7.4 L11.4 14 L10 12.6 L16.6 6 H13 Z M4 6 H10 V8 H6 V18 H16 V14 H18 V20 H4 Z
+
+ M4 6 H20 V8 H4 Z M4 11 H20 V13 H4 Z M4 16 H14 V18 H4 Z
+
F0 M12 3 L22 20 H2 Z M11 9 H13 V14 H11 Z M11 16 H13 V18 H11 Z
diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/Detail/DescriptionStepsCardViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/Detail/DescriptionStepsCardViewModel.cs
new file mode 100644
index 0000000..dab0050
--- /dev/null
+++ b/src/ClaudeDo.Ui/ViewModels/Islands/Detail/DescriptionStepsCardViewModel.cs
@@ -0,0 +1,133 @@
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Text;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+
+namespace ClaudeDo.Ui.ViewModels.Islands.Detail;
+
+public partial class SubtaskRowSampleViewModel : ObservableObject
+{
+ [ObservableProperty] string _title = "";
+ [ObservableProperty] bool _done;
+ [ObservableProperty] bool _isEditing;
+
+ [RelayCommand] void ToggleDone() => Done = !Done;
+ [RelayCommand] void BeginEdit() => IsEditing = true;
+ [RelayCommand] void CommitEdit() => IsEditing = false;
+}
+
+public partial class DescriptionStepsCardViewModel : ClaudeDo.Ui.ViewModels.ViewModelBase
+{
+ [ObservableProperty]
+ [NotifyPropertyChangedFor(nameof(IsDescriptionView))]
+ bool _isStepsView;
+
+ public bool IsDescriptionView => !IsStepsView;
+
+ [ObservableProperty]
+ [NotifyPropertyChangedFor(nameof(ComposedPreview))]
+ string _title = "";
+
+ [ObservableProperty]
+ [NotifyPropertyChangedFor(nameof(ComposedPreview))]
+ string _editableDescription = "";
+
+ [ObservableProperty] bool _isEditingDescription;
+ [ObservableProperty] string _newSubtaskTitle = "";
+
+ public ObservableCollection Subtasks { get; } = new();
+
+ public string ComposedPreview => BuildComposedPreview();
+
+ [RelayCommand] void ToggleCardView() => IsStepsView = !IsStepsView;
+ [RelayCommand] void ToggleEditDescription() => IsEditingDescription = !IsEditingDescription;
+
+ [RelayCommand]
+ void AddSubtask()
+ {
+ if (string.IsNullOrWhiteSpace(NewSubtaskTitle)) return;
+ var row = new SubtaskRowSampleViewModel { Title = NewSubtaskTitle.Trim() };
+ row.PropertyChanged += OnRowPropertyChanged;
+ Subtasks.Add(row);
+ NewSubtaskTitle = "";
+ OnPropertyChanged(nameof(ComposedPreview));
+ }
+
+ [RelayCommand]
+ void ToggleSubtaskDone(SubtaskRowSampleViewModel row)
+ {
+ row.Done = !row.Done;
+ }
+
+ [RelayCommand]
+ void CommitSubtaskEdit(SubtaskRowSampleViewModel row)
+ {
+ row.IsEditing = false;
+ }
+
+ private void OnRowPropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName is nameof(SubtaskRowSampleViewModel.Done)
+ or nameof(SubtaskRowSampleViewModel.Title))
+ OnPropertyChanged(nameof(ComposedPreview));
+ }
+
+ private void OnSubtasksChanged(object? sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (e.NewItems is not null)
+ foreach (SubtaskRowSampleViewModel row in e.NewItems)
+ row.PropertyChanged += OnRowPropertyChanged;
+ if (e.OldItems is not null)
+ foreach (SubtaskRowSampleViewModel row in e.OldItems)
+ row.PropertyChanged -= OnRowPropertyChanged;
+ OnPropertyChanged(nameof(ComposedPreview));
+ }
+
+ private string BuildComposedPreview()
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine(Title);
+
+ if (!string.IsNullOrWhiteSpace(EditableDescription))
+ {
+ sb.AppendLine();
+ sb.AppendLine(EditableDescription.TrimEnd());
+ }
+
+ var openSteps = Subtasks.Where(s => !s.Done).ToList();
+ if (openSteps.Count > 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine("## Sub-Tasks");
+ foreach (var step in openSteps)
+ sb.AppendLine($"- [ ] {step.Title}");
+ }
+
+ return sb.ToString().TrimEnd();
+ }
+
+ public DescriptionStepsCardViewModel()
+ {
+ Subtasks.CollectionChanged += OnSubtasksChanged;
+
+ _title = "Refactor diff viewer";
+ _editableDescription =
+ "Split the current monolithic diff renderer into smaller, testable components.\n\n" +
+ "The goal is to improve readability and allow unit testing of each parsing stage independently.";
+
+ var samples = new[]
+ {
+ new SubtaskRowSampleViewModel { Title = "Extract DiffParser into its own class", Done = true },
+ new SubtaskRowSampleViewModel { Title = "Add unit tests for DiffParser", Done = true },
+ new SubtaskRowSampleViewModel { Title = "Wire new parser into DiffViewerViewModel" },
+ new SubtaskRowSampleViewModel { Title = "Update snapshot tests" },
+ };
+ foreach (var row in samples)
+ {
+ row.PropertyChanged += OnRowPropertyChanged;
+ Subtasks.Add(row);
+ }
+ }
+}
diff --git a/src/ClaudeDo.Ui/Views/Islands/Detail/DescriptionStepsCard.axaml b/src/ClaudeDo.Ui/Views/Islands/Detail/DescriptionStepsCard.axaml
new file mode 100644
index 0000000..be69475
--- /dev/null
+++ b/src/ClaudeDo.Ui/Views/Islands/Detail/DescriptionStepsCard.axaml
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ClaudeDo.Ui/Views/Islands/Detail/DescriptionStepsCard.axaml.cs b/src/ClaudeDo.Ui/Views/Islands/Detail/DescriptionStepsCard.axaml.cs
new file mode 100644
index 0000000..db581db
--- /dev/null
+++ b/src/ClaudeDo.Ui/Views/Islands/Detail/DescriptionStepsCard.axaml.cs
@@ -0,0 +1,35 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Platform;
+using Avalonia.Interactivity;
+using ClaudeDo.Ui.ViewModels.Islands.Detail;
+
+namespace ClaudeDo.Ui.Views.Islands.Detail;
+
+public partial class DescriptionStepsCard : UserControl
+{
+ public DescriptionStepsCard()
+ {
+ InitializeComponent();
+ }
+
+ private async void OnCopyClick(object? sender, RoutedEventArgs e)
+ {
+ if (DataContext is not DescriptionStepsCardViewModel vm) return;
+ var clipboard = TopLevel.GetTopLevel(this)?.Clipboard;
+ if (clipboard is null) return;
+ await clipboard.SetTextAsync(vm.ComposedPreview);
+ }
+
+ private void OnSubtaskTitleTapped(object? sender, TappedEventArgs e)
+ {
+ if (sender is TextBlock { DataContext: SubtaskRowSampleViewModel row })
+ row.IsEditing = true;
+ }
+
+ private void OnSubtaskEditLostFocus(object? sender, RoutedEventArgs e)
+ {
+ if (sender is TextBox { DataContext: SubtaskRowSampleViewModel row })
+ row.IsEditing = false;
+ }
+}