Privacy

AgentGraphed is local-first. By default nothing leaves your machine. The only feature that touches a server is the opt-in leaderboard. This page describes exactly what gets sent when you turn it on, what doesn't, how long we keep it, and how to delete it.

What we collect (and only when you opt in)

When the leaderboard switch is on, your local copy of AgentGraphed posts a batch of session-level rows every six hours (or sooner if you finished a new session since the last submit) to /api/leaderboard/submit. Each row in the batch contains these fields and only these fields:

handlestring
The anonymous handle you picked. Letters, numbers, dashes, underscores. One handle per batch, not per row.
schema_versioninteger
Currently 2. If we ever expand this schema, the version goes up and your app re-asks for consent.
session_uuidstring
The UUID Claude Code / Codex assigned to the session locally. Used to dedupe re-sends — if you submit the same session twice, the second write updates the first row instead of duplicating. The UUID is random; it does not encode anything about you, your project, or your prompts.
started_atISO 8601 timestamp
When the session began. UTC timestamp.
duration_msinteger
How long the session lasted, in milliseconds. From start to last message.
providerstring
claude or codex.
modelstring
Model ID for the session (claude-opus-4-7, gpt-5-mini, etc.). Public model names only.
input_tokensinteger
Fresh input tokens billed by the provider for this session.
output_tokensinteger
Output tokens billed by the provider for this session.
cache_read_tokensinteger
Cached-input tokens read back during this session (the cheap kind).
cache_write_tokensinteger
Cache-creation tokens written during this session (the premium kind).
est_cost_usdnumber
Estimated cost of this session at retail token prices.
message_countinteger
How many messages (yours + Claude's combined) the session contained.
social_linksstring[] (optional)
Up to 3 self-asserted profile URLs (GitHub, X, Reddit, Bluesky, Mastodon, LinkedIn, YouTube, or any other URL) you typed into the opt-in form. Public and unverified — we don't check that the accounts exist or belong to you. Stored in a separate profiles table keyed on your handle; an empty array clears any previously saved links.

You can preview the literal payload that would be sent for the current window inside the app at /leaderboard before you opt in.

What we never collect

This list is what the app is incapable of sending — these fields are not in the payload shape, not in the database schema, and there is no code path that reads them on submit:

  • Your prompts or message content (yours or Claude's).
  • Project names, repository names, or directory names.
  • File paths, file contents, or anything from your cwd.
  • Git branches, remotes, or commit hashes.
  • Session transcripts, system prompts, tool inputs, or tool outputs. (We send a random per-session UUID for de-duping re-submits, but it's a random identifier — it doesn't encode any of the above.)
  • Your email, real name, or any account identifier.
  • Any Anthropic / OpenAI API keys you may have entered in Settings.
  • Your IP address (we hash it with a server-side secret before storage — see the next section).
  • Telemetry of any kind from the rest of the app — dashboard renders, ingest runs, etc.

Identity

v1 handles are anonymous — you pick whatever you want. No email, no account, no third-party login. If two people pick the same handle, last write wins; we treat that as a feature of the no-auth contract, not a bug.

You can optionally attach up to 3 self-asserted social links (GitHub, X, Reddit, Bluesky, Mastodon, LinkedIn, YouTube, or any URL). They're public, unverified, and stored in a separate profiles table keyed only on your handle. Same trust model as the handle itself: anyone could submit anything; we don't check.

How we handle your IP address

Every HTTP request to our endpoints carries your IP address — that's how the internet works. We don't store it.

On every request, we hash your IP with a server-side secret (SHA-256, truncated to 32 hex chars) and use the result as a rate-limit key. The hash is also stored alongside your submission so we can audit specific abuse without ever having raw IPs in the database. The secret is not in the public source — flipping it would invalidate every existing hash.

The exact lines that do this: leaderboard-guards.ts (function hashIp).

Retention

All submissions are kept indefinitely so the leaderboard can show past weeks. There is no scheduled deletion job.

You can delete your data at any time. Two ways:

  • Opt out inside the app. Future submissions stop immediately. Existing rows stay until you delete them explicitly (see next point).
  • Hit DELETE https://agentgraphed.com/api/leaderboard/my-data?handle=YOUR_HANDLE from any tool. Returns the count of rows deleted. No auth needed in v1 — anonymous handles are anonymous both ways.

You can also audit what we have for a handle with GET https://agentgraphed.com/api/leaderboard/my-data?handle=YOUR_HANDLE.

Open source — read the code yourself

The single best way to verify any of this is to read the code. The endpoints are small and audit-friendly:

What changes if we ever expand the leaderboard

If we ever want to collect a new field, the path is:

  • Bump schema_version in the OSS client.
  • The app shows a fresh consent dialog listing the new field before any submission with the new schema is sent.
  • Submissions with the old schema_version keep working in parallel until you upgrade.

In other words: no silent expansion. Consent is per-schema, not blanket.

Questions or concerns

File an issue at github.com/sudomichael/agentgraphed. AgentGraphed is a one-person project; if something here is wrong, vague, or insufficient, please tell me.