fix(grid-agent): move setup into YAML preferences (#135)
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m46s
CI / required (push) Failing after 54s

This commit is contained in:
2026-08-18 21:34:14 +02:00
parent b56b28043f
commit db25a977b7
27 changed files with 1242 additions and 482 deletions

View File

@@ -13,11 +13,11 @@ grid or LLM:
```sh
cargo build --locked --release -p metacrate-grid-agent
target/release/metacrate-grid-agent --config config/grid-agent.example.json --check-config
target/release/metacrate-grid-agent --config config/grid-agent.example.json --run-once
target/release/metacrate-grid-agent --config config/grid-agent.example.yml --check-config
target/release/metacrate-grid-agent --config config/grid-agent.example.yml --run-once
```
`--check-config` parses files, resolves secret files/environment, validates all
`--check-config` parses YAML and any legacy referenced secret files, validates all
bounds and TLS files, then exits before constructing the grid or LLM clients.
The example is fake/offline mode (`integrated=false`, `split=false`) and all
credential-looking values are placeholders.
@@ -26,16 +26,16 @@ For live foreground or an embedded TUI, build intentionally:
```sh
cargo build --locked --release -p metacrate-grid-agent --features live-grid
target/release/metacrate-grid-agent --config /path/to/grid-agent.json
target/release/metacrate-grid-agent --config /path/to/grid-agent.json --tui
target/release/metacrate-grid-agent --config /path/to/config.yml
target/release/metacrate-grid-agent --config /path/to/config.yml --tui
```
Set `integrated=true` for the foreground and embedded-TUI commands. Set
`split=true` for a headless service, then run the same binary as the TUI client:
```sh
metacrate-grid-agent --config /path/to/grid-agent.json
metacrate-grid-agent --config /path/to/grid-agent.json --tui-client
metacrate-grid-agent --config /path/to/config.yml
metacrate-grid-agent --config /path/to/config.yml --tui-client
```
The TUI client and service must use the same control address and operator token.
@@ -46,12 +46,11 @@ the default file is used only when it already exists:
| Platform | Configuration | Non-secret state |
|---|---|---|
| Linux/Unix | `$XDG_CONFIG_HOME/metacrate/grid-agent.json`, otherwise `$HOME/.config/metacrate/grid-agent.json` | `$XDG_DATA_HOME/metacrate/grid-agent`, otherwise `$HOME/.local/share/metacrate/grid-agent` |
| macOS | `$HOME/Library/Application Support/MetaCrate/grid-agent.json` | `$HOME/Library/Application Support/MetaCrate/grid-agent` |
| Windows | `%APPDATA%\MetaCrate\grid-agent.json` | `%LOCALAPPDATA%\MetaCrate\grid-agent` |
| Linux/Unix | `$XDG_CONFIG_HOME/metacrate/config.yml`, otherwise `$HOME/.config/metacrate/config.yml` | `$XDG_DATA_HOME/metacrate/grid-agent`, otherwise `$HOME/.local/share/metacrate/grid-agent` |
| macOS | `$HOME/Library/Application Support/MetaCrate/config.yml` | `$HOME/Library/Application Support/MetaCrate/grid-agent` |
| Windows | `%APPDATA%\MetaCrate\config.yml` | `%LOCALAPPDATA%\MetaCrate/grid-agent` |
`METACRATE_AGENT_STORAGE_PATH` overrides the state directory. Relative paths in
a JSON document resolve relative to that document where specified; service
Relative paths in a YAML document resolve relative to that document where specified; service
deployments should use absolute paths.
## Endpoint, grid identity, and authority
@@ -59,11 +58,11 @@ deployments should use absolute paths.
`llm.endpoint_url` is the exact OpenAI-compatible chat-completions URL. It is
not a base URL: MetaCrate does not append a path, discover models, select a
provider, or rewrite query parameters. `llm.api_key` is sent as the bearer key
only to that exact origin; redirects are refused. Prefer
`METACRATE_AGENT_LLM_API_KEY_FILE` over inline JSON or direct environment text.
only to that exact origin; redirects are refused. Set `llm.model` when the
endpoint requires a model name. These values live in the private `config.yml`.
Live modes require `grid.login_url`, `grid.avatar_name`, and a password from
`METACRATE_AGENT_GRID_PASSWORD_FILE`. `authorized_avatar_uuids` contains exact
Live modes require `grid.login_url`, `grid.avatar_name`, and `grid.password`.
`authorized_avatar_uuids` contains exact
grid UUIDs, never display names. Text claiming an authorized identity grants no
authority. Public chat can request bounded informational work and safe public
LSL delivery; movement, teleport, building, roaming changes, and administration
@@ -72,19 +71,22 @@ or a narrowly bound scheduler grant as documented in the policy matrix.
## Configuration contract and migration
The JSON root uses `"schema_version": 1`. Omitting it is accepted as legacy
The YAML root uses `schema_version: 1`. Omitting it is accepted as legacy
version 1. Any other value fails before startup with a migration message. There
is no automatic in-place migration: copy the file, update the copy using the
release notes/example, validate the copy, then atomically select it. Unknown
fields fail closed. Installers never overwrite or migrate operator files.
Precedence, lowest to highest, is:
Resolution order is:
1. bounded built-in defaults;
2. JSON configuration;
3. secret files named by JSON;
4. environment-referenced secret files;
5. direct environment values.
2. the platform `config.yml` or explicit `--config` document;
3. legacy secret files referenced by that document.
Process environment variables do not override connection, mode, or authority.
Migrate an existing `.env` once with `metacrate-grid-agent --import-env
/path/to/.env`, inspect it using `--preferences`, then remove the old file under
the operator's retention policy. JSON remains readable only for migration.
Mode, endpoints, credentials, authorization UUIDs, TLS, storage, queue/resource
limits, reconnect policy, behavior, and interaction settings are restart-only.
@@ -120,9 +122,8 @@ Rust's portable metadata API cannot prove arbitrary Windows ACL semantics, and
FAT/network filesystems may not enforce them. Treat an unverifiable filesystem
as unsuitable for unattended secrets.
Rotate one credential at a time: write a new restricted file beside the old
one, atomically replace or repoint the `_FILE` setting, run `--check-config`,
then restart. Revoke the old credential only after readiness. Control observer
Rotate one credential at a time in `--preferences` (or an ACL-restricted copy
of `config.yml`), save, run `--check-config`, then restart. Revoke the old credential only after readiness. Control observer
and operator tokens must differ from each other and from grid/LLM credentials.
## Linux systemd
@@ -130,16 +131,15 @@ and operator tokens must differ from each other and from grid/LLM credentials.
The hardened example is
[`../packaging/metacrate-grid-agent/systemd/metacrate-grid-agent.service`](../packaging/metacrate-grid-agent/systemd/metacrate-grid-agent.service).
Create the unprivileged `metacrate-agent` identity, copy (do not overwrite) an
operator configuration to `/etc/metacrate/grid-agent.json`, create
`/var/lib/metacrate/grid-agent`, and copy the environment-file example. The
environment file contains only secret *paths*. Put the actual secret files in
`/etc/metacrate/secrets`, owned by the service identity with mode `0600`.
operator configuration to `/etc/metacrate/config.yml` and create
`/var/lib/metacrate/grid-agent`. Keep the configuration owned by the service
identity with mode `0600`; do not put credentials in the unit environment.
Install the unit, inspect the sandbox, validate, then start:
```sh
sudo systemd-analyze security packaging/metacrate-grid-agent/systemd/metacrate-grid-agent.service
sudo -u metacrate-agent /usr/local/bin/metacrate-grid-agent --config /etc/metacrate/grid-agent.json --check-config
sudo -u metacrate-agent /usr/local/bin/metacrate-grid-agent --config /etc/metacrate/config.yml --check-config
sudo systemctl daemon-reload
sudo systemctl enable --now metacrate-grid-agent.service
```
@@ -150,19 +150,18 @@ writes only under the state directory.
## Windows service operation
Run the same `.exe`, JSON, control TCP protocol, and shutdown path. Portable
Run the same `.exe`, YAML, control TCP protocol, and shutdown path. Portable
foreground operation in PowerShell is the baseline:
```powershell
& 'C:\Program Files\MetaCrate\metacrate-grid-agent.exe' --config 'C:\ProgramData\MetaCrate\grid-agent.json' --check-config
& 'C:\Program Files\MetaCrate\metacrate-grid-agent.exe' --config 'C:\ProgramData\MetaCrate\grid-agent.json'
& 'C:\Program Files\MetaCrate\metacrate-grid-agent.exe' --config 'C:\ProgramData\MetaCrate\config.yml' --check-config
& 'C:\Program Files\MetaCrate\metacrate-grid-agent.exe' --config 'C:\ProgramData\MetaCrate\config.yml'
```
For unattended use, configure a maintained Windows service wrapper (for
example WinSW) to launch exactly that command as a dedicated low-privilege
account and to translate SCM Stop into Ctrl-C/console control before its timeout.
Keep secrets in separate ACL-restricted files and expose only `_FILE` paths in
the wrapper environment. Configure restart-on-failure, not unconditional rapid
Keep `config.yml` ACL-restricted to the service identity. Configure restart-on-failure, not unconditional rapid
restart. Validate as the service identity before registration. The wrapper must
not capture environment values or command output into a world-readable log.
The supplied PowerShell installer replaces only the executable and never state.