# Collection egress policies

> Give each collection a fail-closed transport boundary that follows its content through inference, publishing, exports, Capsules, and traces.

Section: Guides  
Canonical: https://gno.sh/docs/collection-egress  
Markdown: https://gno.sh/docs/collection-egress.md

Each collection has a fail-closed transport policy (`local_only`, `lan`, `remote`) evaluated at transfer time, not at config time. Derived artifacts inherit the most restrictive source policy: one `local_only` passage makes a Capsule `local_only`. Most real setups are mixed: your open notes are fine on a LAN inference box, the client engagement is not, and the vendor contracts should never reach a remote endpoint under any circumstances.

Egress is distinct from source availability: availability (`sourceAvailability: any|local`) controls whether source content may be materialized during indexing on tested macOS File Provider layouts; egress controls where derived data may travel. See [Source availability](https://gno.sh/docs/configuration#source-availability).

## The three levels

| Policy       | Content may reach                                                                                  |
| ------------ | -------------------------------------------------------------------------------------------------- |
| `local_only` | This machine. Loopback destinations only. No LAN model server, no remote inference, no publishing. |
| `lan`        | This machine plus private-network destinations, such as a GPU box in the same network.             |
| `remote`     | Any configured destination, including a remote inference endpoint or gno.sh publishing.            |

Policies loosen in the order `local_only` → `lan` → `remote`. Existing collections migrated to `local_only`: fail-closed, so an upgrade could never widen a boundary you had not thought about. Migration preserves local retrieval and index data in full.

## Reading and checking a policy

```
gno collection policy get notes
gno collection policy check --action export --destination remote \
  --content-class retrieval_trace --collection notes \
  --authenticated --authorized --explain-egress
```

`get` shows the effective policy, where it came from, and its numeric revision. `check` is a dry run: it answers “would this specific transfer be allowed” without attempting it, which is what you want in CI, in a runbook, or before wiring up a remote model. `--explain-egress` shows the reasoning.

## Relaxing a policy

```
gno collection policy set notes local_only
gno collection policy set notes remote --confirm-relaxation 7
```

Tightening is immediate. Loosening is never inferred: run `get`, look at the current value and its source, then pass that exact numeric `revision` to `--confirm-relaxation`. The revision is durable and single-use. Stale, replayed, cross-collection, and cross-target confirmations all fail closed.

That handshake exists so a relaxation cannot be scripted blind. You have to have read the current state, in this collection, at this revision, to widen it. An agent that automates `policy set` without a fresh `get` simply fails.

Tightening invalidates resident sessions and queued work. Jobs that were in flight under the older, looser policy must be retried and rechecked rather than completing under an assumption that no longer holds.

## Policy follows the content

A policy that applied only to the original file would be trivially escaped: build a Capsule from a restricted collection, then publish the Capsule.

Instead, derived artifacts inherit source policy. Snippets, embeddings, Context Capsules, retrieval traces, adapter records, and exports all carry the policy of what they came from. When evidence mixes several collections, the _most restrictive_ participating policy governs the whole thing. One `local_only` passage in a Capsule makes that Capsule `local_only`.

Each Capsule evidence item exposes its own `egress` value and lineage, and the aggregate lineage must account for every contributing collection, so the boundary is inspectable rather than implicit.

## Three independent gates

Authentication, write authorization, and egress are separate checks, and passing one never satisfies another:

- **Authenticated** means GNO knows who is calling. It does not mean content may travel.
- **Authorized for writes** means mutation tools are enabled. It does not mean content may travel.
- **Egress** is owned by the collection and cannot be overridden by either of the above.

A valid bearer token on a non-loopback daemon still cannot pull `local_only` content off the machine.

## How destinations are classified

Classification is conservative by design and covers loopback, LAN, VPN, proxy, redirect, and remote destinations. Cases that would otherwise be laundering routes fail closed: DNS rebinding, redirects to a different class than the one you checked, mixed evidence, active streams, queued jobs, and stale relaxation confirmations.

Denial reasons are stable and content-free across CLI, REST, MCP, SDK, and Web. An error message never leaks the passage it refused to send, the path it came from, or a credential.

## Audit receipts

```
gno egress-audit list
gno egress-audit show <audit-id>
gno egress-audit status
gno egress-audit delete <audit-id>
gno egress-audit purge
```

Receipts are local, bounded, and redacted: what action was attempted, against what destination class, with what outcome. Never the content. Audit inspection and deletion keep working even when an outbound action was denied, so a refusal is always diagnosable.

## A practical setup

```
# Client work never leaves the laptop
gno collection policy set client-engagement local_only

# Personal notes may use the GPU box on the LAN
gno collection policy get notes # note the revision
gno collection policy set notes lan --confirm-relaxation 3

# Verify before wiring a remote endpoint
gno collection policy check --action remote_inference --destination remote \
  --content-class passage --collection notes --explain-egress
```

One caution worth repeating: egress policy governs transport, not authorization to use content. It stops bytes crossing a boundary. It does not encode who is allowed to read what, and it is not a substitute for keeping confidential material in the right collection in the first place.
