Docs

Collaboration

Conflicts

Every conflict kind Comity detects, with examples, severities, statuses, actions, false positives and overrides.

On this page

A conflict (CF-n) is overlapping or incompatible work between two participants: two agents' intents or sessions, an agent and a pushed branch, or an agent and a protected-path rule. Comity detects conflicts from what agents actually edit (and what they declare), persists them, briefs both sides, and closes them when the overlap goes away.

Kinds

Kind Dashboard label Default severity Can block
path_overlap Same files info only exclusive claims
symbol_overlap Same code warn no
contract_break Contract break warn only for high/frozen contracts
dependency_order Dependency order warn no
protected_path Protected path block yes

textual_merge and duplicate_work exist in the API's enums and policy, but no detector produces them.

path_overlap

Both sides touch or claim the same files. Confidence depends on how specific the match is: an exact path edited by both (0.9) is stronger than two overlapping globs in declared scopes (0.3–0.5).

INT-12 (jordan, claude_code, feat/partial-refunds) and INT-14 (maya, codex, feat/refunds) overlap on 2 path(s): src/billing/refund.ts, src/billing/types.ts.

Suggestion: Narrow scope to avoid the shared paths, or coordinate via message_send between INT-12 and INT-14; if both must change them, agree on an order (conflict_respond propose_sequence).

Path overlap is info by default: it appears in briefings and the dashboard but doesn't warn. It blocks when one side holds an exclusive claim on the path (declared with mode: "exclusive", or the path matches the policy's exclusive_by_default, in which case whoever touched it first holds it), the claim covers at most exclusive_max_files files, and the other side is about to edit it:

INT-12 (jordan, …) holds an exclusive claim on db/schema.prisma covering db/schema.prisma; INT-14 (maya, …) is about to edit it.

symbol_overlap

Both sides change, or claim, the same function, class, method or type. A signature change or removal on one side against a modification on the other scores higher than two compatible edits; overlap through a containing class or in test files scores lower.

INT-12 (jordan, claude_code, feat/partial-refunds) and INT-14 (maya, codex, feat/refunds) both work on 1 symbol(s): sym:ts:src/billing/refund.ts#issueRefund. INT-12 changes the signature of sym:ts:src/billing/refund.ts#issueRefund; INT-14 modifies it.

Suggestion: Sequence the work: INT-14 rebases after INT-12 merges (conflict_respond will_rebase), split the symbol's work, or coordinate via message_send to INT-12.

contract_break

One side makes a breaking change to a contract the other side uses or has claimed:

  • an exported function, class or type whose signature changed incompatibly or that was removed,
  • an HTTP route that was removed, moved or whose signature changed (method, path, handler, schemas),
  • an exported zod schema that lost or retyped a field (adding an optional field is compatible).

"Uses" means the other side's new code references it: an import, an HTTP call to the route (fetch, axios, ky, got, HttpClient, Python requests/httpx/aiohttp), or a package import from another repo. A claim on the contract (scope.contracts or symbols) also counts, with lower confidence.

INT-12 (jordan, claude_code, feat/partial-refunds) changes the signature of http:POST /v1/refunds (breaking, criticality normal); INT-14 (maya, codex, feat/refunds) adds 1 reference(s) to it in web/src/api/refunds.ts.

Suggestion: INT-14 can build against the new signature and declare the dependency (intent_update depends_on_add INT-12), or ask jordan to keep a compatible shim until it merges (message_send).

A route whose handler changed but whose signature didn't is reported as a non-blocking contract break, "behavior/response changed", when the other side calls it.

Contract breaks escalate to block only for contracts whose criticality is in the policy's block_contract_break_when_criticality (default high, frozen). Contracts have criticality normal, and there is currently no way to raise it, so contract breaks warn.

Supported code. TypeScript, TSX, JavaScript, Python and Go for symbols and signatures. HTTP routes for Express, Koa, Hono, Fastify, Elysia and similar routers, Next.js app/**/route.ts and pages/api/**, FastAPI, Flask, Sanic, Quart, Starlette (not Go). Zod schemas in TypeScript and JavaScript.

Across repos. When a repo's route or exported package symbol breaks and an agent in another linked repo uses it, the conflict is reported to both, prefixed "Cross-repo: the contract is in X, the code that uses it in Y." Cross-repo conflicts never block. Linked repos are controlled by cross_repo_contracts and projects.

dependency_order

Intents declare dependencies with depends_on. Comity reports:

  • depending on an intent that was abandoned or expired:

    INT-14 (maya, …) depends on INT-12 (jordan, …), which is abandoned.

    Suggestion: Remove the dependency (intent_update depends_on_remove INT-12) or take over the work it was meant to deliver.

  • a cycle of dependencies among live intents:

    Dependency cycle among 2 participants: INT-12 → INT-14. None of them can merge first.

protected_path

A path matches a protected_paths glob and the person whose agent touches it isn't one of the rule's user:<email> owners. Blocks by default (an exact path match has confidence 1; a declared glob that merely overlaps the protected glob has 0.5 and only warns).

db/migrations/0042_refunds.sql (edit) by INT-14 (maya, codex, feat/refunds) falls under protected path db/migrations/** (owners: user:diego@acme.com); the user is not an owner.

Suggestion: Ask an owner (user:diego@acme.com) or an admin to approve (conflict_respond request_override), or move the change outside db/migrations/**.

List owners as user:<email>. Comity has no teams, so other owner forms (such as team:<name>) are rejected when you save the policy.

Severity and blocking

Each kind starts at the severity in the policy's severity map. A finding is blocking only when severity is block, the evidence is declared or observed (not inferred), and confidence is at least block_min_confidence (0.85); otherwise a block finding is downgraded to warn. Only the newcomer (the side that arrived second) is blocked, and only before an edit or shell command. See How it works → Decisions.

Statuses

Status Meaning
open New; needs attention
acknowledged Someone on a side said they've seen it (ack)
resolving A side is sequencing or rebasing (propose_sequence, will_rebase)
resolved Done: marked resolved, the overlap went away (evidence_gone), one side merged/abandoned/ended, or every side marked it a false positive
overridden A human overrode it with a reason
stale Both sides are gone

open, acknowledged and resolving are live. A resolved or stale conflict reopens automatically if the same overlap comes back; an overridden one reopens if the evidence changes. When a session without an intent declares one, its conflicts move to the intent and keep their numbers.

A contract break stays open for the dependent side after the changer merges, because the dependent still has to adapt, unless both share the same checkout.

Actions

Agents act with conflict_respond; people with the buttons in the dashboard's conflict drawer or POST /v1/conflicts/:ref/actions. Only participants (and owners/admins) can act.

Action Status after Use it when
ack acknowledged You've seen it and are coordinating
propose_sequence resolving You propose an order (say which in note or a message)
will_rebase resolving You'll rebase after the other side merges
resolved resolved You've fixed it
false_positive see below It isn't a real conflict
request_override unchanged You need a human to approve working through a block
JSON
{ "conflict": "CF-9", "action": "will_rebase", "note": "Rebasing after INT-12 merges." }

Acting on a closed conflict returns 409.

False positives

  • An agent's false_positive mutes the conflict for its own side only: that agent stops being warned or blocked by it. The conflict resolves as false_positive once every side has muted it (immediately when both sides belong to one developer).
  • A person's False positive in the dashboard (participant, owner or admin) resolves it at once.
  • Feedback (POST /v1/conflicts/:ref/feedback, or Useful / False positive in the dashboard) records a verdict (useful, false_positive, too_late) used for tuning and the time-saved estimate.

To silence a whole class of noise, add paths to ignore_paths (generated files, lockfiles) or lower a kind's severity.

Overrides

An override lets both sides continue despite a conflict, including a blocking one. Only people, never agents:

  1. An agent (or person) calls request_override. Comity sends a system message, "Override requested for CF-n", to everyone whose role is in the policy's override.allowed_roles (default owners and admins).
  2. One of them opens the conflict in the dashboard, clicks Override…, and gives a reason (3–2,000 characters; optional when the policy sets override.require_reason: false). API: POST /v1/conflicts/:ref/override with {"reason": "…"}.

The conflict becomes overridden, the reason is stored encrypted and shown in the audit log, and the agent is no longer blocked by it. If the evidence changes later, the conflict reopens.

Time saved

The dashboard's Est. time saved counts conflicts caught before merge, in minutes per conflict weighted by severity. Overridden, false-positive and too-late conflicts, and conflicts between two agents of one developer, count zero.