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

# TraceCtrl Bootcamp (Openclaw)

> A hands-on workshop — from zero to full security observability for AI agents in 2 hours

<Info>
  **Duration**: 1.5–2 hours | **Level**: Intermediate | **Format**: Hands-on lab
</Info>

<Card title="Using an AI assistant?" icon="robot" href="/agents" horizontal>
  Paste the TraceCtrl agent instructions into Claude Code, Cursor, or Copilot to get contextual help throughout this workshop.
</Card>

***

# Part 1: Introduction to TraceCtrl

## What is TraceCtrl?

TraceCtrl is a **security observability platform for agentic AI**. Our tagline captures the workflow:

1. **See** — Visualize your agent's architecture, topology, and risk posture at a glance
2. **Trace** — Trace every message, tool call, and model request through the full execution lifecycle
3. **Ctrl** — Control and harden your agent's configuration with automated scanning and remediation

## Components

TraceCtrl has five components:

| Component          | What it does                                        | Technology                  |
| ------------------ | --------------------------------------------------- | --------------------------- |
| **CLI**            | `tracectrl scan`, `fix`, `doctor`, `setup`          | Python (pip installable)    |
| **Scanner**        | 33 security/ops/perf/compliance checks for OpenClaw | Python                      |
| **OTel Collector** | Receives spans from agents via OTLP                 | OpenTelemetry Collector     |
| **Engine**         | Processes spans, builds topology, serves API        | FastAPI + ClickHouse        |
| **Dashboard**      | Visualizes scans, traces, topology                  | React + Vite + Cytoscape.js |

## Architecture

<Frame>
  <div style={{ background: '#0D1117', padding: '28px 24px', borderRadius: '8px', fontFamily: 'system-ui, sans-serif' }}>
    <div style={{ display: 'flex', alignItems: 'center', gap: '10px', flexWrap: 'wrap', justifyContent: 'center' }}>
      {/* Data sources — stacked */}

      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
        <div style={{ background: '#0F1C2E', border: '1px solid #4A90D9', borderRadius: '6px', padding: '10px 16px', textAlign: 'center', minWidth: '130px' }}>
          <div style={{ fontSize: '11px', fontWeight: '700', color: '#4A90D9', letterSpacing: '0.06em' }}>AGENT CODE</div>
          <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>OTLP gRPC :4317</div>
        </div>

        <div style={{ background: '#1C0B14', border: '1px solid #FF6B9D', borderRadius: '6px', padding: '10px 16px', textAlign: 'center', minWidth: '130px' }}>
          <div style={{ fontSize: '11px', fontWeight: '700', color: '#FF6B9D', letterSpacing: '0.06em' }}>OPENCLAW</div>
          <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>OTLP HTTP :4318</div>
        </div>
      </div>

      <div style={{ color: '#374151', fontSize: '18px', fontWeight: '300' }}>→</div>

      <div style={{ background: '#091918', border: '1px solid #8BC4BF', borderRadius: '6px', padding: '10px 16px', textAlign: 'center', minWidth: '130px' }}>
        <div style={{ fontSize: '11px', fontWeight: '700', color: '#8BC4BF', letterSpacing: '0.06em' }}>OTEL COLLECTOR</div>
        <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>:4317 / :4318</div>
      </div>

      <div style={{ color: '#374151', fontSize: '18px', fontWeight: '300' }}>→</div>

      <div style={{ background: '#171200', border: '1px solid #FFBB00', borderRadius: '6px', padding: '10px 16px', textAlign: 'center', minWidth: '130px' }}>
        <div style={{ fontSize: '11px', fontWeight: '700', color: '#FFBB00', letterSpacing: '0.06em' }}>CLICKHOUSE</div>
        <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>native :9000</div>
      </div>

      <div style={{ color: '#374151', fontSize: '18px', fontWeight: '300' }}>→</div>

      <div style={{ background: '#0F0A1F', border: '1px solid #A78BFA', borderRadius: '6px', padding: '10px 16px', textAlign: 'center', minWidth: '130px' }}>
        <div style={{ fontSize: '11px', fontWeight: '700', color: '#A78BFA', letterSpacing: '0.06em' }}>ENGINE API</div>
        <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>:8000</div>
      </div>

      <div style={{ color: '#374151', fontSize: '18px', fontWeight: '300' }}>→</div>

      <div style={{ background: '#021A09', border: '1px solid #22C55E', borderRadius: '6px', padding: '10px 16px', textAlign: 'center', minWidth: '130px' }}>
        <div style={{ fontSize: '11px', fontWeight: '700', color: '#22C55E', letterSpacing: '0.06em' }}>DASHBOARD</div>
        <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>:3000</div>
      </div>
    </div>

    <div style={{ display: 'flex', justifyContent: 'center', gap: '12px', marginTop: '20px', paddingTop: '18px', borderTop: '1px solid #1F2937', flexWrap: 'wrap' }}>
      <div style={{ background: '#1A0000', border: '1px solid #FC0404', borderRadius: '6px', padding: '8px 16px', textAlign: 'center' }}>
        <div style={{ fontSize: '11px', fontWeight: '700', color: '#FC0404', letterSpacing: '0.06em' }}>tracectrl scan</div>
        <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>POST findings → Engine</div>
      </div>

      <div style={{ background: '#1A0000', border: '1px solid #FC0404', borderRadius: '6px', padding: '8px 16px', textAlign: 'center' }}>
        <div style={{ fontSize: '11px', fontWeight: '700', color: '#FC0404', letterSpacing: '0.06em' }}>tracectrl fix</div>
        <div style={{ fontSize: '10px', color: '#4B5563', marginTop: '3px' }}>auto-remediates OpenClaw config</div>
      </div>
    </div>
  </div>
</Frame>

**How data flows:**

1. Your agent (or OpenClaw) exports OpenTelemetry spans to the **OTel Collector**
2. The Collector writes spans to **ClickHouse** (column-oriented database optimized for traces)
3. The **Engine** runs a pipeline every 60 seconds — reads new spans, builds agent inventory, discovers topology edges
4. The **Dashboard** queries the Engine API to render trace trees, topology graphs, and scan reports
5. The **CLI Scanner** analyzes OpenClaw config files and uploads findings to the Engine

## What the Scanner Checks

33 checks across four categories:

| Category            | Checks                                           | Examples                                                      |
| ------------------- | ------------------------------------------------ | ------------------------------------------------------------- |
| **Security** (26)   | Network, credentials, tools, sandbox, SSRF, auth | Gateway exposed? Plaintext API keys? Dangerous tools allowed? |
| **Operational** (2) | Model config, fallbacks                          | Primary model set? Fallback configured?                       |
| **Performance** (2) | Sub-agent limits                                 | Timeouts configured? Concurrency bounded?                     |
| **Compliance** (3)  | Retention, isolation, redaction                  | Session data purged? User contexts isolated?                  |

***

# Part 2: Prerequisites

Install all of the following **before** the bootcamp. Each tool has platform-specific instructions and a verification step at the end.

## Required Software

### Git

<Card title="Git Downloads" icon="code-branch" href="https://git-scm.com/downloads">
  Official Git downloads for all platforms.
</Card>

<Tabs>
  <Tab title="macOS">
    ```bash theme={"dark"}
    # Option 1: Homebrew (recommended — no dialog popup)
    brew install git

    # Option 2: Xcode Command Line Tools
    xcode-select --install
    # A system dialog will appear — click Install and wait (~5 min).
    ```
  </Tab>

  <Tab title="Ubuntu / Debian">
    ```bash theme={"dark"}
    sudo apt update && sudo apt install git
    ```
  </Tab>

  <Tab title="Windows (WSL2)">
    ```bash theme={"dark"}
    # Run inside your WSL2 terminal (Ubuntu), not PowerShell
    sudo apt update && sudo apt install git
    ```
  </Tab>

  <Tab title="EC2 (Amazon Linux 2023)">
    ```bash theme={"dark"}
    sudo dnf install git -y
    ```
  </Tab>
</Tabs>

**Verify**

```bash theme={"dark"}
git --version
```

Expected: `git version 2.x.x`

<Warning>
  **macOS**: If you used `xcode-select --install`, the system dialog must fully complete before `git` is available. Do not close it early.

  **Windows**: Run all commands inside your WSL2 (Ubuntu) terminal, not PowerShell or Command Prompt.
</Warning>

***

### Python 3.10+

<Card title="Python Downloads" icon="python" href="https://www.python.org/downloads/">
  Official Python downloads — choose 3.12 or later.
</Card>

<Tabs>
  <Tab title="macOS">
    ```bash theme={"dark"}
    brew install python@3.12

    # If brew warns about PATH, add it:
    echo 'export PATH="$(brew --prefix python@3.12)/bin:$PATH"' >> ~/.zshrc
    source ~/.zshrc
    ```
  </Tab>

  <Tab title="Ubuntu / Debian">
    ```bash theme={"dark"}
    sudo apt update && sudo apt install python3 python3-pip python3-venv
    ```
  </Tab>

  <Tab title="Windows (WSL2)">
    ```bash theme={"dark"}
    # Inside WSL2 terminal
    sudo apt update && sudo apt install python3 python3-pip python3-venv
    ```
  </Tab>

  <Tab title="EC2 (Amazon Linux 2023)">
    ```bash theme={"dark"}
    # AL2023 ships Python 3.9 by default — install 3.12 explicitly:
    sudo dnf install python3.12 python3.12-pip -y

    # Confirm the version:
    python3.12 --version
    ```
  </Tab>
</Tabs>

**Verify**

```bash theme={"dark"}
python3 --version
```

Expected: `Python 3.10.x` or higher

<Warning>
  **`python` vs `python3`**: On Ubuntu and EC2, `python` may point to Python 2 or not exist. Always use `python3` (or `python3.12` on AL2023). All bootcamp scripts use `python3`.

  **pyenv users**: Run `pyenv version` to confirm the active version — pyenv takes precedence over system Python.

  **EC2**: If `python3.12` is not available in dnf, `python3.11` also satisfies the `>= 3.10` requirement.
</Warning>

***

### Node.js 22+

<Card title="Node.js Downloads" icon="node-js" href="https://nodejs.org/en/download">
  Official Node.js downloads — choose the 22 LTS release.
</Card>

<Tabs>
  <Tab title="macOS">
    ```bash theme={"dark"}
    # Option 1: Homebrew
    brew install node

    # Option 2: nvm (recommended if you manage multiple Node versions)
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    source ~/.zshrc
    nvm install 22 && nvm use 22
    ```
  </Tab>

  <Tab title="Ubuntu / Debian">
    ```bash theme={"dark"}
    # Option 1: NodeSource (system-wide install)
    curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
    sudo apt install -y nodejs

    # Option 2: nvm
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    source ~/.bashrc
    nvm install 22 && nvm use 22
    ```
  </Tab>

  <Tab title="Windows (WSL2)">
    ```bash theme={"dark"}
    # Inside WSL2 — use nvm (avoids sudo permission issues)
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    source ~/.bashrc
    nvm install 22 && nvm use 22
    ```
  </Tab>

  <Tab title="EC2 (Amazon Linux 2023)">
    ```bash theme={"dark"}
    # Use nvm — AL2023's dnf Node package is too old
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    source ~/.bashrc
    nvm install 22 && nvm use 22
    ```
  </Tab>
</Tabs>

**Verify**

```bash theme={"dark"}
node -v && npm -v
```

Expected: `v22.x.x` and `10.x.x`

<Warning>
  **nvm not in PATH**: After installing nvm, run `source ~/.bashrc` (Linux) or `source ~/.zshrc` (macOS) before `nvm` is usable. Opening a new terminal also works.

  **Old Node still active**: If `node -v` shows `v14` or `v16` after installing nvm, run `nvm use 22` to switch the active version in that shell.

  **Never use `sudo npm install -g`** when using nvm — nvm installs Node in your home directory and does not need elevated permissions for global packages.
</Warning>

***

### Docker

<Card title="Docker Desktop" icon="docker" href="https://www.docker.com/products/docker-desktop/">
  Docker Desktop for macOS and Windows. Docker Engine for Linux and EC2.
</Card>

<Tabs>
  <Tab title="macOS">
    ```bash theme={"dark"}
    # Option 1: Homebrew Cask
    brew install --cask docker
    # Open Docker.app from /Applications after installing.

    # Option 2: Download directly from docker.com/products/docker-desktop/
    ```

    <Note>Docker Desktop must be **running** (whale icon in menu bar) before any `docker` command works. It needs \~4 GB of RAM.</Note>
  </Tab>

  <Tab title="Ubuntu / Debian">
    ```bash theme={"dark"}
    # Add Docker's official apt repository (more reliable than ubuntu's docker.io package)
    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
      sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
      https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

    # Add your user to the docker group so you don't need sudo
    sudo usermod -aG docker $USER && newgrp docker
    ```
  </Tab>

  <Tab title="Windows (WSL2)">
    ```bash theme={"dark"}
    # Recommended: Install Docker Desktop for Windows, then enable WSL Integration:
    # Docker Desktop → Settings → Resources → WSL Integration → enable your distro
    # Docker commands then work inside WSL2 automatically.

    # Alternative: same official repo install as Ubuntu/Debian, inside WSL2 terminal:
    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
      sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
      https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
    sudo usermod -aG docker $USER && newgrp docker
    ```
  </Tab>

  <Tab title="EC2 (Amazon Linux 2023)">
    ```bash theme={"dark"}
    sudo dnf install docker -y
    sudo systemctl enable --now docker
    sudo usermod -aG docker $USER
    newgrp docker
    ```
  </Tab>
</Tabs>

**Verify**

```bash theme={"dark"}
docker --version && docker compose version
```

Expected: `Docker version 27.x.x` and `Docker Compose version v2.x.x`

<Warning>
  **macOS — daemon not running**: `Cannot connect to the Docker daemon` means Docker Desktop is installed but not started. Open it from Applications and wait for the whale icon.

  **Linux — permission denied on socket**: You added yourself to the `docker` group but haven't started a new shell session. Run `newgrp docker` or log out and back in.

  **WSL2 — Docker Desktop not running on Windows**: Docker commands in WSL2 proxy through Docker Desktop on the host. If Docker Desktop is closed on the Windows side, all `docker` commands inside WSL2 will fail.

  **EC2 — group change not in effect**: `usermod -aG docker` only applies in new sessions. Run `newgrp docker` to avoid re-logging in.
</Warning>

***

### OpenClaw

<Card title="OpenClaw Documentation" icon="terminal" href="https://docs.openclaw.ai/install">
  Full installation guide and platform requirements.
</Card>

<Tabs>
  <Tab title="macOS">
    ```bash theme={"dark"}
    # Option 1: npm (requires Node.js 22+ from the previous step)
    npm install -g openclaw

    # Option 2: Homebrew
    brew install openclaw
    ```
  </Tab>

  <Tab title="Ubuntu / Debian">
    ```bash theme={"dark"}
    # Requires Node.js 22+ installed via nvm (previous step)
    npm install -g openclaw
    ```
  </Tab>

  <Tab title="Windows (WSL2)">
    ```bash theme={"dark"}
    # Inside WSL2 — requires nvm + Node 22 from previous step
    npm install -g openclaw
    ```
  </Tab>

  <Tab title="EC2 (Amazon Linux 2023)">
    ```bash theme={"dark"}
    # Requires nvm + Node 22 from previous step
    npm install -g openclaw
    ```
  </Tab>
</Tabs>

**Verify**

```bash theme={"dark"}
openclaw --version
```

Expected: `openclaw x.x.x`

<Warning>
  **Permission error (EACCES)**: If `npm install -g openclaw` fails with permission denied, you are using a system Node install instead of nvm. Go back to the Node.js step and install via nvm — it does not require sudo for global packages.

  **Command not found after install**: Run `source ~/.bashrc` (or open a new terminal) to update your PATH.

  **Node version**: OpenClaw requires Node.js 22+. Confirm with `node -v` before installing.
</Warning>

***

## Quick Verification

Paste this into your terminal to check all prerequisites at once:

```bash theme={"dark"}
echo "=== Bootcamp Prerequisites Check ==="

git --version >/dev/null 2>&1 && echo "✓ Git: $(git --version)" || echo "✗ Git MISSING"

if python3 -c "import sys; assert sys.version_info >= (3,10)" 2>/dev/null; then
  echo "✓ Python: $(python3 --version) (>= 3.10)"
else
  echo "✗ Python MISSING or < 3.10 (found: $(python3 --version 2>/dev/null || echo 'not found'))"
fi

if node -e "process.exit(parseInt(process.versions.node) >= 22 ? 0 : 1)" 2>/dev/null; then
  echo "✓ Node.js: $(node -v) (>= 22)"
else
  echo "✗ Node.js MISSING or < 22 (found: $(node -v 2>/dev/null || echo 'not found'))"
fi

docker info >/dev/null 2>&1 && echo "✓ Docker: $(docker --version)" || echo "✗ Docker MISSING or daemon not running"
docker compose version >/dev/null 2>&1 && echo "✓ Docker Compose: $(docker compose version)" || echo "✗ Docker Compose v2 MISSING"
openclaw --version >/dev/null 2>&1 && echo "✓ OpenClaw: $(openclaw --version)" || echo "✗ OpenClaw MISSING"

echo "====================================="
```

## API Keys

You'll need an API key for an LLM provider to power your OpenClaw agent. Pick one from the options below — **Gemma via Google AI Studio is free** and works well for the bootcamp.

| Provider                                | Free Tier                              | Sign Up                                                |
| --------------------------------------- | -------------------------------------- | ------------------------------------------------------ |
| **Google AI Studio (Gemma 3 / Gemini)** | **Yes — free API key, no credit card** | [aistudio.google.com](https://aistudio.google.com)     |
| Anthropic (Claude)                      | No — requires billing                  | [console.anthropic.com](https://console.anthropic.com) |
| OpenAI (GPT-4o)                         | No — requires billing                  | [platform.openai.com](https://platform.openai.com)     |
| Groq (Llama, Mixtral)                   | Yes — free tier available              | [console.groq.com](https://console.groq.com)           |

<Note>
  **Recommended for bootcamp**: Get a free Google AI Studio key. Go to [aistudio.google.com](https://aistudio.google.com), sign in with a Google account, and click **Get API key**. No credit card required.
</Note>

***

# Part 3: OpenClaw Setup

## What is OpenClaw?

[OpenClaw](https://docs.openclaw.ai) is a self-hosted AI agent gateway. It connects LLMs to messaging channels (Telegram, WhatsApp, Discord, Slack, WebChat) and manages agent configuration, tool access, session state, and model routing — all from a single JSON config file.

<Card title="OpenClaw Documentation" icon="book" href="https://docs.openclaw.ai">
  Full reference: installation, configuration, plugins, channels, and tools.
</Card>

## Run the Setup Wizard

```bash theme={"dark"}
openclaw
```

The interactive wizard guides you through:

1. **Model provider** — Select **Anthropic** and enter the API key
2. **Channel** — Choose **WebChat** for the bootcamp (no external accounts needed)
3. **Identity** — Name your agent (e.g., "Bootcamp Agent")

<Info>
  **API Key**: Ask the facilitator for the Anthropic API key. It can also be found in the Notion document **"LLM Providers (API Keys)"**.
</Info>

## Understand the Configuration

After setup, your config lives at `~/.openclaw/openclaw.json` (or a custom path if you chose one during the wizard).

**Not sure of your workspace path?** Run this in your normal user shell (not sudo):

```bash theme={"dark"}
openclaw configure
```

The first line of output shows your workspace location. Copy the **absolute path** — for example `/home/yourname/.openclaw` — and use that wherever the docs reference `~/.openclaw`.

<Warning>
  **`~` changes under sudo**: If you ever run a command as a sudoer or with `sudo su`, `~` resolves to `/root/` — not your home directory. So `~/.openclaw` silently becomes `/root/.openclaw`, which doesn't exist. Always use the absolute path (e.g. `/home/yourname/.openclaw/`) when running any TraceCtrl command in an elevated shell. Run `openclaw configure` as your normal user to get it.
</Warning>

Here are the key sections:

```json theme={"dark"}
{
  "agents": {
    "defaults": {
      "model": {
        "primary": "anthropic/claude-sonnet-4-20250514"
      }
    }
  },
  "channels": {
    "webchat": {
      "enabled": true,
      "dmPolicy": "open"
    }
  },
  "gateway": {
    "bind": "loopback",
    "port": 18789
  },
  "tools": {
    "profile": "full"
  }
}
```

| Section                 | What it controls                                                            |
| ----------------------- | --------------------------------------------------------------------------- |
| `agents.defaults.model` | Which LLM to use (primary + fallbacks)                                      |
| `channels`              | Messaging channels and their DM/group policies                              |
| `gateway`               | Network binding, authentication, TLS                                        |
| `tools`                 | Which tools the agent can access (`full`, `coding`, `messaging`, `minimal`) |
| `session`               | Conversation scope (`main`, `per-peer`, `per-channel-peer`) and retention   |
| `logging`               | Log level (`info`, `debug`, `trace`) and sensitive data redaction           |
| `diagnostics`           | OpenTelemetry export for runtime traces                                     |
| `plugins`               | Which plugins are enabled (providers, channels, tools)                      |

<Card title="OpenClaw Configuration Reference" icon="gear" href="https://docs.openclaw.ai/gateway/configuration">
  Full configuration reference with all options.
</Card>

## Enable Diagnostics (OTEL Export)

For TraceCtrl to receive runtime traces from OpenClaw, enable the diagnostics-otel plugin.

Edit `~/.openclaw/openclaw.json` and add these sections:

```json theme={"dark"}
{
  "plugins": {
    "allow": ["diagnostics-otel"]
  },
  "diagnostics": {
    "enabled": true,
    "otel": {
      "enabled": true,
      "endpoint": "http://localhost:4318",
      "protocol": "http/protobuf",
      "serviceName": "openclaw-gateway",
      "traces": true,
      "metrics": false,
      "logs": false,
      "sampleRate": 1.0,
      "flushIntervalMs": 5000
    }
  }
}
```

Restart OpenClaw to apply:

```bash theme={"dark"}
openclaw gateway restart
```

## Test Your Agent

Open the OpenClaw Control UI at [http://localhost:18789](http://localhost:18789) and send a test message via WebChat.

If you set up Telegram, you can message your bot there instead.

<Check>
  **Checkpoint**: You can chat with your agent via WebChat or Telegram. OpenClaw is running with diagnostics enabled.
</Check>

***

# Part 4: TraceCtrl Setup

## Clone and Install

```bash theme={"dark"}
# Clone the repository
git clone https://github.com/tracectrl/tracectrl.git
cd tracectrl

# Create a virtual environment
python3 -m venv .venv
source .venv/bin/activate

# Install the CLI and Scanner
pip install ./scanner
pip install ./sdk/tracectrl

# Verify
tracectrl version
```

<Card title="⭐ Star TraceCtrl on GitHub" icon="star" href="https://github.com/tracectrl/tracectrl" horizontal>
  You just cloned it — if it looks useful, a star helps others find the project. Takes 2 seconds.
</Card>

## Start the Stack

```bash theme={"dark"}
tracectrl setup
```

This launches the interactive setup wizard which guides you through configuration and starts the Docker containers.

<Warning>
  **Docker socket access**: `tracectrl setup` starts Docker containers and needs access to the Docker socket. If you see `permission denied while trying to connect to the Docker daemon socket`, your user is not yet in the `docker` group — go back to the Docker install step and run `newgrp docker` (or log out and back in).

  **Do not run `sudo tracectrl setup`** (or `sudo su` before running it). When you elevate to root, `~` resolves to `/root/` instead of your home directory. Any path that was relative (like `~/.openclaw`) will silently point to the wrong location and the TUI will fail to find your OpenClaw workspace.
</Warning>

Alternatively, you can start containers directly:

```bash theme={"dark"}
docker compose up -d
```

This starts four containers:

| Container          | Port       | Purpose                              |
| ------------------ | ---------- | ------------------------------------ |
| `clickhouse`       | 8123, 9000 | Span storage (ClickHouse database)   |
| `otel-collector`   | 4317, 4318 | Receives OpenTelemetry spans         |
| `tracectrl-engine` | 8000       | Intelligence Engine (API + pipeline) |
| `tracectrl-ui`     | 3000       | Dashboard (React web app)            |

Wait \~30 seconds for all services to start, then verify:

```bash theme={"dark"}
tracectrl doctor
```

Expected output:

```
TraceCtrl Doctor

  Services:
    [OK]   Engine API (http://localhost:8000/api/v1/health)
    [OK]   Dashboard UI (http://localhost:3000)
    [OK]   OTel Collector (http://localhost:4318/v1/traces)

  Docker:
    [OK]   Docker is installed

  All checks passed.
```

## Open the Dashboard

Open [http://localhost:3000](http://localhost:3000) in your browser. You'll see the TraceCtrl dashboard — currently empty. We'll populate it in the next sections.

<Check>
  **Checkpoint**: `tracectrl doctor` shows all green. Dashboard loads at `localhost:3000`.
</Check>

***

# Part 5: Static Scan & Risk Topology

## Run the Scan

First, get your absolute workspace path — run this in your **normal user shell** (not as sudo):

```bash theme={"dark"}
openclaw configure
# The first line shows your workspace path, e.g. /home/yourname/.openclaw
```

Then run the scan using that absolute path:

```bash theme={"dark"}
tracectrl scan /home/yourname/.openclaw/
```

<Warning>
  **Do not use `~` if you are running `tracectrl` as a sudoer or in a `sudo su` session.** In an elevated shell, `~` resolves to `/root/` — not your home directory — so `~/.openclaw` points to a path that doesn't exist and the scan will fail silently.

  Always use the full absolute path (e.g. `/home/yourname/.openclaw/` or `/Users/yourname/.openclaw/`) when running scans from an elevated context. Run `openclaw configure` as your normal user to get the correct path.
</Warning>

The scanner reads your `openclaw.json`, runs **33 checks**, and uploads results to the dashboard.

Terminal output shows a severity summary, findings table, compound risk signals, and topology stats:

<Frame>
  <div style={{ background: '#0D1117', padding: '24px', borderRadius: '8px', fontFamily: 'monospace', fontSize: '13px', color: '#E0E0E0', lineHeight: '1.6' }}>
    <div style={{ marginBottom: '16px' }}>
      <span style={{ color: '#FF4D4D', fontWeight: 700 }}>CRITICAL</span>  5{'    '}
      <span style={{ color: '#FF6B35', fontWeight: 700 }}>HIGH</span>  14{'    '}
      <span style={{ color: '#FFBB00', fontWeight: 700 }}>MEDIUM</span>  14{'    '}
      <span style={{ color: '#22C55E', fontWeight: 700 }}>PASS</span>  0
    </div>

    <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '12px' }}>
      <thead>
        <tr style={{ borderBottom: '1px solid #333' }}>
          <th style={{ textAlign: 'left', padding: '6px 8px', color: '#888' }}>Check ID</th>
          <th style={{ textAlign: 'left', padding: '6px 8px', color: '#888' }}>Severity</th>
          <th style={{ textAlign: 'left', padding: '6px 8px', color: '#888' }}>Finding</th>
        </tr>
      </thead>

      <tbody>
        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-NET-001</td>
          <td style={{ padding: '6px 8px', color: '#FF4D4D', fontWeight: 600 }}>CRITICAL</td>
          <td style={{ padding: '6px 8px' }}>Gateway bind is non-loopback — exposed to network</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-SEC-001</td>
          <td style={{ padding: '6px 8px', color: '#FF4D4D', fontWeight: 600 }}>CRITICAL</td>
          <td style={{ padding: '6px 8px' }}>No auth on network-exposed gateway</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-SEC-002</td>
          <td style={{ padding: '6px 8px', color: '#FF4D4D', fontWeight: 600 }}>CRITICAL</td>
          <td style={{ padding: '6px 8px' }}>Dangerous flags active: browser.ssrfPolicy...</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-TOOL-001</td>
          <td style={{ padding: '6px 8px', color: '#FF4D4D', fontWeight: 600 }}>CRITICAL</td>
          <td style={{ padding: '6px 8px' }}>bash/exec tools enable arbitrary command execution</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-TOOL-002</td>
          <td style={{ padding: '6px 8px', color: '#FF4D4D', fontWeight: 600 }}>CRITICAL</td>
          <td style={{ padding: '6px 8px' }}>Wildcard tool permission — all tools permitted</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-CRED-001</td>
          <td style={{ padding: '6px 8px', color: '#FF6B35', fontWeight: 600 }}>HIGH</td>
          <td style={{ padding: '6px 8px' }}>Plaintext keys found at: models.providers.vllm.apiKey</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-SEC-004</td>
          <td style={{ padding: '6px 8px', color: '#FF6B35', fontWeight: 600 }}>HIGH</td>
          <td style={{ padding: '6px 8px' }}>sandbox.mode is "off" — no tool isolation</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-SEC-005</td>
          <td style={{ padding: '6px 8px', color: '#FF6B35', fontWeight: 600 }}>HIGH</td>
          <td style={{ padding: '6px 8px' }}>Browser SSRF: dangerouslyAllowPrivateNetwork is true</td>
        </tr>

        <tr style={{ borderBottom: '1px solid #1a1a1a' }}>
          <td style={{ padding: '6px 8px', color: '#666' }}>OC-OPS-001</td>
          <td style={{ padding: '6px 8px', color: '#FF6B35', fontWeight: 600 }}>HIGH</td>
          <td style={{ padding: '6px 8px' }}>No primary model configured</td>
        </tr>

        <tr>
          <td style={{ padding: '6px 8px', color: '#555' }} colSpan={3}>... 24 more findings (33 checks total)</td>
        </tr>
      </tbody>
    </table>

    <div style={{ marginTop: '16px', borderTop: '1px solid #333', paddingTop: '12px' }}>
      <div style={{ color: '#888', fontWeight: 600, marginBottom: '4px' }}>Compound Risk Signals</div>
      <div><span style={{ color: '#FF6B35' }}>\[HIGH]</span> COMPOUND-004 Plaintext credentials + public channel = credential exfiltration risk</div>
    </div>

    <div style={{ marginTop: '12px', color: '#888' }}>
      Topology: 9 nodes · 8 edges
    </div>
  </div>
</Frame>

## View in the Dashboard

Open [http://localhost:3000/scan](http://localhost:3000/scan) to see:

1. **Severity cards** — CRITICAL / HIGH / MEDIUM / PASS counts
2. **Architecture risk topology** — your OpenClaw architecture with risk-colored nodes
3. **Category sections** — findings grouped by Security, Operational, Performance, Compliance

### Reading the Topology Graph

| Node Color | Type                                 |
| ---------- | ------------------------------------ |
| **Teal**   | Ingress channels (Telegram, WebChat) |
| **Blue**   | Agents                               |
| **Purple** | LLM Providers (Anthropic, OpenAI)    |
| **Green**  | Tools                                |
| **Orange** | Extensions/Plugins                   |

Nodes with **red borders** have CRITICAL findings. **Orange borders** = HIGH. **Yellow** = MEDIUM.

### Exploring Findings

Expand each category section to see individual findings. Click any finding to see:

* **What was found** — the specific misconfiguration
* **Why it matters** — the security/operational rationale
* **How to fix it** — step-by-step remediation

## Auto-Fix Critical Findings

```bash theme={"dark"}
tracectrl fix ~/.openclaw/ --auto
```

This automatically remediates the most common findings:

| Finding                       | What the fix does                       |
| ----------------------------- | --------------------------------------- |
| `OC-NET-001` Gateway exposed  | Sets `gateway.bind = "loopback"`        |
| `OC-TOOL-001` Dangerous tools | Removes `bash`, `exec` from allow lists |
| `OC-TOOL-002` Wildcard tools  | Removes `*` from tools.allow            |
| `OC-ING-001` Open DM policy   | Sets `dmPolicy = "pairing"`             |
| `OC-PERS-001` Cron enabled    | Sets `cron.enabled = false`             |
| `OC-LOG-002` Debug logging    | Sets `logging.level = "info"`           |

The CLI creates a `.bak` backup, applies fixes, re-scans, and uploads results:

```
  ✓ OC-NET-001: Set gateway.bind = "loopback"
  ✓ OC-TOOL-002: Removed "*" from tools.allow

  Before: 12 findings → After: 6 findings
  Results uploaded to engine.
```

Refresh the dashboard to see the updated report.

## Manual Fixes

Some findings require manual remediation. Here are the most important ones:

### Plaintext API Keys (OC-CRED-001)

**Problem**: API keys stored directly in `openclaw.json`.

**Fix**: Replace with environment variable references:

```json theme={"dark"}
// Before
"apiKey": "sk-ant-abc123..."

// After
"apiKey": "${ANTHROPIC_API_KEY}"
```

Then set the variable in your shell:

```bash theme={"dark"}
export ANTHROPIC_API_KEY="sk-ant-abc123..."
```

Or use `openclaw configure` to reconfigure the provider with an env var.

### Browser SSRF Policy (OC-SEC-002)

**Problem**: `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` is `true` by default — the agent's browser can reach your internal network.

**Fix**: Add to `openclaw.json`:

```json theme={"dark"}
{
  "browser": {
    "ssrfPolicy": {
      "dangerouslyAllowPrivateNetwork": false
    }
  }
}
```

### Sandbox Not Enabled (OC-SEC-004)

**Problem**: Agent tools run directly on the host without isolation.

**Fix**:

```json theme={"dark"}
{
  "agents": {
    "defaults": {
      "sandbox": {
        "mode": "non-main"
      }
    }
  }
}
```

### Session Scope Shared (OC-COMP-002)

**Problem**: All users share the same conversation context.

**Fix**:

```json theme={"dark"}
{
  "session": {
    "dmScope": "per-channel-peer"
  }
}
```

<Card title="OpenClaw Security Guide" icon="shield" href="https://docs.openclaw.ai/gateway/security">
  Full security configuration reference.
</Card>

## Re-scan After Manual Fixes

```bash theme={"dark"}
# Use your absolute workspace path (same one from the scan step above)
tracectrl scan /home/yourname/.openclaw/
```

Refresh the dashboard — your findings should be significantly reduced.

<Check>
  **Checkpoint**: 0 CRITICAL findings. Dashboard shows the updated scan report with risk topology.
</Check>

***

# Part 6: Strands Agent + Runtime Telemetry

## What is Strands?

[AWS Strands](https://strandsagents.com/) is an open-source SDK for building AI agents with tool use. TraceCtrl instruments Strands agents to capture every execution — agent runs, LLM calls, and tool invocations — as OpenTelemetry spans.

## Install the Strands Instrumentation

From the TraceCtrl repo root:

```bash theme={"dark"}
pip install ./sdk/tracectrl-instrumentation-strands
pip install strands-agents strands-agents-tools
```

## Create a Strands Agent

Create a file called `my_agent.py`:

```python theme={"dark"}
import tracectrl
from tracectrl.instrumentation.strands import StrandsInstrumentor

# 1. Configure TraceCtrl — sends spans to the local OTel Collector
tracectrl.configure(service_name="bootcamp-agent")

# 2. Instrument Strands — wraps all agent/LLM/tool calls with span creation
StrandsInstrumentor().instrument()

# 3. Build your agent
from strands import Agent
from strands_tools import calculator

agent = Agent(
    model="us.anthropic.claude-sonnet-4-20250514-v1:0",
    tools=[calculator],
    system_prompt="You are a helpful assistant. Use the calculator tool for math."
)

# 4. Run it
response = agent("What is 42 * 17 + 389?")
print(response)
```

<Info>
  **API Key**: Set your credentials before running:

  ```bash theme={"dark"}
  export AWS_PROFILE=default
  # or
  export ANTHROPIC_API_KEY="sk-ant-..."
  ```

  Ask the facilitator for keys, or check the Notion document **"LLM Providers (API Keys)"**.
</Info>

## Run the Agent

```bash theme={"dark"}
python my_agent.py
```

You should see the agent respond with the calculation result.

## View the Traces

Open [http://localhost:3000/sessions](http://localhost:3000/sessions).

You'll see a new trace for `bootcamp-agent`. Click the row to expand the **trace tree**:

* **Agent span** — the top-level agent execution
* **LLM spans** — each model call with input/output and token counts
* **Tool spans** — calculator tool with arguments and result

Click any span to see its **detail panel** with timing, attributes, and input/output values.

## View the Topology

Open [http://localhost:3000/topology](http://localhost:3000/topology).

The runtime topology graph now shows:

* **Agent node** (bootcamp-agent) → connected to the **LLM provider** (Anthropic/Bedrock)
* **Agent node** → connected to **tool nodes** (calculator)

This graph is built automatically from the trace data — no configuration needed.

## Try More Complex Scenarios

### Multi-tool Agent

```python theme={"dark"}
from strands import Agent
from strands_tools import calculator, http_request

agent = Agent(
    model="us.anthropic.claude-sonnet-4-20250514-v1:0",
    tools=[calculator, http_request],
    system_prompt="You are a research assistant with calculator and web access."
)

response = agent("What is the population of Singapore divided by its area in km²?")
print(response)
```

### Multiple Runs

Run the agent several times to build up session history:

```python theme={"dark"}
questions = [
    "What is 2^10?",
    "Calculate the square root of 144",
    "What is 15% of 2500?",
]

for q in questions:
    print(f"\n> {q}")
    print(agent(q))
```

Each run creates a new session in the dashboard. The topology grows as more tools and models are observed.

## What Gets Captured

| Span Type   | Key Attributes                                                |
| ----------- | ------------------------------------------------------------- |
| **Agent**   | `agent.name`, `openinference.span.kind=AGENT`                 |
| **LLM**     | `llm.model_name`, `input.value`, `output.value`, token counts |
| **Tool**    | `tool.name`, `tool.description`, input/output, risk category  |
| **Session** | `tracectrl.session_id` linking all spans in a conversation    |

TraceCtrl's `TraceCtrlSpanProcessor` automatically enriches every span with:

* **Tool risk category** — one of 8 categories (filesystem, network, code\_execution, data\_store, web\_browsing, communication, system, other)
* **Agent identity** — framework detection and agent naming
* **Session correlation** — links all spans from a single conversation

<Check>
  **Checkpoint**: Sessions page shows traces with agent → LLM → tool spans. Topology page shows your agent connected to its tools and LLM provider.
</Check>

***

# Summary

## What You Built

| Component                                                     | Status                                      |
| ------------------------------------------------------------- | ------------------------------------------- |
| TraceCtrl stack (Engine + Dashboard + Collector + ClickHouse) | Running via Docker                          |
| OpenClaw agent with WebChat                                   | Configured and chatting                     |
| Security scan (33 checks)                                     | Findings visible on dashboard               |
| Auto-remediation                                              | Critical findings fixed                     |
| Manual hardening                                              | SSRF, sandbox, session isolation configured |
| Strands agent with TraceCtrl instrumentation                  | Traces and topology visible                 |

## CLI Reference

```bash theme={"dark"}
tracectrl scan [path]          # Run 33-check security scan
tracectrl fix --auto           # Auto-fix + rescan + upload
tracectrl doctor               # Verify all services are healthy
tracectrl version              # Print version
tracectrl install-plugin       # Install the OpenClaw telemetry plugin
```

## Cleanup & Uninstall

When you're done with the bootcamp — or want a fresh start — work through these steps in order. They remove OpenClaw, its workspace, the TraceCtrl stack, and all local data.

<Warning>
  **These steps are destructive.** `rm -rf` on the workspace deletes your configured agents, chat history, and credentials. `docker compose down -v` deletes the ClickHouse volume — every trace and scan result you collected. Back up anything you want to keep first.
</Warning>

### 1. Stop the TraceCtrl stack

From inside the `tracectrl` repo:

```bash theme={"dark"}
# Stop containers and remove the ClickHouse volume (deletes all traces and scans)
docker compose down -v

# If you only want to stop the containers but keep the data:
# docker compose down
```

### 2. Uninstall OpenClaw

Use the same method you used to install. If you're not sure, run `which openclaw` first — paths under `/opt/homebrew/` or `/usr/local/Cellar/` mean Homebrew; paths under `nvm` or `node_modules` mean npm.

<Tabs>
  <Tab title="macOS">
    ```bash theme={"dark"}
    # If installed via npm
    npm uninstall -g openclaw

    # If installed via Homebrew
    brew uninstall openclaw

    # Not sure which? Run both — the unused one will no-op.
    ```
  </Tab>

  <Tab title="Ubuntu / Debian">
    ```bash theme={"dark"}
    npm uninstall -g openclaw
    ```
  </Tab>

  <Tab title="Windows (WSL2)">
    ```bash theme={"dark"}
    # Run inside your WSL2 shell
    npm uninstall -g openclaw
    ```
  </Tab>

  <Tab title="EC2 (Amazon Linux 2023)">
    ```bash theme={"dark"}
    npm uninstall -g openclaw
    ```
  </Tab>
</Tabs>

**Verify the binary is gone:**

```bash theme={"dark"}
which openclaw || echo "openclaw removed"
```

### 3. Remove the OpenClaw workspace

OpenClaw stores your agent config, chat history, and secrets in its workspace directory — usually `~/.openclaw`. Under `sudo` the home shortcut resolves to `/root/` instead of your user home, so double-check the path before deleting.

```bash theme={"dark"}
rm -rf ~/.openclaw
```

<Note>
  If you installed OpenClaw as root (via `sudo npm install -g ...`), the workspace may live at `/root/.openclaw`. Run `sudo rm -rf /root/.openclaw` in that case.
</Note>

***

## Useful Links

<CardGroup cols={2}>
  <Card title="TraceCtrl GitHub" icon="github" href="https://github.com/tracectrl/tracectrl">
    Source code and issues.
  </Card>

  <Card title="OpenClaw Docs" icon="book" href="https://docs.openclaw.ai">
    Full OpenClaw reference.
  </Card>

  <Card title="OpenTelemetry" icon="signal" href="https://opentelemetry.io">
    The observability standard TraceCtrl is built on.
  </Card>

  <Card title="Strands Agents" icon="aws" href="https://strandsagents.com">
    AWS Strands agent framework.
  </Card>
</CardGroup>
