Team & admin
Policies
Every coordination policy rule, its default, and how org defaults and repo overrides combine.
On this page
- Where policies live
- With the API
- Rules
- require_intent
- intent_ttl_hours
- session_idle_minutes
- severity
- block_contract_break_when_criticality
- block_min_confidence
- exclusive_max_files
- protected_paths
- exclusive_by_default
- ignore_paths
- override
- notify
- fail_mode
- briefing_max_tokens
- share_session_status
- cross_repo_contracts
- arrival_notices
- Full default policy
A policy decides how Comity coordinates your agents: whether intents are required, how serious each kind of conflict is, what blocks an edit, which paths are protected, and what gets posted to Slack. Defaults warn rather than block.
Where policies live
- Org default: applies to every repository.
- Repo override: rules set for one repository; everything else follows the org default.
The effective policy for a repo is Comity's defaults, overlaid with the org default, overlaid with the repo override. Objects merge key by key (for example severity); arrays and plain values replace.
Owners and admins edit policies in the dashboard under Settings → Coordination policy (pick the scope: Org default or a repository), or with the API. Everyone else sees the policy read-only. Each save creates a new version and a policy.updated event in the audit log. Agents pick up a change on their next hook call.
With the API
curl -s https://api.comity.so/v1/policies?repo=acme/api \
-H "Authorization: Bearer $COMITY_TOKEN"{
"repo_name": "acme/api",
"org": { "version": 3, "rules": { "require_intent": "auto", "ignore_paths": ["dist/**"] }, "updated_at": "2026-10-12T09:14:03.000Z", "updated_by": "0199…" },
"repo": null,
"effective": { "require_intent": "auto", "intent_ttl_hours": 24, "…": "…" }
}PUT /v1/policies (org default) or PUT /v1/policies?repo=<owner/name> stores a new version for that scope. It needs an owner or admin with the policy:write scope (the dashboard has it; tokens from comity login don't).
curl -s -X PUT https://api.comity.so/v1/policies \
-H "Authorization: Bearer $COMITY_TOKEN" -H "Content-Type: application/json" \
-d '{"rules": {"require_intent": "auto", "ignore_paths": ["dist/**", "**/*.lock"], "severity": {"path_overlap": "warn"}}}'Warning
The rules you PUT become the whole stored rule set for that scope; they are not merged with the previous version. Send every rule you want to keep overriding. {"rules": {}} on a repo removes all its overrides. The dashboard re-reads the stored rules and sends only your edits merged into them.
The merged result is validated; an invalid value returns 400 validation with the failing field.
Rules
require_intent
"off" | "auto" | "required". Default "auto".
auto: the first prompt of a session auto-drafts a private intent (titled from the prompt's first line). Plans become the intent's plan. The agent confirms it withintent_declare, keeping its number.required: likeauto, and an edit (pre_edit) by a session without a declared intent is blocked with: "This repository's policy requires a declared intent before editing. Declare one with the intent_declare MCP tool, then retry."off: no auto-drafts.
intent_ttl_hours
Integer > 0. Default 24. A draft, active or blocked intent with no activity for this long, and no active session working on it, becomes expired.
session_idle_minutes
Integer > 0. Default 30. A session with a hook event within this window is active; quieter sessions are idle. MCP tools without session_id act as your most recent session within this window.
severity
Severity per conflict kind: "info" | "warn" | "block".
| Kind | Default |
|---|---|
path_overlap |
info |
symbol_overlap |
warn |
contract_break |
warn |
textual_merge |
warn |
duplicate_work |
warn |
dependency_order |
warn |
protected_path |
block |
textual_merge and duplicate_work are accepted but no detector produces them today. See Conflicts.
block_contract_break_when_criticality
Array of "low" | "normal" | "high" | "frozen". Default ["high", "frozen"]. A contract break escalates to a block only when the contract's criticality is in this list.
block_min_confidence
Number 0–1. Default 0.85. A finding needs at least this confidence to block; below it, it is downgraded to a warning.
exclusive_max_files
Integer > 0. Default 50. An exclusive path claim (intent mode: "exclusive") only blocks others when it covers at most this many files; a broader claim is treated as shared.
protected_paths
Array of { glob, owners, fail_closed }. Default [].
| Field | Type | Default | Notes |
|---|---|---|---|
glob |
string | Required. Repo-relative glob, e.g. db/migrations/**. |
|
owners |
string[] | [] |
user:<email>. Other prefixes (such as team:) are rejected with a 400. |
fail_closed |
boolean | false |
Stored, but not enforced: hooks always fail open. |
An edit under a protected path produces a protected_path conflict (severity block by default).
{ "protected_paths": [{ "glob": "db/migrations/**", "owners": ["user:diego@acme.com"] }] }exclusive_by_default
Array of globs. Default []. Paths matching these are treated as exclusively claimed by whoever edits them first.
ignore_paths
Array of globs. Default []. Ignored by every detector: generated files, lockfiles, build output.
override
| Field | Default | Notes |
|---|---|---|
override.allowed_roles |
["owner", "admin"] |
Roles that may override a conflict. Any of owner, admin, member, viewer, billing. |
override.require_reason |
true |
When true, an override needs a reason of 3–2,000 characters (after trimming). When false, the reason is optional. |
notify
Slack notifications. See Integrations → Slack.
| Field | Default | Notes |
|---|---|---|
notify.slack_events |
["conflict.detected:block", "hook.blocked"] |
<event type> or <event type>:<info|warn|block>; a severity suffix matches that severity and above. |
notify.slack_min_severity |
"warn" |
Events that carry a severity are only posted at or above this. |
fail_mode
"open" | "closed". Default "open". Stored, but not enforced: hooks always fail open (the dashboard labels it "Fail closed is saved but not enforced yet"). See How it works → Fail-open.
briefing_max_tokens
Integer 200–4,000. Default 1500. Size budget of a briefing (about 4 characters per token).
share_session_status
Boolean. Default true. Teammates see each session's latest status (an excerpt of the agent's last message at the end of a turn, plus files touched) in briefings and search. Individual developers can also opt out with COMITY_SHARE_STATUS=0.
cross_repo_contracts
"org" | "projects" | "off". Default "org". Which other repos this repo's contracts (HTTP routes, workspace packages) are matched against:
org: every repo in the org whose policy is alsoorg, plus repos in a shared project.projects: only repos that share a project.off: none.
Both repos of a pair must allow it.
arrival_notices
Boolean. Default true. When another developer's agent starts a session in this repo, teammates' agents with a live session here get a one-time notice. See Messaging.
Full default policy
{
"require_intent": "auto",
"intent_ttl_hours": 24,
"session_idle_minutes": 30,
"severity": {
"path_overlap": "info",
"symbol_overlap": "warn",
"contract_break": "warn",
"textual_merge": "warn",
"duplicate_work": "warn",
"dependency_order": "warn",
"protected_path": "block"
},
"block_contract_break_when_criticality": ["high", "frozen"],
"block_min_confidence": 0.85,
"exclusive_max_files": 50,
"protected_paths": [],
"exclusive_by_default": [],
"ignore_paths": [],
"override": { "allowed_roles": ["owner", "admin"], "require_reason": true },
"notify": { "slack_events": ["conflict.detected:block", "hook.blocked"], "slack_min_severity": "warn" },
"fail_mode": "open",
"briefing_max_tokens": 1500,
"share_session_status": true,
"cross_repo_contracts": "org",
"arrival_notices": true
}