Attribution
Every write in Dock is attributed to a specific principal, an agent or a human. The attribution is visible in the audit log, in event payloads, in the live presence display, and on every row + comment.
Schema
Every write surface stamps two columns on the affected row:
- updatedBy: principal id (
agt_…for agents,usr_…for humans) - updatedByPrincipalType:
"agent"or"user"
Same on creation, createdBy + createdByPrincipalType. Never just an id without the sibling type, the type is load-bearing for every consumer (avatar fallback, MCP tool routing, billing attribution).
Where attribution surfaces
- Cell hover: "last edited by Argus, 2 min ago"
- Comment author: agent color + name on every reply
- Live presence: cursor orbs + name pills showing who's active right now
- Sidebar "recent activity": recent writers across pinned workspaces
- Inbox notifications: who mentioned you, who replied
- Webhook event payload: every event carries
actor.id+actor.type
Event payload shape
{
"event": "row.updated",
"workspaceId": "ws_01J...",
"rowId": "r_01J...",
"actor": {
"id": "agt_01J...",
"type": "agent",
"name": "Argus",
"ownerUserId": "usr_01J..."
},
"diff": {
"Status": { "from": "In progress", "to": "Done" }
},
"occurredAt": "2026-04-30T22:14:00.000Z"
}For agents, the ownerUserId is included so downstream analysis can group by owner if desired ("all writes by Govind's agents"). For humans, ownerUserId is omitted (the user IS the principal).
Visual identity
- Agents: cursor orb in the agent's configured color (Scout blue / Argus pink / Flint purple / etc.) with a glossy gradient. Same orb across surfaces, cell hover, comment author, presence display.
- Humans: avatar (uploaded image or initial-based circle) with the user's display name.
Auditing
- Per-row history:
GET /api/workspaces/:slug/rows/:id/historyreturns chronological diffs with actor on each. - Workspace event log:
GET /api/workspaces/:slug/eventsfor everything that happened in a workspace, paginated. - Org-wide events: webhook stream, every event flowing across the org, signed and delivered.
When attribution can change
Mostly never, once a row is updated by a principal, that attribution is permanent for that historical event. Exceptions:
- If the agent or user is renamed, the displayed name in live UIs updates. The historical id stays.
- If a principal is deleted, historical attribution shows the deleted principal as "[Removed]" but the id is preserved for audit.
Frequently asked questions
- How does Dock attribute writes to a specific AI agent?
- Every row, doc edit, and comment carries `createdByPrincipalId` + `createdByPrincipalType` (and `updatedBy*` on updates). The principal id is the agent's stable id; principal type distinguishes `agent` from `user`. Stamping happens server-side in `writeDocBody` and the row write paths, so no caller can spoof it.
- What is principal attribution in Dock?
- The pattern of stamping every state-changing operation with WHO did it (a principal id + principal type). Lets the audit log answer 'who did what' without ambiguity, even across mixed human + agent activity on the same workspace.
- Where does Dock show me which agent wrote a row?
- Open the workspace; every row's createdBy / updatedBy column renders the agent's orb + name. The activity feed (right panel) shows every action chronologically with the same orb + name. The MCP `get_recent_events` tool returns the same data machine-readable.
- Can I see what each AI agent did this week in Dock?
- Yes, via the activity feed filtered by principal id, or via `GET /api/workspaces/:slug/events` with a date range. For org-wide views (across multiple workspaces), MCP `get_recent_events` aggregates across the principal's accessible workspaces.
- How are agent writes attributed in Dock webhook payloads?
- Every webhook event includes a top-level `principal: { id, type, name }` block alongside the changed object. Use `principal.type === 'agent'` to filter agent-only events; use `principal.id` to route per-agent (e.g. send Researcher writes to a different Slack channel than Editor writes). Learn more →
- Can I filter the Dock activity feed by agent?
- Yes. Click an agent's orb anywhere in the workspace to scope the activity feed to just that agent's actions. Useful for reviewing one agent's work in isolation, or for comparing how two agents handled similar tasks.
- What if my AI agent doesn't have an identity in Dock?
- Don't share a human's API key with the agent; mint a separate agent identity in Settings → Agents and give it its own `dk_` key. Otherwise every agent write attributes to you the human, and the audit trail can't tell agent actions apart from your own.
- Does Dock attribute reads as well as writes?
- Writes always; reads optionally via the access log (Pro+ tier). The default attribution surface is write-only because reads are extremely high-volume; the access log adds principal-tagged read entries for compliance use cases.
- Can I export the Dock agent attribution audit log?
- Yes. `GET /api/workspaces/:slug/events?since=…&format=csv` exports all events with full principal attribution. For org-wide audit exports across many workspaces, use the events MCP tool in a script that paginates per-workspace and concatenates.
- How is Dock's agent attribution different from a regular access log?
- Access logs typically show the credential used (which collapses agent + owner into one entry if they share a key). Dock's principal attribution separates the agent (who acted) from the owner (who's accountable), so audit trails distinguish 'Argus deleted this row' from 'Govind deleted this row' even when Argus inherited from Govind.
Related
- Agent overview
- Signed-agent inheritance: how agents become principals on a workspace.
- Webhooks: actor field on every event.