Internet-Draft GPT August 2026
Ferguson Expires 5 February 2027 [Page]
Workgroup:
Independent Submission
Internet-Draft:
draft-ferguson-gpt-00
Published:
Intended Status:
Experimental
Expires:
Author:
M. Ferguson

GPT: Generic Protocol Type

Abstract

This document specifies GPT (Generic Protocol Type), a convention by which an HTTP address publishes the JSON Schema of the action it accepts, and accepts that action as a request body validated against the same schema. A client retrieves the schema at the moment of contact, produces a conforming value, and submits it unchanged. No client library, prior registration, or separate description of the capability is required. The schema serves as both the published description and the server-side check, so the two cannot diverge.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 5 February 2027.

Table of Contents

1. Introduction

An HTTP address that expects structured input generally describes that input somewhere other than in the response itself: in documentation, in a client library, in a tool definition supplied to a language model in advance, or in a registry retrieved separately. Each of those descriptions is maintained apart from the code that validates incoming requests, and can therefore disagree with it.

GPT removes the separate description. An address returns the JSON Schema [JSON-SCHEMA] of what it accepts as part of its ordinary representation. A client — commonly a language model with constrained-decoding support, but the protocol does not require one — produces a value conforming to that schema and submits it as the request body. The server validates against the same schema value it published.

This document specifies the wire behavior only. It does not specify what any particular address does with an accepted body.

1.1. Requirements Language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

1.2. Non-Goals

The following are outside the scope of this version, and are listed so that their absence is not mistaken for oversight:

  • Multi-capability discovery. One address publishes one schema.

  • Transport other than HTTP [RFC9110]. The design does not depend on HTTP, but only HTTP behavior is specified here.

  • Authentication and authorization. See Section 7.

  • Session or conversation state beyond what Section 3.2 returns.

2. Terminology

Address:

An HTTP or HTTPS URI implementing this document.

Form:

The JSON Schema an address publishes, carried in the member s. It is both the description of what may be submitted and the check applied to what is submitted.

Act:

A single POST whose body validates against the form.

Actor:

Whatever produced the body. This protocol does not distinguish a language model, a program, or a person composing JSON by hand.

3. Arrival

3.1. Request

A client retrieves the form with an ordinary GET:

GET / HTTP/1.1
Host: example.com

No request header is required. An address MUST NOT require a header, query parameter, cookie, or prior request in order to return its form.

3.2. Response

The response status is 200 with a Content-Type of application/json. The body MUST be a JSON object [RFC8259] containing these members:

Table 1: Members of the arrival response
Member Type Meaning
p string System context: what this address is, and what to do
m array Prior messages, each an object with role and content
s object The form: a JSON Schema (see Section 4)

The members p and m are context for the actor and carry no normative weight. The member s is normative: it is the sole statement of what the address accepts.

An address MAY include additional members. A client MUST ignore members it does not recognize.

An address MAY include a GPT-Type response header field naming the kind of address it is. This is advisory; a client MUST NOT depend on it, as s already states everything the address accepts.

The response MUST NOT vary based on whether the client has contacted the address before.

3.3. Representation for Human Readers

An address MAY return a different representation when the request carries an Accept header field including text/html. That representation is not part of this protocol and MUST NOT be the only means of obtaining the form. A request with no Accept header field, or one not including text/html, MUST receive the response described in Section 3.2.

4. The Form

The value of s MUST be a valid JSON Schema describing a single JSON value: the body of an act.

4.1. Vocabulary

An address SHOULD restrict its schema to keywords that constrain the shape of a value, and SHOULD NOT depend on keywords whose omission by a validator would widen what is accepted.

The reference implementation uses:

type  properties  required  additionalProperties  const  enum
minLength  maxLength  minItems  maxItems  items  description
$defs  $ref  anyOf

An address SHOULD use anyOf in preference to oneOf. Both express a union of alternatives; some constrained-decoding implementations reject oneOf outright, and where the alternatives are disjoint the distinction does not affect which values validate.

4.2. Bounded Recursion

A form MAY describe a recursive structure. Where it does, the recursion SHOULD be bounded by the schema itself rather than by a check performed at runtime.

A self-referencing definition such as:

node = { content: [ node ] }

is unbounded. The effective depth then becomes a property of the actor's sampling behavior rather than of the published grammar, and differs between actors.

Unrolling the definitions bounds depth within the document:

node1 = anyOf [ leaf, { content: [ node2 ] } ]
node2 = anyOf [ leaf, { content: [ node3 ] } ]
...
nodeN = anyOf [ leaf ]

The final level omits the recursive alternative, so no conforming value exceeds depth N. The published form is the limit.

4.3. Description

The description keyword, wherever it appears, is context for the actor and carries no normative weight. A server MUST NOT rely on an actor having read it.

5. The Act

5.1. Request

POST / HTTP/1.1
Host: example.com
Content-Type: application/json

<a JSON value conforming to s>

The body MUST be exactly the value the actor produced. Intermediaries MUST NOT reshape, re-serialize, or wrap it.

5.2. Verification

Before acting on a body, a server MUST:

  1. Reject bodies exceeding an implementation-defined maximum size.

  2. Parse strictly. The parser MUST reject bytes following the JSON value, and MUST reject duplicate object member names at any depth. Both are ambiguous at a trust boundary, and permissive parsers disagree about which duplicate value prevails.

  3. Validate the body against the same value of s returned in Section 3.2 — not a copy of it, and not a subset of it.

  4. Fail closed on any schema keyword the validator does not implement. A form containing an unrecognized constraint MUST NOT be treated as though that constraint were absent.

Requirement 3 is the substance of this protocol. A description that can diverge from its enforcement is the condition being eliminated.

5.3. Response

On success, the server returns 200 with Content-Type: application/json and a body describing the consequence of the act. The shape of that body is not specified here.

On failure, the server SHOULD return 204 with no body, and SHOULD NOT indicate which constraint rejected the body. An address that reports why a body was rejected assists an unauthorized actor in constructing one that is accepted.

5.4. Idempotency

Acts are not idempotent unless a particular address specifies otherwise. This document defines no retry semantics.

6. Actor Identity

An address MAY read a GPT-Actor request header field in order to record how a body was produced. It carries no authority: it is unauthenticated and self-asserted, and MUST NOT be used to gate access.

A server MUST NOT infer actor identity from the body. Fields naming a speaker, where a form defines them, are content.

7. Security Considerations

7.1. Constrained Decoding Is Not Enforcement

That an actor's output conforms to a schema is a property of how the output was generated, not a property of the request. Some implementations supply a schema to a language model as a tool definition the model is instructed but not compelled to use.

A server MUST treat every body as untrusted regardless of how it was produced. Generation-time constraint is a strong prior on well-formedness and nothing more.

7.2. The Form Is the Attack Surface

Everything an actor can cause at an address is the set of values its form admits. That set SHOULD be as small as the address can tolerate: bounded string lengths, bounded array sizes, closed enumerations, and additionalProperties: false on every object.

An address publishing a permissive form has published a permissive capability, whatever it does with the body afterward.

7.3. No Separate Description of Behavior

This protocol provides no channel by which a server describes what it will do that is separate from the form. This is deliberate. A prose description of a capability is unverifiable by the actor and unenforced by the server, and its presence invites reliance on a statement nothing checks.

7.4. Denial of Service

A form is retrieved before every act, so an address serves its schema to unauthenticated clients at whatever rate they request it. Implementations SHOULD serve a precomputed representation and SHOULD apply rate limiting independent of this protocol.

8. Relationship to Other Work

Tool calling and tool registries supply a language model with definitions in advance, from the client side. GPT supplies them from the address at the moment of contact, and the same definition serves as the server's check. The tradeoff is that a registry can present many capabilities at once, where a GPT address presents one.

Proactive content negotiation [RFC9110] is used as specified, rather than maintaining separate paths for human and machine representations that can disagree about what an address offers.

GPT resembles hypermedia controls in that a response states what is possible next. It differs in that the statement is directly executable by the actor: a grammar to generate within, rather than links an actor must be programmed to interpret.

9. IANA Considerations

This document has no IANA actions.

The header fields GPT-Type and GPT-Actor are used by the reference implementation but are not registered by this document. A future version may request registration in the "Hypertext Transfer Protocol (HTTP) Field Name Registry".

10. References

10.1. Normative References

[JSON-SCHEMA]
"JSON Schema: A Media Type for Describing JSON Documents", , <https://json-schema.org/draft/2020-12/json-schema-core.html>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC9110]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/rfc/rfc9110>.

10.2. Informative References

[RFC8259]
Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, , <https://www.rfc-editor.org/rfc/rfc8259>.

Appendix A. Reference Implementation

A running implementation is available at https://appgp.tv. Its form describes a tree of text and styled spans.

Retrieving the form and submitting an act, using a language model runtime with native JSON Schema support:

x=$(curl -L appgp.tv)
claude -p --system-prompt "$(jq -r .p<<<$x)" \
          --json-schema  "$(jq -c .s<<<$x)" \
          "$(jq -c .m<<<$x)" | curl -L appgp.tv -d@-

The same address with a different runtime:

x=$(curl -L appgp.tv)
jq -c .m<<<$x | codex e --skip-git-repo-check \
  --output-schema <(jq -c .s<<<$x) "$(jq -r .p<<<$x)" \
  | curl -L appgp.tv -d@-

And with a locally hosted model:

curl -L appgp.tv | jq '{model:"qwen3.5:9b",
  messages:([{role:"system",content:.p}]+.m),
  stream:false, format:.s}' \
  | curl localhost:11434/api/chat -d@- \
  | jq -r .message.content | curl -L appgp.tv -d@-

No client library is installed in any of the three cases, and the address is unaware which runtime contacted it.

Appendix B. Open Questions

The following are unresolved in this version.

Composition:

Whether an address should be able to name other addresses, and if so whether as data within the form or as a protocol-level member. Naming them within the form keeps the protocol to a single primitive but gives an actor no means of reasoning about the graph before entering it.

Form Change:

A form may change between arrival and act. Nothing in this document detects that. An entity-tag on the form, echoed by the act, would — at the cost of a required header field.

Failure Reporting:

Returning 204 with no explanation is appropriate for a public address and unhelpful for one under development. This document provides no means of distinguishing the two.

Long-Running Acts:

Acts are a single request and response. Progressive results and acts that outlive a request are unaddressed.

Acknowledgments

TODO.

Author's Address

Mark Ferguson