This gist will be maintained, and supersedes all IRC and email description of Dioscuri.
Dioscuri, a Gemini-adjacent protocol for interaction
Dioscuri is a protocol intended to supplement Gemini for doing things like performing remote actions or running an application server. It is the POST to Gemini's GET. Dioscuri servers will run on a different port from Gemini servers, so that they do not interfere with each other; it will often be useful to run multiple servers on one host, so no fixed port is specified. The use of client certificates for authorization is strongly recommended, especially if requests are interpreted to affect server-side state.
The name "Dioscuri" is the Latin version of the Classical Greek name Διόσκουροι for the Heavenly Twins, Castor and Pollux/Polydeukes, who were called Gemini in Latin; the constellation is named after them. I say dee-OH-skoo-ree, but Greeks, classicists, and others should feel free to pronounce the name their way.
Great thanks to the members of #gemini, especially lukee and aravk, and to the members of the Gemini mailing list, especially meff and snan.
Alternatives to Dioscuri include Titan, which is for upload (the PUT to Gemini's GET), using the query part of an URL (the media type can't be specified and the length is highly limited), and inimeg, which starts out as a Gemini connection in which the client and server switch roles.
A Dioscuri request starts out with the client sending a single line,
<URL><SP><MEDIA-TYPE><CR><LF>. This indicates that a body follows which should be interpreted according to the media type. For example,
gemini://example.org/foo.gmi text/gemini means that the Dioscuri server should do something with the following body, which is of type
text/gemini. This line is limited to 1024 characters including the terminating
<CR><LF>. When no request body is required, by convention a Dioscuri client should use the media type
inode/x-empty (which is used by the
file command when asked to give the media type of an empty file). In that case no body follows.
The client ends the upload by closing the write side of its socket while leaving the read side open. This limits client languages to those having libraries that can do this.
When Dioscuri has received the request line and body, then it does whatever it does, depending on the server, the URL (which does not have to refer to an actually existing resource), and the media type. For example, sending a request line of:
gemini://example.org/foo.gmi text/geminimight replace the contents of
foo.gmiwith the uploaded body.
gemini://example.org/arithmetic text/plainmight evaluate an arithmetic expression in the body and return the result as text/plain.
gemini://example.org/widget-search application/jsonmight ask the server to interpret the JSON body as a complex search request through an application server's list of widges and return another JSON body specifying the matching widgets.
All 2-digit status codes have the same meaning as in Gemini.
If the server has nothing to send to the client, as in the case of an upload it can respond with the media type
inode/x-empty, which means that there is no response body.
In some cases, the server may not wish to return a body, but rather return an URL where the body may be found. This is done by using the media type
message/external-body; access-type=URL; URL="[url]" where [url] is replaced by the URL where the body is. (See RFC 2017 for details.) Note that this is not the same as a 30 status code, which means that the request should be retried at a different URL.
For example, a client wishes to add a new file to a container (directory or whatever) in the server but leaves it up to the server to choose the new URL according to some algorithm (random, timestamp, etc.) So a request of
gemini://example.com/container text/gemini followed by the body could in such a case respond
20 message/external-body; access-type=URL; URL="gemini://example.com/container/20201220202020.gmi" meaning that the new resource can be found at
The protocol URLs used by both clients and servers are URIs; that is, ASCII-only. However, if a client or server obtains an IRI from a body or an external source such as a configuration file that it wishes to use as a protocol URL, it must convert it to an URL by Punycoding the host and then %-encoding all IRI reserved characters. Caution must be taken not to %-encode what is already %-encoded.