diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f0db136..f43035d 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -18,6 +18,16 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + - name: Check required RFC draft shell: bash run: | @@ -26,6 +36,13 @@ jobs: test -s drafts/agent-surface.md grep -q '^# Agent Surface Protocol Specification' drafts/agent-surface.md + - name: Check RFC review dashboard + shell: bash + run: | + set -euo pipefail + python -m pip install --requirement review/requirements.txt + make review-check + - name: Check Markdown hygiene shell: bash run: | diff --git a/.gitignore b/.gitignore index 31bfd70..e8bdab5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ /generated/ .DS_Store +review/__pycache__/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8be7b9a --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +PYTHON ?= python3 + +.PHONY: review-build review-check + +review-build: + $(PYTHON) review/build_review.py + +review-check: + $(PYTHON) review/build_review.py --check + node review/check_review.mjs diff --git a/README.md b/README.md index 228874d..2436aa4 100644 --- a/README.md +++ b/README.md @@ -61,13 +61,33 @@ Agent Surface + Agent Grant bind those pieces into safe app-specific delegation. agent-surface/ .github/ PULL_REQUEST_TEMPLATE.md - workflows/docs.yml Markdown and RFC checks. + workflows/docs.yml Markdown, RFC, and dashboard checks. drafts/ Source RFCs written in Markdown. + review/ Source data, template, and generated RFC review dashboard. LICENSE MIT license for repository source code. LICENSE-CC-BY-4.0 CC BY 4.0 summary for specifications and documents. CONTRIBUTING.md Contribution guidelines. ``` +## Interactive RFC Review Dashboard + +The standalone [RFC review dashboard](review/agent-surface-rfc-review.html) is +generated from the RFC, card data, and UI template. Do not edit the generated +HTML directly. + +```sh +python3 -m pip install -r review/requirements.txt +make review-build +make review-check +``` + +When the RFC changes, update the relevant cards in +[`review/review-data.json`](review/review-data.json), rebuild the dashboard, +and commit the RFC, review data, and generated HTML together. `review-check` +validates card fields and priorities, verifies every linked heading still +exists in the RFC, checks that the generated artifact is current, and parses +the dashboard's inline JavaScript. + ## Status The specification is experimental and subject to change. The current draft is diff --git a/review/agent-surface-rfc-review.html b/review/agent-surface-rfc-review.html index 0f83831..fd0aeaf 100644 --- a/review/agent-surface-rfc-review.html +++ b/review/agent-surface-rfc-review.html @@ -210,6 +210,7 @@

Abstract

Normative and Informative Sections

Unless otherwise stated, the following sections are normative:

Conventions

-

The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in this -document are to be interpreted in the RFC 2119 and RFC 8174 sense when, and only -when, they appear in all capitals.

+

The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", and +"MAY" in this document are to be interpreted in the RFC 2119 and RFC 8174 sense +when, and only when, they appear in all capitals.

This is not an IETF document. The keywords are used to make interoperability and security expectations explicit for future implementers.

Terminology

@@ -743,7 +746,7 @@

Discovery

If the manifest contains sensitive tenant-specific affordances, it MUST require ordinary authenticated app access.

-

The manifest SHOULD be served with:

+

The manifest MUST be served over HTTPS and SHOULD be served with:

Content-Type: application/json
 Cache-Control: max-age=300
 
@@ -932,6 +935,7 @@

Actions

  • output_schema
  • side_effect
  • execution
  • +
  • optional capability_hint
  • idempotency for side-effecting actions
  • receipt for side-effecting actions
  • @@ -957,6 +961,12 @@

    Proposal proposal-only actions.

    A proposal-only action is a typed action whose output is a draft, suggestion, patch, review body, or other non-committed artifact.

    +

    A proposal-only action declares side_effect: false because it does not +commit domain-visible changes. However, when the application persists +proposals as drafts — as the proposal flow in this draft assumes — repeated +proposal requests can still accumulate duplicate drafts under retries and +agent loops. Applications that persist proposals SHOULD accept idempotency +keys for proposal actions and deduplicate stored drafts accordingly.

    Example:

    {
       "id": "pull_request.review.propose",
    @@ -993,6 +1003,11 @@ 

    Events

    "schema": "https://example.com/schemas/ci-failed.event.schema.json" }
    +

    Grant constraints filter events the same way they filter actions: a grant +constrained to one repository SHOULD NOT receive events about other +repositories, even when the event scope matches.

    +

    Event delivery semantics — transport, ordering, acknowledgement, and replay — +are not defined in this draft; see Open Questions.

    Risk Taxonomy

    Every action SHOULD have a standard risk label. Runtimes can map risk labels to local policy defaults.

    @@ -1006,6 +1021,15 @@

    Risk Taxonomy

    | financial_side_effect | Charges, refunds, purchases, invoices, payroll. | Always require explicit approval. | | destructive | Deletes, closes, revokes, disables, or irreversibly changes state. | Deny by default or require step-up approval. | | privileged | Changes permissions, secrets, tokens, admin settings, or access policy. | Deny by default. |

    +

    Risk labels are ordered by increasing severity from read to privileged. +The labels are not mutually exclusive properties of an action: a single action +can plausibly be described by several of them. When more than one label +applies, the action MUST carry the most severe applicable label. For example, +invoice.refund.request is both a mutation and a financial operation; it MUST +be labeled financial_side_effect, not write.

    +

    The risk label and the side_effect flag MUST be consistent: an action +labeled write or a more severe label MUST declare side_effect: true, and +an action labeled read MUST declare side_effect: false.

    Applications MAY define extension risk labels, but they SHOULD map them to the standard labels for runtime interoperability.

    Approval Semantics

    @@ -1018,6 +1042,17 @@

    Approval Seman | user_or_app | Either a runtime approval or app-side approval MAY satisfy the requirement, depending on grant caveats. | | runtime_and_app | Both runtime-side and app-side approval are required. |

    Approval records SHOULD be linked into receipts.

    +

    The runtime and user_or_app modes allow a runtime-side approval to satisfy +the requirement. In those modes the application is accepting the runtime's +assertion that a local user approval occurred. To keep this compatible with +the rule that an application MUST NOT accept a runtime's self-assertion of +authority, that acceptance MUST be an explicit grant caveat presented to the +user at consent time, not a silent default. Action requests that rely on a +runtime-side approval SHOULD carry an approval reference (for example an +approval_ref identifier, or in future profiles a signed approval object) so +the approval can be linked into receipts and audited. Applications that do not +want to accept runtime approval assertions MUST declare app or +runtime_and_app for the affected actions.

    Idempotency

    Every side-effecting action MUST support idempotency.

    Action requests SHOULD include:

    @@ -1030,6 +1065,13 @@

    Idempotency

    same normalized input do not repeat the side effect.

    If the same key is reused with different normalized input, the application SHOULD return an idempotency conflict error.

    +

    Idempotency keys are scoped to the grant and action: the application MUST +treat a request as a duplicate only when the same key is presented under the +same grant_id and action_id. On a duplicate request, the application +SHOULD return the original result and receipt reference rather than an error, +so a retrying runtime can converge on the outcome of the first attempt. +Applications SHOULD retain idempotency state at least for the remaining +lifetime of the grant and SHOULD document their retention window.

    Applications SHOULD define the input normalization procedure per action, or use the declared input schema with a canonical JSON profile. A future draft is expected to define canonicalization requirements for signed receipts and signed @@ -1052,7 +1094,7 @@

    Grant Object

    "resource_server": { "app_id": "code.example.com", "issuer": "https://code.example.com", - "surface_version": "code-review-agent-surface/0.1" + "surface_version": "2026-06-25" }, "scopes": [ "pull_request.read", @@ -1072,6 +1114,16 @@

    Grant Object

    } } +

    Numeric caveats need defined accounting. In this draft, max_actions counts +side-effecting action requests accepted by the application under the grant. +Reads and denied requests do not consume the budget, and neither do idempotent +replays: a retry deduplicated under a previously accepted idempotency key +MUST NOT consume the budget again, or lost responses and transport retries +could exhaust a grant without producing new side effects. max_cost_usd is +advisory in the MVP profile: the runtime SHOULD meter agent-side cost against +it, and applications MAY additionally meter app-side cost where actions carry +a price. When a budget caveat is exhausted, further matching requests MUST be +rejected with limit_exceeded.

    Grant Lifecycle

    discover surface
       -> verify manifest
    @@ -1097,6 +1149,11 @@ 

    M

    This is the RECOMMENDED MVP model because it fits existing OAuth/resource-server deployments.

    +

    Because this draft does not require browser-to-localhost communication, the +consent flow SHOULD support a completion mode that does not depend on a +loopback redirect — for example an OAuth device-authorization-style exchange +or an app-mediated pairing code that the runtime polls or receives over its +outbound channel.

    Pros:

    References