> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentium.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Own sessions and resources

> Scope session history and state to identity, enforce one writer, and clean up resources at the right lifetime.

Harness sessions are scoped by `(tenantId, userId, sessionId)`. Reuse that tuple to continue a conversation. Different users or tenants with the same session ID receive separate state.

## Session history and state

The default `InMemoryHarnessSessionStore` stores:

| Snapshot field | Meaning |
| - | - |
| `history` | Canonical conversation messages. |
| `conversations` | Optional per-execution conversations, used when an executor has multiple conversation streams. |
| `state` | Application state exposed through execution services. |
| `revision` | Store revision incremented on commit. |
| `replayable` | Whether the snapshot represents complete replay state. |

The store allows one writer per scoped session in this process. A concurrent acquisition throws `HarnessSessionConflict` with `code: "session_conflict"`. Serialize runs for the same session in your application, or surface the conflict so the caller can retry after the active run settles.

The runtime acquires a lease, clones history/state, and commits before releasing it. A failed or cancelled run may commit partial history marked `replayable: false`. This avoids representing an incomplete transcript as complete replay state.

The default store advertises `durable: false`, `compareAndSwap: false`, and `singleWriter: "process"`. A custom store must accurately report its guarantees and implement `acquire(identity, sessionId)` returning `read()`, `commit(snapshot)`, and `release()`. A durable store alone does not give `HarnessRuntime` crash-resumable execution.

## Inspect a completed session

Acquire a read lease only after the current run has settled. This uses the same exclusive acquisition contract as a writer:

```typescript theme={null}
import type { HarnessIdentity, HarnessRuntime } from "@agentium/harness";

export async function readSession(
  runtime: HarnessRuntime,
  identity: HarnessIdentity,
  sessionId: string,
) {
  const lease = await runtime.sessions.acquire(identity, sessionId);
  try {
    return lease.read();
  } finally {
    lease.release();
  }
}
```

`InMemoryHarnessSessionStore.importLegacy()` imports display-only `ChatMessage[]` with empty state and `replayable: false`. It is not a recovery adapter. An Agent's own storage is not automatically imported or mirrored into harness sessions.

## Choose a resource lifetime

In a driver, call `services.resource(id, scope, initialize)`. The initializer returns `{ value, ownership, dispose? }`; the runtime tracks the lease and releases it after the run.

| Scope | Reuse and cleanup |
| - | - |
| `run` | Initialized for this acquisition. Runtime-owned value is disposed when its lease releases. |
| `session` | Shared by resource ID within the scoped session, including concurrent initializers. Retained until `closeSession()`. |
| `host` | Must declare `ownership: "host"`; lifecycle belongs to the application. It is not a pool-managed global singleton. |

`ownership: "runtime"` allows the pool to call `dispose()`. `ownership: "host"` leaves disposal to the application. Incompatible host-scope ownership is rejected. Keep resource IDs stable and specific to the resource configuration you intend to reuse.

This factory acquires a session-scoped connection from a custom driver's services:

```typescript theme={null}
import type { HarnessExecutionServices } from "@agentium/harness";

interface Connection {
  read(): Promise<string>;
  close(): Promise<void>;
}

export async function sessionConnection(
  services: HarnessExecutionServices,
  connect: () => Promise<Connection>,
) {
  return services.resource("project-reader", "session", async () => {
    const connection = await connect();
    return {
      value: connection,
      ownership: "runtime",
      dispose: () => connection.close(),
    };
  });
}
```

The host supplies `connect`; construction does not invent credentials or authenticate users. Keep any resource operations within the execution boundary appropriate to their effects.

## Close a session's resources

After all runs for a session finish, call `await runtime.resources.closeSession(identity, sessionId)`. Active or still-initializing leases cause `HarnessSessionConflict`. Runtime-owned resources are disposed in reverse order. The returned string array contains IDs whose disposal failed.

Closing resources does not delete the session transcript or artifact storage. There is no global `runtime.close()` method in the current API. Keep the runtime's lifetime bounded to your application's needs, and handle session-resource cleanup explicitly.

See [exact store and pool contracts](/harness/api/sessions) and [driver ownership](/harness/drivers).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.