Managing servers

Background tasks

How long operations like installs, downloads, and reindexing survive navigation, page close, and bot restart — with live progress bars when you come back.

Why a task system

Installing OpenClaw takes ~5 minutes. Pulling an Ollama embedding model takes 5–15. HTTP timeouts won't hold a connection that long, and users inevitably close the page. If we ran these as synchronous requests, any interruption would leave the server in a half-configured state.

So long operations become backend tasks: fire-and-forget units of work with per-step progress, reconnectable from any client.

Lifecycle

  1. Frontend POSTs to an endpoint like /api/servers/:id/rag/install. Backend returns { taskId: "..." } immediately.
  2. Task runs asynchronously in the task manager. Each phase calls ctx.step(name).complete(detail) or .fail(detail).
  3. Frontend hook useTask(taskId) polls GET /api/tasks/:id every second and renders a live progress bar.
  4. When the task finishes, polling stops automatically.

Reconnecting

If the user navigates away or closes the bot, the task keeps running on the backend. When the user returns:

The UI state is also persisted at the module level (not React state), so expanded panels stay expanded across navigation and the progress bar picks up from where it left off.

Deduplication

Starting a task with the same (type, serverId, userId) tuple as an already-running one returns the existing task ID instead of spawning a parallel one. This prevents double-clicks from launching two parallel ollama pull processes that would corrupt each other.

Per-user authorization

Every task GET checks that the caller's JWT user ID matches the task's creator. You can only see and reconnect to your own tasks.

Retention

Completed and failed tasks stay in memory for 1 hour, then get garbage-collected. This gives enough window for the user to read the final error message.

Which operations use tasks