Skip to content

settings

Global mujoco-mojo settings API for the Dojo dashboard.

get_settings async

Python
get_settings(request: Request) -> dict[str, Any]

Returns the current settings, their JSON Schema, per-leaf display metadata, the Color name-to-hex table, and whether this request is allowed to edit them. Every SecretStr field (dojo.password) is stripped entirely from both the schema and the values - not masked, removed - since the Dojo web frontend has no legitimate need to know these fields exist at all.

Source code in src/mujoco_mojo/utils/layers/dojo/routers/settings.py
Python
@router.get("")
async def get_settings(request: Request) -> dict[str, Any]:
    """Returns the current settings, their JSON Schema, per-leaf display metadata, the Color name-to-hex table, and whether this request is allowed to edit them. Every SecretStr field (dojo.password) is stripped entirely from both the schema and the values - not masked, removed - since the Dojo web frontend has no legitimate need to know these fields exist at all."""
    settings = MujocoMojoSettings()
    return {
        "schema": _dojo_settings_schema(),
        "color_choices": {member.name: member.value for member in Color},
        "is_localhost": shared.is_localhost(request),
        **_settings_payload(settings),
    }

post_settings async

Python
post_settings(
    request: Request, body: dict[str, Any]
) -> dict[str, Any]

Validates and persists a full settings tree posted by the client.

Source code in src/mujoco_mojo/utils/layers/dojo/routers/settings.py
Python
@router.post("")
async def post_settings(request: Request, body: dict[str, Any]) -> dict[str, Any]:
    """Validates and persists a full settings tree posted by the client."""
    _require_localhost(request)
    current = MujocoMojoSettings()
    merged = _merge_preserving_secrets(current, body)
    try:
        updated = _validate_replacing(MujocoMojoSettings, merged)
    except ValidationError as exc:
        # surfaces a schema violation (e.g. a width scale below its `ge=0`
        # minimum, an invalid Color name/hex) as a clean 422 with the
        # specific field/message instead of an unhandled 500 - a
        # ValidationError raised here, inside the handler body rather than
        # during FastAPI's own request parsing, isn't caught by its default
        # RequestValidationError handling
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=exc.errors()
        ) from exc
    updated.save()
    return _settings_payload(updated)

post_settings_reset async

Python
post_settings_reset(request: Request) -> dict[str, Any]

Resets every setting to its code-level default.

Source code in src/mujoco_mojo/utils/layers/dojo/routers/settings.py
Python
@router.post("/reset")
async def post_settings_reset(request: Request) -> dict[str, Any]:
    """Resets every setting to its code-level default."""
    _require_localhost(request)
    updated = MujocoMojoSettings.defaults()
    updated.save()
    return _settings_payload(updated)

resolve_color async

Python
resolve_color(value: str = '') -> dict[str, Any]

Resolves arbitrary color input (a Color enum member name in any case, or a #rrggbb hex code) to its canonical hex and, if it matches one, Color member name - a read-only, general-purpose endpoint, not tied to a specific settings field, so any color picker in Dojo can resolve what a user typed against Color.parse's normalization instead of re-implementing name/case matching client-side.

Not localhost-gated, unlike the write endpoints above - this never modifies anything.

Source code in src/mujoco_mojo/utils/layers/dojo/routers/settings.py
Python
@router.get("/color/resolve")
async def resolve_color(value: str = "") -> dict[str, Any]:
    """
    Resolves arbitrary color input (a `Color` enum member name in any case, or a `#rrggbb` hex code) to its canonical hex and, if it matches one, `Color` member name - a read-only, general-purpose endpoint, not tied to a specific settings field, so any color picker in Dojo can resolve what a user typed against `Color.parse`'s normalization instead of re-implementing name/case matching client-side.

    Not localhost-gated, unlike the write endpoints above - this never modifies anything.
    """
    try:
        parsed = Color.parse(value)
    except ValueError:
        return {"valid": False, "hex": None, "name": None, "hidden": False}
    if parsed is None:
        return {"valid": True, "hex": None, "name": None, "hidden": True}
    if parsed in Color.__members__:
        return {
            "valid": True,
            "hex": Color[parsed].value,
            "name": parsed,
            "hidden": False,
        }
    return {"valid": True, "hex": parsed, "name": None, "hidden": False}