Paperclip AI Activity Logging and Mutation Tracking: Complete Architecture Guide

Paperclip AI captures every data mutation as an immutable activity event, tracking the responsible user or agent across database, API, UI, and CLI layers using a centralized recordActivity service.

The paperclipai/paperclip repository implements a comprehensive activity logging and mutation tracking system that serves as the single source of truth for all data changes. This infrastructure records every mutation—from user edits to automated agent actions—in an immutable audit trail while simultaneously powering real-time UI updates, policy enforcement, and security auditing.

Database Schema and Shared Types

Immutable activity entries persist in PostgreSQL via Drizzle ORM. The schema definition in packages/db/src/schema/activity_log.ts defines the activity_log table with columns for UUID, timestamp, company ID, event type, and a JSON details payload.

Cross-layer type safety comes from packages/shared/src/types/activity.ts, which exports the ActivityEvent interface and enumerates all activity types (e.g., issue.updated, routine.run). This ensures consistent data structures across server, client, and CLI implementations.

Server-Side Activity Tracking

The server layer provides both write and read capabilities through dedicated services in server/src/services/.

Recording Mutations with recordActivity

The server/src/services/activity.ts file exports the core recordActivity helper function. Mutation services invoke this function immediately after successful database writes to create audit records.

The function accepts parameters including companyId, type, actorId, and a details JSON payload. When a user comments on an issue, the service logs:

await recordActivity({
  companyId,
  type: "issue.commented",
  actorId: ctx.user.id,
  details: {
    issueId,
    commentId,
    commentText,
  },
});

Querying and Pagination

Read operations are handled by server/src/services/activity-log.ts, which provides pagination, filtering, and sorting capabilities. This service aggregates data from the activity_log table and optimizes queries for timeline rendering and inbox sorting.

Responsible User Resolution

Every activity record identifies the responsible user—whether a human or the user behind an agent action. The resolution logic inspects the request context to map Bearer tokens to users, handling both direct user tokens and agent-invoked operations. The activity-log-responsible-user.test.ts test suite verifies that the correct userId is stored even when actions are performed by an automated agent.

Activity Flow: From Mutation to UI

The mutation tracking pipeline follows six distinct stages:

  1. Mutation Request – A user POSTs data or an agent invokes runRoutine.

  2. Business Logic Execution – The handling service processes the change and calls recordActivity.

  3. Actor Resolution – The system determines the responsibleUserId from the request context (user token or agent owner).

  4. Persistence – A new row inserts into activity_log with UUID, timestamp, event type, and JSON payload.

  5. Event Propagation – React Query keys (queryKeys.activity) and WebSocket pushes distribute the new activity to connected clients.

  6. Presentation – UI formatters convert raw JSON into human-readable timeline entries.

This flow ensures that server/src/services/activity.ts serves as the single write gateway, while server/src/routes/activity.ts exposes REST endpoints like GET /api/company/:companyId/activity for consumption.

Policy Enforcement and Auditing

Activity logs drive security and workflow policies beyond simple auditing.

Activity-Gated Skips – The system blocks certain routine runs unless recent external activity exists. This check, implemented in routine-run-display.ts, uses the "no_external_activity" flag to prevent automated actions on stale issues.

Write Denial Tracking – When mutations fail authorization checks, Paperclip still records the attempt via issue-write-denial-activity.ts. This module logs denied writes with the denied user's ID, timestamp, and attempted action, ensuring security teams can audit failed access attempts.

Inbox Prioritization – The inbox view in inbox.ts sorts items by the activityAt timestamp, bubbling the most active issues to the top based on recent logged events.

Frontend Presentation

The UI layer transforms raw activity events into interactive timeline components.

ui/src/lib/activity-format.ts converts ActivityEvent objects into formatted rows containing icons, labels, and relative timestamps. For issue-specific views, ui/src/lib/issue-timeline-events.ts extracts and filters events relevant to ticket histories.

Components consume these formatters through React Query hooks keyed to queryKeys.activity, ensuring real-time synchronization with the server state.

CLI Integration

The command-line interface exposes activity streams for automation and debugging. The cli/src/commands/client/activity.ts file implements the paperclip activity command, which queries the same REST endpoints used by the web UI.

Fetch recent events using:

paperclip activity --company=acme --limit=20

The CLI maintains parity with the web interface through cli/src/__tests__/activity-parity.test.ts, ensuring consistent data formatting across all clients.

Cross-Layer Consistency

Paperclip enforces strict Core Engineering Rules for activity system modifications. Any schema change requires synchronized updates to:

End-to-end validation occurs in server/src/__tests__/activity-service.test.ts and activity-routes.test.ts.

Summary

  • Immutable Audit Trail – Every mutation records to packages/db/src/schema/activity_log.ts with full actor attribution via recordActivity.
  • Centralized Recording – The recordActivity function in server/src/services/activity.ts serves as the sole write gateway for all activity events.
  • Responsible User Tracking – The system resolves human users behind both direct actions and agent invocations for complete accountability.
  • Policy Integration – Activity data drives security policies (write denials), workflow gates (external activity checks), and UI sorting (inbox prioritization).
  • Universal Consumption – Events flow to React-based UIs via ui/src/lib/activity-format.ts and to terminals via cli/src/commands/client/activity.ts.

Frequently Asked Questions

How does Paperclip AI attribute activity to the correct user when agents perform actions?

The responsible user resolution logic in server/src/services/activity-log.ts inspects the request context to distinguish between direct user tokens and agent invocations. When an agent performs a mutation, the system traces the Bearer token to the agent's owner and records that userId as the responsibleUserId in the activity log, ensuring human accountability for automated actions.

What happens when a mutation is denied by authorization policies?

Even failed mutations generate activity records. The issue-write-denial-activity.ts module captures denied write attempts with the denied user's ID, timestamp, and attempted action. This creates a complete security audit trail showing both successful changes and blocked access attempts.

Can I query activity logs programmatically outside the web interface?

Yes. The paperclip activity CLI command in cli/src/commands/client/activity.ts exposes the same REST endpoints used by the web UI. You can filter by company, limit results, and output JSON for integration with external monitoring or compliance systems.

How does the activity system affect issue prioritization in the inbox?

The inbox implementation sorts issues by the activityAt timestamp, which updates whenever recordActivity logs a new event. This ensures issues with recent comments, status changes, or routine runs bubble to the top of the priority queue automatically.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →