Skip to content

UI-P3: list runtime presets, each with its used_by app list.

GET
/v1/admin/runtime-presets
curl --request GET \
--url http://localhost:8080/v1/admin/runtime-presets \
--header 'Authorization: Bearer <token>'

A runtime preset is a reusable container configuration (image, args, env, mounts, managed-home defaults) that many apps inherit instead of repeating. It is NOT a launch profile - UI-P4’s launch profiles are the quality/encode chain. RequireAuth -> RequireAdmin, server-enforced.

OK.

Media typeapplication/json
object
items
required
Array<object>
object
id
required
string format: uuid
name
required

Unique. A collision on create/patch is 409 conflict.

string
description
required
string
image
required

Inherited by apps whose own runtime_spec.image is blank/absent; an app that sets one overrides it.

string
args
required

Prepended to the app’s own launch arguments at launch (preset first).

Array<string>
env
required

Merged UNDER the app’s environment at launch - a key set on the app wins.

object
key
additional properties
string
mounts
required

Prepended to the app’s own mounts at launch (preset first), with NO DEDUPE. Two mounts on the same container path is a real misconfiguration and must surface rather than be silently resolved by the server picking one.

Array<string>
managed_home
required

Storage default for inheriting apps. apps.managed_home has no “unset”, so an app can turn a managed home ON when its preset has none but cannot turn a preset’s OFF.

boolean
home_container_path
required

Container-side mount point default; an app with its own non-default path keeps it.

string
network
required

First-run-experience §S2. Docker network mode for app containers launched from an app inheriting this preset. “” (default) = inherit the agent’s host default (QUASAR_CONTAINER_NETWORK, else none). An app’s own runtime_spec.network overrides this at launch, within the same none/bridge range. “host” is NOT available here: –network host removes the container’s network namespace rather than widening it, exposing the host’s own loopback (control plane, Postgres, the docker proxy, any admin-only port) to the app - and because a preset is portable (it can be materialized from a catalog image manifest authored on another machine), accepting “host” here would let a manifest dissolve the isolation boundary on every host that installs it. Host networking stays reachable only through the agent’s own host-local QUASAR_CONTAINER_NETWORK operator knob, never through this API.

string
Allowed values: "" none bridge
used_by
required

The apps inheriting this preset - RESOLVED PER READ, never stored. It is what the admin UI’s “Used by” row and its disabled-Delete affordance render; it is NOT the enforcement (DELETE returns 409 while it is non-empty). [] for an unused preset.

Array<object>

One app inheriting a runtime preset.

object
id
required
string format: uuid
name
required
string
created_at
required
string format: date-time
updated_at
required
string format: date-time
Example
{
"items": [
{
"network": ""
}
]
}

Missing/invalid/expired/revoked token.

Media typeapplication/json
object
error
required
object
code
required

E.g. validation_failed, unauthorized, forbidden, not_found, conflict, session_quota_exceeded, home_in_use, home_not_provisioned, parent_app_disabled, profile_ineligible, profile_not_launchable_for_app, no_host_available, capacity_exhausted, restart_required, rate_limited, internal. Open string, not an enum: new codes are additive and an unknown one falls through to a client’s generic per-status branch.

string
message
required
string
live_sessions

Present on restart_required.

integer
session_id

Steam library discovery Phase 3, ADDITIVE: present on home_in_use when the guard could name the CONFLICTING live session - the one already holding the home. It is here so the client can offer “go to your running session” with a link instead of a dead-end toast. OMITTED rather than empty when the conflict is known but the session is not, so a client branches on presence and never renders a link to nowhere. Load-bearing once derived tiles exist: the lock is held by the PARENT’s home, so a user who clicks a game tile can be refused because a DIFFERENT app (the Steam launcher, or another game from the same install) is running, and without the session id the refusal reads as a bug. See control-api.md §Derived tiles.

string format: uuid
derived_tiles

Steam library discovery Phase 3, ADDITIVE: present on the 409 conflict from DELETE /v1/apps/{id} when the app has derived tiles and ?delete_derived=true was not sent. A LIST, not a count - the point of the confirmation is that the admin sees what they are about to destroy. Capped; an empty array means the tiles could not be listed, never that there are none.

Array<object>
object
id
required
string format: uuid
name
required
string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"live_sessions": 1,
"session_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"derived_tiles": [
{
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"name": "example"
}
]
}
}

Authenticated but insufficient role / not the owner (precedes resource lookup).

Media typeapplication/json
object
error
required
object
code
required

E.g. validation_failed, unauthorized, forbidden, not_found, conflict, session_quota_exceeded, home_in_use, home_not_provisioned, parent_app_disabled, profile_ineligible, profile_not_launchable_for_app, no_host_available, capacity_exhausted, restart_required, rate_limited, internal. Open string, not an enum: new codes are additive and an unknown one falls through to a client’s generic per-status branch.

string
message
required
string
live_sessions

Present on restart_required.

integer
session_id

Steam library discovery Phase 3, ADDITIVE: present on home_in_use when the guard could name the CONFLICTING live session - the one already holding the home. It is here so the client can offer “go to your running session” with a link instead of a dead-end toast. OMITTED rather than empty when the conflict is known but the session is not, so a client branches on presence and never renders a link to nowhere. Load-bearing once derived tiles exist: the lock is held by the PARENT’s home, so a user who clicks a game tile can be refused because a DIFFERENT app (the Steam launcher, or another game from the same install) is running, and without the session id the refusal reads as a bug. See control-api.md §Derived tiles.

string format: uuid
derived_tiles

Steam library discovery Phase 3, ADDITIVE: present on the 409 conflict from DELETE /v1/apps/{id} when the app has derived tiles and ?delete_derived=true was not sent. A LIST, not a count - the point of the confirmation is that the admin sees what they are about to destroy. Capped; an empty array means the tiles could not be listed, never that there are none.

Array<object>
object
id
required
string format: uuid
name
required
string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"live_sessions": 1,
"session_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"derived_tiles": [
{
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"name": "example"
}
]
}
}