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

# Environments

> Environments decide where AI SRE agents run commands, read and write files, execute Skills, and connect to MCP. This page explains how Sandbox and BYOC Runner relate, then covers cloud Sandbox, self-hosted Runner, permission configuration, session selection, and troubleshooting.

<Info>
  **Private beta**: AI SRE is currently in private beta. Pro or higher accounts can apply for free beta access through the [AI SRE private beta application form](https://c9xudyniiq.feishu.cn/share/base/form/shrcn0ngCfdoygiaHnAT80BfZiH); after approval, Flashduty will add your account to the whitelist. Features and the UI may change during the beta.
</Info>

## Overview

***

An **Environment** is where AI SRE agents actually execute actions. Every tool call the agent makes, including running commands, reading and writing files, running Skills, and connecting to MCP services, happens inside an Environment.

AI SRE provides two types of Environments:

<CardGroup cols={2}>
  <Card title="Cloud Sandbox" icon="cloud" href="/en/ai-sre/sandbox">
    A Flashduty-managed temporary container that works out of the box with no install. When no usable BYOC Runner is online for the current member, sessions automatically fall back to the cloud Sandbox.
  </Card>

  <Card title="BYOC Runner" icon="server" href="#byoc-runner">
    A persistent process deployed on your own machine. It connects to AI SRE over WebSocket and lets the agent execute inside your network boundary.
  </Card>
</CardGroup>

The default selection logic is: **AI SRE uses an online BYOC Runner that the current member can use first; otherwise it uses the cloud Sandbox.** Usable Runners include account-scoped Runners and team-scoped Runners that belong to one of the current member's teams. You can also pin a session to the cloud Sandbox, or to a specific Runner, from the environment selector in the chat input.

<Note>
  The console record is called an **Environment**. The process running on your machine is called a **Runner**. One BYOC Environment maps to one Runner process; cloud Sandbox instances are managed by the system per session.
</Note>

## Cloud sandbox

***

The cloud Sandbox is a temporary execution container managed by Flashduty. It is best for quick starts, demos, and investigations that do not need access to your private network. You do not install a process or maintain a machine.

Use the cloud Sandbox when:

* you have not deployed a Runner yet and want to try AI SRE first;
* the investigation only needs Flashduty data, trusted public services, or public documentation;
* the task is one-off and lightweight, so it does not justify a persistent machine;
* you want to force execution into the managed environment instead of using an existing Runner in the account.

<Warning>
  The cloud Sandbox cannot reach your VPC, dedicated line, private databases, private APIs, or jump hosts. When an investigation needs direct access to those resources, use a [BYOC Runner](#byoc-runner) and place execution on a machine that can reach the target.
</Warning>

For lifecycle, egress boundaries, and session-selection details, see [Sandbox](/en/ai-sre/sandbox).

## BYOC Runner

***

A BYOC (Bring Your Own Compute) Runner is a `flashduty-runner` process that you deploy on your own machine. It keeps a persistent WebSocket connection to AI SRE. When it receives work, it runs commands, reads and writes files, executes Skills, and connects to MCP services that are reachable from that machine.

The value of BYOC Runner comes from where execution happens:

<AccordionGroup>
  <Accordion title="Reach your real environment" icon="server">
    The Runner runs on your machine, so it can access whatever that machine can reach: VPCs, intranets, dedicated lines, Kubernetes clusters, cloud-provider CLIs, databases, or jump hosts.
  </Accordion>

  <Accordion title="Data residency" icon="key">
    Command output, logs, temporary files, and tool results primarily stay inside your network boundary. The agent can read and analyze them, while the execution surface remains constrained by your OS account, filesystem permissions, and network policy.
  </Accordion>

  <Accordion title="Local permissions under your control" icon="shield-check">
    You decide which OS user the Runner runs as, which directories it can access, which CLI credentials it has, and whether to load the [permission configuration](#permission-configuration) on this page to narrow the command surface.
  </Accordion>
</AccordionGroup>

<Tip>
  BYOC Runner egress is governed by your machine and firewall. The per-domain egress allowlist used by the cloud Sandbox does not apply to BYOC, so the self-hosted Environment form does not provide network-access configuration.
</Tip>

### Create and connect

Go to **Environments** in the AI SRE sidebar and create a self-hosted Environment. The form asks for:

| Field | Required | Description                                                                                                                                                                                                 |
| ----- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Name  | No       | Unique within the account, up to 128 characters. If left blank, the first Runner heartbeat auto-fills it with the machine hostname; if that hostname already exists, the Environment ID suffix is appended. |
| Scope | Yes      | Account scope is visible to the whole account. Team scope is visible and editable only by that team. See [Scope](#scope).                                                                                   |
| Tags  | No       | Tags used for task routing, comma-separated, for example `linux, docker, gpu`.                                                                                                                              |

After creation, the **setup guide** opens with this Environment's Token, install command, upgrade command, and uninstall command. The key button on a list row, or the "Setup guide" entry for a pending row, opens the same modal.

### Installation methods

The setup guide automatically fills in the real `TOKEN` and `URL`. The examples below use placeholders; use the command generated by the console.

<Tabs>
  <Tab title="Linux (systemd)">
    Run as root / sudo on the target machine:

    ```bash theme={null}
    curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | \
      sudo TOKEN=<your-token> \
      URL=<connect-url> \
      bash
    ```

    The script installs the binary, creates a systemd service, and writes `/etc/flashduty-runner/env`. The same command works for fresh installs and upgrades; if the latest version is already installed, it skips automatically.
  </Tab>

  <Tab title="Docker">
    Start the container on a machine with Docker installed:

    ```bash theme={null}
    docker run -d \
      --name flashduty-runner \
      -e FLASHDUTY_RUNNER_TOKEN=<your-token> \
      -e FLASHDUTY_RUNNER_URL=<connect-url> \
      -v /var/flashduty/workspace:/workspace \
      registry.flashcat.cloud/public/flashduty-runner:latest
    ```

    Docker access depends on container mounts. If the Runner needs kubeconfig, cloud CLI credentials, or the Docker socket, add the required `-v` / `-e` options before the image name.
  </Tab>

  <Tab title="Manual / macOS">
    Install the binary first, then start the process manually:

    ```bash theme={null}
    curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | sudo bash -s -- --no-service

    FLASHDUTY_RUNNER_TOKEN=<your-token> \
    FLASHDUTY_RUNNER_URL=<connect-url> \
    flashduty-runner run
    ```

    Manual mode does not register a systemd service. Use it for macOS, temporary diagnostics, or your own process manager.
  </Tab>
</Tabs>

<Note>
  Both `connect-url` and `install_script_url` are returned by the backend; the frontend does not hardcode them. Private or air-gapped deployments can replace the install-script distribution source with an internal mirror, but the mirror must serve `install.sh`, `releases/latest`, and `releases/download/<version>/...` release assets.
</Note>

### Linux service user

Linux (systemd) installs run as an auto-created `flashduty` user by default. That user has no sudo access. The systemd unit enables hardening such as `NoNewPrivileges=true`, `ProtectSystem=strict`, and `PrivateTmp=true`, and only grants write access to the Runner state directory.

If the Runner needs to read kubeconfig, cloud CLI credentials, or Docker group access from an existing user, enter a "Linux service user" in the setup guide, or add `RUN_AS` manually:

```bash theme={null}
curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | \
  sudo TOKEN=<your-token> \
  URL=<connect-url> \
  RUN_AS=<existing-user> \
  bash
```

`RUN_AS` is equivalent to the install script's `--run-as <user>` flag. The user must already exist on the system. This makes the systemd service run as that user and relaxes the home-directory protection for that user accordingly.

<Warning>
  Only set `RUN_AS` when the Runner truly needs that user's local credentials or group membership. Otherwise, prefer the default `flashduty` user.
</Warning>

### Token, upgrades, and uninstall

The Token is the only credential a Runner uses to connect to AI SRE. It is written into the install command or environment variables. View it only when installing, upgrading, or debugging the connection, and do not share it. If you suspect a leak, delete the Environment and create a new one.

After the Runner starts, it continuously sends heartbeats. List statuses mean:

| Status  | Meaning                                                                          |
| ------- | -------------------------------------------------------------------------------- |
| Pending | The Environment exists, but the Runner has never connected.                      |
| Online  | The Runner is currently connected, heartbeat is healthy, and it can accept work. |
| Offline | The Runner connected before, but its heartbeat is currently lost.                |

The backend compares Runner versions during heartbeats. When a newer version is available, the Runner receives an upgrade notification and downloads, verifies, and replaces itself. Re-running the install command also upgrades manually. Uninstall commands are in the setup guide: `--uninstall` removes the service while preserving config, and `--purge` removes config and data.

## Permission Configuration

***

By default, Runner uses an allow-all rule:

```yaml theme={null}
permission:
  "*": "allow"
```

When you want to narrow which commands the Runner may execute, create a YAML file on the Runner machine and point the Runner to it with `--permission-config` or `FLASHDUTY_RUNNER_PERMISSION_CONFIG`. Permission configuration is a local Runner file; it is not edited in the console form.

For a Linux (systemd) install, add this to `/etc/flashduty-runner/env`:

```bash theme={null}
FLASHDUTY_RUNNER_PERMISSION_CONFIG=/etc/flashduty-runner/permission.yaml
```

Then restart the service:

```bash theme={null}
sudo systemctl restart flashduty-runner
```

For manual mode, pass the flag directly:

```bash theme={null}
flashduty-runner run \
  --token <your-token> \
  --permission-config /etc/flashduty-runner/permission.yaml
```

A common read-only troubleshooting config looks like this:

```yaml theme={null}
permission:
  "*": "deny"
  "kubectl get *": "allow"
  "kubectl describe *": "allow"
  "kubectl logs *": "allow"
  "ls": "allow"
  "ls *": "allow"
  "cat *": "allow"
  "head *": "allow"
  "tail *": "allow"
  "grep *": "allow"
  "pwd": "allow"
  "whoami": "allow"
  "date": "allow"
```

Rule semantics:

* `permission` is the top-level key; beneath it is a flat `glob pattern: allow|deny` map;
* when no config file is set, Runner allows all commands;
* once a config file is set, a missing file, invalid YAML, or empty `permission` map makes Runner refuse to start, avoiding an accidental fallback to allow-all;
* commands are matched after shell normalization, so spacing differences do not affect matching;
* rules are ordered by specificity: the longer literal prefix before `*` wins, and `*` is always the fallback;
* Runner checks commands inside pipelines, command substitution, process substitution, and arithmetic expansion;
* write redirects are checked as synthetic commands such as `> /path`, `>> /path`, and `&> /path`; read redirects are not blocked by themselves.

<Tip>
  Permission configuration loads at Runner startup. Restart the Runner after editing the YAML file.
</Tip>

## Permission Configuration

***

By default, the Runner allows any command — the same trust model as running the AI model directly in your own shell. If you need to restrict which commands the Runner may execute, point it at a YAML rules file with the `--permission-config` flag or the `FLASHDUTY_RUNNER_PERMISSION_CONFIG` environment variable:

```bash theme={null}
flashduty-runner run --token <your-token> --permission-config /etc/flashduty-runner/permission.yaml

# Or via environment variable
export FLASHDUTY_RUNNER_PERMISSION_CONFIG=/etc/flashduty-runner/permission.yaml
```

The rules file's top-level key is `permission`, mapping **glob patterns to `allow`/`deny`**:

```yaml theme={null}
permission:
  "*": "deny"
  "kubectl get *": "allow"
  "kubectl describe *": "allow"
  "cat *": "allow"
```

* Rules apply everywhere a command can appear — inside pipelines (`cmd1 | cmd2`), `$(...)`/backtick command substitution, process substitution, and write-redirect targets (so `echo x > /etc/passwd` is gated the same way as running a command).
* **The most specific rule wins**: the pattern with the longest literal prefix before its first `*` is tried first; the catch-all `"*"` is always tried last, and the first matching rule applies.
* The file is loaded **once, at Runner startup** — edit the rules and restart the Runner for changes to take effect; there is no hot reload.
* If the flag/env var is set but the file is missing, malformed, or defines no rules under the `permission` key, the Runner **refuses to start** (fails closed) rather than silently allowing every command: pointing the Runner at a permission config is a deliberate request to restrict it, so a broken config should surface as an error, not a silent security gap.
* Leaving the flag/env var unset is the default and is equivalent to allowing all commands.

<AccordionGroup>
  <Accordion title="Strict mode (recommended for shared environments)" icon="lock">
    Deny everything by default, then explicitly allow only what you need:

    ```yaml theme={null}
    permission:
      "*": "deny"
      "kubectl get *": "allow"
      "kubectl describe *": "allow"
      "kubectl logs *": "allow"
      "cat *": "allow"
      "ls *": "allow"
    ```
  </Accordion>

  <Accordion title="Trust mode (for dedicated/isolated environments)" icon="unlock">
    Equivalent to not setting `--permission-config` at all, but lets you carve out explicit exceptions:

    ```yaml theme={null}
    permission:
      "*": "allow"                 # Trust the AI model
      "rm -rf /": "deny"           # Block catastrophic commands if desired
    ```

    Suitable when the Runner runs in an isolated VM/container with limited blast radius, or when fast incident response matters more than restricting permissions.
  </Accordion>

  <Accordion title="Read-only mode (for monitoring only)" icon="eye">
    Allow only read-only commands — suitable when the Runner should observe but never modify state:

    ```yaml theme={null}
    permission:
      "*": "deny"
      "cat *": "allow"
      "head *": "allow"
      "tail *": "allow"
      "ls *": "allow"
      "grep *": "allow"
      "ps *": "allow"
      "df *": "allow"
      "free *": "allow"
    ```
  </Accordion>
</AccordionGroup>

<Note>
  Command permission is currently configured only through this file — there is no console UI for it yet.
</Note>

## Selecting an environment in a session

***

The environment selector at the bottom of the chat input decides where a new session executes:

| Option                      | Meaning                                                                                                                    |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **Auto**                    | The default for new sessions. Uses an online Runner the current member can use; otherwise falls back to the cloud Sandbox. |
| **Cloud Sandbox · Default** | Forces the system-managed cloud Sandbox and ignores self-hosted Runners.                                                   |
| **Self-hosted Environment** | Lists Runners the current member can use. Offline, never-connected, or team-mismatched Runners cannot be selected.         |

<Warning>
  Environment selection is locked once per session: the Environment determined when the session sends its first message is recorded and reused for all later turns. Changing the selector afterward does not change that session. To switch environments, start a new session.
</Warning>

When you open a historical session, the selector shows the Environment that session originally locked to, along with its current status, in read-only mode. If the bound Runner is offline or deleted, the session cannot continue sending messages; reconnect that Runner or start a new session and use the cloud Sandbox.

## Scope

***

Each BYOC Environment has account-level or team-level scope:

| Scope   | Visibility                                                              |
| ------- | ----------------------------------------------------------------------- |
| Account | Visible, selectable, and usable by all members in the account.          |
| Team    | Visible, editable, selectable, and usable only by members of that team. |

Edit permissions follow the unified rule:

1. Account owners and account admins can edit any Environment.
2. Team members can edit team-scoped Environments for their team.
3. There is no "creator extra permission"; you do not need to be the creator if the rules above allow the edit.

<Note>
  The account remains the runtime security boundary, but team scope also participates in Runner selection. When the system auto-selects a Runner, or when a session is pinned to a Runner by ID, it only uses account-scoped Runners or team-scoped Runners that belong to one of the current member's teams. This prevents a member from landing a session on a team Runner they cannot use.
</Note>

## Troubleshooting

***

When troubleshooting Runner issues, start with the **Status** and **Last heartbeat** columns in the Environments list.

<AccordionGroup>
  <Accordion title="Runner shows Offline" icon="bug">
    Offline means the Runner connected before, but AI SRE has not received a heartbeat for about 90 seconds. Check whether the systemd service or process is running, whether the machine is sleeping or offline, and whether outbound traffic to AI SRE is blocked by a firewall. After process and network recovery, the Runner reconnects automatically.
  </Accordion>

  <Accordion title="Runner stays Pending" icon="wrench">
    Pending means this Environment has never connected successfully. Confirm that the install command completed, the Token belongs to this Environment, and the `URL` is reachable from the target machine. If you configured permissions, also confirm that the file exists and the YAML parses.
  </Accordion>

  <Accordion title="Session times out or does not respond" icon="server">
    If a session is pinned to an offline Runner, AI SRE does not silently move it to another environment. Restore that Runner, or start a new session and choose Auto or cloud Sandbox. If the Runner is online but the task fails, the likely issue is network or permissions between the Runner and the target resource.
  </Accordion>
</AccordionGroup>

<Tip>
  Fastest split: **Offline / Pending** points to the Runner-to-AI-SRE connection; **Online but execution fails** points to network, credentials, or permissions between the Runner and the target resource.
</Tip>

## Related pages

***

<CardGroup cols={2}>
  <Card title="Sandbox" icon="cloud" href="/en/ai-sre/sandbox">
    Learn the cloud Sandbox lifecycle, use cases, and egress boundary.
  </Card>

  <Card title="Console" icon="comments" href="/en/ai-sre/sessions">
    View the Environment, team, and resources invoked by the agent that are bound to a session.
  </Card>

  <Card title="MCP (External Tools)" icon="plug" href="/en/ai-sre/mcp">
    MCP connections are established inside the selected environment at agent runtime.
  </Card>

  <Card title="Skills" icon="bug" href="/en/ai-sre/skills">
    Skills execute inside the selected Environment.
  </Card>
</CardGroup>
