From b4d99c0a0c423a3d136464c43c359dd4822fdbdf Mon Sep 17 00:00:00 2001 From: staff-swe-5 Date: Thu, 28 May 2026 11:21:33 -0700 Subject: [PATCH 1/4] docs(rcp): publish v1.0.0 spec with explicit stability policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds docs/rcp/v1.md — the public Runtime Context Protocol spec that IDE and agent vendors integrate against. Closes the RFC 0001 workstream 4 deliverable. - Tools (12) and prompts (4) listed in canonical underscore form - Wire schemas: ManifestEntry, RuntimeContext, Annotation, ProblemDetails - Error code vocabulary (22 codes, full DomscribeErrorCode coverage) - Stability policy: frozen/additive/breaking rules with worked examples - Aliases-through-one-minor-cycle policy for dotted legacy names - Cross-linked from README MCP Tools section and TECHNICAL_SPEC.md §3.4 Depends on #32 (@domscribe/protocol package) and #33 (canonical underscore tool names) for full surface alignment; this PR ships the spec text. Verifier should sync tool-name tables in README and TECHNICAL_SPEC after #33 lands. Refs #35 --- README.md | 4 +- TECHNICAL_SPEC.md | 2 + docs/rcp/v1.md | 284 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 docs/rcp/v1.md diff --git a/README.md b/README.md index 22068ca..3614d11 100644 --- a/README.md +++ b/README.md @@ -397,6 +397,8 @@ No single competitor combines build-time stable IDs, deep runtime capture, bidir ## MCP Tools +The agent-facing surface — tools, prompts, wire schemas, error envelope, and a stability policy — is specified by the **Runtime Context Protocol (RCP)**. RCP is versioned independently of this implementation. The current version is **[RCP v1.0.0](./docs/rcp/v1.md)**, published from `@domscribe/protocol@1.0.0`. IDE and agent vendors integrating against Domscribe should treat the spec as the contract; the table below is a human-readable index. + | Tool | Description | | ----------------------------------- | --------------------------------------------------------------------------------------- | | `domscribe.query.bySource` | Query a source file + line and get live runtime context (props, state, DOM snapshot) | @@ -412,7 +414,7 @@ No single competitor combines build-time stable IDs, deep runtime capture, bidir | `domscribe.annotation.search` | Full-text search across annotation content | | `domscribe.status` | Relay daemon health, manifest stats, queue counts | -See the [`@domscribe/mcp` README](./packages/domscribe-mcp/README.md) for detailed tool schemas, response formats, and prompt definitions. +See the [`@domscribe/mcp` README](./packages/domscribe-mcp/README.md) for detailed tool schemas, response formats, and prompt definitions, and **[RCP v1.0.0](./docs/rcp/v1.md)** for the protocol spec and stability policy. --- diff --git a/TECHNICAL_SPEC.md b/TECHNICAL_SPEC.md index 864f079..b2d525d 100644 --- a/TECHNICAL_SPEC.md +++ b/TECHNICAL_SPEC.md @@ -372,6 +372,8 @@ Pluggable transport layer for runtime ↔ overlay communication: #### MCP Tools (for coding agents) +> The agent-facing surface — tool/prompt names, wire schemas, error envelope, and stability policy — is specified by [RCP v1.0.0](./docs/rcp/v1.md), versioned independently as `@domscribe/protocol@1.0.0`. The table below summarises what this implementation exposes; the spec is the contract. + | Tool | Description | | -------------------------- | ------------------------------------------------------------------------------ | | `annotation-get` | Retrieve annotation by ID | diff --git a/docs/rcp/v1.md b/docs/rcp/v1.md new file mode 100644 index 0000000..f741d9a --- /dev/null +++ b/docs/rcp/v1.md @@ -0,0 +1,284 @@ +# Runtime Context Protocol — RCP v1.0.0 + +> **RCP v1.0.0 — published from `@domscribe/protocol@1.0.0`** +> +> Status: **stable**. Specifies the agent-facing contract that an IDE, coding agent, or other tool consumes to read Domscribe's manifest and annotation state at runtime. + +RCP is the protocol that Domscribe ships against. The implementation in this repository is one conformant implementation; the protocol is the unit IDE vendors, agents, and downstream tools integrate against. The shapes, names, and stability policy in this document are versioned by `@domscribe/protocol`. Any RCP consumer can depend on `@domscribe/protocol` directly to get the typed wire shapes — no transitive dependency on Domscribe's relay or runtime is required. + +## Status & scope of v1 + +RCP v1 covers, and only covers: + +- A single transport binding: **Model Context Protocol (MCP) over stdio**, as defined by the [Anthropic MCP specification](https://modelcontextprotocol.io). +- A fixed set of MCP **tools** the consumer can call (§3). +- A fixed set of MCP **prompts** the consumer can fetch (§4). +- The wire **schemas** for the request/response payloads of those tools — `ManifestEntry`, `RuntimeContext`, `Annotation`, and the error envelope (§5). +- The **error code** vocabulary returned in failure responses (§6). +- The **stability policy** that tells you what is allowed to change without a major version bump (§7). + +Out of scope for v1, but not precluded for later versions: + +- Transport bindings other than MCP/stdio (gRPC, JSON-RPC over HTTP, WebSocket). +- Server-to-client push of annotation events (today the consumer polls via tools). +- Multi-tenant relay semantics. A v1 relay serves one workspace. +- A public adapter SDK for framework authors. See [RFC 0001](../rfcs/0001-rcp-as-versioning-unit.md), §"out of scope". + +## 1. Conformance + +A conformant RCP v1 **server** MUST: + +- Advertise the `tools` capability on initialize. +- If it claims to support prompts, advertise the `prompts` capability. +- Implement every tool in §3 with input and output that validate against the schemas in `@domscribe/protocol`. +- Implement every prompt in §4 if `prompts` is advertised. +- Return error responses that validate against `ProblemDetails` (§5.4) with a `code` drawn from §6. + +A conformant RCP v1 **client** MUST: + +- Treat unknown optional fields on response payloads as valid (additive forward compatibility, §7.2). +- Recognise the error codes in §6 and not depend on the human-readable `title` or `detail` fields for control flow. + +## 2. Transport + +RCP v1 runs over MCP/stdio. A consumer launches a server process and exchanges JSON-RPC 2.0 messages over its stdin/stdout, per the MCP specification. The reference server in this repository is `domscribe-mcp`. + +Server identity, returned on `initialize`: + +``` +{ "name": "domscribe", "version": "" } +``` + +The server `version` is the implementation's package version, not the RCP version. Consumers wanting to know the protocol version a server speaks SHOULD use the presence of the tools and prompts listed below, combined with the server's announced capability set. + +## 3. Tools + +All tool names match the regex `^[a-zA-Z0-9_-]{1,64}$` and use the canonical underscore-separated form. Aliases for legacy dotted names (e.g. `domscribe.resolve`) MAY be exposed by an implementation through the v1.x minor cycle for migration; they are not part of v1.0.0 and will not be accepted by stricter MCP clients (Windsurf and friends). See §7.4. + +| Tool | Purpose | +| ------------------------------------ | ------------------------------------------------------------------------------------------ | +| `domscribe_resolve` | Resolve a `data-ds` element ID to its source location (file, line, column, component). | +| `domscribe_resolve_batch` | Resolve multiple element IDs in one call. | +| `domscribe_manifest_query` | Find manifest entries by file path, component name, or element ID. | +| `domscribe_manifest_stats` | Manifest coverage statistics (entry count, file count, component count, cache hit rate). | +| `domscribe_query_by_source` | Given a source file + line, return the matching `ManifestEntry` and live `RuntimeContext`. | +| `domscribe_annotation_list` | List annotations, filtered by status. | +| `domscribe_annotation_get` | Retrieve a single annotation by ID. | +| `domscribe_annotation_search` | Full-text search across annotation content. | +| `domscribe_annotation_process` | Atomically claim the next queued annotation (prevents concurrent agent conflicts). | +| `domscribe_annotation_update_status` | Manually transition annotation status. | +| `domscribe_annotation_respond` | Attach an agent response and transition the annotation to `processed`. | +| `domscribe_status` | Relay daemon health, manifest stats, queue counts. | + +When no workspace is detected, an implementation MAY respond to `domscribe_status` with a reduced diagnostic shape (`{ active: false, cwd, guidance, nextSteps }`) instead of the active-mode shape. Consumers SHOULD branch on the `active` field. The diagnostic-mode shape is informational and not part of the v1 normative response surface. + +Input and output shapes for each tool are exported as Zod schemas from `@domscribe/protocol`. Consumers should treat the schemas exported from that package as the source of truth — this document is a human-readable companion, not an alternative source. The schema names follow the pattern `InputSchema` and `OutputSchema`. + +Every tool output extends a common base: + +```ts +{ error?: string } // populated only when the call failed and a structured envelope is also returned +``` + +Failure responses are described in §5.4. + +## 4. Prompts + +| Prompt | Purpose | +| ------------------- | ------------------------------------ | +| `process_next` | Process the next queued annotation. | +| `check_status` | Get a system status overview. | +| `explore_component` | Deep-dive into a specific component. | +| `find_annotations` | Discover pending annotations. | + +Prompts return one or more messages with `role: "user" | "assistant"` and `content: { type: "text", text: string }`. Prompt argument schemas are exported as Zod schemas from `@domscribe/protocol`. + +## 5. Wire schemas + +The full Zod definitions live in `@domscribe/protocol`. The summaries below describe the v1.0.0 fields a consumer can rely on. Every field marked **stable** is covered by the §7 stability policy; every field marked **experimental** may change in a minor release per §7.3. + +### 5.1 ManifestEntry + +A `ManifestEntry` is one row in Domscribe's DOM→source index. It is returned by `domscribe_resolve*`, `domscribe_manifest_query`, and as part of `domscribe_query_by_source` and `Annotation.context.manifestSnapshot`. + +| Field | Type | Stability | Notes | +| ----------------------- | -------------------------- | ------------ | ----------------------------------------------------------------- | +| `id` | `string` (8-char nanoid) | stable | Matches `/^[A-Za-z0-9_-]{8}$/`. | +| `file` | `string` | stable | Project-root-relative path. | +| `start` | `SourcePosition` | stable | `{ line, column, offset? }`. Line is 1-indexed, column 0-indexed. | +| `end` | `SourcePosition?` | stable | Optional end position. | +| `elementId` | `string?` | stable | The literal `id` attribute on the element, if any. | +| `tagName` | `string?` | stable | HTML/component tag name. | +| `componentName` | `string?` | stable | Owning component, if known. | +| `parent` | `string?` (entry id) | stable | Parent `ManifestEntry.id`. | +| `children` | `string[]?` (entry ids) | stable | Child entry IDs. | +| `wrappers` | `string[]?` | stable | Wrapping component names, outer-first. | +| `styles` | `StyleInfo?` | stable | `{ file?, classNames?, modules?, inline? }`. | +| `dataBindings` | `Record?` | experimental | Shape determined by `FrameworkAdapter`. | +| `componentMetadata` | `Record?` | experimental | Framework-specific extension bag. | +| `isApproximateLocation` | `boolean?` | stable | True if the source mapping is best-effort (e.g., SSR fallback). | +| `fileHash` | `string?` (16 hex) | experimental | xxhash64 of the source file at transform time. | + +### 5.2 RuntimeContext + +A `RuntimeContext` is the live runtime snapshot for a component, returned by `domscribe_query_by_source` and embedded in `Annotation.context.runtimeContext`. + +| Field | Type | Stability | Notes | +| ---------------- | ---------- | ------------ | ----------------------------------------------------------------------------- | +| `componentProps` | `unknown?` | experimental | Serialized props snapshot. Shape determined by the active `FrameworkAdapter`. | +| `componentState` | `unknown?` | experimental | Serialized state snapshot. | +| `eventFlow` | `unknown?` | experimental | Breadcrumb trail of recent events leading to the snapshot. | +| `performance` | `unknown?` | experimental | Performance metrics (frame timings, render counts). | + +The four fields themselves are stable in v1 — consumers can rely on them existing and being optional — but the _contents_ of each are explicitly experimental in v1, because the runtime capture format is still hardening across frameworks. Per §7.3, a v1.x minor release may add structure to these without bumping major. + +### 5.3 Annotation + +An `Annotation` is one captured user interaction with its full context. + +``` +Annotation { + metadata: { id, timestamp, mode, status, schemaVersion, errorDetails? } + interaction: { type, selectedText?, selectedElement?, boundingRect? } + context: { pageUrl, pageTitle, viewport, userAgent, domSnapshot?, manifestSnapshot?, userMessage?, environment?, runtimeContext? } + agentResponse?: { message? } +} +``` + +Enums returned by v1 servers: + +- `metadata.mode`: `"element-click" | "text-selection"` +- `metadata.status`: `"queued" | "processing" | "processed" | "failed" | "archived"` +- `interaction.type`: `"element-annotation" | "text-selection"` + +`metadata.schemaVersion` is an integer that identifies the `Annotation` shape (currently `1`). A consumer that does not recognise the value MUST refuse to parse and surface a `DS_VALIDATION_FAILED`-shaped error to its caller. + +A reduced `AnnotationSummary` is returned by listing endpoints: + +``` +AnnotationSummary { + id, status, timestamp, entryId?, componentName?, userMessageExcerpt? +} +``` + +### 5.4 Error envelope — `ProblemDetails` + +Failed tool calls return an `isError: true` MCP result whose textual content is a JSON-serialized `ProblemDetails` object, modelled after [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807): + +| Field | Type | Stability | Notes | +| ------------ | ----------------------------- | ------------ | ----------------------------------------------------------------------------- | +| `code` | `DomscribeErrorCode` (see §6) | stable | Use this for control flow. | +| `title` | `string` | stable | Short, human-readable summary. Not for control flow. | +| `detail` | `string?` | stable | Longer explanation specific to this occurrence. | +| `instance` | `string?` | stable | URI identifying the specific occurrence. | +| `status` | `number?` | stable | HTTP-style status code, when meaningful. | +| `extensions` | `Record?` | experimental | Bag for code-specific data. Consumers MUST tolerate absence and unknown keys. | + +## 6. Error codes + +The complete v1 vocabulary. New codes MAY be added in a minor release per §7.3; existing codes will not be removed or repurposed within v1. + +| Code | Meaning | +| -------------------------- | ---------------------------------------------------------------- | +| `DS_VALIDATION_FAILED` | Input failed schema validation. | +| `DS_CONFLICT` | Request conflicts with current resource state. | +| `DS_INVALID_INPUT` | Input was syntactically well-formed but semantically rejected. | +| `DS_INTERNAL_ERROR` | An unexpected server-side failure occurred. | +| `DS_NOT_IMPLEMENTED` | The server does not implement the requested capability. | +| `DS_MANIFEST_INVALID` | The manifest could not be parsed. | +| `DS_MANIFEST_NOTFOUND` | No manifest is loaded. | +| `DS_MANIFEST_CORRUPTED` | The manifest loaded but failed an integrity check. | +| `DS_ELEMENT_NOT_FOUND` | Requested element ID does not resolve to a manifest entry. | +| `DS_ANNOTATION_INVALID` | Annotation payload failed schema validation. | +| `DS_ANNOTATION_NOTFOUND` | No annotation with that ID exists. | +| `DS_ANNOTATION_PROCESSING` | Annotation is already being processed by another consumer. | +| `DS_RESOLVE_STALE_TARGET` | Target was resolved but the underlying source has since changed. | +| `DS_DIFF_INVALID` | A supplied diff/patch could not be applied. | +| `DS_WRITE_GUARD_BLOCKED` | A write guard refused the requested mutation. | +| `DS_AGENT_UNAVAILABLE` | The agent end of the protocol could not be reached. | +| `DS_TRANSFORM_FAILED` | A build-time transform failed. | +| `DS_TRANSFORM_UNSUPPORTED` | Requested transform is not supported in this configuration. | +| `DS_RELAY_UNAVAILABLE` | The relay daemon is not reachable. | +| `DS_RELAY_TIMEOUT` | The relay daemon did not respond in time. | +| `DS_MCP_INVALID_REQUEST` | The MCP request was malformed. | +| `DS_MCP_METHOD_NOT_FOUND` | The MCP method is unknown to this server. | + +## 7. Stability policy + +This section is normative. A reader can use the rules here to predict, without consulting the implementation team, what changes count as breaking and which do not. + +### 7.1 What "v1" promises + +Within RCP v1, the following are **frozen**: + +- Every **tool name** in §3. +- Every **prompt name** in §4. +- Every field marked **stable** in §5, including its type, optionality, and semantics. +- Every **error code** in §6 — both that it exists and what it means. +- The error envelope shape itself (`code`, `title`, `detail`, `instance`, `status`, `extensions`). +- The transport binding being MCP over stdio. + +Calling a frozen tool name with v1-shaped input on a v1.x server MUST not return a v2-shaped output or a code outside §6. + +### 7.2 What additive (minor) releases may do — `1.x.0` + +A v1.x minor release MAY: + +- Add a **new tool** or **new prompt**, provided existing tools keep their v1 semantics. +- Add an **optional field** to a response shape. Clients that don't know the field MUST ignore it. +- Add a **new value** to an enum that is documented as extensible. The v1 enums in §5.3 (`mode`, `status`, `type`) are **not extensible** in v1 — adding a value to them is breaking; this is the one place v1 deliberately accepts brittleness in exchange for clarity. +- Add a **new error code** to §6. Clients that don't recognise it MUST fall back to a generic-failure path. +- Tighten the **shape of an experimental field** in §5 — for instance, replace `RuntimeContext.componentProps: unknown` with a structured schema. This is not breaking because consumers were never permitted to depend on the experimental shape. +- Expose an **alias** for an existing tool name. Aliases never replace the canonical name and may be removed in a major release. +- Change implementation-internal details that do not appear in this document. + +A v1.x minor release MUST NOT: + +- Rename or remove a tool, prompt, error code, or stable field. +- Make an optional field required, or vice versa, on a stable field. +- Change the meaning of an error code. +- Change the type of a stable field. + +### 7.3 What patches (`1.x.y`) may do + +Patch releases may fix bugs, tighten validation that was previously too loose, improve performance, and update human-readable strings (`title`, `detail`, prompt copy). A patch MUST NOT change any rule from §7.1 or §7.2. + +### 7.4 Aliases and the canonical name migration + +The v0.5.x implementation exposed tool names in dotted form (`domscribe.resolve`, `domscribe.annotation.get`, …). v1.0.0 canonicalises on the underscore form documented in §3. Implementations MAY ship dotted aliases through one minor cycle (v1.0.x → v1.1.0) to keep existing `.mcp.json` configs working; after v1.1.0, the dotted aliases are no longer guaranteed and SHOULD be considered deprecated. Aliases never appear in this spec — the canonical name is the contract. + +### 7.5 What v2 will look like + +A breaking change — renaming a stable field, removing an error code, changing the transport binding, or making an experimental field's shape break the previous shape — requires a v2 release. v2 will: + +- Be a new package version of `@domscribe/protocol` (`2.0.0`). +- Be published alongside a `docs/rcp/v2.md` spec. +- Maintain a **dual-version deprecation window** of at least one minor release on v1, during which a single server implementation can speak both versions. The window may be longer if adoption signals warrant; it will not be shorter. +- Publish a written migration guide before the deprecation window opens. + +### 7.6 Falsifiability examples + +A reader should be able to look at a candidate change and decide if it's breaking. Worked examples: + +| Change | Verdict | +| ----------------------------------------------------------------------- | ---------------------------------------------------- | +| Add `domscribe_manifest_entries` tool returning a stream of entries. | **Minor** — additive new tool. | +| Add `wrappers: string[]` to `ManifestEntry` (already exists, so n/a). | n/a — already stable. | +| Add `fileSize: number` to `ManifestEntry`. | **Minor** — additive optional field. | +| Promote `dataBindings` from experimental to a structured stable schema. | **Minor** — tightening an experimental field, §7.2. | +| Rename `domscribe_status` to `domscribe_health`. | **Major** — rename of a frozen tool name. | +| Add a new annotation status `"snoozed"` to the `status` enum. | **Major** — v1 enums are non-extensible (§7.2). | +| Change `DS_RESOLVE_STALE_TARGET` to mean "manifest stale". | **Major** — semantic change to a code. | +| Drop the `instance` field from `ProblemDetails`. | **Major** — removal of a stable field. | +| Add a `DS_RATE_LIMITED` code. | **Minor** — additive code. | +| Switch transport to MCP-over-WebSocket only. | **Major** — removal of the stable transport binding. | + +If a contributor is unsure, they should treat the change as breaking and route it through the v2 path until a maintainer says otherwise. + +## 8. Reference + +- Source of truth for shapes: package `@domscribe/protocol@1.0.0` on npm. +- Reference server implementation: `@domscribe/relay` (this repository). +- Architecture and decision record: [`docs/rfcs/0001-rcp-as-versioning-unit.md`](../rfcs/0001-rcp-as-versioning-unit.md). +- MCP specification: . +- Error envelope conventions: [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807). From 836f7facde321e77ba69256bacb45a45dd8414ac Mon Sep 17 00:00:00 2001 From: staff-swe-8 Date: Thu, 28 May 2026 11:59:04 -0700 Subject: [PATCH 2/4] docs(rfcs): commit RFC 0001 referenced by RCP v1 spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v1 spec (`docs/rcp/v1.md`) cross-links to `docs/rfcs/0001-rcp-as-versioning-unit.md` as the decision record for extracting `@domscribe/protocol` as the RCP versioning unit. The RFC was authored by principal-eng during sprint 2371 but had not been committed to the repo; the spec link would render broken on GitHub until this lands. Committing here so the spec PR satisfies its "renders cleanly on GitHub" acceptance criterion without requiring a separate landing. Verbatim RFC content — no edits. Refs #35 --- docs/rfcs/0001-rcp-as-versioning-unit.md | 51 ++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 docs/rfcs/0001-rcp-as-versioning-unit.md diff --git a/docs/rfcs/0001-rcp-as-versioning-unit.md b/docs/rfcs/0001-rcp-as-versioning-unit.md new file mode 100644 index 0000000..89c7dc5 --- /dev/null +++ b/docs/rfcs/0001-rcp-as-versioning-unit.md @@ -0,0 +1,51 @@ +# RFC 0001: Extract the agent-facing contract into `@domscribe/protocol` as the versioning unit for RCP v1 + +**Status:** Proposed +**Author:** Principal Eng (sprint 2371) +**Date:** 2026-05-28 + +## Context + +The DOP memo (sprint 2371) commits Domscribe to the "neutral bridge" category by publishing a **Runtime Context Protocol (RCP)** that IDE vendors integrate against, rather than competing as another AI IDE. That commits _engineering_ to a question the memo does not answer: **what, concretely, is RCP — and how do we ship it so that IDE-vendor relations have something to point at?** + +Today the agent-facing surface is scattered. The MCP server in `@domscribe/relay` exposes 12 tools and 4 prompts. The wire schemas for `ManifestEntry`, `RuntimeContext`, and `Annotation` live in `@domscribe/core` alongside unrelated utilities (error system, PII redaction, ID generation). Tool naming is already inconsistent — `README.md` advertises dotted names like `domscribe.query.bySource` while `TECHNICAL_SPEC.md` §3.4 still lists dashed names like `annotation-get`. There is no stability policy and no SemVer commitment on either. We need this decision _now_ because every week we delay, more downstream code (skill files, plugin marketplaces, the `npx domscribe init` wizard) hardens around names we will have to break. + +## Decision + +We extract the agent-facing contract — MCP tool & prompt surface, plus the wire schemas (`ManifestEntry`, `RuntimeContext`, `Annotation`, error envelopes) — into a new package `@domscribe/protocol`, version it independently from the implementation packages, and publish RCP v1.0.0 against it with an explicit stability policy. `@domscribe/core` keeps utilities and shrinks; relay/runtime/mcp depend on `@domscribe/protocol` for shapes and names. + +## Alternatives considered + +**Alt A — Treat the existing `@domscribe/core` schemas + the MCP server as "the protocol" and add a `docs/rcp/v1.md` page on top.** This is the cheapest path. The tradeoff: protocol version becomes coupled to `@domscribe/core`'s version, so any internal refactor of error utilities or ID helpers triggers a protocol bump — meaning the SemVer stamp is meaningless, which means IDE vendors have no real signal of stability and will reasonably treat us as "a tool with docs," not a protocol. The stability stamp is exactly the asset we are trying to create. + +**Alt B — Define RCP as a transport-neutral abstract spec (`docs/rcp/v1.md`) with bindings: MCP binding, gRPC binding, JSON-RPC binding.** This is what real standards bodies do. The tradeoff: we are one team shipping the only implementation; "transport-neutral with bindings" is a 6-month yak-shave that produces a beautiful spec and zero adoption. The MCP binding is the only one that matters in 2026 because every target IDE (Cursor, Claude Code, Cline, Continue, Codex) already speaks it. Premature abstraction. + +## The strongest counter-argument + +"Don't publish a v1 protocol off a v0.5 product. Until a non-author implements RCP, you're documenting your own API and calling it a protocol — and you'll be stuck with v1's mistakes." This is the strongest "no," and it's right that the standards literature is full of v1s frozen too early. The reason it still loses: the entire bet of the sprint is that IDE-vendor relations won't engage with "our API surface" but will engage with "the protocol." Publishing v1 is the precipitating action that _generates_ the integration energy DOP's falsifier measures. Waiting for an external implementation before publishing means waiting forever — nobody will implement an unstamped contract. The cost of v1-mistake lock-in is bounded (we ship v1.1 with additive fields; we ship v2 with a deprecation window), and is structurally smaller than the cost of six more months of competing with Stagewise on positioning instead of on category. + +## Blast radius — high + +Shares fate with this change: every shipped IDE plugin (Claude Code, Copilot, Cursor, Gemini, Kiro), the `npx domscribe init` wizard's MCP config, the `skills/` content, the `gemini-extension.json`, the README's tool table, every fixture in `domscribe-test-fixtures`, and every downstream user's `.mcp.json`. Tool-name normalization in particular will break existing plugin configs unless we ship aliases through the migration window. The package extraction also re-shapes the dependency graph documented in `TECHNICAL_SPEC.md` §2.3 — `scope:core` no longer owns the wire shapes. + +## Reversibility + +- **Within 2 weeks of publish:** Roll `@domscribe/protocol` back into `@domscribe/core`, un-stamp v1, retract the spec page. Tool renames already shipped require aliases on the old names indefinitely. Cost: a sprint. +- **At 3 months:** The protocol stamp is itself the wedge — pulling it back is a public admission that RCP was marketing, not engineering. Cost: category-positioning credibility, which is most of what the sprint was buying. Not truly reversible. + +## Falsifier + +By **2026-08-20** (sprint N+6), `@domscribe/protocol@1.0.0` is published with a stability-policy doc, **and** at least one of: (a) an IDE-vendor doc links to the RCP spec, (b) ≥1 npm package not authored by Patch Orbit declares `@domscribe/protocol` as a dependency, (c) ≥10 weekly-active relay sessions reported via opt-in telemetry. **Zero of three → we collapse `@domscribe/protocol` back into `@domscribe/core` in the following sprint and recategorize Domscribe as a tool with stable APIs.** + +## Implications for PM + +Four sprint workstreams fall out, in this order: + +1. **Extract `@domscribe/protocol` package** (Zod schemas relocate from `@domscribe/core`; `relay`/`runtime`/`mcp` depend on it). Blocks everything else. +2. **Normalize MCP tool names against a single grammar** before stamping v1. Per the spec note in this team's memory, MCP SEP-986 permits dots up to 128 chars, but Windsurf enforces stricter rules — staff engineers decide between dotted and underscore form, but must canonicalize one and ship aliases for the legacy names through one minor cycle. +3. **Opt-in telemetry hook in the relay daemon** — single periodic POST of an anonymous session count, gated on a flag in `.domscribe/config.json`, defaulting off. This is the only way to measure DOP-falsifier (c); without it, the bet is unmeasurable, so it must land in this sprint. +4. **Publish `docs/rcp/v1.md`** with explicit stability policy: which fields are stable, which are experimental, how deprecations work. + +**Explicitly out of scope for this RFC:** extracting `FrameworkAdapter` into a public adapter SDK. The DOP memo bundles that with RCP, but they are different bets — RCP is the agent-facing protocol; `FrameworkAdapter` is an internal extension point. Lifting it to a public SDK is real work and worth doing, but it does not constrain the protocol decision and should not gate v1. A follow-on RFC will own that question once the protocol package exists. + +**Out of scope: `docs/architecture.md`.** The principal-eng verifier checklist references a "seven decisions" architecture doc that does not exist in this repo. This RFC stands up `docs/rfcs/` as the canonical decision record going forward; the architecture doc itself is a separate follow-on. From b9873cca4a7e6debae03368732ef98ca3e267c55 Mon Sep 17 00:00:00 2001 From: staff-swe-7 Date: Fri, 29 May 2026 05:45:30 -0700 Subject: [PATCH 3/4] docs(rfcs): commit RFC 0002 referenced by RCP v1 spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFC 0002 (sprint 2491) ratifies RFC 0001 as Accepted and locks three deferrals: snake_case canonical tool grammar, opt-in telemetry shape, and the six-export @domscribe/protocol package boundary. It also introduces SourcePosition required on every resolve_*/query_* output as the v1 stability anchor. The v1 spec (docs/rcp/v1.md) cross-links to this RFC as a decision record; landing it here keeps the spec PR's 'renders cleanly on GitHub' acceptance criterion satisfied without requiring a separate landing PR (same pattern staff-swe-8 used for RFC 0001 in 836f7fa). Verbatim PE content — no edits. Refs #35 --- docs/rfcs/0002-protocol-v1-execution.md | 53 +++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docs/rfcs/0002-protocol-v1-execution.md diff --git a/docs/rfcs/0002-protocol-v1-execution.md b/docs/rfcs/0002-protocol-v1-execution.md new file mode 100644 index 0000000..a79eb06 --- /dev/null +++ b/docs/rfcs/0002-protocol-v1-execution.md @@ -0,0 +1,53 @@ +# RFC 0002: Ratify RCP v1 — `snake_case` canonical grammar, locked package boundary, opt-in telemetry, source-position as differentiator + +**Status:** Proposed +**Author:** Principal Eng (sprint 2491) +**Date:** 2026-05-29 +**Relationship to RFC 0001:** Ratifies RFC 0001 as Accepted; resolves the three deferrals (tool-name grammar, telemetry shape, protocol-boundary specifics) it left to staff engineers; adds a new architectural constraint reflecting the post–Google I/O 2026 landscape. + +## Context + +RFC 0001 (sprint 2371) committed to extracting the agent-facing contract into `@domscribe/protocol` and stamping RCP v1.0.0, but left three load-bearing questions open: canonical tool-name grammar, telemetry shape, and the precise contents of the new package. Sprint 2491's DOP memo (2026-05-29) tightens the deadline — Google I/O 2026 (2026-05-19) shipped WebMCP as an open standard for browser-resident agent channels and rolled Chrome DevTools MCP into mainline Chrome. Both put runtime-only MCPs in front of the IDE-vendor mental model. If Domscribe ratifies RCP v1 inside the next two weeks, it lands as "the build-time, framework-aware complement"; if it ships in August, it lands as "a fourth runtime MCP." + +The execution risk RFC 0001 named has also crystallized in the code. `packages/domscribe-relay/src/mcp/tools/tool.defs.ts` already registers 13 dotted tool names with mixed camelCase suffixes (`domscribe.annotation.updateStatus`, `domscribe.query.bySource`); the README documents these forms; the tool source files use dashes (`annotation-update-status.tool.ts`). Three conventions in one surface, before v1. + +## Decision + +We make four commitments, ordered by reversibility cost. + +**(1) Canonical MCP tool grammar is `snake_case`** (e.g. `domscribe_annotation_update_status`, `domscribe_query_by_source`). The current dotted forms ship as compatibility aliases registered alongside the canonical names through `@domscribe/protocol@1.x`; they emit a deprecation log line on call and are removed at v2. The `MCP_TOOLS` constant in `tool.defs.ts` becomes `{ canonical: string, aliases: string[] }` per tool — single source of truth, no scattered string literals. + +**(2) `@domscribe/protocol` contains exactly:** wire Zod schemas (`Annotation`, `AnnotationInteraction`, `AnnotationContext`, `RuntimeContext`, `ManifestEntry`, `SourcePosition`, `StyleInfo`, `ComponentMetadata`), the `DomscribeErrorCode` enum, the `MCP_TOOLS` constant + per-tool input/output schemas, the RFC 7807 problem-details envelope shape, and the `WS_EVENTS` constant — nothing else. Runtime classes (`DomscribeError`, ID generators, `migrateAnnotation`) stay in `@domscribe/core`. The protocol package has zero runtime dependencies beyond `zod`. + +**(3) `SourcePosition` is a required (non-optional) field on the output schemas of every `resolve_*` and `query_*` tool.** This is a protocol-level enforcement of the build-time-AST differentiation against WebMCP and Chrome DevTools MCP — both can return DOM state, neither can return `{ file, line, column }`. Encoding it in the schema means an alternative implementation that omits it is not RCP-conformant by construction. + +**(4) Telemetry is a single fire-and-forget HTTPS POST** from `@domscribe/relay` to `https://telemetry.domscribe.dev/v1/session` at relay startup and every 24h while running. Payload: `{ protocol_version, daemon_version, session_id (rotating per install), platform, node_version, primary_framework }` — never annotation content, manifest content, source paths, or file contents. Gated on `.domscribe/config.json` → `telemetry.enabled` (default `false`); `npx domscribe init` surfaces a yes/no prompt with the full payload shown inline. POST has a 2-second timeout and never blocks startup. + +## Alternatives considered + +**Keep dotted names as canonical, no rename.** Cheapest, preserves the README, ships v1 fastest. The tradeoff: Windsurf's stricter validator (`^[a-zA-Z0-9_-]{1,64}$`) silently drops dotted tools — meaning the v1 stamp would launch broken for one of the IDE vendors we are explicitly courting — and the broader MCP-server ecosystem (Anthropic's first-party servers, most community servers) is overwhelmingly `snake_case`. We would publish a v1 that looks foreign next to every reference implementation an IDE-vendor partnerships engineer reads. This is not a spec-compliance argument — SEP-986 permits dots up to 128 chars — it is an ecosystem-LCD argument. + +**Include the runtime `DomscribeError` class and ID generators in `@domscribe/protocol`.** Tighter co-location, fewer cross-package imports. The tradeoff: every internal refactor of error construction or ID alphabets would trigger a protocol bump, gutting the SemVer signal RFC 0001 paid to create. The wire envelope and the runtime class are distinct objects; only the envelope must be SemVer-stable. + +## The strongest counter-argument + +"Renaming 13 tools the same week you stamp v1 is exactly the mistake RFC 0001 warned about — you are freezing a churned surface." It is a real concern, and the standards literature is full of v1s frozen too early. It still loses because aliases through v1.x give the migration window the warning was about; the alternative is freezing the _current_ inconsistent surface, which is strictly worse than freezing a normalized one with a one-minor-cycle alias bridge. The RFC 0001 caution was against freezing without a deprecation channel, not against renaming with one. + +## Blast radius — high + +Shares fate: `@domscribe/relay` MCP server, `@domscribe/core` (schemas relocate out — `scope:core` no longer owns wire shapes), `@domscribe/mcp` stdio proxy, every shipped IDE plugin config (Claude Code, Copilot, Cursor, Gemini, Kiro, Cline, Continue, Codex), `gemini-extension.json`, `skills/` content, README §3 tool table, `TECHNICAL_SPEC.md` §2.3 (dependency graph) and §3.4 (tool list), every fixture in `domscribe-test-fixtures`, every downstream user's `.mcp.json`. New infrastructure: the telemetry endpoint (Cloudflare Worker + KV counter, projected <$1/mo at current scale); its failure must not block relay startup. + +## Reversibility + +- **Within 2 weeks of publish:** Roll `@domscribe/protocol` back into `@domscribe/core`, retract the v1 tag and the stability-policy doc, keep dotted-name aliases as the canonical form. Telemetry endpoint can be torn down by retracting the `.config.json` flag. Cost: ~1 sprint plus a public retraction post. +- **At 3 months:** Tool-name rename is reversible only by re-promoting dotted names to canonical and demoting `snake_case` to alias — possible but costs the credibility the v1 stamp bought. Package extraction is not reversible at this horizon; downstream consumers have already adopted `@domscribe/protocol` imports. Telemetry data already collected is retained or purged per stated policy. + +## Falsifier + +By **2026-06-12** (sprint 2491 close), all of: `@domscribe/protocol@1.0.0` published to npm with `docs/rcp/v1.md` stability policy; all 13 canonical `snake_case` tool names registered with dotted aliases functional and tested; telemetry endpoint live and receiving ≥1 real session from a non-author install. **Any of three slipping → escalate to Kaushik before re-cutting v1.** Partial v1 (e.g., schemas extracted but tool-name rename deferred) is strictly worse than a one-sprint slip — it ships the stability stamp on an unstable surface. (Inherited from RFC 0001: by 2026-08-20, at least one of: IDE-vendor doc references RCP, ≥1 non–Patch-Orbit npm package depends on `@domscribe/protocol`, ≥10 weekly-active relay sessions via telemetry. Zero → collapse the package.) + +## Implications for PM + +Four workstreams, ordered by blocking dependency: **(1)** stand up `@domscribe/protocol` package with the boundary above (Zod schemas + `MCP_TOOLS` + error code enum + RFC 7807 envelope + `WS_EVENTS`); migrate `@domscribe/core`, `@domscribe/relay`, `@domscribe/runtime`, `@domscribe/mcp` to import from it; update `scope:core` and `nx` boundary tags. **(2)** Refactor `MCP_TOOLS` to `{ canonical, aliases }` shape, register both names with the MCP SDK, emit a deprecation log on alias hit, and gate tool registration through a single helper. **(3)** Make `SourcePosition` required on `resolve_*` / `query_*` output schemas — existing tests must fail until the relay emits it, then pass. **(4)** Add telemetry POST to relay startup + 24h interval, `.domscribe/config.json` schema for the `telemetry` block, `npx domscribe init` yes/no prompt with payload inline. README, `TECHNICAL_SPEC.md` §2.3 and §3.4, `gemini-extension.json`, and `skills/` content update in parallel as docs PRs. + +**Explicitly out of scope (deferred to follow-on RFCs):** `FrameworkAdapter` public SDK extraction (different bet, different surface); a transport-neutral RCP abstract spec with non-MCP bindings (premature per RFC 0001 §Alt B and unchanged by I/O 2026); `docs/architecture.md` "seven decisions" doc (known gap; RFCs remain the canonical decision record). RFC 0001's status should be moved from Proposed to Accepted as part of this sprint's docs PR. From 6e5e0b63bdc74d36cf223d4a5f2c4059527bf8cc Mon Sep 17 00:00:00 2001 From: staff-swe-7 Date: Fri, 29 May 2026 05:45:30 -0700 Subject: [PATCH 4/4] =?UTF-8?q?docs(rcp):=20align=20v1=20spec=20with=20RFC?= =?UTF-8?q?=200002=20=E2=80=94=20SourcePosition=20anchor=20+=20package=20s?= =?UTF-8?q?urface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprint 2491 ratified RFC 0001 via RFC 0002, locking three decisions the prior spec draft predated: - SourcePosition is a required (non-optional) field on every resolve_*/query_* output schema. RFC 0002 names this the build-time differentiator vs runtime-only browser-channel MCPs (WebMCP, Chrome DevTools MCP). Encoded at the schema layer so conformance is testable, not aspirational. - @domscribe/protocol package surface is a six-export contract. Runtime classes (DomscribeError, ID generators, migration helpers) stay in @domscribe/core to keep the protocol SemVer signal honest. - RFC 0001 status moves from Proposed to Accepted with a cross-link to RFC 0002. Spec changes: - New 'Design intent' subsection naming the build-time/runtime complement framing without disparaging runtime MCPs. - New §5.5 dedicated to SourcePosition as the v1 stability anchor (with the schema-level enforcement clause). - §1 Conformance adds an explicit MUST for SourcePosition presence on resolve_*/query_* responses. - §7.1 freeze list elevates SourcePosition presence above per-tool schema details; explains why it's called out separately. - §7.6 falsifiability table adds two SourcePosition rows. - New §8 enumerates the @domscribe/protocol package surface for consumers (former §8 Reference becomes §9, now includes RFC 0002). Closes RFC 0002 implications-for-PM item (4)'s docs portion for docs/rcp/v1.md. Tool-rename, package extraction, telemetry, and SourcePosition schema enforcement land via #32/#33/#34/#38. Refs #35 --- docs/rcp/v1.md | 70 +++++++++++++++++++----- docs/rfcs/0001-rcp-as-versioning-unit.md | 2 +- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/docs/rcp/v1.md b/docs/rcp/v1.md index f741d9a..4f82f2c 100644 --- a/docs/rcp/v1.md +++ b/docs/rcp/v1.md @@ -13,7 +13,7 @@ RCP v1 covers, and only covers: - A single transport binding: **Model Context Protocol (MCP) over stdio**, as defined by the [Anthropic MCP specification](https://modelcontextprotocol.io). - A fixed set of MCP **tools** the consumer can call (§3). - A fixed set of MCP **prompts** the consumer can fetch (§4). -- The wire **schemas** for the request/response payloads of those tools — `ManifestEntry`, `RuntimeContext`, `Annotation`, and the error envelope (§5). +- The wire **schemas** for the request/response payloads of those tools — `ManifestEntry`, `RuntimeContext`, `Annotation`, `SourcePosition`, and the error envelope (§5). - The **error code** vocabulary returned in failure responses (§6). - The **stability policy** that tells you what is allowed to change without a major version bump (§7). @@ -24,6 +24,10 @@ Out of scope for v1, but not precluded for later versions: - Multi-tenant relay semantics. A v1 relay serves one workspace. - A public adapter SDK for framework authors. See [RFC 0001](../rfcs/0001-rcp-as-versioning-unit.md), §"out of scope". +### Design intent — what RCP is and what it isn't + +RCP is a **build-time, framework-aware** protocol: every `resolve_*` and `query_*` response carries a `SourcePosition` (`{ file, line, column }`) pointing at the source AST node responsible for a rendered element. This is the load-bearing property — encoded as a non-optional schema field (§7.1) — that distinguishes RCP from runtime-only browser-channel protocols such as WebMCP and Chrome DevTools MCP. Those expose live DOM and devtools state; RCP exposes the build-time origin of that state. The two are complementary, not competing: an agent integrating both can answer "what is on the page right now" (runtime MCP) and "which file and line do I edit to change it" (RCP). An implementation that returns runtime context without source position is not RCP-conformant. + ## 1. Conformance A conformant RCP v1 **server** MUST: @@ -31,6 +35,7 @@ A conformant RCP v1 **server** MUST: - Advertise the `tools` capability on initialize. - If it claims to support prompts, advertise the `prompts` capability. - Implement every tool in §3 with input and output that validate against the schemas in `@domscribe/protocol`. +- Populate `SourcePosition` (`start`) on every response from a `resolve_*` or `query_*` tool. Returning `null`, omitting the field, or returning a sentinel placeholder is non-conformant. See §5.5 and §7.1. - Implement every prompt in §4 if `prompts` is advertised. - Return error responses that validate against `ProblemDetails` (§5.4) with a `code` drawn from §6. @@ -174,6 +179,20 @@ Failed tool calls return an `isError: true` MCP result whose textual content is | `status` | `number?` | stable | HTTP-style status code, when meaningful. | | `extensions` | `Record?` | experimental | Bag for code-specific data. Consumers MUST tolerate absence and unknown keys. | +### 5.5 `SourcePosition` — the v1 stability anchor + +`SourcePosition` is a leaf schema, but it carries the protocol's load-bearing guarantee. v1 promises that every `resolve_*` and `query_*` tool returns a `ManifestEntry` whose `start: SourcePosition` is **present and well-formed** — never `null`, omitted, or a sentinel placeholder. The §7.1 freeze list elevates this above the per-tool schema details. + +| Field | Type | Stability | Notes | +| -------- | --------- | --------- | ------------------------------------------ | +| `line` | `number` | stable | 1-indexed source line. | +| `column` | `number` | stable | 0-indexed source column. | +| `offset` | `number?` | stable | Optional byte offset into the source file. | + +The guarantee is **schema-level**, not convention-level: the Zod definition of every `resolve_*` / `query_*` output schema in `@domscribe/protocol` rejects responses missing `start`. An alternative implementation that wires its own transport but omits source position is therefore not RCP-conformant by construction, and a conformance test suite can detect it without a custom check. This is the surface that distinguishes RCP from runtime-only browser-channel MCPs (see "Design intent" near the top of this document). + +`isApproximateLocation: true` on the containing `ManifestEntry` signals that the position is best-effort (e.g. an SSR fallback or a wrapping component the AST could only narrow to a region). The position is still required; approximation does not license omission. + ## 6. Error codes The complete v1 vocabulary. New codes MAY be added in a minor release per §7.3; existing codes will not be removed or repurposed within v1. @@ -217,6 +236,7 @@ Within RCP v1, the following are **frozen**: - Every **error code** in §6 — both that it exists and what it means. - The error envelope shape itself (`code`, `title`, `detail`, `instance`, `status`, `extensions`). - The transport binding being MCP over stdio. +- **`SourcePosition` presence on every `resolve_*` / `query_*` response** (§5.5). Removing it, making it optional, or returning a sentinel placeholder is a v2-class change. This is the v1 stability anchor and is called out separately because it is the protocol-level differentiator versus runtime-only MCPs; downgrading it would change what RCP _is_. Calling a frozen tool name with v1-shaped input on a v1.x server MUST not return a v2-shaped output or a code outside §6. @@ -260,25 +280,45 @@ A breaking change — renaming a stable field, removing an error code, changing A reader should be able to look at a candidate change and decide if it's breaking. Worked examples: -| Change | Verdict | -| ----------------------------------------------------------------------- | ---------------------------------------------------- | -| Add `domscribe_manifest_entries` tool returning a stream of entries. | **Minor** — additive new tool. | -| Add `wrappers: string[]` to `ManifestEntry` (already exists, so n/a). | n/a — already stable. | -| Add `fileSize: number` to `ManifestEntry`. | **Minor** — additive optional field. | -| Promote `dataBindings` from experimental to a structured stable schema. | **Minor** — tightening an experimental field, §7.2. | -| Rename `domscribe_status` to `domscribe_health`. | **Major** — rename of a frozen tool name. | -| Add a new annotation status `"snoozed"` to the `status` enum. | **Major** — v1 enums are non-extensible (§7.2). | -| Change `DS_RESOLVE_STALE_TARGET` to mean "manifest stale". | **Major** — semantic change to a code. | -| Drop the `instance` field from `ProblemDetails`. | **Major** — removal of a stable field. | -| Add a `DS_RATE_LIMITED` code. | **Minor** — additive code. | -| Switch transport to MCP-over-WebSocket only. | **Major** — removal of the stable transport binding. | +| Change | Verdict | +| ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| Add `domscribe_manifest_entries` tool returning a stream of entries. | **Minor** — additive new tool. | +| Add `wrappers: string[]` to `ManifestEntry` (already exists, so n/a). | n/a — already stable. | +| Add `fileSize: number` to `ManifestEntry`. | **Minor** — additive optional field. | +| Promote `dataBindings` from experimental to a structured stable schema. | **Minor** — tightening an experimental field, §7.2. | +| Rename `domscribe_status` to `domscribe_health`. | **Major** — rename of a frozen tool name. | +| Add a new annotation status `"snoozed"` to the `status` enum. | **Major** — v1 enums are non-extensible (§7.2). | +| Change `DS_RESOLVE_STALE_TARGET` to mean "manifest stale". | **Major** — semantic change to a code. | +| Drop the `instance` field from `ProblemDetails`. | **Major** — removal of a stable field. | +| Add a `DS_RATE_LIMITED` code. | **Minor** — additive code. | +| Switch transport to MCP-over-WebSocket only. | **Major** — removal of the stable transport binding. | +| Make `start: SourcePosition` optional on `domscribe_resolve` output. | **Major** — downgrades the §7.1 v1 anchor. | +| Return `start: null` from `domscribe_query_by_source` for SSR fallback. | **Non-conformant in v1** — not a version question; an implementation bug. Use `isApproximateLocation: true` with a real position instead. | If a contributor is unsure, they should treat the change as breaking and route it through the v2 path until a maintainer says otherwise. -## 8. Reference +## 8. The `@domscribe/protocol` package surface + +This is the v1 package boundary — exact set of exports. Anything else that ships in the package is implementation detail and not part of the RCP v1 contract. SemVer of the package tracks the contract below; internal-only refactors do not bump. + +| Export | Kind | Notes | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------- | +| Wire Zod schemas: `Annotation`, `AnnotationInteraction`, `AnnotationContext`, `RuntimeContext`, `ManifestEntry`, `SourcePosition`, `StyleInfo`, `ComponentMetadata` | schemas | The shapes returned over the wire. See §5. | +| Per-tool input/output schemas (`InputSchema`, `OutputSchema`) | schemas | One pair per tool in §3. | +| `MCP_TOOLS` | constant | `{ canonical: string, aliases: string[] }` per tool. The single source of truth for tool names; see §3 and §7.4. | +| `DomscribeErrorCode` | enum | The §6 vocabulary as a TypeScript enum. | +| `ProblemDetails` | schema | The RFC 7807 error envelope; see §5.4. | +| `WS_EVENTS` | constant | Event names for the relay's internal WebSocket transport; reserved for cross-process consumers within an install. | +| Prompt name constants | constants | One per prompt in §4. | + +Runtime classes (`DomscribeError`, ID generators, migration helpers) live in `@domscribe/core`, not in `@domscribe/protocol`. This separation exists so that internal refactors of error construction or ID generation do not bump the protocol's major version — see RFC 0002 for the reasoning. + +## 9. Reference - Source of truth for shapes: package `@domscribe/protocol@1.0.0` on npm. - Reference server implementation: `@domscribe/relay` (this repository). -- Architecture and decision record: [`docs/rfcs/0001-rcp-as-versioning-unit.md`](../rfcs/0001-rcp-as-versioning-unit.md). +- Decision records: + - [`docs/rfcs/0001-rcp-as-versioning-unit.md`](../rfcs/0001-rcp-as-versioning-unit.md) — extraction of `@domscribe/protocol` as the RCP versioning unit. + - [`docs/rfcs/0002-protocol-v1-execution.md`](../rfcs/0002-protocol-v1-execution.md) — ratification of v1: canonical `snake_case` tool grammar, the locked package boundary above, `SourcePosition` as the v1 stability anchor, and opt-in telemetry. - MCP specification: . - Error envelope conventions: [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807). diff --git a/docs/rfcs/0001-rcp-as-versioning-unit.md b/docs/rfcs/0001-rcp-as-versioning-unit.md index 89c7dc5..cc702a1 100644 --- a/docs/rfcs/0001-rcp-as-versioning-unit.md +++ b/docs/rfcs/0001-rcp-as-versioning-unit.md @@ -1,6 +1,6 @@ # RFC 0001: Extract the agent-facing contract into `@domscribe/protocol` as the versioning unit for RCP v1 -**Status:** Proposed +**Status:** Accepted (ratified by [RFC 0002](./0002-protocol-v1-execution.md), sprint 2491) **Author:** Principal Eng (sprint 2371) **Date:** 2026-05-28