# Activity

> Read what people and their keys did in a workspace or the organization

`client.activity` reads the dashboard's Activity table: what people and their
API keys did, newest first. A workspace's activity holds what happened in it.
The organization's holds every workspace's and its own (members, keys,
workspaces, credits). Reading needs a key with `data:read` and a role there. A
key restricted to workspaces cannot read activity.

`client.events` is something else: one job's live stream.

## List activity

```python
from qualia import Qualia

client = Qualia()

# the workspace this client acts in (workspace=, QUALIA_WORKSPACE, else the key's own)
page = client.activity.list()

# the organization's, filtered and paged
page = client.activity.list(
    client.account,
    filter='verb = KEEP AND actor = API_KEY',
    limit=100,
)
for row in page.items:
    print(row.create_time, row.verb, row.dataset_label, row.changed_count)
next_page = client.activity.list(client.account, cursor=page.page_info.end_cursor)
```

`parent` is `accounts/{a}` for the organization, `accounts/{a}/workspaces/{w}`
or a workspace id for one workspace, or `None` for this client's workspace.
`filter` is AIP-160: comparisons joined by `AND` over `verb`, `actor`
(`PERSON`, `API_KEY`, `SERVICE`, `MODEL`, `SYSTEM`), `workspace`, `text`,
`create_time`, `subject` and `action`. `view="raw"` lists every recorded event
instead of intentional actions.

**Response**: a `PaginatedPage` of `qualia.v1.ActivitySummary`.

```json title="ActivitySummary (row.to_wire())"
{
"event": "accounts/<a>/workspaces/<w>/events/<e>",
"uid": "<e>",
"createTime": "2026-10-30T09:00:00Z",
"verb": "KEEP",
"changedCount": 12,
"actor": { "kind": "API_KEY", "credential": "<key id>" },
"dataset": "accounts/<a>/datasets/<d>",
"datasetLabel": "folding"
}
```

## One event

`get` returns the event as the record holds it. `details` returns what it
touched (episodes and their state before) and the fields it changed, as you may
still see them. Both take the event's full name, which list rows carry as
`row.event`, or its id, read through the organization.

```python
event = client.activity.get(row.event)
print(event.action, event.summary, event.actor.display_name)

details = client.activity.details(row.event)
for change in details.changes:
    print(change.field, change.previous, change.current)
```

## Who acted

The recorded names of who did up to 100 actions, and each recorded key's current
label and owner.

```python
actors = client.activity.actors([row.event for row in page.items])
names = {a.event: a.display_name for a in actors.actors}
```

## Export the record

Download the organization's events record as JSON lines, oldest first.

```python
lines = client.activity.export(
    "events.jsonl",
    start="2026-10-01T00:00:00Z",
    end="2026-11-01T00:00:00Z",
)
```

It returns the number of events written. The file is personal data: member
events carry usernames and emails. It needs a key with `audit:read`, not
restricted to workspaces, whose creator is an Admin or Owner of the
organization. The file appears only once the whole record has arrived; a
download that breaks raises `QualiaError` and leaves nothing behind.
