Activity Records

4 min read

Activity Records answers one question: who did what, when, and on what?

It saves one record per action, for example an admin turning on an MCP tool, or an assistant calling one. Users with permission read the records on the Activity Records page in Admin. Records are append-only: the database blocks changing or deleting them.

Each feature's docs list the actions it records, starting with The MCP Hub. What Is Stored lists what a record holds, including the input and output of tool calls.

Activity Records and Audit Logs: Audit Logs record API requests in log files, so you can investigate after an incident. Activity Records keeps chosen actions, with names, in a database that admins search in Admin. Both run side by side.

Who does what

On SaaS (multi-tenant or single tenant), Unique installs and runs Activity Records. You ask Unique to turn it on for your company, and give the role activity.records.read only to people that need access.
On Self-Hosted, follow this whole page. See Unique AI Service Models.

Before You Start

You need

Notes

Unique platform 2026.44 or later

Activity Records ships with every release. The chart and image have the release version

Its own PostgreSQL server, version 14 or later

Not a new database on the platform's server. See Why a Separate Database

Redis

Holds events until they are saved, so set it up like a database: maxmemory-policy noeviction, appendonly yes, data on a persistent volume. Otherwise events can be lost

RabbitMQ

Same virtual host. Its default queue type must be classic, which is the RabbitMQ default

Deploy the activity-records chart (oci://uniquecr.azurecr.io/helm/activity-records) with the same version as your platform. In its values, set:

Install

  • intake.routes.hostname: the hostname the Admin app calls.

    yaml
    intake:
      routes:
        hostname: api.<your company>.unique.app
  • Host and credentials of PostgreSQL and Redis, under both intake and worker, and of RabbitMQ, under intake.

    yaml
    intake:            # and the same postgresql and redis under worker
      postgresql:
        connection:
          host: activity-records.postgres.database.azure.com
          url:
            fromSecret: { name: activity-records-database, key: DATABASE_URL }
      redis:
        connection:
          host: redis.example.internal
          password:
            fromSecret: { name: redis-auth, key: password }
      rabbitmq:
        connection:
          host: rabbitmq.example.internal
          username:
            fromSecret: { name: rabbitmq-auth, key: username }
          password:
            fromSecret: { name: rabbitmq-auth, key: password }
  • If your platform runs Gatekeeper: intake.internalServices.dependencies.gatekeeper.enabled: true and GATEKEEPER_RUNNING_MODE: enforce under intake.env.

    yaml
    intake:
      env:
        GATEKEEPER_RUNNING_MODE: enforce
      internalServices:
        dependencies:
          gatekeeper:
            enabled: true

The chart's values.yaml describes every other option.

Network Policies

If you turn on networkPolicy.enabled for Activity Records, or if the platform services, Redis or RabbitMQ run network policies, let Activity Records in before you install. Otherwise the migration job fails.

Service

Value

Gatekeeper

internalServices.dependents.activityRecords.enabled: true

Chat backend

internalServices.dependents.activityRecordsWorker.enabled: true

Scope management

internalServices.dependents.activityRecordsWorker.enabled: true

Redis

Allow activity-records and activity-records-worker on port 6379

RabbitMQ

Allow activity-records on port 5672. The worker does not use RabbitMQ

Redis and RabbitMQ are not part of the Unique charts, so add these rules where their network policies are defined. Match the pods by the label app.kubernetes.io/name in the namespace Activity Records runs in. The migration job runs as activity-records-worker.

Sync all changes to gatekeeper, node-chat, node-scope-management, Redis and RabbitMQ before you sync activity-records. Otherwise Cilium blocks Activity Records.

Turn It On

  1. Admin app (chart admin-app): before 2026.46, set backends.endpoints.activityRecords.enabled: true, or the page stays empty. From 2026.46 on there is nothing to set.

  2. Feature flag: Set FEATURE_FLAG_ENABLE_ACTIVITY_RECORDS_EVENTS_UN_22616 to true for the company that you want to enable Activity Records for. Without it, nothing is recorded.

  3. Zitadel role: add activity.records.read to the project and to each organization's grant, then give it to the users who may read records. Admin roles do not include it. Users get access on their next login.

Check It Works

  1. Both deployments are ready, and /health on port 8080 reports database, redis and, on intake, rabbitmq as up.

  2. Do an action, for example turn on a tool in MCP Hub. It shows up under Activity Records in Admin within a few seconds.

Upgrade and Rollback

Upgrade the chart together with the platform. A rollback does not undo database migrations, so ask Unique before you roll back past a release that changed the database.

Alerts

They are how you know the audit trail is complete. They fire when events are lost, rejected, or stuck anywhere on the way: in the chat backend or MCP Hub, in RabbitMQ, in Redis, or in the worker. Without them, missing records go unnoticed.

The chart ships alerts as a PrometheusRule, your cluster needs the Prometheus Operator. The chat backend and MCP Hub charts ship their own alerts for events they could not send. The chart also installs a Grafana dashboard.

Replay the Dead-Letter Queue

An alert will be fired when a message gets to DLQ. Move the messages from unique.activity-records.ingest.dlq back to unique.activity-records.ingest. With the RabbitMQ Shovel plugin: open the DLQ in the management UI, expand Move messages, enter the ingest queue, and click Move messages. Without it, republish each message with the same body and properties, messageId included. Make sure messages republished are removed from DLQ.

Replaying is safe: an event that was already saved is not saved twice.

Failed Events

In case there is an error the worker retries a failed save 10 times, over about 4 hours. An alert is fired when an event fails. After that, the event stays in Redis DLQ as failed for 30 days. Fix the cause, replay the messages and if error persists, contact Unique for assistance.

Common Problems

Symptom

Check

Install stops at the migration job

Job logs. Usually a network policy or a wrong Service name

Migration or pod logs show connect ETIMEDOUT for Redis or RabbitMQ

A network policy on Redis or RabbitMQ that does not let Activity Records in. See Network Policies

No Activity Records page in Admin

The user's role. Log out and in again

The page is there but empty

Before 2026.46: backends.endpoints.activityRecords.enabled in the Admin app

No new records

The feature flag, then the worker logs

Messages pile up in RabbitMQ

Redis CPU, worker CPU, and PostgreSQL write times.

Limitations

  • Records are kept forever. Settings to delete old records after a set time are planned.

  • No export, no API key access. Records are read on the Admin page only.

  • One role sees everything in the company, including the input and output of every tool call.

Last updated