Integration Contract
Status: Implemented contract for Cite2Site integration authors.
Purpose
This document defines the stable contract that editor, browser, document-tool, and automation integrations must follow when calling Cite2Site. It covers selection citation, contextual lookup, overlap picking, handle editing, action availability, cancellation, error handling, and accessibility. An integration that follows this contract calls C2S for state and actions without storing authoritative overlay state.
Authority
The authoritative implementation of this contract is:
src/c2s/cli.py— CLI command surface;src/c2s/core.py— replay, lookup, and mutation logic;examples/integration/thin_client.py— reference thin-client implementation;examples/integration/editor_plugin_mock.py— editor-plugin mock;examples/integration/fixtures/— request/response contract fixtures.
Generated JSON, exports, and MkDocs pages are projections. The integration
must not treat them as authority and must not persist C2S state outside .c2s.
Selection Citation
An uncited text selection becomes a citation through one command:
Range Encoding
Ranges use unicode-scalar offsets (not byte offsets, line:column pairs, or
grapheme-cluster indices). The start is inclusive; the end is exclusive. Line
numbers are derived by counting \n characters and reported in
locator.start_line / locator.end_line for display only.
Integrations that use line:column positioning must convert to scalar offsets
before calling C2S. The reference implementation in thin_client.py passes
offsets directly.
Selection Normalization
The adapter canonicalizes the artifact content (line-ending normalization, encoding) before computing the evidence hash. Integrations must not pre-normalize the selection before sending it to C2S — canonicalization is the adapter's responsibility and must remain deterministic.
Artifact Identity
Artifact identity is a stable hash of {adapter, uri, path}. Integrations must
supply:
uri— relative or absolute path to the artifact (C2S normalizes\to/and resolves against the citation workspace root);adapter—"filesystem-text","markdown", or another supported adapter.
Absolute URIs outside the workspace root are rejected with
E_ARTIFACT_OUTSIDE_WORKSPACE.
Contextual Lookup
An integration inspects a cursor position or selected range through
lookup-actions:
No Match
When no citation overlaps the query range, the response contains
"actions": ["cite"]. The integration should offer "Cite with C2S" as the
primary action.
Single Match
When exactly one citation overlaps, the response lists that citation with its available actions. The integration may show actions directly without a picker.
Multiple Matches (Overlap Picker)
When two or more citations overlap the query range, the response contains
"requires_picker": true. The integration must present an ordered picker
before any mutating action can proceed. The picker must:
- show each citation's
preferred_handle(orcitation_idwhen no handle); - display
range_summaryandstatusfor disambiguation; - order matches by the deterministic overlap sort order.
Overlap Sort Order
Citations are ordered by:
- Match kind (exact > contains > contained_by > overlaps);
- Range size (smallest range first for
containsmatches); - Handle presence (citations with a preferred handle sort before those without);
- Citation ID (lexical order as tiebreaker).
This ordering is deterministic for the same histories and artifacts. The integration must preserve it; re-sorting by last-used, recency, or display name would make the picker inconsistent with the authoritative match order.
Note: The current implementation sorts by handle presence (has handle /
no handle). The target spec (CITE2SITE_IMPLEMENTATION_SPEC_V0_3.md) defines
most-recent-binding order. See CURRENT_STATUS_MATRIX.md overlap-ordering
row for the gap status.
Mutation Requires Concrete citation_id
Any mutating action (set-handle, note, accept-current, relocate,
retract, restore) must include the selected citation_id. The
integration must reject the mutation if the user has not selected a concrete
citation from the picker. C2S will also reject the command if called without
a --citation-id, but the integration must enforce this client-side to avoid
a confusing error round-trip.
Action Labels And Availability
Implemented Actions
| Action ID | Label | Command | Requires citation_id |
|---|---|---|---|
cite |
Cite with C2S | cite-selection |
No |
set_handle |
Rename handle | set-handle --action rename |
Yes |
note |
Add note | note |
Yes |
accept_current |
Accept current evidence | accept-current |
Yes |
relocate |
Relocate citation | relocate |
Yes |
retract |
Retract citation | retract |
Yes |
restore |
Restore citation | restore |
Yes |
Host Actions
| Action ID | Label | Implementation |
|---|---|---|
open |
Open citation | Host-native: open the artifact at the cited range. |
Unavailable Actions
| Action ID | Reason |
|---|---|
retire |
Citation retirement is not implemented in this runtime. |
undo |
Undo is not implemented in this runtime. |
redo |
Redo is not implemented in this runtime. |
Integrations must display unavailable actions with their reason rather than showing them as disabled buttons with no explanation.
Cancellation
Picker cancellation is read-only. The integration must not modify history,
state, or the cited artifact when the user dismisses the picker. The fixture
picker-cancelled.json documents the expected integration-side response shape.
Error Presentation
C2S returns structured JSON errors with stable codes. Integrations must:
- Parse the
error.codefield. - Display the
error.messagetext to the user. - Never parse prose, match substrings, or guess the error from unstructured output.
- Never expose resolved filesystem paths — error details may contain the
user-supplied
artifactURI but not the internal resolved path.
Common integration-facing error codes:
| Code | Meaning | Source |
|---|---|---|
E_ARTIFACT_MISSING |
The artifact file does not exist. | C2S CLI |
E_ADAPTER_UNSUPPORTED |
The requested adapter is not installed or recognized. | C2S CLI |
E_ARTIFACT_OUTSIDE_WORKSPACE |
The artifact path is outside the citation workspace. | C2S CLI |
E_CITATION_NOT_FOUND |
The citation ID does not exist. | C2S CLI |
E_HANDLE_COLLISION |
The handle is already bound to a different citation. | C2S CLI |
E_PRIVACY_POLICY |
The requested privacy mode is not authorized. | C2S CLI |
E_INTEGRATION_PICKER_REQUIRED |
Overlapping citations require a selected citation ID before mutation. | thin-client |
E_INTEGRATION_BAD_JSON |
C2S did not return a JSON envelope. | thin-client |
Accessibility
Integrations should provide:
- Keyboard path: Every action reachable without a pointer device. The picker must support arrow-key navigation and Enter to select.
- Visible text labels: Every action must have a human-readable label. Citation IDs are not displayed as primary labels when a preferred handle exists.
- Focus behavior: Opening the picker should not move keyboard focus to an unrelated element. Closing the picker should return focus to the originating selection or context-menu trigger.
- Picker ordering: The picker must preserve the authoritative sort order defined above. Screen-reader announcement should include match kind and range summary.
Transport Notes
Editor Plugin
An editor plugin calls C2S as a subprocess or via the Python library. It sends
the current selection's artifact URI and scalar offsets. The editor_plugin_mock.py
example demonstrates the minimal interaction loop: select text → lookup → display
picker → execute action → refresh display.
Browser Extension
A browser extension cannot call C2S as a subprocess directly. It should:
- Serialize the selection contract as a JSON request;
- Send it to a local native-messaging host or a local HTTP endpoint that calls C2S;
- Receive the structured JSON response;
- Render actions in the extension popup or context menu.
The extension must not cache citation state across page reloads — it must
re-call lookup-actions on every interaction.
Document Tool
A document tool with a scripting interface (e.g., a PDF viewer with a plugin API) should expose selection as artifact URI + adapter + scalar offsets. The tool must not convert offsets to a different encoding without an explicit, documented transformation. If the tool cannot produce deterministic scalar offsets, it must document the limitation and the expected drift in replay status.