Auditing your AI memory: what your different clients wrote
The written_by field on every Gnosem memory turns your memory graph into a per-vendor audit log. Useful for catching hallucinations, tracking which client is most useful, and spotting rogue tool calls.
Every memory in Gnosem carries a written_by field. It's a plain string — the client sets it on write, Gnosem stores it verbatim, and it comes back on every read. It's the smallest possible provenance signal you can add to a memory system, and it turns out to be one of the most useful.
The field is set by the caller on memory_write. Well-behaved MCP clients set it to something identifying — "claude-code", "claude-desktop", "cursor", "windsurf", "chatgpt-custom-action". Some don't set it at all. Some set it to something wrong. All three cases are informative.
The basic audit loop
Ask any MCP-connected assistant something like:
Call memory_list with limit=100 and group the results by written_by. Show me counts and the earliest/latest timestamp per group.
You'll get back a breakdown that looks something like:
claude-code: 127 memories (2026-05-14 → 2026-07-29)
cursor: 43 memories (2026-06-02 → 2026-07-28)
claude-desktop: 31 memories (2026-04-30 → 2026-07-22)
chatgpt-custom-action: 9 memories (2026-07-08 → 2026-07-25)
(unset): 4 memories (2026-06-14 → 2026-06-14)
kimi-web: 1 memory (2026-07-11)
Nothing exotic on the server side — memory_list just returns rows including written_by, and the assistant does the counting client-side. But immediately you can see three interesting patterns:
- Claude Code is doing most of the writing. Makes sense if you spend most of your day in it. This is your primary tool.
- Something wrote 4 memories with no
written_byset, all on the same day. Worth looking at. Maybe an experimental script you ran, maybe a client with a broken tool implementation. - Kimi wrote once and never again. Either you tried it once and stopped, or Kimi's memory tooling is worse than the others and rarely fires. Either interpretation tells you something.
Catching hallucinated facts
The most valuable audit case: catching a memory that contains a made-up fact.
Long-running assistants sometimes save memories with false confidence. A common pattern: model runs a tool, misreads the output, and saves a memory summarizing what it thinks happened. Weeks later that memory surfaces on a search and quietly poisons a future decision.
Sorting by written_by lets you audit per-vendor with more focus. If you notice Cursor tends to over-summarize test output as passing when it wasn't, you can pull just Cursor's memories:
Call memory_list with limit=200, filter the results client-side to only those where written_by="cursor", and show me the ones tagged "test" or "ci".
Scan those. Any that look wrong, use memory_supersede to replace them with a corrected version (preserves audit trail), or memory_forget to delete outright. This is far more tractable than auditing the whole memory graph as one blob, because different clients have different hallucination patterns and reviewing them by client makes the patterns visible.
Spotting rogue tool calls
Every memory that shows up with a written_by you don't recognize is worth 30 seconds of investigation. Reasons this can happen:
- You installed a new MCP client for one experiment last month and forgot about it. It's still writing.
- An MCP proxy or bridge is calling Gnosem on behalf of a client, and setting
written_byto its own identifier. - Somebody got hold of your API key. This one is not paranoid — Bearer tokens are copyable. If you see a client name you never installed, rotate the key immediately from the dashboard.
The threat model here isn't "hackers." It's more mundane: an API key ends up in a config file that gets shared, a machine gets lent to someone, a laptop gets set up at work when the key was meant for personal use. The written_by field surfaces this in a way that raw memory content doesn't, because the identity of the writer is the only signal that separates "Claude Code on my laptop" from "Claude Code on someone else's laptop that got hold of my key."
Which client is actually the most useful?
Everyone has opinions about which AI assistant is best. The audit answers empirically — for you, on your work.
Two useful measures:
- Write rate per vendor. How much is each vendor saving? Higher writes usually mean deeper engagement.
- Read rate per vendor. Which memories get retrieved most, and which vendor's writes are getting recalled? Gnosem doesn't currently expose per-memory read counts, but you can approximate by inspecting which memories keep showing up when different clients call
memory_search.
Anecdotal observation from a few months of dogfooding: Claude Code writes the most useful long-form memories (architectural decisions, non-obvious workarounds). Cursor writes the most memories overall but they skew shorter and more mechanical (file locations, function signatures). ChatGPT writes rarely, but when it does, the memories are usually opinionated summaries of legal or security reasoning — the kind of thing you asked for a second opinion on and want to remember. Different clients have different personalities as memory writers.
If a vendor writes rarely and their writes get recalled rarely, that's a signal the vendor isn't earning its slot in your workflow. If a vendor writes constantly but nothing gets recalled, they're generating noise — worth turning off or tuning.
Team and org audit
Gnosem's Pro tier supports unlimited API keys. A common pattern: one key per client (one for Claude Desktop, one for Cursor, one for a CI/CD script), all writing to the same memory. Set written_by to a descriptive label per key.
Now the audit becomes a project inventory. You can see "we have 400 CI memories, half of which are stale build errors from a version of the pipeline we're not running anymore." That's a good excuse to bulk-forget by filter and reclaim signal-to-noise.
For actual teams (the future team-scoped memory feature will make this cleaner), written_by is the field that carries per-user identity in a shared memory. "Alice wrote this memory, Bob wrote that one" surfaces disagreements and duplicates that would otherwise sit undetected in the pile.
Dashboard vs. MCP audit
Two audit surfaces:
- The dashboard at gnosem.dev. Human eyeball — visual list, tag filter, per-memory delete. Best for spot-checking or catching one specific bad memory you remember seeing.
- Through an assistant via
memory_list. Better for scale, aggregation, and comparison. The assistant does the counting and grouping and can help you formulate follow-up queries.
The MCP audit path scales better because you can ask the assistant to summarize, filter, and take corrective action in one loop. "Look at everything cursor wrote in the last 30 days, tell me if anything mentions a specific outdated library, and forget those" is a five-tool-call session on the assistant's part, not a manual scroll.
Privacy note
written_by is client-set and stored verbatim. Gnosem does not add any inferred provenance — no IP-based geo, no user-agent parsing, no fingerprint. If a client sets written_by: "user-supplied-lie", that's what gets stored. This is intentional: the field is a hint for the user's own audit, not a security control. Anyone who has your API key can write memories under any written_by label they choose. Treat the field as accountability-by-convention, not enforcement.
If you need enforced per-client identity, use different API keys per client — key rotation, key revocation, and key-scoped tracking would then bind the identity to the key rather than the free-text field. That's a stronger model and works today.
Try it
If you already have a Gnosem account and a few weeks of memories accumulated, ask your primary assistant right now: "List my recent memories, group by written_by, show me counts." The pattern of vendor contribution to your knowledge should surprise you at least a little. Any patterns that don't match your usage story are worth chasing down. Sign up at gnosem.dev if you don't have an account yet — the free tier is enough to try the audit workflow.