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:
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_onlyapplies 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
fullstores signature text again from the next edits on. - The CLI reads the mode at
comity login. Ask each member to runcomity loginagain 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 logincreates a personal token per machine, namedcli · <hostname>, stored in your user config file with owner-only permissions.comity initnever 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(needstokens: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.