§ 05 · Read

Operator quickstart

Bring Conversational Factory up on a workstation in about ten minutes — and ask your plant a question.

View as .md

Bring Conversational Factory up on a workstation in about ten minutes — and ask your plant a question.

This is the operator runbook. You don’t need to know Rust, Python, or how the internals work. You’ll use Docker, a web browser, and Claude Desktop.

If you’re a developer who wants the chain running from source, see the dev quickstart instead.

This runbook drives one reference implementation — illustrative, not definitive. The canonical product is the role specification (read-only, one-way, outside copy); see the system architecture. The commands below are real for this reference build.

What you’ll have at the end

  • A local data source running in Docker, seeded from a sample capture (no real plant needed).
  • A read-only gateway exposing a small set of tools to any AI client that speaks MCP.
  • Claude Desktop connected to the gateway. You can ask “what’s on the network?” and get answers grounded in the data — with no write path to anything.
  • An audit log capturing every tool call, so you can always trace why the AI said what it said.

Before you start

You need:

  • A workstation. macOS or Linux. 8 GB RAM, ~20 GB free disk.
  • Docker. On macOS, Colima is the easiest path:
    brew install colima docker docker-compose
    colima start
    On Linux, install Docker Engine via your distro’s package manager.
  • Git to clone the repo.
  • Claude Desktop installed (download). Optional but expected for the conversational layer.

You do not need:

  • Rust, Python, or any language toolchain installed locally.
  • Network access during bring-up — once the images are pulled, the entire stack runs offline on your laptop.
  • A real plant network. The data source can replay a sample capture for testing.

Step 1 — Get the code

git clone https://github.com/eris-ot/conversational-factory.git
cd conversational-factory

If you don’t have access to the repo, contact river@riverman.io.

Step 2 — One-time bootstrap

Run the bootstrap. It handles everything that has to happen exactly once: secrets, database schema, the default organization, and the API key the gateway uses.

make first-run

Expected output (abridged):

==> Step 1/6 — Ensuring secrets are set
  ok   appended DB_PASSWORD to services/witness/.env
==> Step 2/6 — Bringing up the data stack (db, redis, app, workers)
  ok   db reachable
==> Step 3/6 — Running database migrations (alembic upgrade head)
  ok   migrations applied
==> Step 4/6 — Starting the app
  ok   app healthy
==> Step 5/6 — Provisioning default org + API key
  ok   provisioned new API key
==> Step 6/6 — Writing WITNESS_API_KEY to ./.env
  ok   wrote WITNESS_API_KEY to ./.env

First-run complete.

Re-running make first-run is safe — it’s idempotent and skips work that’s already done.

Heads up — first run is slow. Building the images takes about 10 minutes the first time. After that, restarts are seconds.

Step 3 — Bring up the chain

make up

This starts everything — the data source, the query plane, the gateway, and supporting services — as Docker containers. Verify with:

make ps

You should see something like:

NAME                    STATUS         PORTS
eriswitness-dev-app     Up (healthy)   127.0.0.1:5001->5001/tcp
eriswitness-dev-db      Up (healthy)   5432/tcp
eriswitness-dev-redis   Up (healthy)   6379/tcp
cf-query-plane          Up             127.0.0.1:8090->8090/tcp
cf-gateway              Up             127.0.0.1:8091->8091/tcp
... (worker containers)

If anything is restarting or unhealthy, see Troubleshooting.

Step 4 — Open the console

Open http://127.0.0.1:5001 in your browser.

Log in:

  • Username: admin
  • Password: admin-dev-password (set in services/witness/.env — change it for any non-dev use)

After login you land on the asset map. The data source can be populated two ways: by capturing live network traffic, or by replaying a sample capture. The fastest demo path is replay.

Step 5 — Load a sample capture

The repo ships realistic ICS/OT captures under the bundled presets directory (services/witness/presets/). In the console:

  1. Click New Scan in the top-right of the assets page.
  2. Click Upload PCAP.
  3. Browse to a preset capture under services/witness/presets/.
  4. Click Start scan.

Wait ~30 seconds for the scan to complete, then click back to Assets — you’ll see entries annotated with vendor, role, and Purdue level.

Confirm the gateway sees them too:

open http://127.0.0.1:8091/tools

You should get a JSON response listing the tools the gateway exposes. That’s the read-only MCP surface Claude Desktop will use.

Step 6 — Connect Claude Desktop

Open the Claude Desktop config file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

If the file doesn’t exist, create it. Add (or merge into) this block:

{
  "mcpServers": {
    "factory": {
      "command": "curl",
      "args": [
        "-N", "-s",
        "-H", "content-type: application/json",
        "--data-binary", "@-",
        "http://127.0.0.1:8091/mcp"
      ]
    }
  }
}

Note. This wires Claude Desktop to the gateway over HTTP. If you’d rather run the gateway as a stdio subprocess (fewer moving parts, but requires building from source), see the dev quickstart Step 5.

Restart Claude Desktop. In a new conversation, click the tools icon — you should see factory listed with its tools available.

Step 7 — Ask your plant a question

In Claude Desktop:

“Use the factory MCP server. What objects are visible right now? For each one, get its current state.”

Claude will call list_objects first, then get_current_state on each result, then compose an answer like:

“I can see four objects on the network. The first is an Allen-Bradley PLC at 10.5.0.10 (role identified as PLC), currently active. The second is a Siemens HMI at…”

Try other questions:

  • “Show me history for the Allen-Bradley PLC over the last hour.”
  • “What relationships exist between these assets?”
  • “Are any objects showing degraded quality right now?”

Every answer is a read. There is no tool that writes — nothing Claude does, or anything that compromised Claude could do, can change a setpoint, a register, or a configuration.

Each tool call writes to the audit log. Inspect it any time:

docker exec cf-gateway cat /var/log/cf/gateway-audit.jsonl | tail -5

Each line records: the natural-language question (when provided), the exact tool dispatched, the parameters, the downstream call (path, latency, status), and the result returned to the AI. “Why did the AI tell me X?” is always answerable.

Daily lifecycle

make up         # bring up after a reboot
make down       # shut down (preserves data)
make logs       # tail logs from all services
make ps         # status check

To start fresh (wipe all data, keep code):

make down
docker volume rm conversational-factory_eriswitness-dev-data \
                conversational-factory_eriswitness-dev-pgdata \
                conversational-factory_cf-audit
make first-run
make up

Troubleshooting

make first-run fails at “could not start db+redis. Is Docker running?” On macOS, run colima start. On Linux, sudo systemctl start docker. Then re-run.

make up fails with WITNESS_API_KEY: variable required. You haven’t run make first-run yet, or the .env file at the repo root is missing. Re-run make first-run.

Console loads but the assets list is empty after upload. Check the scan finished: in the console, click Scans to see status. If it failed, the log tab shows why. The most common cause is uploading a non-PCAP file.

Claude Desktop shows the factory server but tools fail with “connection refused.” The gateway isn’t running. Verify with make pscf-gateway should be up. If not, docker compose up -d gateway and check docker logs cf-gateway.

Port already in use. Something else is bound to 5001, 8090, or 8091. Stop the conflicting process, or change the host-side port in the compose file.

What’s next