# 0033 · Every read and edit by an AI tool says which tool it was, and who can see it

**Status:** Accepted · 2026-11-05. Tornike decided who sees what (below). It extends
[0021](https://codna.me/docs/adr/0021-agents-are-members.md), whose agent accounts already have their reads counted, to the
AI tools people connect as themselves.

## Context

On 2026-10-25 the read audit moved up, from "before a bank or hospital" to the first project
(wiki:decisions/codna-sits-under-the-ai-tools): CoDNA is the memory under Claude, ChatGPT and the
coding agents, and the record of what they read is part of what it offers. Georgia's data law
expects operations on data to be logged, and the National Bank's 2026 plans ask for controlled data
sources.

What CoDNA records today stops short of that:

- **It does not know which tool is calling.** The MCP endpoint is stateless and keeps nothing
  between requests. It never reads the client's name from `initialize`, nor the access token's
  client (`azp`). A person's Claude and their ChatGPT are the same person to it.
- **A person's own AI tool reading a page is not counted.** Only agent accounts' reads are
  (`agent_reads`, [0021](https://codna.me/docs/adr/0021-agents-are-members.md)). Usage counts ([data-model.md](https://codna.me/docs/data-model.md#usage-counts))
  name tools and days, never documents.
- **A version does not say what made it.** `revisions` has an author and a summary. An edit a
  person's AI tool made over MCP looks like one they typed, so the strand margin
  ([data-model.md](https://codna.me/docs/data-model.md#suggested-changes)) lights only accepted suggestions.

The design system (Ink and Strand) draws all of this: a Reads tab in the Activity panel, "Your AI
tools this week" in the Inbox, versions that say "Dana's Claude edited it", and the margin's strand
on every line an AI wrote.

## Decision

### Which tool it was

- **The tool is named by what it says it is when it connects,** kept against the OAuth client it
  signed in through. Every MCP session starts with `initialize`, whose `clientInfo` names the
  client (`claude-ai`, `openai-mcp`, `claude-code`, `codex-mcp-client` and so on). CoDNA stores
  that name and version in `mcp_clients`, keyed by the access token's `azp` (or `client_id`),
  which the identity provider issued for that connection. Each later call on a token from that
  client is that tool's.
- **Known names read as people say them:** Claude, ChatGPT, Claude Code, Codex, Gemini CLI. Any
  other name is shown as it was given. A client whose `initialize` CoDNA has not seen since this
  shipped is "an AI tool" until it connects again.
- **The name labels; it does not authorise.** A client can call itself anything. What it may read
  is still what the person may read, and the `azp` is the identity provider's, not the client's.

### What is recorded

- **Each version records how it was made,** in `revisions.via`: `web` (the editor), `api` (a
  person's token on the REST API), `mcp:<tool>` (an AI tool over MCP), `suggestion` (an accepted
  suggested edit, which also keeps the tool that suggested it in `edit_suggestions.via`),
  `automation`, `import` or `cli`. Versions from before this have none.
- **Each page an AI tool opens is counted,** per person, tool, page and day, in `document_reads`
  (`count`, `last_at`): when `get_document` returns it, or `get_file` returns one of its files.
  Agent accounts keep `agent_reads`. Searching, listing and history are not reads: they show
  titles and snippets, and would count every result.
- **A person reading in the browser is not counted.** The decision was about AI tools; the web app
  stays as it was ("on the web that hour").
- **Kept for 90 days,** pruned nightly, as `agent_reads` is.

### Who sees what (Tornike, 2026-11-05)

1. **Everyone who can read a page sees what read it, by tool,** with no names: "Claude read it 31
   times this week, for 3 people". Agent accounts are named, since an agent is not a person.
2. **Each person sees their own reads in full:** which of their tools read which page, and when.
3. **Naming colleagues is the instance's choice, off by default.** With `reads.names` on, the
   Reads tab also lists who each tool read for. Management sets it (`PATCH
   /api/manage/reads-policy`, `codna reads policy --names on|off`), and the change is audited.
4. **Viewing as an agent counts nothing,** and neither does the web app's own reading.

**Before a bank or another regulated customer uses it,** the names setting and the 90 days are to
be checked against Georgia's Law on Personal Data Protection. That is Tornike's.

### Where it shows

- **The Activity panel's Reads tab:** this week and the last 30 days, by tool, then your own.
- **The Inbox, "Your AI tools this week":** for each of your tools, the pages it read and edited,
  of those you can read now.
- **Versions** say which tool made them: "Dana's Claude edited it".
- **The strand margin** lights the lines an AI tool wrote directly (`via mcp:…`) as well as
  accepted suggestions: not raw material it filed, nor lines a revert put back.

## Alternatives weighed

- **The User-Agent header.** Rejected: it varies by library and platform, is no harder to fake
  than `clientInfo`, and is not what the protocol names the client by.
- **Asking the identity provider for each client's registered name.** Rejected: the core holds no
  admin credentials for Keycloak, and an instance may use another provider.
- **A row per call.** Rejected: it grows with every call and says nothing a daily count does not.
  The tool-call log (`logCalls`) stays a log line.
- **Counting the web app's reads too.** Rejected for now: it would show who read what in the
  browser, which nobody asked for.

**Trade-off accepted:**

- The tool's name is what it says it is.
- Versions and reads from before this have no tool.
- Read counts per person are personal data, kept 90 days; colleagues' names stay hidden unless the
  instance turns them on.

## Where it stands

- **2026-11-05:** accepted and built: the record (clients, `via`, reads), the API and its setting,
  the Activity panel's Reads tab, "Your AI tools this week" in the Inbox, versions and suggestions
  naming the tool, and the margin marking what a tool wrote directly. Tested end to end against
  an MCP client naming itself `claude-ai` and `openai-mcp` (internal/api/reads_api_test.go).
