Skip to content

Local sessions

Sessions your users run in Claude apps on their own machines: Cowork in Claude Desktop, Claude Code, Claude Science, and Claude for Microsoft 365. For Cowork sessions that run in Anthropic-managed cloud environments, see Remote sessions.

local_sessions

Local Sessions resource group.

Local sessions are the conversations your users run in Claude apps on their own machines while signed in with a Claude Enterprise account: Cowork in Claude Desktop, Claude Code (terminal, desktop, or IDE extension), the Claude Science desktop app, and Claude for Microsoft 365. Sessions that run in Anthropic-managed cloud environments are a separate family — see remote_sessions.

Wraps three endpoints, all read-only:

  • GET /v1/compliance/apps/sessions/local — page of session metadata. Exposed via list and iter.
  • GET /v1/compliance/apps/sessions/local/{id} — one session's metadata. Exposed via get.
  • GET /v1/compliance/apps/sessions/local/{id}/messages — one session's transcript. Exposed via list_messages and iter_messages.

Requires a Compliance Access Key with read:compliance_user_data. Admin API keys are rejected with 403.

Example
from claude_compliance_sdk import ComplianceClient

with ComplianceClient(api_key="sk-ant-api01-...") as client:
    for session in client.local_sessions.iter(
        created_at_gte="2026-07-01T00:00:00Z",
    ):
        print(session.id, session.product_surface)
        for message in client.local_sessions.iter_messages(session.id):
            print("  ", message.role, message.content)

LocalSession dataclass

Metadata for one session run on a user's machine.

Attributes:

Name Type Description
id str

Session identifier (clls_...). Opaque; the format may change without notice.

type str

Always "compliance_local_session".

organization_uuid str

UUID of the organisation the session ran in.

user SessionUser | None

The authenticated user at the time of the session.

product_surface str | None

Which product created the session — cowork, claude_code, claude_science, or one of the office_agents/... values. None when not recorded. Kept as a plain string: new surfaces ship as coverage expands, and unrecognised values must pass through rather than raise.

created_at str

Timestamp of the session's earliest retained call. This advances as older calls age out of retention, so deduplicate on id rather than assuming it is stable.

updated_at str

Timestamp of the session's last retained call. On the list endpoint this is a lower bound and can briefly lag a still-active session's true last activity.

workspace_id str | None

Tagged workspace identifier (wrkspc_...), or None when the session had no workspace.

extra dict[str, Any]

Any additional fields the API adds in a later revision.

from_dict classmethod

from_dict(body: Mapping[str, Any]) -> 'LocalSession'

Build a LocalSession from one decoded record.

LocalSessionMessage dataclass

One user or assistant turn in a local session transcript.

Attributes:

Name Type Description
id str

Message identifier (clsm_...), stable for as long as the turn is retained.

role str

"user" or "assistant".

created_at str

When the message was recorded. Every message reconstructed from the same inference call carries that call's timestamp, so consecutive messages often share one. Preserve the returned order rather than re-sorting.

content list[dict[str, Any]]

Content blocks, each a raw dict discriminated on typetext, tool_use, or tool_result. Kept as dicts so block types that have not shipped yet pass through untouched. Note that a tool_use block's input is a JSON-encoded string, and a truncated one is no longer valid JSON.

model str | None

The model that served an assistant turn, or None on user messages and on any message carrying provenance.

provenance dict[str, Any] | None

None for verified content, which is the common case. Otherwise a dict whose type marks the exception: content_unavailable (with a reason), client_asserted, or synthetic_marker. Kept as a raw dict; tolerate unrecognised types and reasons.

type str

Always "compliance_local_session_message".

extra dict[str, Any]

Any additional fields the API adds in a later revision.

from_dict classmethod

from_dict(body: Mapping[str, Any]) -> 'LocalSessionMessage'

Build a LocalSessionMessage from one decoded record.

LocalSessionTranscript dataclass

A page of transcript, plus the session it belongs to.

The messages endpoint returns a session envelope alongside the paginated data array, so the SDK exposes them together rather than making the caller re-fetch metadata.

Attributes:

Name Type Description
session LocalSession

The session the messages belong to. Its user.email_address is always None on this endpoint.

messages OffsetPage[LocalSessionMessage]

One OffsetPage of LocalSessionMessage objects.

from_dict classmethod

from_dict(
    body: Mapping[str, Any]
) -> "LocalSessionTranscript"

Split the envelope into a session and a page of messages.

SessionUser dataclass

A user associated with a session.

Attributes:

Name Type Description
id str

Tagged user identifier (user_...). Always set on local sessions, so attribution survives the account being deleted.

email_address str | None

Current email address, or None. On the list and retrieve endpoints None means the account was deleted or the user is no longer in an organisation the key can read. On the messages endpoint it is always None — that endpoint does not resolve email addresses, so join on id instead of reading anything into it.

extra dict[str, Any]

Any additional fields the API adds in a later revision.

from_dict classmethod

from_dict(body: Mapping[str, Any]) -> 'SessionUser'

Build a SessionUser from one decoded record.

LocalSessions

Synchronous client for the local session endpoints.

list

list(
    *,
    created_at_gte: str | None = None,
    created_at_lt: str | None = None,
    updated_at_gte: str | None = None,
    limit: int | None = None,
    page: str | None = None
) -> OffsetPage[LocalSession]

Fetch one page of local session metadata, newest first.

The endpoint has no organisation or user filter, so bound the results in time instead. To poll for sessions active since a previous pass, use updated_at_gte set a few minutes before your last run started: a bound set to the exact previous time silently and permanently drops a session whose final call was still being indexed at that moment.

Parameters:

Name Type Description Default
created_at_gte str | None

Sessions whose first call is at or after this time (RFC 3339, UTC offset required).

None
created_at_lt str | None

Sessions whose first call is strictly before this time. When both bounds are given this must be strictly after created_at_gte, or the API returns 400.

None
updated_at_gte str | None

Sessions whose last call is at or after this time. Combines with the created_at bounds without changing the ordering.

None
limit int | None

Maximum results (default 100, max 500).

None
page str | None

Opaque token from a prior response's next_page. Complete a walk within 24 hours; an older token is still accepted but is re-evaluated against the current retention boundary and can skip sessions.

None

Returns:

Type Description
OffsetPage[LocalSession]

One OffsetPage of LocalSession objects.

Raises:

Type Description
LocalSessionsUnavailableError

When local sessions are not available to the parent organisation. Keep any queued session IDs and retry on a later run.

InsufficientScopeError

When the key lacks read:compliance_user_data.

APIError

For any other non-2xx response.

iter

iter(
    *,
    created_at_gte: str | None = None,
    created_at_lt: str | None = None,
    updated_at_gte: str | None = None,
    limit: int | None = None
) -> Iterator[LocalSession]

Iterate every matching local session, auto-paginating.

Same filters as list except that page is managed by the iterator. Because created_at shifts as calls age out of retention, deduplicate on id when you re-walk over time.

get

get(session_id: str) -> LocalSession

Fetch one local session's metadata, with no transcript.

Parameters:

Name Type Description Default
session_id str

Session identifier (clls_...).

required

Raises:

Type Description
BadRequestError

When session_id is not a well-formed clls_ identifier.

LocalSessionsUnavailableError

When local sessions are not available to the parent organisation.

NotFoundError

When the session is not readable by this key, never existed, is under zero data retention, or has entirely aged past retention. The API does not distinguish these four.

list_messages

list_messages(
    session_id: str,
    *,
    order: str | None = None,
    limit: int | None = None,
    page: str | None = None,
    tool_use_input_max_bytes: int | None = None,
    tool_result_max_bytes: int | None = None
) -> LocalSessionTranscript

Fetch one page of a local session's transcript.

A page can end early when the response hits its size limit, so a short page does not mean you have reached the end. Keep paginating until next_page is None.

Parameters:

Name Type Description Default
session_id str

Session identifier (clls_...).

required
order str | None

"asc" (oldest first, the server default) or "desc".

None
limit int | None

Maximum messages per page (default 100, max 1000).

None
page str | None

Opaque token from a prior response's next_page. Cursors are bound to the session and the sort order they were issued under, and expire 24 hours after the walk's first page.

None
tool_use_input_max_bytes int | None

Truncate each tool-use input to this many bytes (server default 10,000). -1 asks for the server maximum, roughly 1 MiB. 0 raises ValueError.

None
tool_result_max_bytes int | None

Truncate each text item inside a tool result the same way.

None

Returns:

Type Description
LocalSessionTranscript

A LocalSessionTranscript — the session envelope plus one

LocalSessionTranscript

page of messages.

Raises:

Type Description
ValueError

When either truncation cap is 0.

BadRequestError

For a malformed session ID, or a page cursor that is expired or was issued for a different session or sort order.

LocalSessionsRetentionUnavailableError

When a retention setting could not be evaluated. Not transient — skip the session and retry on a later run rather than holding the walk open.

NotFoundError

When every call in the session has aged past retention, or the session is otherwise unreadable.

iter_messages

iter_messages(
    session_id: str,
    *,
    order: str | None = None,
    limit: int | None = None,
    tool_use_input_max_bytes: int | None = None,
    tool_result_max_bytes: int | None = None
) -> Iterator[LocalSessionMessage]

Iterate a local session's whole transcript, auto-paginating.

Same arguments as list_messages except that page is managed by the iterator. The session envelope is dropped; call get if you need it.

AsyncLocalSessions

Asynchronous client for the local session endpoints.

list async

list(
    *,
    created_at_gte: str | None = None,
    created_at_lt: str | None = None,
    updated_at_gte: str | None = None,
    limit: int | None = None,
    page: str | None = None
) -> OffsetPage[LocalSession]

Async analogue of list.

iter

iter(
    *,
    created_at_gte: str | None = None,
    created_at_lt: str | None = None,
    updated_at_gte: str | None = None,
    limit: int | None = None
) -> AsyncIterator[LocalSession]

Async analogue of iter.

get async

get(session_id: str) -> LocalSession

Async analogue of get.

list_messages async

list_messages(
    session_id: str,
    *,
    order: str | None = None,
    limit: int | None = None,
    page: str | None = None,
    tool_use_input_max_bytes: int | None = None,
    tool_result_max_bytes: int | None = None
) -> LocalSessionTranscript

Async analogue of list_messages.

iter_messages

iter_messages(
    session_id: str,
    *,
    order: str | None = None,
    limit: int | None = None,
    tool_use_input_max_bytes: int | None = None,
    tool_result_max_bytes: int | None = None
) -> AsyncIterator[LocalSessionMessage]

Async analogue of iter_messages.