Skip to content

Latest commit

 

History

History
253 lines (214 loc) · 13.3 KB

0052-managed-control-plane-cli.md

File metadata and controls

253 lines (214 loc) · 13.3 KB
rfc 0052
title Managed control-plane CLI
track maintainer
status accepted
implementation complete
authors
andrew
created 2026-09-05
updated 2026-10-20
discussion #629
supersedes
superseded_by
blocked_on

RFC 0052: Managed control-plane CLI

RFC 0059 disposition: RFC 0059 replaces managed mode flags and folder routing with managed account/cluster targets. Historical: Summary and User behavior's routing forms, Design's folder context, organization-selection inputs and use, and Compatibility's selector promises. Current: exact saved-plan execution, service-owned authorization and leases, captured principal identity, operation keys/outcomes, bounded observation and refusal without fallback. The accepted replacement design remains subject to RFC 0059's implementation cutover and qualification.

The identity and applied-policy extension replaces this RFC's original authentication contract with provider-native login and automatic identity acquisition. The exact-plan execution contract remains applicable; the RFC 0059 disposition above governs the later routing change.

Summary

The explicit cluster <command> --managed mode addresses the managed Intent API. A folder's .omnigraph/context selects the service and cluster only after that mode is chosen. Without --managed, cluster commands never inspect it. Managed authentication establishes identity, and current permissions authorize execution of an exact saved plan. There is no separate managed approval workflow. Engine behavior and storage formats are unchanged.

Motivation

The managed executor, operator, and Intent API can plan and apply a bound external repository, but users currently need raw HTTP requests. The CLI has direct cluster commands and per-server token login, neither of which can substitute for managed identity, durable runs, leases, and signed offers. Routing and credential ownership are public contracts, so this is an RFC rather than a local command refactor.

User and operational behavior

omnigraph login --api https://control.example
omnigraph use CLUSTER_ID --api https://control.example
omnigraph cluster plan --managed --config . --json
omnigraph cluster apply --managed --config . --plan PLAN_RUN_ID --json
omnigraph cluster status --managed --config . --json
omnigraph cluster history --managed --config . --json
omnigraph cluster cancel --managed RUN_ID --config . --json
omnigraph logout --api https://control.example

Users commit and push external config with git before planning. plan uses the bound head unless --rev selects a revision the API accepts. A saved plan retains the service's change lease. Apply requires that exact --plan; it does not commit files, upload a bundle, silently replan, or ask for another approval. Current permissions, binding, digests, and lease are checked by the API and execution authority is independently checked by the executor.

The mode flag selects authority before context discovery. cluster without --managed uses self-hosted configuration or its explicit server/root target; with --managed it uses only the service API. Managed mode rejects --direct, --server, --cluster, --store, --profile, --graph, and --as before context, credentials, HTTP, or storage access. Malformed context, unknown context version, provider/API errors and permission refusals fail closed. No managed failure may invoke Core or consult graph-root credentials.

Service-only create, push, delete, undo-delete, token, operation, history, and cancel require --managed. Local validate, observe, force-unlock, and upgrade-ledger reject it. Shared plan, apply, and status validate arguments against the selected mode before dispatch. Managed plan uses --rev, apply requires --plan, and status accepts an optional positional run ID. Self-hosted deployment uses local configuration or exact --deployment-id; served status alone permits deployment --wait. No argument or folder context infers a mode. The flag may precede or follow the subcommand.

--no-wait returns the accepted run envelope. Otherwise the CLI polls every two seconds for up to 300 seconds; --timeout selects 1–3,600 seconds. Timeout ends the local wait, not the run. A stable --idempotency-key permits explicit plan/apply replay; an omitted key is generated once and printed to stderr. Retries within an invocation reuse that key. Cancellation and abandonment retry by the same run id, without a separate key. Run JSON is the API's envelope, with its requested/effective/observed and service provenance labels intact. Progress is stderr. Managed exit codes are 0 success, 1 failed/transport, 2 refused/blocked, 3 partially converged, 4 recovery required, 5 stalled or wait timeout, and 6 cancelled. Direct exit codes do not change.

cancel uses the existing pending-run cancellation API. For a converged unused plan it calls :abandon, which retains the converged result, marks it unusable, and releases only its lease. Apply reservation and abandonment are serialized by the API. It never cancels accepted effects through lease expiry.

Design

The versioned, secret-free context is at most 16 KiB and lives only in the selected config directory; parent directory search is not performed. Context must be a regular file and neither it nor .omnigraph may be a symbolic link; a dangling link is a refusal, never permission to select Core:

version: 2
cluster: CLUSTER_ID
api: https://control.example
organization_id: org_customer

use first verifies access to the cluster, then atomically writes this file. The organization is selected explicitly with --organization, by the bound folder, or by the sole cached organization for that API. Multiple cached organizations without a selection refuse; there is no most-recent fallback. Ordinary commands refuse an explicit API or organization conflicting with a bound folder before a request. Fully explicit login and logout select the named API/organization session independently of the folder. Fully explicit use CLUSTER_ID --api ORIGIN --organization ORG_ID verifies access, then may replace a previous binding or obsolete/invalid regular context file; symbolic links and special files still refuse. login, logout, use, and unbound cluster create and cluster operation accept --organization. Each invocation pins its verified account and principal across refresh, submission, polling and recovery. Unknown fields and malformed values refuse. API addresses are canonical origins, without userinfo, path, query, or fragment. HTTPS is mandatory except exact loopback hosts for local integration. Redirects are refused; each request has a 10-second deadline and 8 MiB body limit.

The original authentication contract used service-brokered device login and an opaque session, stored only in the OS keychain for at most 15 minutes. That protocol is superseded by the provider-native authentication contract. The current CLI uses the provider SDK directly and does not retain the broker's device, refresh or opaque-session cache paths. Upgrade the API and CLI together and sign in again; no broker migration period is required. Named-server credentials and the public restricted data-token verifier are separate compatibility contracts, not fallbacks for managed login.

Scoped automation may supply OMNIGRAPH_CONTROL_TOKEN only together with OMNIGRAPH_CONTROL_API matching the selected canonical origin. Data-plane credentials, existing server token files, and actor flags cannot supply managed human authority. The CLI has no private managed-crate dependency; the public HTTP envelope is the boundary. No Lance domain is changed or relied on by this HTTP path.

Invariants

Invariants 3 and 5 remain owned by the Core/executor: the CLI submits exact plan identity rather than inventing state or recovery authority. Invariant 8 requires typed context and API refusals instead of fallback. Invariant 10 keeps trusted actor resolution at the API; the client cannot assert human identity. Invariant 11 supplies numeric request/wait/body bounds. Invariant 12 keeps durable runs and leases service-owned; context is routing, not a shadow cluster ledger. No deny-list item is introduced: there is no cloud fork, cloud-only correctness fix, duplicated lock, or new writer fence.

Compatibility and reversibility

Existing profiles/servers/clusters config and login SERVER --token / logout SERVER remain intact. The new --api mode is mutually exclusive with named-server login. Self-hosted commands retain their own addressing regardless of folder context. Managed control requires cluster <command> --managed; the top-level managed command is removed, with no alias. Omitting the mode flag cannot select service execution.

No stored graph or server API format changes. Bound managed commands refuse without context; its absence cannot select direct execution. Deploy a compatible CLI and API together. Managed discovery and context version 2 require a fresh managed sign-in and folder binding. Version 1 contexts and credential custody are not migrated. Named-server/static credentials, graph HTTP contracts and storage formats are unchanged. The server SDK and Python SDK gain no new authority or dependencies.

Alternatives

  • Raw HTTP keeps the current gap in bounded waits, identity storage, and context isolation and makes every script reproduce the managed contract.
  • Ambient context dispatch makes identical cluster commands select different protocols. Explicit --managed keeps the choice visible and mode validation refuses arguments belonging to another protocol before any access.
  • Separate top-level command families repeat cluster concepts and workflows. One cluster noun with an explicit mode retains the authority boundary.
  • Inferring managed mode from storage roots or existing server aliases risks forwarding the wrong credential; explicit context and origin binding win.
  • Requiring browser sign-in after every short access lifetime interrupts long-running commands. The provider-native extension owns bounded renewal and keeps provider credentials in the OS keychain.
  • Plaintext fallback helps headless setup but silently weakens human secret storage. Explicit scoped automation credentials cover unattended execution.

Evidence and tests

The existing CLI unit and cluster process owners cover exact saved-plan and idempotency bodies, envelope and outcome parity, device pending/slowdown/expiry, credential-origin isolation, malformed context, redirect and size limits, and API-down refusal without Core effects. Unit tests inject a credential store; process tests do not touch user keychains or operator configuration. The focused baseline passed 91 unit tests and 45 cluster process tests, including the existing direct behavior.

API implementations separately own transactional permission/revocation, device replay, and abandon/apply races. Integration qualification must compare CLI/API plan and bundle digests, terminal outcomes, and readiness witnesses, and exercise cancellation, idempotency and denied access. Provider fixtures do not establish live browser or multi-user interoperability.

Rollout

Land the public contract and implementation together with CLI user docs and release notes. A compatible API supplies authentication and plan abandonment without changing executor or engine gates. Existing CLI/direct and managed HTTP tests must pass before recommending the managed client. Data-plane tokens, managed-store editing, provisioning, console and SSE were outside the initial increment. Managed-store editing and service provisioning are extended by RFC 0061.

Unresolved questions

None for this bounded increment.

Decision log

2026-09-05: Recorded the requested managed CLI increment before code. Reused the existing config-directory addressing contract with explicit --direct rather than introducing a root-URI override the Core does not currently expose.

2026-09-05: Accepted after maintainer-authorized review of the implementation, compatibility, bounded HTTP and credential handling, focused regression suites and native CLI integration qualification. No engine or storage contract changes are required. Data access remains a separate increment; this decision authorizes control-plane operations only.

2026-09-06: The Rollout scope sentence now explicitly limits its deferral of managed-store editing and provisioning to this original increment, and links RFC 0061 as the owner of those additional client commands. Its authentication, folder context, direct routing and exact-plan execution contract is unchanged.

2026-10-06: The maintainer chose cluster <command> --managed. Summary and User behavior replace command-family routing with explicit mode selection, early conflicts and shared-command argument rules. Compatibility removes the top-level managed command without an alias. Alternatives replaces separate command families with one cluster noun while rejecting ambient interception. Managed data-command context and service protocols remain unchanged. Existing CLI owners cover mode refusal and self-hosted isolation from malformed context.