# Shallow vs Recursive Watching in agentsview: A Technical Guide

> Understand shallow vs recursive watching in agentsview. Learn how shallow watching conserves OS file descriptors while recursive watching detects instant changes in subdirectories. Optimize file system monitoring.

- Repository: [Kenn Software/agentsview](https://github.com/kenn-io/agentsview)
- Tags: deep-dive
- Published: 2026-06-20

---

**agentsview employs two distinct file-system monitoring modes—recursive watching, which registers every subdirectory for instant change detection, and shallow watching, which monitors only root directories to conserve OS file descriptors.**

The **agentsview** sync engine leverages the **fsnotify** library to detect file changes within session directories. To balance immediate change detection against operating system resource constraints, the codebase implements specific **shallow and recursive watching** strategies that prevent `EMFILE` errors while ensuring the synchronization engine captures critical file events.

## What Is Recursive Watching in agentsview?

Recursive watching establishes comprehensive monitoring across an entire directory tree. When activated, the watcher traverses the target path and registers every subdirectory with the underlying **fsnotify** instance.

### How Recursive Watching Works

In [`internal/sync/watcher.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/watcher.go), the `WatchRecursive` function implements this behavior using `filepath.WalkDir` to enumerate directories. For each directory encountered, it invokes `watcher.Add` to register the path with the kernel's notification subsystem 【/blob/main/internal/sync/watcher.go#L72-L79】.

The system also monitors for newly created directories dynamically. The `watchIfDir` helper automatically adds these paths to the watch list upon receiving a `Create` event, ensuring the watcher maintains complete coverage as the filesystem evolves 【/blob/main/internal/sync/watcher.go#L85-L99】.

This mode provides immediate notification of any file creation, modification, or deletion within the watched hierarchy. It suits session directories containing moderate numbers of subfolders where synchronization latency must remain minimal.

## What Is Shallow Watching in agentsview?

Shallow watching restricts monitoring to the root directory only, explicitly excluding subdirectories from the watch list. This conservative approach targets directories containing thousands of subfolders—such as dated session archives—where recursive watching would exhaust available file descriptors.

### When to Use Shallow Mode

The `WatchShallow` method in [`internal/sync/watcher.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/watcher.go) adds the specified path to an internal `roots` slice and marks it as a shallow root. Unlike its recursive counterpart, this function calls `watcher.Add` exactly once for the root directory 【/blob/main/internal/sync/watcher.go#L30-L38】.

Rather than depending on filesystem events for nested content, shallow mode relies on the periodic sync engine (running every 15 minutes) to discover and process new files. This trades immediacy for scalability, preventing the `EMFILE` or `ENOSPC` errors that occur when **fsnotify** consumes the operating system's per-process file descriptor limit.

## Key Differences: Resource Utilization and Responsiveness

The distinction between these modes centers on two critical factors:

- **File Descriptor Consumption**: Recursive watching consumes one descriptor per subdirectory, while shallow watching uses exactly one descriptor per root. On systems with thousands of session subfolders, shallow mode avoids exhausting the `ulimit` or `inotify` watch limits.
- **Detection Latency**: Recursive watching triggers immediate callbacks for any file change. Shallow watching delays detection until the next periodic synchronization cycle, making it suitable for archival directories where real-time sync is unnecessary.

## Interaction Between Shallow and Recursive Roots

A critical architectural detail involves how these modes coexist within the same watcher instance. A **shallow root does not shadow a deeper recursive root**.

If a shallow parent (for example, `.codex`) contains a nested directory configured for recursive watching (such as `.codex/sessions`), the child maintains its autonomous watch behavior. New subdirectories created within the recursive child are automatically added to the watch list, while those created in the shallow parent remain unwatched.

The `isUnderShallowRoot` function enforces this logic by identifying the most specific containing root before deciding whether to auto-watch a newly detected directory 【/blob/main/internal/sync/watcher.go#L55-L69】. This check ensures that granular watch policies take precedence over broad shallow declarations.

## Implementation Examples

The following examples demonstrate how to instantiate watchers using the agentsview sync package.

Recursive watch configuration:

```go
import "github.com/kenn-io/agentsview/internal/sync"

// Monitor all subdirectories under /data/sessions
w, _ := sync.NewWatcher(500*time.Millisecond, onChange, nil)
w.WatchRecursive("/data/sessions")   // Walks tree and adds every directory
w.Start()

```

Shallow watch configuration:

```go
import "github.com/kenn-io/agentsview/internal/sync"

// Monitor only the root /data/sessions directory
w, _ := sync.NewWatcher(500*time.Millisecond, onChange, nil)
w.WatchShallow("/data/sessions")    // Watches only the root, ignores subdirs
w.Start()

```

## Summary

- **Recursive watching** traverses the entire directory tree via `WatchRecursive` in [`internal/sync/watcher.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/watcher.go), registering each subdirectory with **fsnotify** for immediate change detection.
- **Shallow watching** monitors only the root directory via `WatchShallow`, conserving file descriptors by ignoring subdirectories and relying on periodic synchronization every 15 minutes.
- The **resource trade-off** involves file descriptor consumption: recursive mode risks `EMFILE` errors on large trees, while shallow mode scales indefinitely but delays change detection.
- **Hierarchical isolation** via `isUnderShallowRoot` ensures recursive children of shallow parents maintain independent auto-watch capabilities without interference.

## Frequently Asked Questions

### What is the main performance difference between shallow and recursive watching in agentsview?

The primary distinction involves file descriptor consumption and detection latency. Recursive watching consumes one file descriptor per subdirectory and provides instant notifications, while shallow watching uses minimal descriptors but delays detection until the next periodic sync cycle (approximately 15 minutes).

### Can I mix shallow and recursive watching in the same agentsview instance?

Yes. The watcher supports heterogeneous configurations where shallow roots coexist with recursive ones. The `isUnderShallowRoot` function ensures that directories under recursive roots maintain their auto-watch behavior even when nested inside shallowly-watched parent directories.

### Where does agentsview handle automatic directory addition in recursive mode?

The `watchIfDir` helper function in [`internal/sync/watcher.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/watcher.go) processes `Create` events to determine if the new path is a directory. If so, it automatically adds the directory to the **fsnotify** watcher, ensuring recursive coverage expands dynamically as the filesystem changes.

### When should I use shallow watching over recursive watching?

Apply shallow watching to directories containing thousands of subfolders (such as date-based session archives) where recursive watching risks exhausting the OS file descriptor limit. Use recursive watching for smaller, actively modified directory trees where immediate synchronization is critical.