Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions apps/docs/next/deployment/blue-yaml.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ The `governance` section is the deployment-authored baseline delivered to client
| `contract_version` | Wire contract version. Current clients support version 3. |
| `required_capabilities` | Features a client must support before accepting policy. |
| `minimum_client_version` | Operator-visible rollout floor; required when using harness version ranges or versioned package adapters. |
| `required_client_version` | Optional canonical exact SemVer recommendation for the Blue CLI and major compatibility boundary. Same-major differences warn; different majors block. |
| `ttl_seconds` | Client cache and polling interval; defaults to 300 seconds. |
| `required` | When true, clients fail closed instead of launching from stale cached policy. |
| `allowed_harnesses` | Supported agent keys users may launch through Blue. |
Expand Down Expand Up @@ -402,3 +403,46 @@ Every source must be immutable and SHA-256 pinned. Use `platform_sources` when h
<Check>
A complete rollout has healthy service probes, no unresolved environment references, the expected governance revision in the dashboard, and matching desired/applied revisions on a test client.
</Check>

## Tenant-compatible Blue CLI

The reference control API advertises its deployment version as the exact
recommended Blue CLI release and the major-version compatibility boundary. Set
`governance.required_client_version` to a published, compatible release to
override that default, for example during a rolling upgrade. The default is
applied when serving a document, so old revisions follow new deployments without
being rewritten. An explicit value stays fixed across rollouts. Use canonical
SemVer without a `v` prefix or range operators. `minimum_client_version` remains
informational.

The `tenant_client_version_pin` capability is required whenever a pin is served.
The `X-Blue-Required-Client-Version` header exposes the same pin on successful
config responses and capability/contract rejections (HTTP 426). Older clients
without this capability are blocked and need a manual install.

A CLI with the same major version continues governed commands and prints a
neutral recommendation when its minor, patch, prerelease, or build metadata
differs. This applies whether the client is older or newer. Exact matches are
silent. Foreground commands warn at most once; background watchers log the
recommendation without interrupting a running harness.

A CLI with a different major version blocks governed commands before launching a
harness or applying managed configuration. In an interactive foreground command,
Blue offers to install the exact recommended release, with consent defaulting to
no. It stages and verifies the release before replacing the running executable.
After success, rerun the original command; the old process never continues the
operation and returns a nonzero exit code. Automatic installation supports stable
releases only and requires a writable, safely resolved installation destination.

Noninteractive commands, daemons and internal hooks never prompt or install.
`blue apply --yes` does not approve replacing Blue. A difference displays the
recommended installer command when available. A major mismatch also displays
`blue reset` as a way to detach; declining or failing installation leaves that
command blocked.

A live cross-major mismatch invalidates the previous cached policy. Cached
documents are also checked against the executing CLI version. Same-major drift
does not invalidate the cache or managed state. A client that has never observed
a remote version change cannot discover it offline; otherwise compatible cached
policy retains the usual offline behavior. `blue reset` remains available without
fetching governance policy.
28 changes: 28 additions & 0 deletions apps/docs/next/reference/governance-config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ harnesses:
| `allowed_harnesses` | Harness names permitted by policy. |
| `harnesses` | Per-harness policy keyed by supported harness name. |
| `minimum_client_version` | Operator-visible rollout floor; it does not replace capability enforcement. |
| `required_client_version` | Optional canonical exact SemVer recommendation for the Blue CLI and major compatibility boundary. Same-major differences warn; different majors block. |
| `packages` | Organization-selected, immutable extension packages and their harness adapters. |
| `gateway` | Global inference routing policy applied to every allowed coding agent. |
| `session_upload` | Global portable-session capture policy; compatible profiles upload integrity-checked bundles while older clients remain accepted as non-resumable raw artifacts. |
Expand Down Expand Up @@ -138,3 +139,30 @@ Standalone skills can live anywhere in an archive and do not require a native pl
The dashboard can inspect `github:owner/repository@ref` for a public GitHub repository, a public HTTPS archive, or a deployment-managed GitHub/Bitbucket connection. Public GitHub refs resolve to immutable codeload URLs; clients download public sources directly and verify their exact digest. Managed repositories are resolved to an immutable commit and mirrored into organization-scoped object storage. Governance contains an `artifact_id` and exact digest; clients use their existing harness session to request a fresh short-lived download and never receive repository credentials.

Removing a package disables it for subsequent governed launches. Unmodified owned content is deleted; locally changed content is moved to quarantine and reported as drift.

## Tenant-compatible Blue CLI

The reference control API advertises its deployment version as the exact
recommended Blue CLI release and the major-version compatibility boundary. Set
`governance.required_client_version` to a published, compatible release to
override that default. The value remains an exact canonical SemVer, not a range.
`minimum_client_version` remains informational.

The `tenant_client_version_pin` capability is required whenever a pin is served.
The `X-Blue-Required-Client-Version` header exposes the same pin on successful
config responses and capability/contract rejections (HTTP 426). Older clients
without this capability are blocked and need a manual install.

A different minor, patch, prerelease, or build value within the same major emits
a neutral recommendation and continues, whether the client is older or newer.
Exact matches are silent. A different major blocks before launch or configuration
changes and may offer a consent-based install of the exact recommended release.

Noninteractive commands, daemons and internal hooks never prompt or install;
background sessions only log same-major recommendations. `blue apply --yes` does
not approve replacing Blue. Cross-major errors include `blue reset` as a way to
detach.

A live cross-major mismatch invalidates the previous cached policy. Same-major
drift keeps cached policy and managed state usable. Cached documents are checked
on load, and `blue reset` remains available without fetching governance policy.
17 changes: 15 additions & 2 deletions apps/docs/openapi/next.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,21 @@ paths:
responses:
"200":
description: The governance config
headers:
X-Blue-Required-Client-Version:
description: Exact recommended Blue CLI release, identical to required_client_version in the document. Same-major differences warn; different majors block.
schema: { type: string }
content:
application/json:
schema: { $ref: "#/components/schemas/GovernanceConfig" }
"403": { description: Authenticated email has no provisioned gateway account }
"409": { description: Gateway key provisioning is required }
"426": { description: Client contract version or capabilities are insufficient }
"426":
description: Client contract version or capabilities are insufficient
headers:
X-Blue-Required-Client-Version:
description: Exact recommended Blue CLI release and major compatibility boundary, provided even when the document cannot be consumed.
schema: { type: string }

/harness-metadata:
get:
Expand Down Expand Up @@ -1684,8 +1693,12 @@ components:
contract_version: { type: integer, default: 1, description: Governance wire contract version }
required_capabilities:
type: array
items: { type: string, enum: [adapter_intervals, compiled_harness_registry, transactional_reconcile, unverified_harness_versions, versioned_state] }
items: { type: string, enum: [adapter_intervals, compiled_harness_registry, tenant_client_version_pin, transactional_reconcile, unverified_harness_versions, versioned_state] }
minimum_client_version: { type: string, description: Operator-visible rollout floor; required capabilities enforce compatibility }
required_client_version:
type: string
description: Canonical exact SemVer of the recommended Blue CLI release and major compatibility boundary. Unequal versions within the same major warn and continue; different majors block. Defaults to the control API deployment version. Requires tenant_client_version_pin capability.
example: "0.1.0"
ttl_seconds: { type: integer, description: Client cache TTL (default 300), example: 300 }
required: { type: boolean, description: "If true, client fails closed without fresh config" }
allowed_harnesses:
Expand Down
8 changes: 5 additions & 3 deletions crates/gh-agent/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,9 +399,10 @@ pub fn reconcile_loop(
/// not be, because nothing the daemon does will fix it.
fn failure_backoff(error: &GhError) -> (u64, bool) {
match error {
GhError::Unauthorized(_) | GhError::Forbidden(_) | GhError::ActionRequired(_) => {
(GovernanceConfig::DEFAULT_TTL_SECONDS * 4, true)
}
GhError::ClientVersionMismatch { .. }
| GhError::Unauthorized(_)
| GhError::Forbidden(_)
| GhError::ActionRequired(_) => (GovernanceConfig::DEFAULT_TTL_SECONDS * 4, true),
_ => (GovernanceConfig::DEFAULT_TTL_SECONDS, false),
}
}
Expand Down Expand Up @@ -475,6 +476,7 @@ mod tests {
contract_version: GovernanceConfig::CONTRACT_VERSION,
required_capabilities: Vec::new(),
minimum_client_version: None,
required_client_version: None,
ttl_seconds: None,
allowed_harnesses: vec!["codex".into(), "claude".into()],
harnesses: Default::default(),
Expand Down
Loading
Loading