diff --git a/dedup.go b/dedup.go
deleted file mode 100644
index b53b8ff18c2d1f70cca24e98544d2f8d771099bb..0000000000000000000000000000000000000000
--- a/dedup.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package watch
-
-//
-//// dedup is a function that watches a set of paths and prints a message when
-//func (w *Watch) Decouple(waitFor time.Duration) {
-//	if waitFor == 0 {
-//		waitFor = 100 * time.Millisecond
-//	}
-//	go decoupleLoop(w.watcher, waitFor)
-//	<-make(chan struct{}) // Block forever
-//}
-//
-//// dedupLoop is the main loop for dedup.
-//func decoupleLoop(w *fsnotify.Watcher, waitFor time.Duration) {
-//	var (
-//		mu     sync.Mutex
-//		timers = make(map[string]*time.Timer)
-//
-//		printEvent = func(e fsnotify.Event) {
-//			fmt.Printf("%s: %s\n", e.Op, e.Name)
-//
-//			// Don't need to remove the timer if you don't have a lot of files.
-//			mu.Lock()
-//			delete(timers, e.Name)
-//			mu.Unlock()
-//		}
-//	)
-//
-//	for {
-//		select {
-//		// Read from Errors.
-//		case err, ok := <-w.Errors:
-//			if !ok { // Channel was closed (i.e. Watcher.Close() was called).
-//				return
-//			}
-//			fmt.Println("error:", err)
-//		// Read from Events.
-//		case e, ok := <-w.Events:
-//			if !ok { // Channel was closed (i.e. Watcher.Close() was called).
-//				return
-//			}
-//
-//			if e.Op&fsnotify.Chmod == fsnotify.Chmod {
-//				//util.Remove(fullPath)
-//			}
-//
-//			if e.Op&fsnotify.Write == fsnotify.Write {
-//				//util.Remove(fullPath)
-//			}
-//
-//			if e.Op&fsnotify.Create == fsnotify.Create {
-//				//logging.LogInfo("watching: created file: %s", d)
-//				//scanDirectory(fullPath, "")
-//				//navigation.AddFile(fullPath)
-//			}
-//
-//			if e.Op&fsnotify.Remove == fsnotify.Remove {
-//				//logging.LogInfo("watching: removed file: %s", d)
-//				//removeFromWatchlist(fullPath)
-//				//util.Remove(fullPath)
-//				//navigation.RemoveFile(fullPath)
-//			}
-//
-//			if e.Op&fsnotify.Rename == fsnotify.Rename {
-//				//logging.LogInfo("watching: renamed file: %s", event.Name)
-//				//removeFromWatchlist(fullPath)
-//				//util.Remove(fullPath)
-//				//navigation.RemoveFile(fullPath)
-//			}
-//
-//			// Get timer.
-//			mu.Lock()
-//			t, ok := timers[e.Name]
-//			mu.Unlock()
-//
-//			// No timer yet, so create one.
-//			if !ok {
-//				t = time.AfterFunc(math.MaxInt64, func() { printEvent(e) })
-//				t.Stop()
-//
-//				mu.Lock()
-//				timers[e.Name] = t
-//				mu.Unlock()
-//			}
-//
-//			// Reset the timer for this path, so it will start from 100ms again.
-//			t.Reset(waitFor)
-//		}
-//	}
-//}
diff --git a/lighthouse.go b/lighthouse.go
index 723cbea3ae3cc80cd949fd0510df1bc78e81150f..a2b503c64c27a5b34fc733b1f3525a64abe83dc1 100644
--- a/lighthouse.go
+++ b/lighthouse.go
@@ -15,6 +15,7 @@ type Watch struct {
 	OnChange EventCallback
 	OnDelete EventCallback
 	OnRename EventCallback
+	Tags     []string
 }
 
 type EventErrorCallback func(err error)
@@ -64,6 +65,10 @@ type Lighthouse interface {
 	Sync() error
 
 	IsInSync() bool
+
+	WatchListByTags(tags []string) []string
+
+	RemoveByTags(tags []string) error
 }
 
 // NewLighthouse creates a new lighthouse instance.
@@ -121,6 +126,33 @@ func (l *lighthouse) WatchList() []string {
 
 }
 
+// WatchListByTags returns a list of all watched paths with the given tags.
+func (l *lighthouse) WatchListByTags(tags []string) []string {
+
+	if len(tags) == 0 {
+		return l.WatchList()
+	}
+
+	l.mutex.Lock()
+	defer l.mutex.Unlock()
+	var list []string
+	for k := range l.watchers {
+
+		if len(l.watchers[k].Tags) == 0 {
+			continue
+		}
+
+		for _, tag := range tags {
+			if tag == k {
+				list = append(list, k)
+				break
+			}
+		}
+	}
+	return list
+
+}
+
 // IsInSync returns true if all paths are watched by fsnotify.
 func (l *lighthouse) IsInSync() bool {
 	l.mutex.Lock()
@@ -238,6 +270,46 @@ func (l *lighthouse) Add(watch *Watch) error {
 	return nil
 }
 
+func (l *lighthouse) RemoveByTags(tags []string) error {
+
+	if len(tags) == 0 {
+		return nil
+	}
+
+	l.mutex.Lock()
+	defer l.mutex.Unlock()
+
+	var errReturn error
+
+	for _, tag := range tags {
+
+		for k := range l.watchers {
+
+			if len(l.watchers[k].Tags) == 0 {
+				continue
+			}
+
+			for _, t := range l.watchers[k].Tags {
+				if t == tag {
+					err := l.fsnotify.Remove(k)
+					if err != nil {
+						if errReturn == nil {
+							errReturn = err
+						} else {
+							errReturn = fmt.Errorf("%w, %v", errReturn, err)
+						}
+					}
+					delete(l.watchers, k)
+					break
+				}
+			}
+		}
+	}
+
+	return errReturn
+
+}
+
 // Remove removes a path from the watcher. If the path is not being watched or
 // the watcher is not active, an error is returned.
 func (l *lighthouse) Remove(path string) error {
@@ -254,9 +326,9 @@ func (l *lighthouse) Remove(path string) error {
 		return UnwatchedPathError{UnwatchedPath: path}
 	}
 
+	err := l.fsnotify.Remove(path)
 	delete(l.watchers, path)
 
-	err := l.fsnotify.Remove(path)
 	if err != nil {
 		return err
 	}
diff --git a/lighthouse_test.go b/lighthouse_test.go
index f9118fd3938bc6a5d12995ae88dfaa0fda8dcc05..a62edbcc86f57a549de046782051fefd8bf3a6a9 100644
--- a/lighthouse_test.go
+++ b/lighthouse_test.go
@@ -2,12 +2,62 @@ package watch
 
 import (
 	"errors"
+	"github.com/stretchr/testify/assert"
 	"os"
 	"testing"
-
-	"github.com/stretchr/testify/assert"
+	"time"
 )
 
+func TestRemoveByTagsAndWatchListByTags(t *testing.T) {
+	l := NewLighthouse()
+	l.SetDebounce(500 * time.Millisecond)
+
+	tmpDir1 := t.TempDir()
+	tmpDir2 := t.TempDir()
+	tmpDir3 := t.TempDir()
+
+	// Add a few watches
+	err := l.Add(&Watch{Path: tmpDir1, Tags: []string{"tag1", "tag2"}})
+	if err != nil {
+		t.Errorf("Failed to add watch: %v", err)
+	}
+
+	err = l.Add(&Watch{Path: tmpDir2, Tags: []string{"tag1"}})
+	if err != nil {
+		t.Errorf("Failed to add watch: %v", err)
+	}
+
+	err = l.Add(&Watch{Path: tmpDir3, Tags: []string{"tag2"}})
+	if err != nil {
+		t.Errorf("Failed to add watch: %v", err)
+	}
+
+	// Test WatchListByTags
+	list := l.WatchListByTags([]string{"tag1"})
+	expectedList := []string{tmpDir1, tmpDir2}
+	for i, path := range list {
+		if path != expectedList[i] {
+			t.Errorf("Expected %s, got %s", expectedList[i], path)
+		}
+	}
+
+	// Test RemoveByTags
+	err = l.RemoveByTags([]string{"tag1"})
+	if err != nil {
+		t.Errorf("Failed to remove by tags: %v", err)
+	}
+
+	// Confirm removal
+	if l.IsWatched(tmpDir1) || l.IsWatched(tmpDir2) {
+		t.Errorf("RemoveByTags did not remove the watches correctly")
+	}
+
+	// Confirm remaining watch
+	if !l.IsWatched(tmpDir3) {
+		t.Errorf("RemoveByTags removed an unrelated watch")
+	}
+}
+
 func TestAddWatch(t *testing.T) {
 	tempDir, err := os.MkdirTemp("", "watchtest")
 	assert.Nil(t, err)