# Grid-agent architecture foundation

The grid agent is a workspace-owned Rust library and small service binary. Its
core depends on Tokio for scheduling and bounded channels. Its `live-grid`
feature owns the existing `libremetaverse` composition root for grid protocol
managers; the default offline graph does not compile live transports. It does
not create a second login, UDP, capabilities, inventory, or world client. It contains no
CLR/.NET loading, sidecar, subprocess adapter, provider SDK, native ABI, or
platform-specific core path.

## Ownership and bounds

`AgentService::start` owns offline task creation, while
`SessionSupervisor::start` owns the live lifecycle task. Configuration is
validated before either allocates channels, calls a backend, or permits network
access. Their handles exclusively own cancellation, join handles, controls, and
observable receivers.

| Resource | Owner | Hard/configured bound | Backpressure/termination |
| --- | --- | --- | --- |
| Grid-event queue | coordinator receives; backend sends | 8,192 / `grid_event_queue` | async send or cancellation |
| Control queue | coordinator receives; handle sends | 256 / `control_queue` | async send; closed after stop |
| Observable queue | handle receives; coordinator/backend send | 8,192 / `observable_queue` | async send or cancellation |
| Backend task | `ServiceHandle.tasks[0]` | exactly one in offline mode | shared cancellation token, joined first |
| Coordinator task | `ServiceHandle.tasks[1]` | exactly one | shared cancellation token, joined second |
| Live session supervisor | `SessionSupervisorHandle` | one owner; one active generation/session | generation cancellation, exact-once logout, bounded join |
| Offline session work | live supervisor | 1,024 hard / `reconnect.offline_work_capacity` | read-only queue; mutations rejected while not ready |
| Body / message | typed boundary owners | 8 MiB / 64 KiB hard ceilings, with lower configured limits | rejected before enqueue |
| Conversation / tool calls | request owner | 256 messages / 64 calls, with lower configured limits | rejected before request |
| Per-avatar conversation memory | `ConversationStore` mutex | 4,096 sessions / 64 MiB hard, lower `conversation` limits | monotonic expiry, deterministic compaction/LRU eviction |
| Interaction ingress / observations | `InteractionHandle` | 8,192 each hard, lower queue configuration | bounded admission; lifecycle uses nonblocking watch state |
| Per-avatar interaction FIFO | `InteractionCoordinator` | 4,096 senders / 64 messages each hard, lower `interaction` limits | fair ready queue, one active request per avatar/channel |
| Interaction inference / outbound | generation tasks and channel rate limiters | 64 concurrent hard; 1,023 bytes per grid part | timeout/cancellation fencing; independent public/IM pacing |
| LLM conversation runtime | avatar-scoped Mentra agent | configured model/tool budgets and 2-minute default wall time | SSE cancellation, compaction, or supersession |
| Autonomous approval review | fresh volatile Mentra runtime | one model request, no tools/history/memory | exact ALLOW/DENY; every error fails closed |
| Policy tools / approvals / schedules | `PolicyGateway` mutex | 64 tools / 4,096 approval records / 1,024 scheduler grants hard | deny before opaque authorization |
| Principal/global resource budget | `PolicyGateway` time window | validated calls, zero L$, upload, inventory, movement, and build ceilings | atomic charge or stable denial |
| Authorized avatars | immutable `AgentConfig` set | 1,024 hard ceiling, lower configured limit | malformed, nil, duplicate, and wildcard input rejected |
| Configuration / secret file | loader | 64 KiB / 16 KiB | regular non-symlink file only |

`BoundedText` and `BoundedVec` make message and collection ceilings part of the
type. Dynamic configuration can lower these absolute ceilings but cannot raise
them. Backend error text is not forwarded; observations publish a fixed bounded
diagnostic.

## State machines and shutdown

The explicit service states are `starting -> running <-> paused -> stopping ->
stopped`, with `failed` reserved for task failure. The offline backend publishes
`BackendReady`, after which the coordinator enters `running`. A shutdown control,
direct handle shutdown, backend failure, closed owner queue, or handle drop
triggers the same cancellation token.

Orderly shutdown first cancels, joins the backend, and then joins the
coordinator. Each join has the validated shutdown timeout. A late task is
aborted and awaited before return. A partially polled shutdown future only
borrows each join handle, so cancelling that future leaves every task in the
handle's fixed ownership slots for a retry or final drop. Dropping the handle
cancels and aborts all remaining owned tasks, so no task is detached. A
feature-enabled live adapter drops its
`LibremetaverseClientOwner` last, invoking the existing client ownership
shutdown.

Live modes use `stopped`, `connecting`, `degraded` (transport connected but not
fully ready), `online`, `backoff`, `authentication-blocked`, `paused`, and
`shutting-down`. Every attempt rotates a generation cancellation token.
Disconnect, pause, logout, force reconnect, or shutdown invalidates it before
cleanup, fencing old events and late LLM/tool results. See
[`grid-agent-session.md`](grid-agent-session.md).

## Trust boundaries

- YAML configuration and legacy migration input are untrusted. Unknown fields,
  oversized files, invalid booleans, conflicting modes, non-HTTP(S) URLs,
  URL fragments, malformed/noncanonical/nil UUIDs, wildcard authorization,
  multiline secrets, and unsafe limits fail before startup.
- `SecretString` and `EndpointUrl` are the only credential-bearing value types.
  Secrets are never serializable or printable. Endpoint diagnostics replace
  user information, passwords, and the complete query.
- Grid input crosses `GridBackend` only through bounded `GridEvent` values.
  The `live-grid` feature supplies `LibremetaverseClientOwner`; live
  implementations must own it and reuse its client and managers.
- World changes cross only `WorldMutator::apply`, which always receives the
  non-forgeable `AuthorizedAction` produced by `PolicyGateway`. Raw calls and
  caller-created decisions are not accepted. This issue supplies no live
  mutation implementation.
- LLM traffic crosses the configured provider base through Mentra's Responses
  SSE runtime. MetaCrate supplies only endpoint, credential, model, permitted
  tools, and run bounds. Proposed calls cross `PolicyToolExecutor` only after
  Mentra schema handling and MetaCrate's independent policy evaluation.
- Conversation context is keyed by immutable avatar UUID and either public chat
  or direct IM. Group channels are not representable. The LLM projection can
  retrieve only one exact key, and recovered/untrusted summaries remain user-role
  prompt data rather than system authority.
- Public-chat and direct-IM input crosses a bounded normalization boundary.
  Authority is derived only from channel plus sender UUID; public chat can never
  acquire operator authority. Output is safety-filtered, UTF-8 split, rate
  limited, and associated with its trigger, session, generation, and delivery
  result.
- Signals and console output belong to the binary. The reusable core relies on
  no terminal, Unix socket, Unix signal, separator, or fixed platform path.

## Dependency diagram

```text
metacrate-grid-agent binary (portable Ctrl-C + config path)
                    |
                    v
offline AgentService -> bounded Tokio channels/tasks -> injected GridBackend
     |                                           |
     v                                           v
typed config/events/policy boundaries    live-grid feature boundary
     |                                           |
     +-----------------> libremetaverse-types    +--> libremetaverse::GridClient

avatar session -> persistent Mentra agent -> Responses SSE / compaction / memory
                       |
                       +-> PolicyToolExecutor -> PolicyGateway
                               |                   |
                               |                   +-> AuthorizedToolBackend
                               +-> one-shot Mentra safety reviewer when required

scene snapshot -> cached headless wgpu color/depth render -> JPEG -> Mentra image
                      `-> deterministic software fallback
```

The package has no build script. Its cross-platform `wgpu` path uses the
platform graphics backend selected by wgpu and requires no window or display;
the software fallback remains available when adapter creation or rendering
fails. The focused
`dependency_policy` test rejects subprocess launch sites, unsafe/native ABI
source, build scripts, and unreviewed direct dependency names in this package.
The precise LLM compatibility and cancellation contract is documented in
[`grid-agent-llm.md`](grid-agent-llm.md).
The origin/capability matrix and opaque mutation boundary are documented in
[`grid-agent-policy.md`](grid-agent-policy.md).
The live lifecycle and generation contract is documented in
[`grid-agent-session.md`](grid-agent-session.md).
The conversation isolation and persistence contract is documented in
[`grid-agent-conversation.md`](grid-agent-conversation.md).
The public-chat/IM admission, fairness, authorization, egress, and lifecycle
contract is documented in
[`grid-agent-interaction.md`](grid-agent-interaction.md).
