diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs
index ba13b96a..5d9916c9 100644
--- a/helix-dap/src/client.rs
+++ b/helix-dap/src/client.rs
@@ -27,8 +27,6 @@ pub struct Client {
     server_tx: UnboundedSender<Request>,
     request_counter: AtomicU64,
     pub caps: Option<DebuggerCapabilities>,
-    //
-    pub breakpoints: HashMap<PathBuf, Vec<SourceBreakpoint>>,
     // thread_id -> frames
     pub stack_frames: HashMap<usize, Vec<StackFrame>>,
     pub thread_states: HashMap<usize, String>,
@@ -77,7 +75,6 @@ impl Client {
             request_counter: AtomicU64::new(0),
             caps: None,
             //
-            breakpoints: HashMap::new(),
             stack_frames: HashMap::new(),
             thread_states: HashMap::new(),
             thread_id: None,
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index d74f9198..5fc35977 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -320,10 +320,18 @@ impl Application {
                         None => "Debug:".to_owned(),
                     };
 
+                    log::info!("{}", output);
                     self.editor.set_status(format!("{} {}", prefix, output));
                 }
                 Event::Initialized => {
                     // send existing breakpoints
+                    for (path, breakpoints) in &self.editor.breakpoints {
+                        // TODO: call futures in parallel, await all
+                        debugger
+                            .set_breakpoints(path.clone(), breakpoints.clone())
+                            .await
+                            .unwrap();
+                    }
                     // TODO: fetch breakpoints (in case we're attaching)
 
                     if let Ok(_) = debugger.configuration_done().await {
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 3e740ead..7b207837 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -1999,35 +1999,38 @@ mod cmd {
                 bail!("Can't edit breakpoint: document has no path")
             }
         };
-        if let Some(debugger) = &mut cx.editor.debugger {
-            if breakpoint.condition.is_some()
-                && !debugger
-                    .caps
-                    .as_ref()
-                    .unwrap()
-                    .supports_conditional_breakpoints
-                    .unwrap_or_default()
-            {
-                bail!("Can't edit breakpoint: debugger does not support conditional breakpoints")
-            }
-            if breakpoint.log_message.is_some()
-                && !debugger
-                    .caps
-                    .as_ref()
-                    .unwrap()
-                    .supports_log_points
-                    .unwrap_or_default()
-            {
-                bail!("Can't edit breakpoint: debugger does not support logpoints")
-            }
 
-            let breakpoints = debugger.breakpoints.entry(path.clone()).or_default();
-            if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) {
-                breakpoints.remove(pos);
-                breakpoints.push(breakpoint);
+        let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
+        if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) {
+            breakpoints.remove(pos);
+            breakpoints.push(breakpoint);
 
-                let breakpoints = breakpoints.clone();
+            let breakpoints = breakpoints.clone();
 
+            if let Some(debugger) = &mut cx.editor.debugger {
+                // TODO: handle capabilities correctly again, by filterin breakpoints when emitting
+                // if breakpoint.condition.is_some()
+                //     && !debugger
+                //         .caps
+                //         .as_ref()
+                //         .unwrap()
+                //         .supports_conditional_breakpoints
+                //         .unwrap_or_default()
+                // {
+                //     bail!(
+                //         "Can't edit breakpoint: debugger does not support conditional breakpoints"
+                //     )
+                // }
+                // if breakpoint.log_message.is_some()
+                //     && !debugger
+                //         .caps
+                //         .as_ref()
+                //         .unwrap()
+                //         .supports_log_points
+                //         .unwrap_or_default()
+                // {
+                //     bail!("Can't edit breakpoint: debugger does not support logpoints")
+                // }
                 let request = debugger.set_breakpoints(path, breakpoints);
                 if let Err(e) = block_on(request) {
                     bail!("Failed to set breakpoints: {:?}", e)
diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs
index 7618fca2..5c415ca4 100644
--- a/helix-term/src/commands/dap.rs
+++ b/helix-term/src/commands/dap.rs
@@ -279,12 +279,7 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) {
     // TODO: need to map breakpoints over edits and update them?
     // we shouldn't really allow editing while debug is running though
 
-    let debugger = match &mut cx.editor.debugger {
-        Some(debugger) => debugger,
-        None => return,
-    };
-
-    let breakpoints = debugger.breakpoints.entry(path.clone()).or_default();
+    let breakpoints = cx.editor.breakpoints.entry(path.clone()).or_default();
     if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) {
         breakpoints.remove(pos);
     } else {
@@ -293,6 +288,10 @@ pub fn dap_toggle_breakpoint(cx: &mut Context) {
 
     let breakpoints = breakpoints.clone();
 
+    let debugger = match &mut cx.editor.debugger {
+        Some(debugger) => debugger,
+        None => return,
+    };
     let request = debugger.set_breakpoints(path, breakpoints);
     if let Err(e) = block_on(request) {
         cx.editor
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 17a2df3d..818d275f 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -26,7 +26,7 @@ use helix_view::{
     keyboard::{KeyCode, KeyModifiers},
     Document, Editor, Theme, View,
 };
-use std::borrow::Cow;
+use std::{borrow::Cow, collections::HashMap, path::PathBuf};
 
 use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind};
 use tui::buffer::Buffer as Surface;
@@ -76,6 +76,7 @@ impl EditorView {
         loader: &syntax::Loader,
         config: &helix_view::editor::Config,
         debugger: &Option<helix_dap::Client>,
+        breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
     ) {
         let inner = view.inner_area();
         let area = view.area;
@@ -93,7 +94,15 @@ impl EditorView {
 
         Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights);
         Self::render_gutter(
-            doc, view, view.area, surface, theme, is_focused, config, debugger,
+            doc,
+            view,
+            view.area,
+            surface,
+            theme,
+            is_focused,
+            config,
+            debugger,
+            breakpoints,
         );
 
         if is_focused {
@@ -113,7 +122,7 @@ impl EditorView {
             }
         }
 
-        self.render_diagnostics(doc, view, inner, surface, theme, debugger);
+        self.render_diagnostics(doc, view, inner, surface, theme, breakpoints);
 
         let statusline_area = view
             .area
@@ -417,6 +426,7 @@ impl EditorView {
         is_focused: bool,
         config: &helix_view::editor::Config,
         debugger: &Option<helix_dap::Client>,
+        all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
     ) {
         let text = doc.text().slice(..);
         let last_line = view.last_line(doc);
@@ -448,10 +458,9 @@ impl EditorView {
 
         let mut breakpoints: Option<&Vec<SourceBreakpoint>> = None;
         let mut stack_frame: Option<&StackFrame> = None;
-        if let Some(debugger) = debugger {
-            if let Some(path) = doc.path() {
-                breakpoints = debugger.breakpoints.get(path);
-
+        if let Some(path) = doc.path() {
+            breakpoints = all_breakpoints.get(path);
+            if let Some(debugger) = debugger {
                 // if we have a frame, and the frame path matches document
                 if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id)
                 {
@@ -551,7 +560,7 @@ impl EditorView {
         viewport: Rect,
         surface: &mut Surface,
         theme: &Theme,
-        debugger: &Option<helix_dap::Client>,
+        all_breakpoints: &HashMap<PathBuf, Vec<helix_dap::SourceBreakpoint>>,
     ) {
         use helix_core::diagnostic::Severity;
         use tui::{
@@ -589,26 +598,23 @@ impl EditorView {
             lines.extend(text.lines);
         }
 
-        if let Some(debugger) = debugger {
-            if let Some(path) = doc.path() {
-                if let Some(breakpoints) = debugger.breakpoints.get(path) {
-                    let line = doc.text().char_to_line(cursor);
-                    if let Some(breakpoint) = breakpoints
-                        .iter()
-                        .find(|breakpoint| breakpoint.line - 1 == line)
-                    {
-                        if let Some(condition) = &breakpoint.condition {
-                            lines.extend(
-                                Text::styled(condition, info.add_modifier(Modifier::UNDERLINED))
-                                    .lines,
-                            );
-                        }
-                        if let Some(log_message) = &breakpoint.log_message {
-                            lines.extend(
-                                Text::styled(log_message, info.add_modifier(Modifier::UNDERLINED))
-                                    .lines,
-                            );
-                        }
+        if let Some(path) = doc.path() {
+            if let Some(breakpoints) = all_breakpoints.get(path) {
+                let line = doc.text().char_to_line(cursor);
+                if let Some(breakpoint) = breakpoints
+                    .iter()
+                    .find(|breakpoint| breakpoint.line - 1 == line)
+                {
+                    if let Some(condition) = &breakpoint.condition {
+                        lines.extend(
+                            Text::styled(condition, info.add_modifier(Modifier::UNDERLINED)).lines,
+                        );
+                    }
+                    if let Some(log_message) = &breakpoint.log_message {
+                        lines.extend(
+                            Text::styled(log_message, info.add_modifier(Modifier::UNDERLINED))
+                                .lines,
+                        );
                     }
                 }
             }
@@ -1224,6 +1230,7 @@ impl Component for EditorView {
                 loader,
                 &cx.editor.config,
                 &cx.editor.debugger,
+                &cx.editor.breakpoints,
             );
         }
 
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index f87ae318..adc40eb4 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -11,6 +11,7 @@ use futures_util::stream::select_all::SelectAll;
 use tokio_stream::wrappers::UnboundedReceiverStream;
 
 use std::{
+    collections::HashMap,
     path::{Path, PathBuf},
     sync::Arc,
     time::Duration,
@@ -24,6 +25,7 @@ pub use helix_core::diagnostic::Severity;
 pub use helix_core::register::Registers;
 use helix_core::syntax::{self, DebugConfigCompletion};
 use helix_core::Position;
+use helix_dap as dap;
 
 use serde::Deserialize;
 
@@ -81,8 +83,9 @@ pub struct Editor {
     pub theme: Theme,
     pub language_servers: helix_lsp::Registry,
 
-    pub debugger: Option<helix_dap::Client>,
-    pub debugger_events: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>,
+    pub debugger: Option<dap::Client>,
+    pub debugger_events: SelectAll<UnboundedReceiverStream<dap::Payload>>,
+    pub breakpoints: HashMap<PathBuf, Vec<dap::SourceBreakpoint>>,
     pub debug_config_picker: Option<Vec<String>>,
     pub debug_config_completions: Option<Vec<Vec<DebugConfigCompletion>>>,
     pub variables: Option<Vec<String>>,
@@ -127,6 +130,7 @@ impl Editor {
             language_servers,
             debugger: None,
             debugger_events: SelectAll::new(),
+            breakpoints: HashMap::new(),
             debug_config_picker: None,
             debug_config_completions: None,
             variables: None,