# Configuration Everything you are meant to edit is in [`../configs/`](../configs/). Nothing else in the tree needs changing to run this. ``` configs/ owuitools.env the stack's settings and its one required token (gitignored) owuitools.env.example the template to copy it from (tracked) tools.toml which tools the assistant can see vms.toml the machines the VM sub-agent can be given vmd.env the VM daemon's settings, installed to /etc/owuivm/ host.env.example overrides for vm/host/install.sh (optional) assistant/ system-prompt.md what you paste into Open WebUI agent/ params.env the sub-agent's model, sampling and session bounds tools.toml every one of the sub-agent's tool definitions prompt.md its system prompt, shared by both machines prompt.ubuntu.md the Ubuntu half prompt.windows.md the Windows half prompt.screen.md the part about looking at the screen services/ gateway.nginx.conf the ingress proxy egress.squid.conf the one route to the internet searxng.settings.yml the search back end vmgw.nginx.conf.template the sub-agent's one path to Ollama ``` --- ## `owuitools.env` Copy the example and fill it in: ```sh cp configs/owuitools.env.example configs/owuitools.env sed -i "s|^OWUITOOLS_AUTH_TOKEN=.*|OWUITOOLS_AUTH_TOKEN=$(openssl rand -hex 32)|" \ configs/owuitools.env ``` `.env` in the project root is a symlink to it, because that is the file `docker compose` reads. Both are gitignored. **`OWUITOOLS_AUTH_TOKEN` is the only required setting.** The same value goes in Open WebUI's tool connection, and in the `vm_agent_progress` filter's valve if you use it. | Setting | Default | What it does | |---|---|---| | `OWUITOOLS_AUTH_TOKEN` | — | **Required.** The bearer token Open WebUI presents. | | `OWUITOOLS_CONTACT` | `owuitools@localhost` | Goes in the User-Agent. Wikimedia **403s** without a real one — see [setup/contact.md](setup/contact.md). | | `OWUITOOLS_MAX_RESPONSE_CHARS` | `12000` | Ceiling on any one tool response. Open WebUI does not truncate tool results, so this is what stands between one greedy fetch and a blown context. | | `OWUITOOLS_PROBE_RATE_PER_HOUR` | `30` | Per-user hourly budget for the four tools that touch a named host. `0` disables the limiter. | | `OWUITOOLS_LOG_LEVEL` | `INFO` | | | `OWUITOOLS_VM_WAIT_SECONDS` | `7000` | How long one `vm_agent` call may block. One of [three clocks](advanced-params.md#the-three-clocks). | | `OWUITOOLS_GITHUB_TOKEN` | — | Optional. [setup/github-token.md](setup/github-token.md) | | `OWUITOOLS_STACKEXCHANGE_KEY` | — | Optional. [setup/stackexchange.md](setup/stackexchange.md) | | `OWUITOOLS_NVD_KEY` | — | Optional. [setup/nvd.md](setup/nvd.md) | --- ## `tools.toml` — the on/off switch One line per tool. `false` **removes** it: the operation leaves the OpenAPI spec, so the model is never told it exists, and the endpoint stops answering. That matters because the 22 schemas cost about **9,700 tokens on every turn of every conversation**, whether or not a tool is used. A tool you will not use is a standing tax. ```toml [tools] web_search = true pcb_calc = false # not doing electronics ``` Tools needing setup carry a comment pointing at the page for it. After editing: ```sh docker compose restart api ``` …and then **re-save the tool connection in Open WebUI**, which caches the spec it fetched. Both steps are needed. A tool the file does not mention stays **on**, so an old config never silently removes a new tool. A name that does not exist is reported in the log and ignored. --- ## `vms.toml` — the machines ```toml [[machine]] id = "ubuntu" name = "Ubuntu" iso = "ubuntu*.iso" ``` **`id` is identity, not a label.** It names the base disk, the systemd unit instance, the saved-machine directory, and the value the assistant passes as `os` — and it appears in regex allowlists inside the privileged launch scripts, which is what lets those scripts refuse a path. Changing it does not rename a machine; it describes one that does not exist. **`name` is yours.** Change it here, or press **Rename** in the maintenance app. Renames made in the app are written to `/var/lib/owuivm/registry/vm-names.toml` and merged over the top, so the registry keeps its comments. `shell`, `project` and `example` are prompt text, substituted into the sub-agent's tool descriptions so one set of definitions describes both machines. --- ## `agent/` — the second model `params.env` holds its model, sampling and session bounds; see [advanced-params.md](advanced-params.md). `tools.toml` holds **every one of its tool definitions** — name, description and parameters. The descriptions are prompt text the model reads, and rewording one is often the most effective change available. It is bind-mounted, so: ```sh docker compose restart vmagent ``` is enough — no rebuild. What that file **cannot** do is give the agent a new capability. Dispatch lives in code, and a tool named there with nothing behind it is refused at startup, naming the file. There is an allowlist (`DISPATCHABLE` in `vmagent/app/tools.py`) precisely so that a config file cannot widen what the agent can reach. The prompts beside it are loaded the same way. If `prompt.md` is missing the agent **refuses to start**: one that runs with no instructions still calls tools and still reports success, which is the worst failure available. --- ## `services/` — the supporting containers Bind-mounted read-only into their containers. Restart the one you changed. | File | Container | Watch out for | |---|---|---| | `gateway.nginx.conf` | `owuitools-gw` | `/tools/vm_agent` has its own 7200s timeout; everything else keeps 240s | | `egress.squid.conf` | `owuitools-egress` | The private-range denies are a security control, not tuning | | `searxng.settings.yml` | `owuitools-searxng` | Set your own `secret_key`. The engine list is a measurement from one IP — see [setup/searxng.md](setup/searxng.md) | | `vmgw.nginx.conf.template` | `owuitools-vmgw` | The `location =` exact matches are load-bearing. Ollama is unauthenticated and serves `DELETE /api/delete` | **Restarting `netguard` or `vmguard` strands the containers that share their network namespace.** They keep running, keep passing their own healthchecks, and have no route to anything. Recreate the dependents too: ```sh docker compose up -d --force-recreate netguard api searxng docker compose up -d --force-recreate vmguard vmagent ``` --- ## Host-side settings The VM sub-agent's daemon reads `/etc/owuivm/vmd.env`, created from [`../configs/vmd.env`](../configs/vmd.env) by `vm/host/install.sh` — **only if it is not already there**, because the live copy holds the Gitea token. Edit the live file to change the running daemon. `configs/host.env` (optional, gitignored) overrides what `install.sh` works out for itself. Copy `host.env.example` if any of its guesses are wrong for your machine. Nothing in it is required — the installer derives the operator from `sudo`, the VM's memory and CPU from `nproc` and installed RAM, and defaults the pool to `/Pool`. What you are most likely to need is: | Setting | Why | |---|---| | `OWUIVM_POOL_ROOT` | Your ZFS pool's mountpoint. `/Pool` is this project's default and nothing more — `zfs list` shows yours. The installer creates `/vmrun` and `/vmprojects` if they are missing. | | `OWUIVM_GITEA_ALLOW` | The daemon runs `IPAddressDeny=any`. Gitea is not on the allowlist by default, because a fresh install has none. | | `OWUIVM_ALLOWED_CPUS` | Pin the VM to particular cores. Empty — the default — means no pinning. | These are read at **install time** and written into the units and scripts, so re-run `sudo ./vm/host/install.sh` after changing them. The installer refuses to install a file that still has an unrendered placeholder in it, so a value added to a template and not to the installer fails loudly rather than producing a unit that will not start.