Bearer tokens and the bind address are deliberately *not* cluster facts —
they are per-replica, set by flag or environment
([server.md](server.md#modes) for the token sources).
## 2. The day-2 loop: edit → plan → apply → restart
Every change follows the same loop, whatever its kind:
```bash
$EDITOR company-brain/people.pg # or any .gq / policy / cluster.yaml edit
omnigraph cluster plan --config ./company-brain
omnigraph cluster apply --config ./company-brain --as andrew
# restart cluster-booted servers to pick it up
```
`--as <actor>` attributes the run: it is recorded in recovery sidecars and
audit entries and threaded into the engine's commit history. Make it a habit
on every apply (it is required for `approve`).
What each change kind does:
| You edit | Plan shows | Apply does |
|---|---|---|
| a `.gq` file or `queries:` entry | `Update query.<g>.<n>` | publishes the new content-addressed blob, updates the ledger |
| a policy file | `Update policy.<n>` | same — new blob, ledger update |
| a policy's `applies_to` | `Update policy.<n> [bindings]` | records the new bindings (the file digest is unchanged; bindings are first-class changes) |
| a `.pg` schema | `Update schema.<g>`**with the real migration steps embedded** | runs the engine's schema apply on the live graph — soft drops only, sidecar-fenced |
| `graphs:` gains an entry | `Create graph.<g>` (+ schema, queries) | initializes the graph at its derived root; dependents apply in the same run |
| `graphs:` loses an entry | `Delete graph.<g>` — **blocked, `approval_required`** | nothing, until approved (see §4) |
Two properties worth internalizing:
- **One apply, ordered correctly.** Creates run first, then schema
migrations, then catalog writes, then (approved) deletes — so a schema
change plus a query that uses the new field converge together in one run.
- **Soft drops only.** A removed schema property disappears from the current
version while prior versions retain the data (reversible until `cleanup`).
Data-loss migrations are not reachable from cluster apply.
Read the plan before applying when the change is non-trivial — for schema
updates it embeds the engine's actual migration plan (`add_property`,
`drop_property [soft]`, `unsupported: …`), so you see data impact before
anything runs.
## 3. Inspect: status, refresh, drift
```bash
omnigraph cluster status --config ./company-brain --json # ledger only, read-only
omnigraph cluster refresh --config ./company-brain # re-observe live graphs
```
`status` never touches the graphs; `refresh` opens them read-only and
records what it finds — manifest versions, live schema digests, catalog blob
integrity. If someone changed a graph behind the control plane's back (a
direct `omnigraph schema apply`, a tampered catalog file), refresh marks the
resource **`drifted`**.
**Drift is converged, not just reported.** After a refresh records drift,
the next `plan` proposes migrating the live graph back to the declared
schema — with the steps visible, including the soft drops of out-of-band
fields — and `apply` executes it like any other change. If the out-of-band
change is the one you want, change the *config* to match instead, and apply
converges the ledger.
## 4. Destructive changes: the approval gate
Removing a graph from `cluster.yaml` never executes silently: