# Maka Session States Explained: Lifecycle vs. CUA Statuses

> Understand Maka session states including lifecycle (absent, live, terminal) and CUA statuses (unobserved, active, etc.) to manage UI interaction permissions effectively.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: internals
- Published: 2026-09-08

---

**Maka sessions operate in two distinct state dimensions: three durable lifecycle states (`absent`, `live`, `terminal`) that track graph-level existence, and seven CUA statuses (`unobserved`, `active`, `intervention_debounce`, `reobserve_required`, `screen_locked`, `blocked_url`, `user_stopped`) that govern UI interaction permissions.**

The **apache/maka** repository defines a dual-layer state model that separates long-term session persistence from real-time UI observation. Understanding how these **Maka session states** interact is critical for building reliable AI agents that can gracefully handle interruptions, policy violations, and completion events. The runtime coordinates these states through specific TypeScript classes found in the `packages/runtime/src` directory.

## Session Lifecycle States: Absent, Live, and Terminal

At the durable graph level, every Maka session maintains a lifecycle state stored in the session header. The `AgentGraphCoordinator` class exposes this through the `readSessionState()` method, which returns one of three possible values.

In [`packages/runtime/src/stream-graph-coordinator.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/stream-graph-coordinator.ts) (lines 23-33), the implementation distinguishes:

- **`absent`**: The session header does not exist. This indicates either a brand-new session that has not been initialized or a previously deleted session.
- **`live`**: The session is currently active and its graph can be reconciled. Only live sessions accept new actions or observations.
- **`terminal`**: The session has reached a finished or stopped state and will no longer produce new graph activity. Terminal sessions are immutable.

This lifecycle state determines whether the runtime should attempt to drive the session forward or treat it as complete.

## CUA Session Statuses: The UI Observation Layer

While the lifecycle state tracks existence, the **CUA (Computer-Use-Agent)** session status tracks the fine-grained UI state required for desktop automation. Defined in [`packages/runtime/src/cua-session-state.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/cua-session-state.ts) (lines 20-28) within the `CUA_SESSION_STATUSES` constant, these seven statuses control when actions are permitted:

- **`unobserved`**: The session has not yet captured a UI frame. No actions can be taken until the first observation.
- **`active`**: Normal operation. The runtime may execute actions and observations.
- **`intervention_debounce`**: User intervention was detected. A short cooldown period must elapse before re-observing to avoid racing with human input.
- **`reobserve_required`**: The UI has changed significantly and must be refreshed before further actions.
- **`screen_locked`**: The host machine's screen is locked, preventing UI interaction.
- **`blocked_url`**: A policy-blocked URL was detected. This is a terminal status that stops the session.
- **`user_stopped`**: The user explicitly terminated the session. This is also a terminal status.

The `CuaSessionState` class encapsulates these transitions and validates every action through its `beforeAction()` and `beforeObservation()` methods.

## How Lifecycle and CUA States Interact

The two state systems operate in a hierarchy. The lifecycle state answers "Does this session exist and can it run?" while the CUA status answers "Is the UI ready for the next action?"

When a session is `live` at the lifecycle level, the runtime continuously monitors the CUA status. If the CUA status transitions to a terminal condition—specifically `blocked_url` or `user_stopped`—the `AgentGraphCoordinator` propagates this to the lifecycle layer. As implemented in `#readSessionStateForGraph`, this promotion causes the durable session header to update to `terminal`, ensuring the session stops permanently even if the CUA object is garbage collected.

Non-terminal CUA statuses like `intervention_debounce` or `screen_locked` do not affect the lifecycle state; they merely pause execution until the condition clears.

## Querying Maka Session States in Code

You can inspect both state dimensions programmatically using the runtime API.

### Query the Durable Lifecycle State

Use `AgentGraphCoordinator.readSessionState()` to check graph-level existence:

```typescript
// Assume coordinator is an AgentGraphCoordinator instance
const rootSessionId = 'sess-123';
const state = await coordinator.readSessionState(rootSessionId);
// state: 'absent' | 'live' | 'terminal'

if (state === 'live') {
  // Proceed with graph reconciliation
} else if (state === 'terminal') {
  // Session completed or stopped
}

```

### Inspect CUA Session Status

Create a `CuaSessionState` instance to monitor UI-level readiness:

```typescript
import { CuaSessionState } from '@maka/runtime';

const cua = new CuaSessionState('sess-123');
const snap = cua.snapshot(); // { status: 'active', generation: 4 }

// Validate before executing an action
const leaseResult = cua.beforeAction();
if (leaseResult.ok) {
  console.log('Action lease granted:', leaseResult.lease.generation);
} else {
  console.warn('Action blocked:', leaseResult.reason); // e.g., 'screen_locked'
}

```

### Handle Terminal Transitions

Detect policy violations or user stops and verify lifecycle propagation:

```typescript
// Simulate a policy block
cua.blockedUrlDetected();

// CUA status immediately reflects the block
console.log(cua.snapshot().status); // -> 'blocked_url'

// Lifecycle eventually synchronizes to terminal
const lifecycle = await coordinator.readSessionState('sess-123');
console.log(lifecycle); // -> 'terminal'

```

## Key Implementation Files

The complete state model spans several packages:

- **[`packages/runtime/src/stream-graph-coordinator.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/stream-graph-coordinator.ts)**: Implements `readSessionState()` and the lifecycle transition logic for `absent`, `live`, and `terminal`.
- **[`packages/runtime/src/cua-session-state.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/cua-session-state.ts)**: Defines `CUA_SESSION_STATUSES` and the `CuaSessionState` class that manages UI observation state.
- **[`packages/storage/src/session-repository.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/session-repository.ts)**: Persists durable `SessionState` objects to storage, backing the coordinator's queries.
- **[`packages/runtime/src/session-manager.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/session-manager.ts)**: Exposes higher-level APIs like `getPlanState()` that aggregate both lifecycle and CUA information.

## Summary

- Maka uses **two complementary state systems**: durable lifecycle states (`absent`, `live`, `terminal`) and transient CUA statuses (`unobserved` through `user_stopped`).
- The **lifecycle state** persists in the session header and determines if a graph can be driven.
- **CUA statuses** control real-time UI interaction permissions and are checked before every action.
- Terminal CUA statuses (`blocked_url`, `user_stopped`) automatically promote the lifecycle to `terminal`.
- Query states via `AgentGraphCoordinator.readSessionState()` for persistence and `CuaSessionState.snapshot()` for UI readiness.

## Frequently Asked Questions

### What is the difference between lifecycle states and CUA statuses in Maka?

Lifecycle states (`absent`, `live`, `terminal`) are durable properties stored in the session header that indicate whether a graph exists and can accept new operations. CUA statuses (`active`, `screen_locked`, etc.) are runtime UI observation states managed by the `CuaSessionState` class that determine if the specific action can execute right now. A session can be `live` at the lifecycle level but temporarily `screen_locked` at the CUA level.

### How do I check if a Maka session is still active programmatically?

Call `await coordinator.readSessionState(sessionId)` where `coordinator` is an `AgentGraphCoordinator` instance. If the returned value is `'live'`, the session accepts new graph operations. For UI-specific readiness, instantiate `CuaSessionState` and call `snapshot().status` to verify it equals `'active'` before attempting interactions.

### What causes a Maka session to enter the terminal state?

A session becomes `terminal` either through explicit user action (`user_stopped` CUA status), policy enforcement (`blocked_url` CUA status), or natural completion of all tasks. According to the source code in [`stream-graph-coordinator.ts`](https://github.com/apache/maka/blob/main/stream-graph-coordinator.ts), both `blocked_url` and `user_stopped` CUA statuses trigger an immediate transition of the durable lifecycle to `terminal`.

### Where are Maka session states stored and managed?

The durable lifecycle state persists in the storage layer via [`packages/storage/src/session-repository.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/session-repository.ts), while the ephemeral CUA status resides in memory within the `CuaSessionState` class. The `AgentGraphCoordinator` bridges these layers, reading from storage to determine `absent`/`live`/`terminal` and querying the in-memory CUA object for UI-level status during active sessions.