<!--
Sitemap:
- [Installation](/installation)
- [Upgrading](/upgrading): Version-specific steps for upgrading an existing Bento install.
- [Concepts](/concepts)
- [Build your first pipeline](/tutorials/pipeline-args)
- [Target a specific issue or PR from a URL](/tutorials/url-targeting)
- [Keep state across runs](/tutorials/pipeline-state)
- [Fire a pipeline on a schedule or on demand](/tutorials/schedule-and-fire)
- [Deploy a box to Railway](/tutorials/deploy-to-railway)
- [Operate a hosted daemon](/tutorials/operate-a-hosted-daemon)
- [Configuration](/configuration)
- [Members](/members)
- [Knowledge base](/knowledge-base/)
- [Method and delivery](/knowledge-base/modes)
- [Config](/knowledge-base/config)
- [MCP](/knowledge-base/mcp)
- [Pipeline configuration reference](/pipelines/config)
- [Filters](/pipelines/filters)
- [Triggers](/triggers/)
- [GitHub trigger](/triggers/github)
- [Linear trigger](/triggers/linear)
- [Webhook trigger](/triggers/webhook)
- [Schedule trigger](/triggers/schedule)
- [Manual trigger](/triggers/manual)
- [Traces](/pipelines/traces)
- [Slack](/integrations/slack)
- [Public access](/public-access)
- [Context engineering](/context-engineering)
- [Best practices](/best-practices)
- [Troubleshooting](/troubleshooting)
- [Architecture](/architecture/vision)
- [Workspaces](/workspaces)
- [Authentication](/authentication)
- [Identity](/identity)
- [Security](/security)
- [References](/references)
- [Changelog](/changelog): Bento release history.
- [CLI reference](/cli/)
- [Setup](/cli/setup)
- [Secrets](/cli/secrets)
- [Lifecycle](/cli/lifecycle)
- [Sandbox image](/cli/image)
- [Sandboxes](/cli/sandbox)
- [Observability](/cli/observability)
- [Diagnostics](/cli/diagnostics)
- [Triggers](/cli/triggers)
- [Workbench](/cli/workbench)
- [Auth](/cli/auth)
- [Knowledge](/cli/knowledge)
- [Evals](/cli/evals)
- [Bento](/index)
- [Runtime wrapper](/architecture/runtime-wrapper)
- [Skill evolve](/architecture/skill-evolve)
-->

# Operate a hosted daemon

This tutorial covers daemon access, job dispatch, logs, and run inspection on a host such as Railway. It assumes the deployment from [Deploy a box to Railway](/tutorials/deploy-to-railway). The examples use Railway's CLI. Daemon operations are the same on other hosts.

## 1. Reach the daemon

The health endpoint is the first check. `curl https://<domain>/health` returns a status and a `bootId`. A new `bootId` means the daemon restarted.

The daemon log is the second check. `railway logs -s daemon` prints a recent window of the log. A line that left the window is gone, so read an older run from disk, as step 4 shows.

A shell is the third check. `railway ssh -s daemon -- sh -c '<command>'` runs a command in the container. The daemon's state is under `/home/agent/.bento`.

The CLI can address the daemon from a workstation. Set `BENTO_DAEMON_URL` to the domain, and put the daemon's auth token in the `token` field of `~/.bento/credentials` on the workstation. Put the same token in the file that the deployment seeds on the daemon. A caller without that token gets `unauthorized`.

```bash
BENTO_DAEMON_URL=https://<domain> bento trigger fire <pipeline>
```

## 2. Start work

Each type of work has one way to start.

| Work | Command or action |
|------|-------------------|
| A scheduled pipeline, now | `bento trigger schedule <pipeline>`. The log shows `schedule [<pipeline>] fired`. |
| Any pipeline, on demand | `bento trigger fire <pipeline>`, with `--branch` or `--pr` when the pipeline needs a target. The log shows `manual [<pipeline>] fired`. |
| A solve of a Linear ticket | Delegate the ticket to the application in the Linear UI, or mention the application in a comment. Both open an agent session. |
| A follow-up on a solve | Reply in the session thread on the ticket. The run resumes with the notes of the thread. |

Replace `<pipeline>` with any configured pipeline. `bento trigger fire` starts every configured pipeline. Add its required arguments and target flags.

A delegate set through the Linear API opens no session. That is why the dispatch pipeline returns the ticket in its result and lets the daemon open the session.

Fire sweeps one at a time. Each sweep selects the oldest ticket without a verdict at the moment it looks, so two sweeps that start together can select the same ticket.

## 3. Follow a run in the log

Each run has an id of the form `run_xxxxxx`. Filter the log on that id to see one run.

```
schedule [linear-triage] fired
pipeline [linear-triage] queued            run_x
invocation workspace ready                 run_x     3.3s
pipeline [linear-triage] executing triager run_x
invocation stream-json                     run_x    37.1s
invocation completed                       run_x    45.9s
```

`workspace ready` means the sandbox is up and holds a clone of the repository. `stream-json` is a progress line with the elapsed time. `completed` or `failed` is the end. A Linear session run also logs `linear: "thought on session ..." published` each time it posts progress. The same text appears in the session thread on the ticket.

## 4. Read what an agent did

The daemon keeps each run on disk, in one directory.

```
/home/agent/.bento/workspaces/<workspace>/runs/<run_id>/
  meta.json                                     event type, trigger id, timestamps, result
  output.md                                     the declared result of the run
  attempts/1/agent.stdout.log                   the transcript of the run
  tasks/<n>-<agent>/attempts/1/agent.stdout.log one transcript per orchestrator task
```

A transcript is Claude Code's stream-json format, with one JSON object per line. Three types of line tell the story.

* `assistant`: the `message.content` array holds `text` items, which are what the agent said, and `tool_use` items, which hold the tool `name` and its `input`.
* `user`: a `tool_result` item holds what a command returned.
* `result`: the last line. It holds `subtype`, `num_turns`, `duration_ms`, the cost under `modelUsage`, and `result`, which is the final message of the agent.

Copy a transcript to a workstation with `cat` over SSH and parse it there. A short script that prints the last `text` and `tool_use` items of a file shows where a run went and where it stopped.

An orchestrated run has tasks. A scout appears as a numbered task with the persona of the scout in its name. The implementation appears as a task with `-solver` in its name. The transcript of the orchestrator is short. It says why it dispatched each task, and it records a retry. An `exit 137` in that transcript means the sandbox ran out of memory.

## 5. Read a failure

A run fails at the daemon, at the sandbox, or in the agent. The log line tells which.

| Log line | Where | Meaning |
|----------|-------|---------|
| `Total memory limit exceeded` | Daytona | The memory of all sandboxes that run at the same time is at the account limit. The run retries at its next tick. Set `queue.remote.concurrency` to the number of sandboxes that fit. |
| `Snapshot <name> is building` | Daytona | The dispatch landed while the snapshot was in a rebuild. Rebuild a snapshot when no pipeline is about to fire. |
| `agent process exited with code 137` | Sandbox | Out of memory in the sandbox. The snapshot's size is fixed when the snapshot is built. |
| `Module "<name>" is not available in the "bun" runtime` | Daemon | A release binary without a module. Update to a release that has it. |
| `unauthorized` from the CLI | Daemon | The caller has no token, or a different one. Use the token the deployment seeds. |

## 6. Deploy without a loss

A deploy restarts the daemon, and a restart stops every run in progress. A session run can take an hour. A push, a `railway up`, a `railway config apply`, and a variable change without `--skip-deploys` each cause a deploy. Before one of them, read the log for a run in progress. Such a run has an `invocation running` line and no `completed` or `failed` line after it. Deploy when none is in progress, or accept the loss. A ticket whose run stopped stays delegated, and a mention in its session thread starts it again.
