---
title: "POST /lifecycle/restart — request a controlled restart/promotion of a"
method: POST
path: "/lifecycle/restart"
tags: ["lifecycle"]
---

# POST /lifecycle/restart — request a controlled restart/promotion of a

`POST /lifecycle/restart`

transient (Oneshot) daemon (ADR-008 P5-L).

REFUSES unless this daemon is an Oneshot residency AND the single-instance
lock is enabled AND the target is not itself Oneshot. The accepted path raises
the L8b `quiescing` flag (via the coordinator) so admission gates drain
in-flight work; the Oneshot supervisor then self-terminates and `app.rs`
persists the handover record. Production-neutral: no Oneshot daemon exists
until L8d, so the accept path is unreachable in production.

## Request body

- RestartRequest — POST /lifecycle/restart request body (ADR-008 P5-L L8d-1). `targetMode` is the residency the successor daemon should launch in.
  - `targetMode` 'standalone' | 'serverHeadless' | 'oneshot', required — Daemon residency mode reported in the health/status handshake (ADR-008 P5-L L1). Wire values (camelCase, to match the `HealthResponse`/`StatusResponse` field naming these enums travel inside): `"standalone" | "serverHeadless" | "oneshot"`. The wire enum is defined HERE in the contract — it deliberately does NOT depend on `uc-daemon`'s internal `DaemonRunMode`; the producer maps `DaemonRunMode -> DaemonResidency` at the daemon/webserver boundary. Consumers (CLI L2 version-check, future R8-F2 takeover) read this to learn whether the daemon they are talking to is a persistent member node (`Standalone`/`ServerHeadless`) or a transient `Oneshot` that a persistent client may later take over. As of L1 the CLI/GUI do NOT act on this field. Backward-tolerant: the field carries `#[serde(default)]`, so an OLDER daemon body that omits `residency` decodes to [`Self::Standalone`], and a NEWER body's `residency` is simply ignored by an older client. New variants must be added at the END so existing clients keep deserializing known values.

## Response `202`

Controlled restart accepted; quiescing/drain started

- RestartAcceptedEnvelope — Canonical success envelope: `{ "data": T, "ts": <unix millis i64> }`. `ts` is `chrono::Utc::now().timestamp_millis()`, set in the webserver handler via [`ApiEnvelope::now`] (the contract carries only the type + the clock helper, not a hard dependency on when the handler reads the clock). `rename_all = "camelCase"` is a no-op for the single-word fields here but is declared for forward-compat. IMPORTANT (utoipa v4): every concrete `ApiEnvelope<X>` that needs a named OpenAPI component is declared in the `#[aliases(...)]` block below. Add a new alias line whenever a new payload type needs enveloping. NEVER register the bare `ApiEnvelope` in `components(schemas(...))` — utoipa errors on a bare generic, and an un-aliased generic inlines an anonymous schema.
  - `data` RestartAccepted, required — POST /lifecycle/restart 202 ACCEPTED body (ADR-008 P5-L L8d-1). Echoes the locked-in `generation` + `targetMode` so the requester can correlate the accepted restart with the eventual handover record.
    - `generation` integer, required
    - `targetMode` 'standalone' | 'serverHeadless' | 'oneshot', required — Daemon residency mode reported in the health/status handshake (ADR-008 P5-L L1). Wire values (camelCase, to match the `HealthResponse`/`StatusResponse` field naming these enums travel inside): `"standalone" | "serverHeadless" | "oneshot"`. The wire enum is defined HERE in the contract — it deliberately does NOT depend on `uc-daemon`'s internal `DaemonRunMode`; the producer maps `DaemonRunMode -> DaemonResidency` at the daemon/webserver boundary. Consumers (CLI L2 version-check, future R8-F2 takeover) read this to learn whether the daemon they are talking to is a persistent member node (`Standalone`/`ServerHeadless`) or a transient `Oneshot` that a persistent client may later take over. As of L1 the CLI/GUI do NOT act on this field. Backward-tolerant: the field carries `#[serde(default)]`, so an OLDER daemon body that omits `residency` decodes to [`Self::Standalone`], and a NEWER body's `residency` is simply ignored by an older client. New variants must be added at the END so existing clients keep deserializing known values.
  - `ts` integer, required — Server time when the response was built (unix epoch milliseconds).

## Other responses

- `400` — Invalid target mode (cannot promote to a transient target)
- `409` — Restart unavailable (already in progress / not a transient daemon / single-instance disabled)

---

[API](https://skmtc.net/uniclipboard/apis/uniclipboard-daemon-api.md) · [All operations](https://skmtc.net/uniclipboard/apis/uniclipboard-daemon-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/uniclipboard/uniclipboard-daemon-api/versions/a5d29889448a/schema)
