diff --git a/docs/steam-compat-tool-interface.md b/docs/steam-compat-tool-interface.md
new file mode 100644
index 0000000000000000000000000000000000000000..20165876d2b1997dfe66e0c67e77706a5963d38e
--- /dev/null
+++ b/docs/steam-compat-tool-interface.md
@@ -0,0 +1,417 @@
+# Steam compatibility tool interface
+
+## Compatibility tool declaration
+
+Compatibility tools are declared by a file `compatibilitytool.vdf`,
+which is a [VDF](https://developer.valvesoftware.com/wiki/KeyValues)
+text file in this format:
+
+```
+"compatibilitytools"
+{
+  "compat tools"
+  {
+    "my_compat_tool"
+    {
+      "install_path" "."
+      "display_name" "My Compatibility Tool"
+      "from_oslist" "windows"
+      "to_oslist" "linux"
+    }
+  }
+}
+```
+
+`compat tools` can presumably contain one or more compatibility tools,
+each identified by a unique name, in this case `my_compat_tool`.
+
+Each compatibility tool can have these fields:
+
+`install_path`
+: Installation directory containing `toolmanifest.vdf` and other
+    necessary files, for example
+    `/path/to/steamapps/common/Proton - Experimental` for Proton
+
+`display_name`
+: Name to display in the Steam user interface
+
+`from_oslist`
+: Operating system(s?) whose executables can be run by this
+    compatibility tool, for example `windows` for Proton
+
+`to_oslist`
+: Operating system(s?) that can run this compatibility tool,
+    for example `linux` for Proton
+
+For the compatibility tools provided by Steam itself, such as
+Steam Linux Runtime and Proton, the equivalent of this information is
+downloaded out-of-band and stored in `~/.steam/root/appcache/appinfo.vdf`,
+so the depot downloaded into the Steam library will not contain this file.
+
+Third-party compatibility tools can be installed in various locations
+such as `~/.steam/root/compatibilitytools.d`.
+
+Each subdirectory of `compatibilitytools.d` that contains
+`compatibilitytool.vdf` is assumed to be a compatibility tool. The
+installation path should be `"."` in this case.
+
+Alternatively, the manifest can be placed directly in
+`compatibilitytools.d` with the `install_path` set to the relative or
+absolute path to the tool's installation directory.
+
+## Tool manifest
+
+Each compatibility tool has a *tool manifest*, `toolmanifest.vdf`, which
+is a [VDF](https://developer.valvesoftware.com/wiki/KeyValues) text
+file with one top-level entry, `manifest`.
+
+`manifest` has the following known fields:
+
+`version`
+: The version number of the file format. The current version is `2`.
+    The default is `1`.
+
+`commandline`
+: The command-line for the entry point.
+
+`require_tool_appid`
+: If set, this compatibility tool needs to be wrapped in another
+    compatibility tool, specified by its numeric Steam app ID. For
+    example, Proton 5.13 needs to be wrapped by "Steam Linux Runtime -
+    soldier", so it sets this field to `1391110`.
+
+`unlisted`
+: If `1`, this compatibility tool will not be shown to users as an option for
+    running games. For example, until Steam is able to distinguish between
+    Steam Runtime 1 'scout' and Steam Runtime 2 'soldier' as distinct
+    platforms, it is not useful to run ordinary Steam games under 'soldier',
+    due to it being incompatible with 'scout'.
+
+`use_sessions`
+: If set to `1`, older versions of Steam would use the "session mode"
+    described below.
+
+`use_tool_subprocess_reaper`
+: If set to `1`, Steam will send `SIGINT` to the compatibility tool
+    instead of proceeding directly to `SIGKILL`, to give it a chance
+    to do graceful cleanup.
+
+## Command-line
+
+In a version 1 manifest, the `commandline` is a shell expression.
+The first word should start with `/` and is interpreted as being
+relative to the directory containing the compat tool, so `/run`
+really means something like
+`~/.local/share/Steam/steamapps/common/MyCompatTool/run`.
+
+The game's command-line will be appended to the tool's command-line,
+so if you are using `getopt` or a compatible command-line parser, you
+might want to use a `commandline` like `/run --option --other-option --`
+to get the game's command-line to appear after a `--` separator.
+
+In a version 2 manifest, the special token `%verb%` can appear in the
+`commandline`. It is replaced by either `run` or `waitforexitandrun`.
+
+If a compatibility tool has `require_tool_appid` set, then the command-line
+is built up by taking the required tool, then appending the tool that
+requires it, and finally appending the actual game: so if a compat tool
+named `Inner` requires a compat tool named `Outer`, and both tools have
+`/run %verb% --` as their `commandline`, then the final command line will
+look something like this:
+
+    /path/to/Outer/run waitforexitandrun -- \
+    /path/to/Inner/run waitforexitandrun -- \
+    /path/to/game.exe
+
+(In reality it would all be one line, rather than having escaped newlines
+as shown here.)
+
+## Launch options
+
+If a Steam game has user-specified launch options configured in its
+Properties, and they contain the special token `%command%`, then
+`%command%` is replaced by the entire command-line built up from the
+compatibility tools. For example, if a compat tool named `Inner` requires
+a compat tool named `Outer`, both tools have `/run %verb% --` as their
+`commandline`, and the user has set the Launch Options in the game's
+properties to
+
+    DEBUG=yes taskset --cpu-list 0,2 %command% -console
+
+then the final command line will look something like this:
+
+    DEBUG=yes taskset --cpu-list 0,2 \
+    /path/to/Outer/run waitforexitandrun -- \
+    /path/to/Inner/run waitforexitandrun -- \
+    /path/to/game.exe -console
+
+(In reality it would all be one line, rather than having escaped newlines
+as shown here.)
+
+If the user-specified launch options for a Steam game do not contain
+`%command%`, then they are simply appended to the command-line. For
+example, setting the launch options to `--debug` is equivalent to
+`%command% --debug`.
+
+Shortcuts for non-Steam games do not currently implement the special
+handling for `%command%`: the configured launch options are simply
+appended to the command-line, regardless of whether they contain
+`%command%` or not.
+
+Please note that not all invocations of compatibility tools take the
+user-specified launch options into account: they are used when running
+the actual game, but they are not used for install scripts.
+
+## Environment
+
+Some environment variables are set by Steam, including:
+
+`LD_LIBRARY_PATH`
+: Used to load Steam Runtime libraries.
+
+`LD_PRELOAD`
+: Used to load the Steam Overlay.
+
+`STEAM_COMPAT_APP_ID`
+: The decimal app-ID of the game, for example 440 for Team Fortress 2.
+
+`STEAM_COMPAT_CLIENT_INSTALL_PATH`
+: The absolute path to the directory where Steam is installed. This is the
+    same as the target of the `~/.steam/root` symbolic link.
+
+`STEAM_COMPAT_DATA_PATH`
+: The absolute path to a directory that compatibility tools can use to
+    store game-specific data. For example, Proton puts its `WINEPREFIX`
+    in `$STEAM_COMPAT_DATA_PATH/pfx`.
+
+`STEAM_COMPAT_INSTALL_PATH`
+: The absolute path to the game's installation directory, for example
+    `/home/you/.local/share/Steam/steamapps/common/Estranged Act I`,
+    even if the current working directory is a subdirectory of this
+    (as is the case for Estranged: Act I (261820) for example).
+
+`STEAM_COMPAT_LIBRARY_PATHS`
+: Colon-delimited list of paths to Steam Library directories containing
+    the game, the compatibility tools  if  any,  and any  other resources
+    that the game will need, such as DirectX installers.
+
+`STEAM_COMPAT_MOUNTS`
+: Colon-delimited list of paths to additional directories that are to be
+    made available read/write in a pressure-vessel container.
+
+`STEAM_COMPAT_SESSION_ID`
+: In the historical session mode (see below), this is used to link together
+    multiple container invocations into a logical "session".
+
+`STEAM_COMPAT_SHADER_PATH`
+: The absolute path to the variable data directory used for cached
+    shaders, if any.
+
+`STEAM_COMPAT_TOOL_PATHS`
+: Colon-delimited list of paths to Steam compatibility tools in use.
+    Typically this will be a single path, but when using tools with
+    `require_tool_appid` set, such as Proton, it is a colon-separated
+    list with the "innermost" tool first and the "outermost" tool last.
+
+`SteamAppId`
+: The same as `STEAM_COMPAT_APP_ID`, but only when running the actual
+    game; not set when running
+    [install scripts](https://partner.steamgames.com/doc/sdk/installscripts)
+    or other setup commands. The Steamworks API assumes that every process
+    with this environment variable set is part of the actual game.
+
+When Steam invokes a tool with `require_tool_appid` set, such as Proton,
+the environment variables are set as described for the "outermost" tool,
+which can change them if required before it invokes the "innermost" tool
+(although most should not be changed).
+
+For example, when using Proton with "Steam Linux Runtime - soldier", the
+"outer" compatibility tool "Steam Linux Runtime - soldier" is run with
+`LD_LIBRARY_PATH` set by the Steam Runtime to point to mixed host and
+scout libraries. After setting up the container, it runs the "inner"
+compatibility tool (Proton) with an entirely new `LD_LIBRARY_PATH`
+pointing to mixed host and soldier libraries.
+
+## Native Linux Steam games
+
+This is the simplest situation and can be considered to be the baseline.
+
+In recent versions of Steam, the game process is wrapped in a `reaper`
+process which sets itself as a subreaper using `PR_SET_CHILD_SUBREAPER`
+(see
+[**prctl**(2)](https://manpages.debian.org/unstable/manpages-dev/prctl.2.en.html)
+for details).
+
+Version 1 compat tools are not invoked specially.
+
+Version 2 compat tools are invoked with a `%verb%` in the `commandline`
+(if any) replaced by `waitforexitandrun`.
+
+The game is expected to run in the usual way. Conventionally, it does not
+double-fork to put itself in the background, but if it does, any background
+processes will be reparented to have the subreaper as their parent.
+
+The current working directory is the working directory configured in the
+game's Steam metadata (for example `estrangedact1` for Estranged: Act 1,
+261820), or the game's directory (or maybe the executable's directory?)
+if unconfigured. The compatibility tool is expected to preserve this
+working directory when running the actual game.
+
+The environment variable `STEAM_COMPAT_SESSION_ID` is not set.
+
+The environment variable `STEAM_COMPAT_APP_ID` is set to the app-ID
+of the game. The environment variable `SteamAppId` has the same value.
+
+The [launch options](#launch-options) are used.
+
+## Windows games with no install script
+
+Some Windows games, such as Soldat (638490), do not have an
+"install script" in their metadata. Running these games behaves much the
+same as a native Linux game: it is wrapped in a subreaper, version 1
+compat tools are not invoked specially, and version 2 compat tools
+are invoked with a `%verb%` in the `commandline` (if any) replaced by
+`waitforexitandrun`.
+
+The environment variable `STEAM_COMPAT_SESSION_ID` is not set.
+Historically, it was set to a unique token that was not used in any
+previous invocation.
+
+The environment variable `STEAM_COMPAT_APP_ID` is set to the app-ID
+of the game. The environment variable `SteamAppId` has the same value.
+
+The current working directory is the working directory configured in the
+game's Steam metadata, as usual.
+
+The [launch options](#launch-options) are used.
+
+## Windows games with an install script (since Steam beta 1623823138)
+
+Other Windows games, such as Everquest (205710), have an
+[install script](https://partner.steamgames.com/doc/sdk/installscripts),
+conventionally named `installscript.vdf`, which must be run by an
+interpreter.
+
+Since Steam beta 1623823138, these games are run like this:
+
+* Run the install script. For version 1 compat tools, the compat
+    tool is run as usual, except that the command appended to the
+    command-line is the install script interpreter, not the actual game.
+    For version 2 compat tools, the `%verb%` is set to `run` instead
+    of the usual `waitforexitandrun`.
+
+    The environment variable `STEAM_COMPAT_SESSION_ID` is not set.
+
+    The environment variable `STEAM_COMPAT_APP_ID` is set to the app-ID
+    of the game.
+
+    The environment variable `SteamAppId` is *not* set in this case.
+
+    The current working directory is *not* the game's directory in this case.
+    As currently implemented, it appears to be the Steam installation
+    (usually `~/.local/share/Steam` or `~/.steam/debian-installation`)
+    but this is probably not guaranteed.
+
+    The [launch options](#launch-options) are **not** used here.
+
+* Run the actual game in the usual way.
+
+    The environment variable `STEAM_COMPAT_SESSION_ID` is not set.
+
+    The environment variables `STEAM_COMPAT_APP_ID` and `SteamAppId`
+    are both set to the app-ID of the game as usual.
+
+    The current working directory is the working directory configured in
+    the game's Steam metadata, as usual.
+
+    The [launch options](#launch-options) are used, as usual.
+
+## Historical behaviour of Windows games (session mode v2)
+
+Before Steam beta 1623823138, each Windows game had several setup commands
+to run before it could be launched. They were invoked like this:
+
+* Run the first setup command. For version 1 compat tools, the compat
+    tool is run as usual, except that the command appended to the
+    command-line is the setup command, not the actual game.
+    For version 2 compat tools, additionally the `%verb%` is set to `run`
+    instead of `waitforexitandrun`.
+
+    The environment variable `STEAM_COMPAT_SESSION_ID` is set to a
+    unique token (in practice a 64-bit number encoded in hex).
+
+    The environment variable `STEAM_COMPAT_APP_ID` is set to the app-ID
+    of the game.
+
+    The environment variable `SteamAppId` is *not* set in this case.
+
+    The current working directory is *not* the game's directory in this case.
+    As currently implemented, it appears to be the Steam installation
+    (usually `~/.local/share/Steam` or `~/.steam/debian-installation`)
+    but this is probably not guaranteed.
+
+    The [launch options](#launch-options) are **not** used here.
+
+    The compat tool is expected to do any setup that it needs to do
+    (for example pressure-vessel must start a container), then run
+    the given command and exit. The compat tool may leave processes
+    running in the background.
+
+* Run the second setup command, in the same way as the first, and so on.
+    More than one command can be run in parallel, so tools that need to
+    do setup (such as pressure-vessel) must use a lock to ensure the setup
+    is only done by whichever setup command wins the race to be the first.
+
+    All environment variables are the same as for the first setup command,
+    and in particular the `STEAM_COMPAT_SESSION_ID` is the same. This is
+    how compatibility tools can know which containers or subprocesses
+    to reuse.
+
+* When all setup commands have finished, run the actual game. For
+    version 2 compat tools, the `%verb%` is set to `waitforexitandrun`.
+    The compat tool is expected to terminate any background processes
+    (for example pressure-vessel terminates the container and Proton
+    terminates the `wineserver`) and wait for them to exit, then launch
+    the actual game.
+
+    The environment variable `STEAM_COMPAT_SESSION_ID` is set to the
+    same unique token as for all the setup commands, so that the compat
+    tool can identify which subprocesses or containers to tear down.
+
+    The environment variables `STEAM_COMPAT_APP_ID` and `SteamAppId`
+    are both set to the app-ID of the game as usual.
+
+    The [launch options](#launch-options) are used, as usual.
+
+## Non-Steam games
+
+Version 1 compat tools are not invoked specially.
+
+Version 2 compat tools are invoked with a `%verb%` in the `commandline`
+(if any) replaced by `waitforexitandrun`.
+
+The environment variable `STEAM_COMPAT_SESSION_ID` is not set.
+Historically, it was set to a unique token that was not used in any
+previous invocation.
+
+`STEAM_COMPAT_APP_ID` is set to `0`. `SteamAppId` is not set.
+
+`STEAM_COMPAT_DATA_PATH` is set to a unique directory per non-Steam game.
+It is currently in the same format as Steam games' equivalent directories,
+but with a large arbitrary integer replacing the Steam app ID.
+
+`STEAM_COMPAT_INSTALL_PATH` is not set.
+
+`LD_LIBRARY_PATH` is usually set to the empty string to "escape" from
+the Steam Runtime library stack for non-Steam games, although games
+configured in Steam via development tools can be flagged to use the
+Steam Runtime library stack (this is done for games that are intended to
+be released onto Steam as native Linux games).
+
+The current working directory defaults to the directory containing the
+main executable, but can be reconfigured through the shortcut's properties.
+Steam Linux Runtime (pressure-vessel) containers will not work as expected
+unless this is set to the game's top-level directory.
+
+Launch options are appended to the command-line. The special token
+`%command%` in Steam games' launch options is not used here.