Skip to content
Merged
4 changes: 2 additions & 2 deletions crates/omnigraph-api-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,8 @@ pub struct QueryCatalogEntry {
pub params: Vec<ParamDescriptor>,
}

/// Response for `GET /queries`: the `mcp.expose` subset of a graph's
/// stored-query registry, each with typed parameters.
/// Response for `GET /queries`: every stored query in a graph's
/// registry, each with typed parameters.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct QueriesCatalogOutput {
pub queries: Vec<QueryCatalogEntry>,
Expand Down
6 changes: 4 additions & 2 deletions crates/omnigraph-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,10 @@ pub(crate) enum ClusterCommand {
#[arg(long)]
json: bool,
},
/// Apply the config-only (query/policy) subset of the plan to the local
/// cluster catalog. Graph/schema changes are deferred to a later stage.
/// Converge the cluster to its config: create graphs, apply schema updates
/// (soft drops), write stored-query/policy catalog resources, and execute
/// approved graph deletes, in one ordered run. Serving picks up the applied
/// revision after an `omnigraph-server --cluster` restart.
Apply {
/// Cluster config directory containing cluster.yaml.
#[arg(long, default_value = ".")]
Expand Down
7 changes: 4 additions & 3 deletions crates/omnigraph-server/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1026,18 +1026,19 @@ pub(crate) async fn server_invoke_query(
tag = "queries",
operation_id = "list_queries",
responses(
(status = 200, description = "Stored-query catalog (the mcp.expose subset, with typed params)", body = QueriesCatalogOutput),
(status = 200, description = "Stored-query catalog (every stored query, with typed params)", body = QueriesCatalogOutput),
(status = 401, description = "Unauthorized", body = ErrorOutput),
(status = 403, description = "Forbidden", body = ErrorOutput),
),
security(("bearer_token" = [])),
)]
/// List the graph's exposed stored queries as a typed tool catalog.
///
/// Returns the `mcp.expose == true` subset of the `queries:` registry, each
/// Returns every stored query in the `queries:` registry, each
/// with its MCP tool name, read/mutate flag, description/instruction, and
/// typed parameters — enough for a client to register them as tools without
/// fetching `.gq` source. Read-gated; the catalog is graph-wide (branch
/// fetching `.gq` source. Cluster-served graphs have no per-query expose flag,
/// so the catalog lists them all. Read-gated; the catalog is graph-wide (branch
/// independent — `read` is authorized against `main`). **Not** Cedar-filtered
/// per query yet, so it can list a query whose `invoke_query` the caller
/// lacks (a known gap until per-query authorization lands).
Expand Down
68 changes: 68 additions & 0 deletions docs/dev/docs-issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# User Docs Coherence Ledger

**Last review:** 2026-06-20 (against 0.7.1)
**Status:** all open findings resolved — living ledger for future audits.

This page tracks stale or incoherent user-doc claims found during broad docs
reviews. Findings are validated against current **code/behavior**, not just
cross-doc consistency. Record new findings as they surface; mark them resolved
(with the fixing commit) once the public pages are corrected.

## Resolved — 2026-06-20 docs/user coherence sweep

Every finding from the 2026-06-20 review was validated (all reproduced) and
fixed. Branch `docs/user-coherence-0-7-1`.

| Pri | Finding | Resolution |
|---|---|---|
| P1 | `cluster apply` documented as catalog-only / "Stage 3A" with graph+schema deferred — in both `cli/reference.md` and the shipped CLI help (`cli.rs`) | Rewrote both to describe the real converge behavior (creates graphs, applies schema with soft drops, writes catalog, executes approved deletes in one ordered run); `deferred` now means the genuinely-unsupported case (standalone schema delete). |
| P1 | Stored-query exposure had two contracts: `server.md` documented a per-query `mcp:{expose:false}` knob; cluster docs said all queries are listed | Confirmed in code: cluster registry has no expose field (`QueryConfig`), boot bridge hardcodes `expose: true` (`omnigraph-server` settings), no GQ-level annotation. Removed the knob from `server.md`; documented "every applied query is listed; per-query exposure may become a Cedar-policy decision later". |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 omnigraph-cookbooks best-practices still references removed bearer_token_env chain

omnigraph-cookbooks/docs/best-practices.md:372 describes client-side auth as "token resolves via OMNIGRAPH_TOKEN_<NAME> → the credentials file → the legacy bearer_token_env chain." The bearer_token_env key is one of the removed omnigraph.yaml keys documented as "no longer exist" in this very PR. If the ledger's purpose is to be a living coherence checklist, the cookbook drift is worth tracking here (or opening a follow-up in the cookbooks repo) so the removal of that chain is fully reflected across the docs ecosystem.

Fix in Claude Code

| P1 | The same stale "`mcp.expose == true` subset" contract lived in the **OpenAPI surface**: utoipa annotations (`handlers.rs:1029,1037`, `omnigraph-api-types/src/lib.rs:404`) drove `openapi.json` (Greptile catch on #293) | Updated the three Rust doc-comment/annotation strings to "every stored query" and regenerated `openapi.json` (`OMNIGRAPH_UPDATE_OPENAPI=1`); drift test green. Same-change per AGENTS.md rule 4. |
| P2 | `schema/index.md` claimed `allow_data_loss` honored "uniformly across transports" incl. HTTP `POST /schema/apply` | Scoped to the direct/embedded path; added that cluster-managed graphs evolve via `cluster apply` (soft drops only) and the HTTP route is 409-disabled for cluster serving. |
| P2 | `/load` missing from admission / body-limit / rate-limit / manifest-conflict prose (named `/ingest` only); constants called it "Ingest body limit" | Documented `/load` as canonical everywhere with `/ingest` as the deprecated alias; renamed the constant to "Load (bulk-write) body limit". |
| P2 | CLI "Bearer token resolution" section listed removed `omnigraph.yaml` keys (`graphs.<name>.bearer_token_env`, `auth.env_file`) | Replaced with a pointer to the keyed-credential model (`OMNIGRAPH_TOKEN_<NAME>` → `~/.omnigraph/credentials` → `OMNIGRAPH_BEARER_TOKEN`); no plaintext-in-config path. |
| P2 | Flat route names in a cluster-only server (`POST /query`, `POST /mutate`, `GET /queries`, `POST /queries/{name}`) | Added a one-line note that the per-graph subsections use shorthand under `/graphs/{id}/…`; the endpoint table is already fully qualified. |
| — | `version` printed `omnigraph 0.3.x` | → `0.7.x`. |
| — | `search/indexes.md` used deprecated `ingest --mode merge` | → `load --mode merge`. |
| — | `config.md` `deferred` disposition described as "graph/schema change, later phase" | → "an unsupported change (e.g. standalone schema delete)". |
| — | Stale stage labels (`Stage 3A`, `Stage 2C`, `Stage 1`) in active reference docs | Removed / reworded to plain language; release notes keep history. |

## Open — surfaced 2026-06-20, not yet fixed

- **Stale "config-only apply" / "Stage 3A" comments in `omnigraph-cluster`
source** (internal rustdoc, not user docs — out of scope for the docs sweep
above): `src/types.rs:147` ("Applied changes execute (config-only query/policy
catalog writes)"), `src/types.rs:265` ("Output of config-only cluster apply"),
`src/diff.rs:256`, and `src/tests.rs:1129` ("config-only apply (Stage 3A)").
Apply now also runs graph creates, schema applies, and approved deletes
(`diff.rs:411` `GraphCreate` / `SchemaApply`; the Stage-4 create/schema/delete
executors + tests `apply_creates_graph_and_unblocks_dependents`,
`apply_schema_update_and_dependent_query_in_one_run`,
`apply_blocks_graph_delete_without_approval`). Update these comments in a
cluster-crate change.
- **Cross-repo drift from this sweep** (separate repos — track here, fix in a
follow-up in each repo):
- `omnigraph-ts` SDK ships a stale generated `spec/openapi.json` +
`packages/sdk/src/generated/types.gen.ts` still describing the `GET /queries`
catalog as the `mcp.expose` subset. Regenerate from this repo's
`openapi.json` once the SDK's deferred refresh happens (the SDK is known to
lag the API by design).
- `omnigraph-cookbooks/docs/best-practices.md` (~line 372) still describes
client-side auth as resolving through the removed `bearer_token_env` chain.
Update to the keyed-credential model (`OMNIGRAPH_TOKEN_<NAME>` →
credentials file → `OMNIGRAPH_BEARER_TOKEN`).

## Verification checklist (re-run on the next docs audit)

```bash
rg -n "Stage [0-9]|graph/schema changes are deferred|reserved for later stages" docs/user crates/omnigraph-cli/src/cli.rs
rg -n "POST /query|POST /mutate|GET /queries|POST /queries/\{name\}|POST /schema/apply" docs/user
rg -n "ingest --mode|Ingest body limit|/ingest" docs/user
rg -n "0\.3\.x|bearer_token_env|auth\.env_file" docs/user
rg -n "expose: false|mcp\.expose" docs/user
```

Expected: active user docs have no matches for stale phrases, or the remaining
matches are explicitly marked as deprecated aliases, "no longer exist" notes, or
route shorthand disclaimed relative to `/graphs/{id}`. Release notes are allowed
to preserve historical behavior.
1 change: 1 addition & 0 deletions docs/dev/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ constraints. User-facing behavior should still be documented through
| Error taxonomy and serialization | [errors.md](../user/operations/errors.md) |
| Constants and tunables | [constants.md](../user/reference/constants.md) |
| Transaction model public contract | [transactions.md](../user/branching/transactions.md) |
| User-doc coherence cleanup ledger | [docs-issues.md](docs-issues.md) |

## Project Operations

Expand Down
41 changes: 24 additions & 17 deletions docs/user/cli/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Top-level command families and subcommands. Graph-targeting commands accept a po
| `policy validate \| test \| explain` | Cedar tooling against a cluster's applied policies (`--cluster <dir>`; `--graph <id>` picks a graph's bundle when several apply). `test` takes `--tests <file>`; `explain` takes `--actor`/`--action`/`--branch`/`--target-branch` |
| `queries list \| validate` | inspect a cluster's applied stored-query registry (`--cluster <dir\|uri>`; `--graph <id>` to scope one graph). `list` prints each query's kind (read/mutation), name, typed params, and `[mcp: …]` exposure; a query's `@description`/`@instruction` are shown as indented `description:` / `instruction:` lines when declared (omitted otherwise). `--json` emits `{name, mcp_expose, tool_name, mutation, params}` plus `description`/`instruction` **only when present** — matching the HTTP `GET /queries` catalog ([server.md](../operations/server.md)). `validate` type-checks the registry and exits non-zero on a broken query |
| `profile list \| show [<name>]` | read-only inspection of `~/.omnigraph/config.yaml` profiles. `list` shows each profile's binding (server/cluster/store) + default graph and marks the `$OMNIGRAPH_PROFILE`-active one; JSON keeps `binding` and adds `scope_kind`, `target`, `valid`, and `error`; `show` resolves one profile's scope (endpoint + default graph), defaulting to the active profile, else the flat operator defaults |
| `version` / `-v` | print `omnigraph 0.3.x` |
| `version` / `-v` | print `omnigraph 0.7.x` |

## Command capabilities

Expand Down Expand Up @@ -189,22 +189,26 @@ omnigraph cluster import --config company-brain --json
omnigraph cluster force-unlock <LOCK_ID> --config company-brain --json
```

`--config` is a directory containing `cluster.yaml`; it defaults to `.`.
Stage 3A accepts graphs, schemas, stored queries, and policy bundle file
`--config` is a directory containing `cluster.yaml`; it defaults to `.`. The
config declares graphs, schemas, stored queries, and policy bundle file
references. `cluster plan` reads local JSON state from
`<config-dir>/__cluster/state.json`; a missing file means empty state. Plan,
apply, refresh, and import acquire `__cluster/lock.json` by default and release
it before returning. `cluster apply` executes only stored-query/policy catalog
writes (content-addressed under `__cluster/resources/`) and requires an
existing `state.json`; graph/schema changes are deferred with warnings, and
applied resources do not serve traffic until an `omnigraph-server --cluster
<dir>` restart picks them up. `cluster status` reads state only and reports any existing
lock metadata. `force-unlock` removes a lock only when the supplied id exactly
matches the lock file. `refresh` requires an existing `state.json`; `import`
creates one only when it is missing. Both observe declared graphs read-only at
`<config-dir>/graphs/<graph-id>.omni`. External state backends, graph/schema
apply, automatic stale-lock breaking, `plan --refresh`, pipelines, UI specs,
embeddings, aliases, and bindings are reserved for later stages. See
it before returning. `cluster apply` converges the cluster to its config in one
ordered run: it creates declared graphs, applies schema updates (soft drops
only — see [schema](../schema/index.md)), writes stored-query/policy catalog
resources (content-addressed under `__cluster/resources/`), and executes
approved graph deletes; it requires an existing `state.json` (run `import`
first). Applied state does not serve traffic until an `omnigraph-server
--cluster <dir>` restart picks up the new revision. Standalone schema deletes
remain unsupported and are reported as `deferred` with a warning. `cluster
status` reads state only and reports any existing lock metadata. `force-unlock`
removes a lock only when the supplied id exactly matches the lock file.
`refresh` requires an existing `state.json`; `import` creates one only when it
is missing. Both observe declared graphs read-only at
`<config-dir>/graphs/<graph-id>.omni`. External state backends, automatic
stale-lock breaking, `plan --refresh`, pipelines, UI specs, embeddings,
aliases, and bindings are not yet supported. See
[cluster-config.md](../clusters/config.md).

## Output formats (`query` command, alias: `read`)
Expand All @@ -221,9 +225,12 @@ Precedence (high to low): explicit `--params` / `--params-file`, alias positiona

## Bearer token resolution (CLI)

1. `graphs.<name>.bearer_token_env`
2. `OMNIGRAPH_BEARER_TOKEN` global env
3. `auth.env_file` referenced `.env`
See **Credentials keyed by server name** above: a remote command resolves its
token via `OMNIGRAPH_TOKEN_<NAME>` env → the `[<name>]` section in
`~/.omnigraph/credentials` → the default `OMNIGRAPH_BEARER_TOKEN` env, and a
keyed token is only ever sent to the server it is keyed to. Plaintext tokens are
never stored in operator config; the removed `omnigraph.yaml` keys
(`graphs.<name>.bearer_token_env`, `auth.env_file`) no longer exist.

## Duration parsing (cleanup)

Expand Down
13 changes: 7 additions & 6 deletions docs/user/clusters/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ resource is planned as a create. If present, the file must use this shape:
```

`state_revision`, `resource_statuses`, `approval_records`, `recovery_records`,
and `observations` are optional so older Stage 1 state fixtures keep working.
and `observations` are optional so earlier state fixtures keep working.
Missing `state_revision` is treated as `0`. Resource status values are
`pending`, `planned`, `applying`, `applied`, `drifted`, `blocked`, or `error`.

Expand All @@ -238,9 +238,10 @@ profile in the ledger; pre-profile ledgers are backfilled by an Update with
catalog changes and count toward convergence.

Each plan change carries a `disposition` field — an honest preview of what
`cluster apply` will do with it in this stage: `applied` (executes), `derived`
(a `graph.<id>` composite-digest update that converges automatically once its
query digests land), `deferred` (graph/schema change, later phase), or
`cluster apply` will do with it: `applied` (executes — graph creates, schema
updates, catalog writes, approved deletes), `derived` (a `graph.<id>`
composite-digest update that converges automatically once its query digests
land), `deferred` (an unsupported change, e.g. a standalone schema delete), or
`blocked` (query/policy gated by an unapplied or missing dependency, with the
condition in `reason`).

Expand Down Expand Up @@ -496,5 +497,5 @@ matches the argument. A wrong id, missing lock, invalid lock JSON, or unsupporte
lock version exits non-zero and leaves the file untouched.

This is manual recovery for abandoned local locks. OmniGraph does not perform
PID-liveness checks, TTL expiry, stale-lock breaking, or automatic unlock in
Stage 2C.
PID-liveness checks, TTL expiry, stale-lock breaking, or automatic unlock
today.
Loading