# How tuicr Tracks Active Sessions: The `active_sessions.json` Manifest Explained

> Discover how tuicr tracks active sessions using the active_sessions.json manifest. Learn about process IDs, slugs, file paths, and timestamps for efficient session management.

- Repository: [Almog Gavra/tuicr](https://github.com/agavra/tuicr)
- Tags: internals
- Published: 2026-08-02

---

**tuicr maintains a JSON manifest called [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) that records every running TUI review session by process ID, unique slug, file path, and last-seen timestamp, enabling session discovery, automatic cleanup, and cross-process coordination.**

The `tuicr` codebase (available at `agavra/tuicr`) implements a robust session tracking system for its terminal-based code review interface. When multiple TUI sessions run concurrently—or when crashes leave behind stale state—the [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) manifest provides the source of truth for which review sessions are currently active.

## What is the [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) Manifest?

The [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) file is a machine-readable index stored alongside review data in `~/.local/share/tuicr/reviews/`. Unlike [`index.json`](https://github.com/agavra/tuicr/blob/main/index.json), which catalogs all review sessions ever created, this manifest specifically tracks **currently running TUI processes**.

Each entry in the manifest contains four critical fields:

- **`pid`** — The operating-system process ID of the running TUI instance
- **`slug`** — A unique identifier for the review (e.g., `gh:owner/repo/pr/42`)
- **`path`** — Absolute filesystem path to the session's JSON file
- **`last_seen`** — Unix timestamp of the most recent heartbeat from the process

This design allows external tools and the CLI to identify active sessions without polling the TUI processes directly.

## Where the Manifest is Defined and Managed

### Core Data Structures in [`src/persistence/storage.rs`](https://github.com/agavra/tuicr/blob/main/src/persistence/storage.rs)

The persistence layer in **[`src/persistence/storage.rs`](https://github.com/agavra/tuicr/blob/main/src/persistence/storage.rs)** defines all session tracking logic:

**Line 49** declares the filename constant:

```rust
const ACTIVE_SESSIONS_FILENAME: &str = "active_sessions.json";

```

**Line 246** introduces the `ActiveSessionsFile` struct, which wraps a vector of session entries:

```rust
struct ActiveSessionsFile {
    sessions: Vec<ActiveSessionEntry>,
}

```

This struct implements `Default` to initialize an empty session list, ensuring graceful handling of missing or corrupted manifest files.

### Loading and Saving the Manifest

Two unlocked I/O functions handle atomic read/write operations:

| Function | Line | Purpose |
|----------|------|---------|
| `load_active_sessions_unlocked` | 311 | Deserializes [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) from disk |
| `save_active_sessions_unlocked` | 321 | Atomically writes the manifest back to disk |

Both functions operate within the `reviews_dir` directory and use standard Rust JSON serialization.

## How Sessions are Registered and Cleaned Up

### Session Creation at TUI Startup

When `App::new()` initializes a TUI session, it invokes the persistence helpers to record the new process. The current PID is captured via `std::process::id()` at **line 205** in [`src/app.rs`](https://github.com/agavra/tuicr/blob/main/src/app.rs), then bundled with the session slug and file path into an `ActiveSessionEntry`.

The entry is appended to the manifest via `save_active_sessions_unlocked`, making the session discoverable immediately.

### Normal Exit Cleanup

Upon graceful shutdown, **`clear_active_session_for_pid_in_dir`** (line 224 in [`storage.rs`](https://github.com/agavra/tuicr/blob/main/storage.rs)) filters the manifest to remove the entry matching the exiting process's PID. This prevents accumulated stale entries during normal operation.

### Stale Entry Detection and Pruning

The system handles crashes and unclean shutdowns through automatic stale detection. The helper `process_is_running` at **line 286** checks whether a recorded PID still corresponds to a live process on the system.

During the next `load_active_sessions_unlocked` call, entries with dead PIDs are silently dropped before the manifest is returned to callers. This self-healing behavior ensures the manifest never references ghost sessions.

## Practical Uses of the Session Manifest

The [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) manifest enables three core features in `tuicr`:

- **`tuicr review list`** — The CLI command reads the manifest to display which review sessions have active TUI instances, letting users attach to or manage running sessions
- **Automatic cleanup** — No manual intervention required to purge orphaned entries after crashes
- **Multi-instance coordination** — Multiple `tuicr` processes coexist safely, each tracked independently by PID

## Inspecting and Interacting with the Manifest

### Command-Line Inspection

View the raw manifest contents:

```bash
cat "$XDG_DATA_HOME/tuicr/reviews/active_sessions.json"

```

Pretty-print with jq for readability:

```bash
jq . "$XDG_DATA_HOME/tuicr/reviews/active_sessions.json"

```

### Programmatic Access in Rust

Load and iterate over active sessions:

```rust
use tuicr::persistence::storage::{load_active_sessions_unlocked, ACTIVE_SESSIONS_FILENAME};
use std::path::PathBuf;

let reviews_dir = dirs::data_dir()
    .unwrap()
    .join("tuicr")
    .join("reviews");

let active = load_active_sessions_unlocked(&reviews_dir)
    .expect("could not read active_sessions.json");

for entry in active.sessions {
    println!(
        "PID {} – slug {} – file {}",
        entry.pid,
        entry.slug,
        entry.path.display()
    );
}

```

### Triggering Manual Cleanup

Force removal of stale entries for the current process:

```rust
use tuicr::persistence::storage::clear_active_session_for_pid_in_dir;

let reviews_dir = /* path as above */;
clear_active_session_for_pid_in_dir(&reviews_dir)
    .expect("failed to purge stale sessions");

```

## Key Source Files

| File | Responsibility |
|------|--------------|
| [`src/persistence/storage.rs`](https://github.com/agavra/tuicr/blob/main/src/persistence/storage.rs) | `ActiveSessionsFile` struct, I/O helpers, cleanup logic |
| [`src/app.rs`](https://github.com/agavra/tuicr/blob/main/src/app.rs) | Session registration during TUI startup |
| [`AGENTS.md`](https://github.com/agavra/tuicr/blob/main/AGENTS.md) | Documentation of manifest location and format |
| [`docs/REVIEW_CLI.md`](https://github.com/agavra/tuicr/blob/main/docs/REVIEW_CLI.md) | CLI command reference including session listing |

## Summary

- **[`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json)** stores running TUI session metadata by PID, slug, path, and timestamp
- Defined in **[`src/persistence/storage.rs`](https://github.com/agavra/tuicr/blob/main/src/persistence/storage.rs)** with atomic load/save operations at lines 311 and 321
- Sessions register at startup via `std::process::id()` and clean up on exit through `clear_active_session_for_pid_in_dir`
- Stale entry detection at line 286 ensures self-healing after crashes
- Powers `tuicr review list` and enables safe multi-instance operation

## Frequently Asked Questions

### Where is the [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) file located?

The manifest resides in your system's data directory under `tuicr/reviews/`, typically `~/.local/share/tuicr/reviews/active_sessions.json` on Linux or the equivalent platform-specific path via `dirs::data_dir()`.

### What happens if tuicr crashes without cleaning up its session entry?

The stale entry remains in [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) until the next load operation. The `process_is_running` check at line 286 detects the dead PID and filters it out automatically—no manual cleanup required.

### Can I run multiple tuicr sessions simultaneously?

Yes. Each TUI instance receives a unique PID-based entry in the manifest. The system distinguishes concurrent sessions by their operating-system process IDs, preventing conflicts between overlapping review sessions.

### How does the CLI know which sessions are active?

The `tuicr review list` command deserializes [`active_sessions.json`](https://github.com/agavra/tuicr/blob/main/active_sessions.json) via `load_active_sessions_unlocked` and displays entries whose PIDs pass the `process_is_running` validation, showing only genuinely active TUI processes.