diff --git a/src/main/java/com/maddyhome/idea/vim/group/MotionGroup.kt b/src/main/java/com/maddyhome/idea/vim/group/MotionGroup.kt
index 692278764..b5043497a 100755
--- a/src/main/java/com/maddyhome/idea/vim/group/MotionGroup.kt
+++ b/src/main/java/com/maddyhome/idea/vim/group/MotionGroup.kt
@@ -33,6 +33,8 @@ import com.maddyhome.idea.vim.api.VimEditor
 import com.maddyhome.idea.vim.api.VimMotionGroupBase
 import com.maddyhome.idea.vim.api.addJump
 import com.maddyhome.idea.vim.api.anyNonWhitespace
+import com.maddyhome.idea.vim.api.getJump
+import com.maddyhome.idea.vim.api.getJumpSpot
 import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
 import com.maddyhome.idea.vim.api.getVisualLineCount
 import com.maddyhome.idea.vim.api.injector
@@ -163,8 +165,8 @@ internal class MotionGroup : VimMotionGroupBase() {
 
   override fun moveCaretToJump(editor: VimEditor, caret: ImmutableVimCaret, count: Int): Motion {
     val jumpService = injector.jumpService
-    val spot = jumpService.getJumpSpot()
-    val (line, col, fileName) = jumpService.getJump(count) ?: return Motion.Error
+    val spot = jumpService.getJumpSpot(editor)
+    val (line, col, fileName) = jumpService.getJump(editor, count) ?: return Motion.Error
     val vf = EditorHelper.getVirtualFile(editor.ij) ?: return Motion.Error
     val lp = BufferPosition(line, col, false)
     val lpNative = LogicalPosition(line, col, false)
diff --git a/src/main/java/com/maddyhome/idea/vim/group/VimJumpServiceImpl.kt b/src/main/java/com/maddyhome/idea/vim/group/VimJumpServiceImpl.kt
index 077740d24..e8f668501 100644
--- a/src/main/java/com/maddyhome/idea/vim/group/VimJumpServiceImpl.kt
+++ b/src/main/java/com/maddyhome/idea/vim/group/VimJumpServiceImpl.kt
@@ -15,6 +15,7 @@ import com.intellij.openapi.components.Storage
 import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
 import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl.PlaceInfo
 import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl.RecentPlacesListener
+import com.intellij.openapi.project.Project
 import com.intellij.openapi.util.text.StringUtil
 import com.maddyhome.idea.vim.api.VimEditor
 import com.maddyhome.idea.vim.api.VimJumpServiceBase
@@ -26,6 +27,7 @@ import com.maddyhome.idea.vim.newapi.globalIjOptions
 import com.maddyhome.idea.vim.newapi.ij
 import org.jdom.Element
 
+
 @State(name = "VimJumpsSettings", storages = [Storage(value = "\$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)])
 internal class VimJumpServiceImpl : VimJumpServiceBase(), PersistentStateComponent<Element?> {
   companion object {
@@ -40,60 +42,72 @@ internal class VimJumpServiceImpl : VimJumpServiceBase(), PersistentStateCompone
     }
   }
 
+  // We do not delete old project records.
+  // Rationale: It's more likely that users will want to review their old projects and access their jump history 
+  // (e.g., recent files), than for the 100 jumps (max number of records) to consume enough space to be noticeable.
   override fun getState(): Element {
-    val jumpsElem = Element("jumps")
-    for (jump in jumps) {
-      val jumpElem = Element("jump")
-      jumpElem.setAttribute("line", jump.line.toString())
-      jumpElem.setAttribute("column", jump.col.toString())
-      jumpElem.setAttribute("filename", StringUtil.notNullize(jump.filepath))
-      jumpsElem.addContent(jumpElem)
-      if (logger.isDebug()) {
-        logger.debug("saved jump = $jump")
+    val projectsElem = Element("projects")
+    for ((project, jumps) in projectToJumps) {
+      val projectElement = Element("project").setAttribute("id", project)
+      for (jump in jumps) {
+        val jumpElem = Element("jump")
+        jumpElem.setAttribute("line", jump.line.toString())
+        jumpElem.setAttribute("column", jump.col.toString())
+        jumpElem.setAttribute("filename", StringUtil.notNullize(jump.filepath))
+        projectElement.addContent(jumpElem)
+        if (logger.isDebug()) {
+          logger.debug("saved jump = $jump")
+        }
       }
+      projectsElem.addContent(projectElement)
     }
-    return jumpsElem
+    return projectsElem
   }
 
   override fun loadState(state: Element) {
-    val jumpList = state.getChildren("jump")
-    for (jumpElement in jumpList) {
-      val jump = Jump(
-        Integer.parseInt(jumpElement.getAttributeValue("line")),
-        Integer.parseInt(jumpElement.getAttributeValue("column")),
-        jumpElement.getAttributeValue("filename"),
-      )
-      jumps.add(jump)
-    }
-
-    if (logger.isDebug()) {
-      logger.debug("jumps=$jumps")
+    val projectElements = state.getChildren("project")
+    for (projectElement in projectElements) {
+      val jumps = mutableListOf<Jump>()
+      val jumpElements = projectElement.getChildren("jump")
+      for (jumpElement in jumpElements) {
+        val jump = Jump(
+          Integer.parseInt(jumpElement.getAttributeValue("line")),
+          Integer.parseInt(jumpElement.getAttributeValue("column")),
+          jumpElement.getAttributeValue("filename"),
+        )
+        jumps.add(jump)
+      }
+      if (logger.isDebug()) {
+        logger.debug("jumps=$jumps")
+      }
+      val projectId = projectElement.getAttributeValue("id")
+      projectToJumps[projectId] = jumps
     }
   }
 }
 
-internal class JumpsListener : RecentPlacesListener {
+internal class JumpsListener(val project: Project) : RecentPlacesListener {
   override fun recentPlaceAdded(changePlace: PlaceInfo, isChanged: Boolean) {
     if (!injector.globalIjOptions().unifyjumps) return
-
+    
     val jumpService = injector.jumpService
     if (!isChanged) {
       if (changePlace.timeStamp < jumpService.lastJumpTimeStamp) return // this listener is notified asynchronously, and
       // we do not want jumps that were processed before
       val jump = buildJump(changePlace) ?: return
-      jumpService.addJump(jump, true)
+      jumpService.addJump(project.basePath ?: IjVimEditor.DEFAULT_PROJECT_ID, jump, true)
     }
   }
 
   override fun recentPlaceRemoved(changePlace: PlaceInfo, isChanged: Boolean) {
     if (!injector.globalIjOptions().unifyjumps) return
-
+    
     val jumpService = injector.jumpService
     if (!isChanged) {
       if (changePlace.timeStamp < jumpService.lastJumpTimeStamp) return // this listener is notified asynchronously, and
       // we do not want jumps that were processed before
       val jump = buildJump(changePlace) ?: return
-      jumpService.removeJump(jump)
+      jumpService.removeJump(project.basePath ?: IjVimEditor.DEFAULT_PROJECT_ID, jump)
     }
   }
 
diff --git a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt
index 7f8bf665f..e1fc2b503 100644
--- a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt
+++ b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt
@@ -64,6 +64,11 @@ import java.lang.System.identityHashCode
 
 @ApiStatus.Internal
 internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
+  companion object {
+    // For cases where Editor does not have a project (for some reason)
+    // It's something IJ Platform related and stored here because of this reason
+    const val DEFAULT_PROJECT_ID = "no project" 
+  }
 
   // All the editor actions should be performed with top level editor!!!
   // Be careful: all the EditorActionHandler implementation should correctly process InjectedEditors
@@ -369,6 +374,8 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor() {
     return EditorHelper.getVirtualFile(editor)?.getUrl()?.let { VirtualFileManager.extractProtocol(it) }
   }
 
+  override val projectId = editor.project?.basePath ?: DEFAULT_PROJECT_ID
+
   override fun visualPositionToOffset(position: VimVisualPosition): Offset {
     return editor.visualPositionToOffset(VisualPosition(position.line, position.column, position.leansRight)).offset
   }
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt
index 8abca73b6..38a33e4fa 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt
@@ -242,6 +242,9 @@ public interface VimEditor {
 
   public fun getPath(): String?
   public fun extractProtocol(): String?
+  
+  // Can be used as a key to store something for specific project
+  public val projectId: String
 
   public fun exitInsertMode(context: ExecutionContext, operatorArguments: OperatorArguments)
   public fun exitSelectModeNative(adjustCaret: Boolean)
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpService.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpService.kt
index 272622adf..ac58aded6 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpService.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpService.kt
@@ -9,9 +9,14 @@
 package com.maddyhome.idea.vim.api
 
 import com.maddyhome.idea.vim.mark.Jump
+import org.jetbrains.annotations.TestOnly
 
 // todo should it be multicaret?
 // todo docs
+// todo it would be better to have some Vim scope for this purpose (p:), to store things project-wise like for buffers
+/**
+ * This service manages jump lists for different projects
+ */
 public interface VimJumpService {
   /**
    * Timestamp (`System.currentTimeMillis()`) of the last Jump command <C-o>, <C-i>
@@ -19,17 +24,23 @@ public interface VimJumpService {
    * and messes up our jump list
    */
   public var lastJumpTimeStamp: Long
-
-  public fun includeCurrentCommandAsNavigation(editor: VimEditor)
-  public fun getJumpSpot(): Int
-  public fun getJump(count: Int): Jump?
-  public fun getJumps(): List<Jump>
-  public fun addJump(jump: Jump, reset: Boolean)
+  
+  public fun getJump(projectId: String, count: Int): Jump?
+  public fun getJumps(projectId: String): List<Jump>
+  public fun getJumpSpot(projectId: String): Int
+  
+  public fun addJump(projectId: String, jump: Jump, reset: Boolean)
   public fun saveJumpLocation(editor: VimEditor)
-  public fun removeJump(jump: Jump)
-  public fun dropLastJump()
-  public fun updateJumpsFromInsert(editor: VimEditor, startOffset: Int, length: Int)
-  public fun updateJumpsFromDelete(editor: VimEditor, startOffset: Int, length: Int)
+  
+  public fun removeJump(projectId: String, jump: Jump)
+  public fun dropLastJump(projectId: String)
+  
+  public fun updateJumpsFromInsert(projectId: String, startOffset: Int, length: Int)
+  public fun updateJumpsFromDelete(projectId: String, startOffset: Int, length: Int)
+  
+  public fun includeCurrentCommandAsNavigation(editor: VimEditor)
+  
+  @TestOnly
   public fun resetJumps()
 }
 
@@ -37,5 +48,33 @@ public fun VimJumpService.addJump(editor: VimEditor, reset: Boolean) {
   val path = editor.getPath() ?: return
   val position = editor.offsetToBufferPosition(editor.currentCaret().offset.point)
   val jump = Jump(position.line, position.column, path)
-  addJump(jump, reset)
+  addJump(editor, jump, reset)
+}
+
+public fun VimJumpService.getJump(editor: VimEditor, count: Int): Jump? {
+  return getJump(editor.projectId, count)
+}
+public fun VimJumpService.getJumps(editor: VimEditor): List<Jump> {
+  return getJumps(editor.projectId)
+}
+public fun VimJumpService.getJumpSpot(editor: VimEditor): Int {
+  return getJumpSpot(editor.projectId)
+}
+
+public fun VimJumpService.addJump(editor: VimEditor, jump: Jump, reset: Boolean) {
+  return addJump(editor.projectId, jump, reset)
+}
+
+public fun VimJumpService.removeJump(editor: VimEditor, jump: Jump) {
+  return removeJump(editor.projectId, jump)
+}
+public fun VimJumpService.dropLastJump(editor: VimEditor) {
+  return dropLastJump(editor.projectId)
+}
+
+public fun VimJumpService.updateJumpsFromInsert(editor: VimEditor, startOffset: Int, length: Int) {
+  return updateJumpsFromInsert(editor.projectId, startOffset, length)
+}
+public fun VimJumpService.updateJumpsFromDelete(editor: VimEditor, startOffset: Int, length: Int) {
+  return updateJumpsFromDelete(editor.projectId, startOffset, length)
 }
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpServiceBase.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpServiceBase.kt
index 78f15883a..9dc6c3575 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpServiceBase.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimJumpServiceBase.kt
@@ -11,51 +11,36 @@ package com.maddyhome.idea.vim.api
 import com.maddyhome.idea.vim.mark.Jump
 
 public abstract class VimJumpServiceBase : VimJumpService {
-  @JvmField
-  protected val jumps: MutableList<Jump> = ArrayList() // todo should it be mutable?
-  @JvmField
-  protected var jumpSpot: Int = -1
+  protected val projectToJumps: MutableMap<String, MutableList<Jump>> = mutableMapOf()
+  protected val projectToJumpSpot: MutableMap<String, Int> = mutableMapOf()
 
-  override fun getJumpSpot(): Int {
-    return jumpSpot
-  }
-
-  override fun getJump(count: Int): Jump? {
-    val index = jumps.size - 1 - (jumpSpot - count)
-    return if (index < 0 || index >= jumps.size) {
-      null
-    } else {
-      jumpSpot -= count
-      jumps[index]
+  override fun getJump(projectId: String, count: Int): Jump? {
+    val jumps = projectToJumps[projectId] ?: mutableListOf()
+    projectToJumpSpot.putIfAbsent(projectId, -1)
+    val index = jumps.size - 1 - (projectToJumpSpot[projectId]!! - count)
+    return jumps.getOrNull(index)?.also { 
+      projectToJumpSpot[projectId] = projectToJumpSpot[projectId]!! - count 
     }
   }
 
-  override fun getJumps(): List<Jump> {
-    return jumps
+  override fun getJumps(projectId: String): List<Jump> {
+    return projectToJumps[projectId] ?: emptyList()
   }
 
-  override fun addJump(jump: Jump, reset: Boolean) {
+  override fun getJumpSpot(projectId: String): Int {
+    return projectToJumpSpot[projectId] ?: -1
+  }
+
+  override fun addJump(projectId: String, jump: Jump, reset: Boolean) {
     lastJumpTimeStamp = System.currentTimeMillis()
-    val filename = jump.filepath
-
-    for (i in jumps.indices) {
-      val j = jumps[i]
-      if (filename == j.filepath && j.line == jump.line) {
-        jumps.removeAt(i)
-        break
-      }
-    }
-
+    val jumps = projectToJumps.getOrPut(projectId) { mutableListOf() }
+    jumps.removeIf { it.filepath == jump.filepath && it.line == jump.line }
     jumps.add(jump)
 
-    if (reset) {
-      jumpSpot = -1
-    } else {
-      jumpSpot++
-    }
+    projectToJumpSpot[projectId] = if (reset) -1 else (projectToJumpSpot[projectId] ?: -1) + 1
 
     if (jumps.size > SAVE_JUMP_COUNT) {
-      jumps.removeAt(0)
+      jumps.removeFirst()
     }
   }
 
@@ -65,26 +50,25 @@ public abstract class VimJumpServiceBase : VimJumpService {
     includeCurrentCommandAsNavigation(editor)
   }
 
-  override fun removeJump(jump: Jump) {
-    val lastIndex = jumps.withIndex().findLast { it.value == jump }?.index ?: return
-    jumps.removeAt(lastIndex)
+  override fun removeJump(projectId: String, jump: Jump) {
+    projectToJumps[projectId]?.removeIf { it == jump }
   }
 
-  override fun dropLastJump() {
-    jumps.removeLast()
+  override fun dropLastJump(projectId: String) {
+    projectToJumps[projectId]?.removeLastOrNull()
   }
 
-  override fun updateJumpsFromInsert(editor: VimEditor, startOffset: Int, length: Int) {
+  override fun updateJumpsFromInsert(projectId: String, startOffset: Int, length: Int) {
     TODO("Not yet implemented")
   }
 
-  override fun updateJumpsFromDelete(editor: VimEditor, startOffset: Int, length: Int) {
+  override fun updateJumpsFromDelete(projectId: String, startOffset: Int, length: Int) {
     TODO("Not yet implemented")
   }
 
   override fun resetJumps() {
-    jumps.clear()
-    jumpSpot = -1
+    projectToJumps.clear()
+    projectToJumpSpot.clear()
   }
 
   public companion object {
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMarkServiceBase.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMarkServiceBase.kt
index c4f3c78c5..e3b350a5a 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMarkServiceBase.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMarkServiceBase.kt
@@ -46,10 +46,10 @@ public abstract class VimMarkServiceBase : VimMarkService {
   }
 
   @JvmField
-  protected val globalMarks: java.util.HashMap<Char, Mark> = HashMap()
+  protected val globalMarks: HashMap<Char, Mark> = HashMap()
 
   // marks are stored for primary caret only
-  protected val filepathToLocalMarks: java.util.HashMap<String, LocalMarks<Char, Mark>> = HashMap()
+  protected val filepathToLocalMarks: HashMap<String, LocalMarks<Char, Mark>> = HashMap()
 
   public class LocalMarks<K, V> : HashMap<K, V>() {
     public var myTimestamp: Date = Date()
@@ -185,7 +185,7 @@ public abstract class VimMarkServiceBase : VimMarkService {
         if (caret.isPrimary) {
           if (mark.key == BEFORE_JUMP_MARK) {
             val jump = Jump(mark.line, mark.col, mark.filepath)
-            injector.jumpService.addJump(jump, true)
+            injector.jumpService.addJump(editor, jump, true)
           }
           getLocalMarks(mark.filepath)[markChar] = mark
         } else {
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt
index cac4440d9..ad0778740 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt
@@ -11,6 +11,8 @@ package com.maddyhome.idea.vim.vimscript.model.commands
 import com.intellij.vim.annotations.ExCommand
 import com.maddyhome.idea.vim.api.ExecutionContext
 import com.maddyhome.idea.vim.api.VimEditor
+import com.maddyhome.idea.vim.api.getJumpSpot
+import com.maddyhome.idea.vim.api.getJumps
 import com.maddyhome.idea.vim.api.injector
 import com.maddyhome.idea.vim.command.OperatorArguments
 import com.maddyhome.idea.vim.ex.ranges.Ranges
@@ -25,8 +27,8 @@ import kotlin.math.absoluteValue
 public data class JumpsCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) {
   override val argFlags: CommandHandlerFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY)
   override fun processCommand(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments): ExecutionResult {
-    val jumps = injector.jumpService.getJumps()
-    val spot = injector.jumpService.getJumpSpot()
+    val jumps = injector.jumpService.getJumps(editor)
+    val spot = injector.jumpService.getJumpSpot(editor)
 
     val text = StringBuilder(" jump line  col file/text\n")
     jumps.forEachIndexed { idx, jump ->