# How OpenMAIC Handles Lease Coordination for Session Claims in the Agent Runtime

> Learn how OpenMAIC ensures exclusive session access with its token-based lease coordination mechanism. Discover how it validates leases and handles interruptions for robust agent runtime operations.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: internals
- Published: 2026-09-06

---

**OpenMAIC uses a token-based lease mechanism stored in `localStorage` and an in-memory map to ensure only one active agent owns a workspace session at any time, with lease validation before every operation and graceful interruption handling when leases are contested.**

The **lease coordination** system in OpenMAIC's agent runtime prevents race conditions and guarantees exclusive access to workspace sessions. When multiple browser tabs or agent instances compete for the same session, this mechanism ensures deterministic ownership and clean handoffs. The implementation centers on [`lib/workbench/workspace-session-memory.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-session-memory.ts), which provides the core primitives for claiming, validating, and releasing session leases.

## Lease Acquisition: Claiming a Session

When an agent initiates a session, it must first acquire a lease from the shared **lease manager**. This process generates a unique token that serves as proof of ownership for the duration of the session.

The acquisition logic in [`lib/workbench/workspace-session-memory.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-session-memory.ts) handles three concurrent storage targets:

- A **UUID-based lease token** created via `crypto.randomUUID()`
- **localStorage persistence** using the `LAST_WORKSPACE_SESSION_STORAGE_KEY` constant for survival across reloads
- An **in-memory Map** (`activeLeases`) for fast synchronous validation

```typescript
// lib/workbench/workspace-session-memory.ts
export async function claimSession(
  sessionId: string,
  storage: Storage,
): Promise<void> {
  // Generate a unique lease token
  const lease = crypto.randomUUID();
  // Store token in localStorage for persistence
  storage.setItem(LAST_WORKSPACE_SESSION_STORAGE_KEY, lease);
  // Keep token in the in‑memory map for fast checks
  activeLeases.set(sessionId, lease);
}

```

The dual-storage approach balances **durability** (localStorage) with **performance** (in-memory lookups). This allows sub-millisecond validation checks during critical path operations while maintaining lease state through browser restarts.

## Lease Validation: Enforcing Exclusive Access

Before executing any session-specific operation, the runtime validates that its held lease matches the stored token. This check prevents **stale agents** from performing destructive operations on sessions they no longer own.

The validation function compares the localStorage lease against the in-memory entry:

```typescript
// lib/workbench/workspace-session-memory.ts
function isLeaseValid(sessionId: string, storage: Storage): boolean {
  const storedLease = storage.getItem(LAST_WORKSPACE_SESSION_STORAGE_KEY);
  return storedLease === activeLeases.get(sessionId);
}

// Example usage in an agent action
if (!isLeaseValid(currentSessionId, localStorage)) {
  emit('session_interrupted', { reason: 'lease lost' });
  return; // abort the action
}

```

Validation failures trigger the **`session_interrupted`** event with reason `"lease lost"`. This event-driven architecture decouples lease detection from response handling, allowing different runtime components to react appropriately.

## Lease Release: Graceful Session Termination

When an agent completes its work or loses focus, it explicitly releases its lease. This cleanup is mandatory for proper resource management and prevents **lease leaks** that would block future session claims.

The `releaseSession` function in [`lib/workbench/workspace-session-memory.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-session-memory.ts) performs atomic cleanup:

```typescript
// lib/workbench/workspace-session-memory.ts
export function releaseSession(sessionId: string, storage: Storage): void {
  activeLeases.delete(sessionId);
  storage.removeItem(LAST_WORKSPACE_SESSION_STORAGE_KEY);
}

```

Lease release occurs in three scenarios:

- **User-initiated session switch** — the agent voluntarily surrenders the current session
- **Page unload event** — the browser invokes cleanup handlers before navigation
- **Lease loss detection** — validation failure prompts defensive release to avoid conflicts

## Handling Interruptions: Recovery from Lease Contention

When lease contention occurs—typically from multiple tabs attempting to claim the same session—the runtime broadcasts `session_interrupted` events. Components subscribe to these events and execute **graceful degradation** logic.

The UI layer in [`components/workbench/WorkspaceShell.tsx`](https://github.com/THU-MAIC/OpenMAIC/blob/main/components/workbench/WorkspaceShell.tsx) demonstrates this pattern:

```tsx
// components/workbench/WorkspaceShell.tsx
useEffect(() => {
  const handler = ({ reason }: { reason: string }) => {
    if (reason === 'lease lost') {
      // Gracefully close the current session UI
      closeCurrentSession();
    }
  };
  eventBus.on('session_interrupted', handler);
  return () => eventBus.off('session_interrupted', handler);
}, []);

```

The **event bus architecture** enables multiple listeners to react to lease changes without tight coupling between the lease manager and individual components.

## Persistence and Recovery Across Reloads

The lease system supports **session recovery** after browser refreshes. When the runtime initializes, it checks `localStorage` for existing lease tokens via `rememberWorkspaceSession` and `validateRememberedWorkspaceSession`.

This recovery flow handles two edge cases:

- **Valid token** — the runtime seamlessly reclaims the session if the lease hasn't expired or been claimed by another agent
- **Stale token** — validation fails against the current session state, triggering lease cleanup and preventing phantom session ownership

The test suite in [`tests/workbench/workspace-session-memory.test.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/tests/workbench/workspace-session-memory.test.ts) verifies both persistence scenarios and ensures lease integrity across page lifecycle events.

## Key Source Files and Responsibilities

| File | Responsibility |
|------|----------------|
| [`lib/workbench/workspace-session-memory.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-session-memory.ts) | Core lease implementation: `claimSession`, `releaseSession`, `isLeaseValid`, `rememberWorkspaceSession` |
| [`tests/workbench/session-fold.test.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/tests/workbench/session-fold.test.ts) | Integration tests for `session_interrupted` event with "lease lost" reason |
| [`tests/workbench/workspace-session-memory.test.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/tests/workbench/workspace-session-memory.test.ts) | Unit tests for lease persistence, validation, and cleanup |
| [`components/workbench/WorkspaceShell.tsx`](https://github.com/THU-MAIC/OpenMAIC/blob/main/components/workbench/WorkspaceShell.tsx) | UI event handler for lease-loss notifications |
| [`components/workbench/WorkspaceRail.tsx`](https://github.com/THU-MAIC/OpenMAIC/blob/main/components/workbench/WorkspaceRail.tsx) | Session navigation with lease-aware activation logic |

## Summary

- **Lease tokens** stored in `localStorage` and in-memory Maps provide durable, fast session ownership verification
- **Validation before operations** ensures only the current lease holder can mutate session state
- **Event-driven interruption handling** via `session_interrupted` enables graceful recovery from contention
- **Explicit release** on session end prevents resource leaks and blocks stale claims
- **Cross-reload persistence** allows seamless session recovery with automatic stale lease detection

## Frequently Asked Questions

### What happens when two tabs try to claim the same OpenMAIC session?

The second tab's `claimSession` call generates a new lease token that overwrites the `localStorage` entry. When the first tab next validates its lease via `isLeaseValid()`, the token mismatch triggers a `session_interrupted` event with reason `"lease lost"`. The first tab's UI components respond by closing the session view, leaving only the second tab with active ownership.

### How does OpenMAIC detect and recover from stale leases after a browser crash?

On initialization, `rememberWorkspaceSession` retrieves any existing token from `localStorage` and calls `validateRememberedWorkspaceSession`. This function checks the token against the current session state on the server or in shared memory. Invalid or expired tokens are cleared automatically, allowing the new agent instance to claim a fresh lease without manual intervention.

### Why does OpenMAIC use both localStorage and an in-memory Map for lease storage?

The **in-memory Map** provides O(1) lookup performance for high-frequency validation checks during agent operations. **localStorage** provides durability across page reloads and browser tabs, ensuring lease state survives crashes and navigation. This dual-layer design optimizes for both speed and reliability without sacrificing correctness.

### Can the lease coordination mechanism handle server-side session validation?

The current implementation focuses on **client-side coordination** between browser tabs and agent instances. The `storage` parameter in `claimSession` and `validateRememberedWorkspaceSession` is injectable, allowing future extensions to wrap server-validated storage backends. The core lease logic remains agnostic to the storage implementation details.