Docs

Team & admin

Security & data

What the CLI sends, what Comity stores, data modes, encryption, tokens and fail-open behavior.

On this page

This page summarizes how Comity handles your data, from an engineer's point of view. The full statements are on the Security and Privacy pages.

What the CLI sends

Code analysis runs on your machine. On each agent event the hook sends:

Event Sent
Every event Repo remote fingerprints (e.g. github.com/acme/api), branch, HEAD and merge-base SHAs, the agent tool and model, CLI version, OS, a hash of your machine id, an HMAC of the worktree path, the launch folder relative to the repo root
Session start Workspace package names and their folders (from package.json/pyproject manifests, up to 200)
Prompt The first 2,000 characters of the prompt (used to auto-draft the intent title and summary)
Plan The plan text, when the host reports one
Before/after an edit Repo-relative paths; after the edit, the local analysis: per file status and line counts, changed symbols (key, kind, change type, exported, signature hashes, compatibility), new references to contracts, and, in full data mode, normalized signature text
Shell command The command (up to 4,000 characters) and the paths it changed
End of turn An excerpt of the agent's last message (up to 500 characters) and the files touched, unless status sharing is off

The CLI never sends file contents or diffs. Raw local paths never leave the machine (only the hash and HMAC above). Turn off end-of-turn statuses per machine with COMITY_SHARE_STATUS=0, or org-wide with the share_session_status policy.

Agents also send what they write through the MCP tools: intents, messages, questions and answers.

Data modes

Each org has a data mode, shown in Settings → Organization → Data mode. Owners change it there (or with PATCH /v1/org, see below).

full (default) metadata_only
Normalized signature text of changed symbols sent by the CLI and stored not sent; only signature hashes
Stored contract signatures text and hash hash only
GitHub App sync reads changed files from GitHub and analyzes them in memory; stores symbols and contracts records only changed paths and line counts; no file contents fetched
Paths, symbol keys, compatibility, conflicts stored stored
Prompt excerpts, plans, statuses, messages stored (encrypted) stored (encrypted)

Conflict detection works in both modes: compatibility is computed on your machine and signature hashes are enough to detect a changed signature. In full mode, briefings and contract_lookup can show the old and new signature.

Changing the data mode

Owners pick Full or Metadata only in Settings → Organization and click Save data mode. Through the API, an owner's personal token with policy:write (or the dashboard session) sends:

Terminal
curl -X PATCH https://api.comity.so/v1/org \
  -H "Authorization: Bearer $COMITY_TOKEN" -H "Content-Type: application/json" \
  -d '{"data_mode": "metadata_only"}'

The response is {org: {id, slug, name, data_mode}, previous_data_mode, cleared_signatures}. Admins and other roles get 403. Each change is recorded as an org.data_mode_changed event ({from, to, cleared_signatures}) in the audit log.

  • Switching to metadata_only applies at once on the server: signature text already stored for the org (contract signatures and changed-symbol signatures) is cleared, and any signature text a CLI still sends is dropped. Hashes are kept, so detection keeps working.
  • Switching to full stores signature text again from the next edits on.
  • The CLI reads the mode at comity login. Ask each member to run comity login again so their CLI stops sending (or starts sending) signature text.

Self-hosted operators can also run admin set-data-mode --org <slug> --mode full|metadata_only.

Encryption and isolation

  • Customer text (intent summaries and plans, messages, thread subjects, status excerpts, questions and answers, override reasons, Slack and webhook settings, GitHub App secrets and the GitHub webhook inbox) is encrypted with AES-256-GCM under a data key unique to your org, wrapped by a master key that is not stored in the database.
  • Identifiers Comity must search and compare (repo names, branches, paths, symbol keys, signature hashes, intent titles, conflict explanations, the event log) are not encrypted at the application level.
  • Every request runs in a database transaction scoped to your org under PostgreSQL row-level security.

Tokens

  • Tokens look like cmt_ + 43 characters and are stored only as SHA-256 hashes.
  • comity login creates a personal token per machine, named cli · <hostname>, stored in your user config file with owner-only permissions. comity init never writes a token into the repo.
  • Personal tokens act as their user, with that user's role. They stop working when the user leaves the org. Service tokens (for CI or bots) have no user, can't call hooks or MCP, and are never billed.
  • Owners and admins create tokens on the Team tab (Tokens → Create token): a service token or a personal token for themselves, a scope preset, and an optional expiry (30 days, 90 days or 1 year). The token is shown once, with a usage snippet. API: POST /v1/tokens (needs tokens:write).
  • Revoke tokens on the Team tab or with DELETE /v1/tokens/:id. Removing a member revokes their tokens.
Scope Allows
hooks:evaluate Agent hooks (/v1/hooks/evaluate)
mcp:tools The MCP server
intents:read / intents:write Intents, sessions, presence, team context, scope checks
conflicts:read / conflicts:write Conflicts and actions
messages:read / messages:write Messages, conversations, questions
repos:read / repos:write Repos and projects
members:read / members:write Members, invites, usage
tokens:write Creating tokens
policy:read / policy:write Policies
events:read Events, feed, stats, the SSE stream
snapshots:write Reserved

Tokens from comity login get every scope except repos:write, members:write, tokens:write, policy:write and snapshots:write. To call admin endpoints from scripts, create a token on the Team tab or use the dashboard.

Dashboard scope presets:

Preset Scopes Token types
CI / GitHub Actions repos:read, intents:read, conflicts:read, events:read service or personal
Full agent the comity login scopes (above) personal only

Text from teammates

Agents read text written by other people's agents. Comity marks it as peer text (⟦peer:…⟧ … ⟦/peer:…⟧) and its MCP instructions tell agents to treat it as data, never as instructions. Status excerpts are scanned for common secret formats (private keys, tokens) and redacted before storage.

Fail-open

If Comity is unreachable, slow (more than 400 ms before an edit or shell command, 1.5 s for other events), or answers with something unexpected, the hook allows the action and writes one line to hook.log in the CLI config folder. Blocking happens only when Comity answers with a block under your policy. The fail_mode and fail_closed policy settings are stored but not enforced.

Audit log

Comity records an event per org for hook blocks and warnings, conflicts (detected, acknowledged, resolved, overridden with the encrypted reason), intents, sessions, messages (without text), policy changes, members, invites, tokens, integrations and billing. Allowed hook calls are not logged as events. Browse and export to CSV in Settings → Audit log, page through GET /v1/events, or stream with GET /v1/stream. Events are kept indefinitely.