---
name: rune
description: >-
  Interact with the Rune AI Agent CLI for sandboxed command execution, file operations,
  and URL fetching with zero-trust security. Use when you need to run commands in an
  isolated environment with network restrictions, filesystem sandboxing, and syscall filtering.
metadata:
  version: "0.1.0"
  repository: "https://github.com/fourdollars/rune"
  license: "MIT"
---

# Rune — Zero-Trust AI Agent

## Overview

Rune is a high-performance, zero-trust AI agent built in Rust. It provides sandboxed tool execution with 5 isolation layers: network namespace, cgroups, seccomp BPF, Landlock filesystem, and DNS allowlist.

Use this skill when you need to:
- Execute commands in a security-isolated environment
- Read/write files with filesystem restrictions
- Fetch URLs with domain-level access control
- Inspect processes safely
- Serve a notes/markdown interface via `rune notes`

## Installation

```bash
# From source
git clone https://github.com/fourdollars/rune.git
cd rune && cargo build --release
cp target/release/rune ~/.local/bin/

# First-time setup
rune init
```

## Usage

### Interactive Mode
```bash
rune
```

Use ↑/↓ to browse previous prompts in interactive mode.

### JSON Mode (for programmatic use)
```bash
echo "your prompt here" | rune --json
# Output: {"answer":"...","tools_used":[...],"steps":N,"tokens":N}
```

### Non-interactive pipe mode
```bash
echo "Get weather for Taoyuan from wttr.in" | rune --json --yes
```

When stdin is piped into Rune, it runs once and exits immediately. It does not enter interactive mode. If confirm mode would require approval, rerun with `--yes`. In pipe mode, the policy defaults to `allowlist` unless explicitly overridden with `--unrestricted`.

### With specific model/provider
```bash
rune --model gpt-4o
rune --provider gemini
```

## Rune Notes (Serve Mode)

Rune can serve a markdown notes interface over HTTP:

```bash
rune notes --bind 0.0.0.0 --port 9527
```

This starts an AI-assisted notes server. When running in serve mode, four additional contextual tools become available to the agent:

| Tool | Description |
|------|-------------|
| `search_chat` | Search through chat/conversation history |
| `list_markdown` | List available markdown notes/documents |
| `read_markdown` | Read a specific markdown note |
| `write_markdown` | Write or update a markdown note |

These tools are **only available in `rune notes` serve mode** — they are not present in standard CLI mode.

### Notes Configuration

Add a `[notes]` section to `~/.rune/rune.toml` to configure serve-mode defaults:

```toml
[notes]
token_budget = 131072      # token budget for notes mode
thinking = "low"           # thinking level for notes mode
```

### Container Usage for Notes Mode

The same container image works for both CLI and notes serve mode:

```bash
docker run --rm -it \
  -v ~/.rune:/home/rune/.rune \
  -p 9527:9527 \
  ghcr.io/fourdollars/rune notes --bind 0.0.0.0 --port 9527
```

## CLI Flags

| Flag | Env Var | Description |
|------|---------|-------------|
| `--provider <name>` | `RUNE_PROVIDER` | LLM provider [github-copilot, gemini, openai, openrouter, ollama, anthropic] |
| `--model <name>` | `RUNE_MODEL` | Model name [e.g. gpt-4o, gemini-2.0-flash, claude-3.5-sonnet] |
| `--api-key <key>` | `RUNE_API_KEY` | API key for the LLM provider |
| `--base-url <url>` | `RUNE_BASE_URL` | Provider base URL (auto-detected for Copilot/Gemini) |
| `--unrestricted` | — | Disable all security policy checks (sandbox, allowlists, confirm prompts) |
| `--yes`, `-y` | — | Auto-approve dangerous tool calls (does NOT bypass policy allowlist) |
| `--mount-home`, `-H [path]` | — | Mount specified folder over real HOME in sandbox with RW access (defaults to CWD if omitted) |
| `--mount-rw`, `-M [path]` | — | Mount path(s) or file(s) as Read-Write in sandbox (defaults to CWD if omitted, repeatable) |
| `--mount-ro`, `-m [path]` | — | Mount path(s) or file(s) as Read-Only in sandbox (defaults to CWD if omitted, repeatable) |
| `--max-steps <n>` | `RUNE_MAX_STEPS` | Maximum agent loop iterations [default: 50, 0 = unlimited] |
| `--token-budget <n>` | `RUNE_TOKEN_BUDGET` | Maximum tokens per run [default: 256k, 0 = unlimited] |
| `--timeout-secs <n>` | `RUNE_TIMEOUT_SECS` | Command timeout in seconds [default: 30, 0 = unlimited] |
| `--json` | — | Output in JSON format (machine-readable, for scripting) |
| `--trace <dir>` | `RUNE_TRACE` | Enable trace recording to specified directory |
| `--compact-keep-last <n>` | `RUNE_COMPACT_KEEP_LAST` | Keep last N messages during compact [default: 6] |
| `--log-level <lvl>` | `RUNE_LOG_LEVEL` | Log level [trace, debug, info, warn, error] |
| `--thinking <level>` | `RUNE_THINKING` | Thinking/reasoning effort level [off\|low\|medium\|high\|xhigh] |
| `--skills-dir <path>` | `RUNE_SKILLS_DIR` | Directory containing skill definitions |
| `--system-prompt <text>` | `RUNE_SYSTEM_PROMPT` | Custom system prompt (replaces default; AGENTS.md still appended) |
| `--skills a,b` | `RUNE_SKILLS` | Preload specific skills (comma-separated names); disables @ref and semantic discovery |

## Configuration

Config file: `~/.rune/rune.toml` (also reads `./.rune/rune.toml` for per-project overrides)

```toml
model = "gpt-4o"
provider = "github-copilot"
api_key = "ghu_..."        # GitHub Copilot PAT (auto-detected)
thinking = "high"          # off|low|medium|high|xhigh
# system_prompt = "You are a helpful assistant."  # optional: override default system prompt (AGENTS.md still appended)

[policy]
mode = "allowlist"         # allowlist | confirm | unrestricted
allowed_commands = ["ls", "cat", "head", "ps", "echo", "date"]
allowed_domains = ["wttr.in", "*.github.com"]
allowed_paths_rw = ["/tmp", "/workspace"]
allowed_paths_ro = ["/bin", "/usr", "/lib"]
allowed_files_ro = ["/home/user/.netrc"]
allowed_files_rw = ["/tmp/data.json"]
denied_paths = ["/root", "/etc/shadow"]

[notes]
token_budget = 131072      # token budget for notes serve mode
thinking = "low"           # thinking level for notes serve mode

[embedding]
enabled = true             # default: false
model = "text-embedding-3-small"
threshold = 0.3            # similarity threshold for skill matching

[[mcp_servers]]
name = "my-server"
command = "npx"
args = ["-y", "@my/mcp-server"]
timeout_secs = 30
required = false
```

## CLI Commands (Interactive Mode)

### Input

| Command | Description |
|---------|-------------|
| `<text>` | Send a prompt to the agent |
| `/multi` | Enter multi-line mode (end with `;;`) |
| `/image <path>` or `/img <path>` | Attach an image for vision models |

### Session

| Command | Description |
|---------|-------------|
| `/info` | Show session status (model, provider, context) |
| `/info context` | Show detailed context usage (tokens, %) |
| `/compact` | Compact (summarize) older conversation context |
| `/reset` | Reset conversation history |
| `/clear` | Clear the screen |

### Configuration

| Command | Description |
|---------|-------------|
| `/config` | Show current configuration |
| `/policy` | Show policy summary |
| `/policy full` | Show full sandbox + policy status |
| `/tools` | List available built-in tools |
| `/skills` | List loaded skills |
| `/skills full` | Show skill details (frontmatter, tools) |
| `/mcps` | MCP servers summary |
| `/mcps full` | MCP servers full details (tools, schema) |
| `/trace` | Show trace output directory |

### Runtime

| Command | Description |
|---------|-------------|
| `/add-dir <path>` | Add directory to read-only paths (saved to config) |
| `/add-rw-dir <path>` | Add directory to read-write paths (saved to config) |

### Other

| Command | Description |
|---------|-------------|
| `/thinking [level]` | Show/set thinking level: off\|low\|medium\|high\|xhigh |
| `/version` | Show version info |
| `/help` | Show help |
| `/exit`, `/quit` | Exit the CLI |

Use ↑/↓ to browse previous prompts in interactive mode.

## Security Model

All tool executions are sandboxed:

| Layer | Protection |
|-------|-----------|
| Network namespace | No outbound connections (unless domain allowed) |
| cgroups v2 | Memory limit (default 512 MB), max processes (default 64) |
| Seccomp BPF | Blocks ptrace, mount, kexec_load, bpf, setns, unshare |
| Landlock | Only allowed paths readable/writable |
| DNS allowlist | Only listed domains resolvable (wildcard support) |

### Command Policy Modes

| Mode | Behavior |
|------|----------|
| `allowlist` | Default. Auto-executes within allowlist, blocks everything else. |
| `confirm` | Interactive prompt mode. Prompts `Execute? [Y/n]` before dangerous tool calls. When a command is blocked (permission denied), Rune uses strace to probe which files were denied and prompts: `Add to allowed_files_ro/rw? [Y/n]`. Approved paths are persisted to config. |
| `unrestricted` | All policy checks skipped — sandbox, allowlists, confirm prompts are disabled. Development only. |

### Automatic Allowlist Expansion (confirm mode)

When a tool call is blocked in `confirm` mode, Rune automatically:

1. Detects the permission error (command not allowed, domain blocked, file access denied)
2. For file access: re-runs the command under `strace` to identify exactly which files triggered EACCES
3. Prompts the user: `Add to allowed_files_ro/rw? [Y/n]` (or `allowed_domains` / `allowed_commands`)
4. On approval, persists the entry to `~/.rune/rune.toml`

## Built-in Tools

Rune provides 10 built-in tools. The first 6 are always available; the last 4 are contextual (serve mode only):

### Standard Tools (always available)

| Tool | Description |
|------|-------------|
| `read_file` | Read file contents (sandboxed, 32KB limit) |
| `write_file` | Write to file (sandboxed, allowed dirs only) |
| `list_dir` | List directory contents |
| `execute_cmd` | Execute shell command (sandboxed) |
| `fetch_url` | Fetch URL content (requires domain in allowlist) |

### Serve-Mode Tools (only available in `rune notes`)

| Tool | Description |
|------|-------------|
| `search_chat` | Search through chat/conversation history |
| `list_markdown` | List available markdown notes/documents |
| `read_markdown` | Read a specific markdown note |
| `write_markdown` | Write or update a markdown note |

## Skills

Rune supports loading skills via `+skill_name` in prompts:

```
ᚱ› Use +sysadmin skill. Show system uptime.
```

Skills are stored in the `skills_dir` (default: `./skills`). Skill files (`SKILL.md`) are discovered recursively up to 3 levels deep within the skills directory.

### Preloading Skills

Use `--skills a,b` to preload specific skills by name at startup. When set, only the specified skills are injected into context; `+ref` dynamic loading and semantic search are disabled.

### Semantic Skill Matching

When the `[embedding]` section is enabled in config, skills can be matched semantically based on the user's prompt — Rune automatically selects relevant skills without explicit `@ref` invocation.

## Container Usage

The same container image works for both CLI and notes serve mode:

```bash
# First-time setup
docker run --rm -it -v ~/.rune:/home/rune/.rune ghcr.io/fourdollars/rune init

# Interactive with skills
docker run --rm -it \
  -v ~/.rune:/home/rune/.rune \
  -v ./skills:/home/rune/skills \
  ghcr.io/fourdollars/rune

# Run against a project directory
docker run --rm -it \
  -v ~/.rune:/home/rune/.rune \
  -v $(pwd):/workspace -w /workspace \
  ghcr.io/fourdollars/rune

# Notes serve mode (expose port 9527)
docker run --rm -it \
  -v ~/.rune:/home/rune/.rune \
  -p 9527:9527 \
  ghcr.io/fourdollars/rune notes --bind 0.0.0.0 --port 9527
```

## Testing

The test suite covers 762 unit tests:

```bash
cargo test
```

## Concourse CI Resource Type

Rune can be used as a Concourse CI resource type. Minimal example:

```yaml
resource_types:
  - name: rune-agent
    type: registry-image
    source:
      repository: ghcr.io/fourdollars/rune
      tag: latest

resources:
  - name: weather
    type: rune-agent
    check_every: 1h
    source:
      api_key: ((copilot-pat))
      model: gpt-4o-mini
      prompt: "Fetch the weather for Taoyuan from wttr.in using curl."
      policy:
        allowed_commands: ["curl"]
        allowed_domains: ["wttr.in"]

jobs:
  - name: weather-check
    plan:
      - get: weather
        trigger: true
      - task: show
        config:
          platform: linux
          image_resource:
            type: registry-image
            source: { repository: ghcr.io/fourdollars/rune, tag: latest }
          inputs: [{name: weather}]
          run:
            path: sh
            args: [-c, "cat weather/response.txt"]
```

## Examples

```bash
# Quick question
echo "What time is it?" | rune --json

# With a skill
echo "Use @sysadmin. Check disk usage." | rune --json --yes

# Fetch weather (requires wttr.in in allowed_domains)
echo "Get weather for Tokyo from wttr.in" | rune --json --yes

# Use specific thinking level
rune --thinking high

# Preload specific skills only
rune --skills jira,launchpad

# Start notes serve mode
rune notes --bind 0.0.0.0 --port 9527
```
