> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# blobhub-worker start

> Run the worker

`blobhub-worker start` loads the configuration, runs preflight checks, and runs each configured
section. The per-section behavior — what the worker does once it's attached — is determined by
the section's [`job_type`](/worker/job-types).

## Synopsis

```bash theme={null}
blobhub-worker start [--profile <name>] [--api-key <key>] [--api-url <url>] [--tui]
```

| Flag        | Default                                                                    | Description                                                                |
| ----------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `--profile` | the stored default                                                         | [Profile](/worker/auth) to run as. Also selects the state tree.            |
| `--api-key` | from `BLOBHUB_API_KEY`, then the profile                                   | API key, overriding profile and environment.                               |
| `--api-url` | from `BLOBHUB_API_URL`, then the profile, then `https://api.blobhub.io/v1` | API URL.                                                                   |
| `--tui`     | off (headless)                                                             | Render the live Textual dashboard. Press `q` to request graceful shutdown. |

The profile decides more than the credential: each one owns its own `config.yaml`, cursors, logs and lock, so
several workers run side by side on one machine. See [Authentication and Profiles](/worker/auth).

In headless mode (the default) the worker writes structured JSON log lines to **stderr**, which
makes it suitable for running under systemd, a container supervisor, or `tmux`. With `--tui`, those
same JSON lines are redirected to a file at `{state tree}/logs/{instance_id}/worker.jsonl`
(append mode, line-buffered) so the dashboard has the terminal to itself; stderr is silenced while
the dashboard runs. Log rotation is not implemented in v1.

## Preflight

Before any section is contacted, `start` runs the following steps **in this order**. A failure here exits the
process with a clear code; nothing on the server is touched.

1. **Migration**, if a pre-profiles install is found — it operates on fixed locations that exist before any
   profile is chosen, and may create the very credentials file step 2 then reads. See
   [Upgrading](/worker/auth#upgrading-from-a-pre-profiles-worker).
2. **Credential resolution**: profile name, then key, then URL, each `--flag` > environment > stored — else
   `PROFILE_NOT_FOUND`, `CREDENTIALS_NOT_FOUND` or `INSECURE_CREDENTIALS_PERMISSIONS`.
3. **State-tree selection**, from where the key came from. Everything after this resolves inside that tree.
   The tree is announced on the first log line (`worker_resolved`) — the way to see that a `blobhub profile
   use` elsewhere has moved which profile a bare `start` picks up.
4. `config.yaml` loaded and validated from that tree — else `INVALID_CONFIG`, which names the full path it
   looked at. Each section's [`job_type`](/worker/job-types) is dispatched to the corresponding job-type
   validator, which may surface additional codes (e.g. `UNKNOWN_JOB_TYPE`, or job-type-specific section
   errors).
5. **Identity**: `GET /v1/users/me` resolves the key's user. If the tree has no `identity.yaml` yet it is
   recorded now; otherwise the server's `user_id` must match the recorded one — else `AUTH_INVALID` /
   `USER_IDENTITY_MISMATCH`.
6. **Lock** acquired at `{state tree}/instance.yaml` (atomic `O_EXCL`; a stale file with a dead PID is
   replaced) — else `WORKER_ALREADY_RUNNING`, naming the profile. A worker on a *different* profile does not
   collide.

See [Configuration](/worker/configuration) for the full `config.yaml` schema and
[Reference](/worker/reference) for process-level remediation.

## Per-section behavior

For each configured section the worker dispatches to the section's `job_type`. The runtime
behavior — what gets attached, what gets polled, what gets posted — is documented on the
corresponding job-type page:

* `session_agent_harness` → [Overview](/worker/session-agent-harness/overview).

## Shutdown

`SIGINT` (Ctrl-C) and `SIGTERM` trigger a graceful shutdown:

1. Stop accepting new events.
2. Ask each running section to drain — the per-job-type teardown is documented on the
   corresponding job-type page.
3. Remove the tree's `instance.yaml` and exit 0.

`SIGKILL` skips the graceful path; the next `start` on that profile will replace the stale `instance.yaml`
and run each job type's recovery routine.

In `--tui` mode, a `SIGINT`/`SIGTERM` delivered from outside the process — for example, from
[`blobhub-worker instance stop`](/worker/cli/instance) — now drains exactly as headless does: it waits
for the in-flight run to finish however long that takes, with no cap of its own. Previously a `--tui`
worker took the default disposition on those signals instead: no drain, no lock release, an agent turn
cut mid-flight.

Pressing `q` at the keyboard is a different path with a different need: it drains too, but bounded to 10
seconds before cancelling the in-flight run, since someone at the terminal wants it back promptly. Reach
for `instance stop` rather than `q` when you want to stop a `--tui` worker without risking an in-flight
turn.

## Exit codes

`start` exits non-zero on any preflight failure, on any unhandled fatal error, and on user-requested
shutdown after surfacing the cause. Diagnostic detail is emitted to the structured log stream
(stderr by default; the `worker.jsonl` file under `--tui`) as a `worker_exit` JSON record.

Full code catalog: [Reference](/worker/reference).

## See also

* [Authentication and Profiles](/worker/auth)
* [`blobhub-worker login`](/worker/cli/login)
* [Configuration](/worker/configuration)
* [Job types](/worker/job-types)
