halos

module
v0.1.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 2, 2026 License: Apache-2.0

README

Ship AI coding tools like software.
Versioned · signed · ring-deployed · proven by evals

CI Go Report Card Apache-2.0 Docs

Open in GitHub Codespaces

Quickstart · Architecture · CLI · Threat model


Halos is the open-source control plane for AI coding CLIs: Claude Code, Codex, Gemini CLI and Copilot CLI.

  • One policy repo becomes a signed release.
  • Releases roll out ring by ring, behind A/B tests, canaries, shadows and feature toggles.
  • Each step can be gated on evals and live telemetry.
  • A human-merged PR promotes. A regression measured at the gateway is killed automatically when halo-server serves a signed kill list; any other regression opens a rollback PR.
Today With Halos
Every laptop runs a different CLI version and settings.json One signed release per ring, enforced by the CLI and the halod agent
A model or CLI upgrade hits 100% of engineers at once Dark launch → 1% → 5% → 25% → GA, each step gated
Nobody knows whether the new version is better pass@k evals, LLM-judged shadow traffic, sequential stats, a verdict
Rollback is a Slack message A signed kill switch that gateways pick up within ~10 s, plus rollback PRs

How it works

Your platform team keeps a policy repo: a Git repo that halo init creates. It starts as one file, and developers never touch it.

# halos.yaml: the whole policy, in simple mode
org: acme
tools: {claude-code: 2.1.280, codex: {version: 0.99.0, model: codex}}
provider: anthropic                    # bedrock | vertex | openai | gemini | multi
models: {default: claude-sonnet-4-5, strong: claude-opus-4-1, codex: openai/gpt-5-codex}
gateway: https://ai.acme.example
identity: {issuer: https://login.acme.example, audience: halos, adminGroups: [ai-platform]}
safety: standard                       # strict | standard | relaxed: never bypasses permissions
rollout: standard                      # fast | standard | careful: rings, canary steps, bake times, gates

Presets expand into profiles, rings and gateway routes. Intent commands write the rest for you. The ones that write policy (upgrade start, model switch, enable, eject) support --dry-run, validate their output and list the files they change; halo kill writes to halo-server at once (no release) and takes effect at the next poll, by default 10 s at gateways and 60 s on devices:

# A/B + gated rollout for a CLI upgrade. Builds and signs a candidate release, so it needs a registry
# and key (HALO_REGISTRY / HALO_KEY) and the GA ring's published pointer, or --baseline <digest>.
# --dry-run still reads that pointer.
halo upgrade start claude-code 2.1.300 --registry ghcr.io/acme/halos --key halo.key
halo model switch strong claude-opus-5 --canary
halo enable mcp github --url https://… --for 10%
halo kill <experiment|toggle|rollout> --reason "…"
halo status                                   # rings, rollouts, experiments, toggles
halo explain | halo eject                     # see, or take over, the full policy

A change is a pull request:

  1. CI runs halo validate, halo plan and evals.
  2. On merge, halo release publish builds and signs a release for each ring.
  3. Every environment picks it up: halod on laptops and CI runners, the Dev Container Feature in workspaces, and halo-proxy or Kong for model traffic.

examples/simple is the one-file version and examples/acme-corp the full one; make demo runs it locally, or open the repo in Codespaces (UNVERIFIED: not yet run in a real Codespace). More: how Halos works.

Every rollout technique, as code

Progressive rings, canary ramp, blue-green, dark launch, holdout

A Rollout is an ordered list of steps. Each step sets:

  • a strategy and an exposure
  • a bake time and a minimum sample size
  • gates: metric guardrails, an eval scorecard, a human approval
apiVersion: halos.dev/v1alpha1
kind: Rollout
name: opus-5-5-upgrade
axis: traffic                    # client: a CLI/config release · traffic: a model route
experiment: opus-5-5-canary
change: {alias: opus}
steps:
  - name: dark-launch            # mirrored to the candidate, nothing served
    strategy: dark-launch
    percent: 10
    bake: 2d
    gates:
      scorecard: {file: evals/opus-5-5.scorecard.json, variant: opus-5-5, minPass1: 0.75}
  - name: canary-5
    strategy: canary
    percent: 5
    bake: 12h
    minSamples: 500
    gates:
      guardrails: [{metric: halo.api.error_rate, direction: decrease, maxRegression: 0.05}]
  - name: holdout                # 5% stay on the old model for 14 days
    strategy: holdout
    percent: 5
    bake: 14d
    gates: {approval: true}

The controller evaluates every active step on each tick (default every 5 minutes):

  • A guardrail breach measured at the gateway trips the signed kill switch on its own (traffic axis, when halo-server serves a kill list). Any other breach opens a rollback PR and notifies.
  • Progress always opens a PR that a human merges. Nothing auto-promotes.

Commands: halo rollout plan | status | simulate | advance | rollback (docs).

Experiments and feature toggles

A/B on the client axis, canary on the traffic axis, shadow mirrored to a judge, all assigned by one deterministic hash
  • A/B a CLI version or settings change. Each arm is its own signed release channel, and halod picks the arm with the same hash the gateway uses.
  • Canary a model at the gateway, sticky per user and session, so agents never switch model mid-task.
  • Shadow first-turn requests to a candidate model and grade the pairs with an LLM judge. Nothing from the candidate is served.
  • Toggles turn one capability (an MCP server, a hook, a model route) on for a ring, an IdP group or a percentage of users. The payload ships inside the signed release. A kill needs no new release and takes effect at the next poll: about 10 s at gateways, 60 s on devices.

Measure, don't guess

Change, offline evals, ring exposure, telemetry, mSPRT verdict, promote PR or auto-rollback
Offline evals Replay real tasks in containers, N trials each. Reports pass@1, pass@k and pass^k, with paired bootstrap CIs on pass rate, cost, tokens and time. Flaky tasks are detected and excluded. Verdict: ship, hold or block.
Matrix Runs one suite across harness × model × provider (Claude Code vs Codex vs Gemini, Anthropic vs Bedrock) and produces a PR-ready report.
Online Shadow pairs are graded against a pinned LLM-judge rubric and land in the same evidence plane as cost, latency and errors.
Sequential stats mSPRT guardrails stop an experiment as soon as a regression is real, not at an arbitrary horizon.
Upgrade watch halo upgrade watch spots a new CLI or model release, pins it on a branch, runs the suite and opens a PR with the scorecard.

Any CLI, any provider

Claude Code Codex Gemini CLI Copilot CLI
Version pin CLI-enforced halod halod halod
Model lock ✓ ✓ ✓ default only
MCP allowlist ✓ ✓ ✓ ✓
Permissions ✓ ✓ partial partial (bypass disable only; UNVERIFIED)
Gateway + telemetry ✓ ✓ partial telemetry only

A setting a CLI can't enforce produces a warning in the release manifest; it is never silently dropped. The full matrix and its sources are in the harness reference.

Traffic goes through halo-proxy to Anthropic, Bedrock (SigV4), Vertex, OpenAI, Azure OpenAI or the Gemini API:

  • Model aliases map to weighted splits and priority failover, with a circuit breaker per target.
  • Moving a model to another provider is a one-line policy change.
  • If you already run Kong, the halo-kong plugin applies the same identity, cohort and experiment decisions. It routes each alias to its first target, with no translation or failover.

Runs everywhere

macOS, Linux, Windows, Dev Containers, Codespaces and Coder workspaces, CI runners, Kubernetes via Helm

Pre-release. No version is tagged yet, so build from source: git clone https://github.com/dshakes/halos && cd halos && make build && bin/halo validate --policy-dir examples/acme-corp The binaries, deb/rpm/apk packages and install.sh/install.ps1 come from the GitHub release once a version is tagged. Homebrew and Scoop publish only after the HOMEBREW_TAP_TOKEN secret and the tap and bucket repos are set up; the winget manifest is submitted by hand (see RELEASING.md).

# macOS / Linux: the CLI
curl -fsSL https://raw.githubusercontent.com/dshakes/halos/main/install/install.sh | sh -s -- --version vX.Y.Z

# The halod agent runs as root from a root-owned prefix
curl -fsSL https://raw.githubusercontent.com/dshakes/halos/main/install/install.sh | sudo sh -s -- --version vX.Y.Z --prefix /usr/local --with-agent

# Windows (elevated)
irm https://raw.githubusercontent.com/dshakes/halos/main/install/install.ps1 | iex

Also available:

The installers verify sha256 checksums, and verify the cosign signature on checksums.txt when cosign is installed (otherwise they warn). See the install guide.

Agent-native

halo mcp serve exposes these to any MCP client: validate, plan, rollout status, experiment analysis, toggle evaluation and eval scorecards.

The write tools (propose a rollout step, a rollback or a toggle change) are opt-in and dry-run by default. They commit to a new local branch. Only propose_promotion opens a PR, which pushes its own review branch; none pushes to the base branch, merges or publishes. The Claude Code plugin and the Codex config drive the same flow: edit → validate → eval → experiment → propose.

Architecture

Client plane, traffic plane and evidence plane with their components

Deep dive, traced to the code: tech stack, components and low-level design.

Security by construction

  • Signed everything. Releases, ring pointers and the kill list are ed25519-signed; releases and pointers can also be co-signed with cosign. Ring pointers carry sequence numbers and an expiry, so a registry can't replay an old one.
  • Identity, never headers. The gateway verifies OIDC JWTs (or, in trusted_header mode, accepts identity only from pinned proxy CIDRs), strips client x-halo-* headers and fails closed on unknown models.
  • Guardrails twice. bypassPermissions and danger-full-access are rejected at validate time and again on the rendered output.
  • Humans own the irreversible step. There is no auto-merge, no auto-promote and no agent (MCP) tool that publishes. Privileged actions land in a hash-chained audit log.

Threat model · SECURITY.md

Status

Every component is implemented and covered by unit, race, e2e (make e2e) and evidence-plane (make obs-e2e) tests. Every pull request also runs three acceptance suites against real software:

Suite Runs against Report
make uat-clis the real Claude Code, Codex, Gemini and Copilot CLIs, including the eval runner CLI-REPORT.md
make uat-k8s a kind cluster with the Helm chart installed REPORT.md
make uat-kong open-source Kong 3.9.3 with the halo-kong plugin KONG-REPORT.md

Unit tests also run on Windows and macOS in CI.

Not yet exercised against the real systems:

  • AWS Bedrock, Vertex, Azure OpenAI, OpenAI and Gemini API accounts (fixture-tested only)
  • Kong Enterprise
  • halod as a service on a real Windows machine, and the PowerShell installer and enroll scripts
  • MDM-managed devices
  • Codespaces and Coder workspaces
  • the GitHub Action and GitLab CI template
  • the Helm chart on a managed cloud cluster

Contributing

CONTRIBUTING.md · AGENTS.md for coding agents · ADRs · Apache-2.0

Directories

Path Synopsis
cmd
halo command
Command halo is the Halos CLI: validate, render, release, publish and experiment tooling for a policy repo.
Command halo is the Halos CLI: validate, render, release, publish and experiment tooling for a policy repo.
halo-kong command
Command halo-kong is a Kong Go-PDK plugin (Access phase).
Command halo-kong is a Kong Go-PDK plugin (Access phase).
halo-proxy command
Command halo-proxy is Halos's stack-agnostic traffic plane: a reverse proxy that verifies the caller (OIDC JWT or trusted-proxy headers), assigns the rollout ring / experiment variant, rewrites the model, mirrors eligible first-turn requests to halo-shadow, and forwards to the decided upstream or a single --next-hop.
Command halo-proxy is Halos's stack-agnostic traffic plane: a reverse proxy that verifies the caller (OIDC JWT or trusted-proxy headers), assigns the rollout ring / experiment variant, rewrites the model, mirrors eligible first-turn requests to halo-shadow, and forwards to the decided upstream or a single --next-hop.
halo-server command
Command halo-server serves the Halos API and console.
Command halo-server serves the Halos API and console.
halo-shadow command
Command halo-shadow receives mirrored first-turn requests from halo-kong / halo-proxy, replays them against control and candidate, and stores the pairs as JSONL.
Command halo-shadow receives mirrored first-turn requests from halo-kong / halo-proxy, replays them against control and candidate, and stores the pairs as JSONL.
halo/scaffold
Package scaffold generates a minimal, valid Halos policy repo.
Package scaffold generates a minimal, valid Halos policy repo.
halod command
Command halod is the Halos fleet agent: pull the ring's signed release, verify it, apply it atomically, report status.
Command halod is the Halos fleet agent: pull the ring's signed release, verify it, apply it atomically, report status.
deploy
compose/gen command
Command gen renders kong.yml from policy.json: go run ./deploy/compose/gen
Command gen renders kong.yml from policy.json: go run ./deploy/compose/gen
compose/mockidp command
Command mockidp is a demo OIDC issuer standing in for Okta/Entra/Keycloak: it serves discovery + JWKS and mints signed JWTs at GET /token.
Command mockidp is a demo OIDC issuer standing in for Okta/Entra/Keycloak: it serves discovery + JWKS and mints signed JWTs at GET /token.
compose/mockllm command
Command mockllm is a tiny fake model upstream for the compose demo.
Command mockllm is a tiny fake model upstream for the compose demo.
Package features embeds the checked-in Dev Container Feature and Coder module so internal/delivery exporters and the repo share one source of truth.
Package features embeds the checked-in Dev Container Feature and Coder module so internal/delivery exporters and the repo share one source of truth.
internal
assign
Package assign is the single source of cohort assignment.
Package assign is the single source of cohort assignment.
bundle
Package bundle publishes and pulls signed release bundles as OCI artifacts.
Package bundle publishes and pulls signed release bundles as OCI artifacts.
controller
Package controller is the automated experiment loop: every tick it evaluates each running experiment (promote.Evaluate), persists the verdict for halo-server, and acts on it.
Package controller is the automated experiment loop: every tick it evaluates each running experiment (promote.Evaluate), persists the verdict for halo-server, and acts on it.
delivery/devcontainer
Package devcontainer exports the Halos Dev Container Feature source (features/halos) with option defaults baked in for one org/ring.
Package devcontainer exports the Halos Dev Container Feature source (features/halos) with option defaults baked in for one org/ring.
delivery/mdm
Package mdm exports a release for MDM delivery: a .mobileconfig (Jamf, Kandji) carrying Claude Code managed settings under com.anthropic.claudecode, an Intune PowerShell script writing HKLM\SOFTWARE\Policies\ClaudeCode, and halod bootstrap scripts.
Package mdm exports a release for MDM delivery: a .mobileconfig (Jamf, Kandji) carrying Claude Code managed settings under com.anthropic.claudecode, an Intune PowerShell script writing HKLM\SOFTWARE\Policies\ClaudeCode, and halod bootstrap scripts.
docgen
Package docgen renders the CLI (cobra tree) and policy (JSON Schema) reference pages for the docs site.
Package docgen renders the CLI (cobra tree) and policy (JSON Schema) reference pages for the docs site.
eval
Package eval is Halos's offline replay harness: it runs a suite of coding tasks against harness variants (CLI version x model x settings) in isolated environments, scores each run with the task's own success check, and renders a scorecard with bootstrap CIs and a paired comparison.
Package eval is Halos's offline replay harness: it runs a suite of coding tasks against harness variants (CLI version x model x settings) in isolated environments, scores each run with the task's own success check, and renders a scorecard with bootstrap CIs and a paired comparison.
fsutil
Package fsutil holds small filesystem helpers shared across commands.
Package fsutil holds small filesystem helpers shared across commands.
gateway
Package gateway holds the traffic-plane logic shared by the halo-kong plugin and halo-shadow: request inspection, cohort decision and model rewrite.
Package gateway holds the traffic-plane logic shared by the halo-kong plugin and halo-shadow: request inspection, cohort decision and model rewrite.
gateway/adapters
Package adapters renders the "put halo-proxy in front of / behind stack X" config snippets shipped under deploy/integrations.
Package adapters renders the "put halo-proxy in front of / behind stack X" config snippets shipped under deploy/integrations.
gateway/kong
Package kong generates the decK declarative config for Kong OSS (db-less) that fronts an org's model traffic and attaches the halo-kong plugin.
Package kong generates the decK declarative config for Kong OSS (db-less) that fronts an org's model traffic and attaches the halo-kong plugin.
gateway/upstreamauth
Package upstreamauth signs requests to provider upstreams that need a gateway-held credential instead of the caller's, so halo-proxy can talk to Amazon Bedrock directly (no orchestrator, no SigV4 sidecar).
Package upstreamauth signs requests to provider upstreams that need a gateway-held credential instead of the caller's, so halo-proxy can talk to Amazon Bedrock directly (no orchestrator, no SigV4 sidecar).
harness
Package harness defines the adapter contract every AI coding CLI implements.
Package harness defines the adapter contract every AI coding CLI implements.
harness/all
Package all registers every built-in harness adapter via blank imports.
Package all registers every built-in harness adapter via blank imports.
harness/claudecode
Package claudecode renders Claude Code's managed settings.
Package claudecode renders Claude Code's managed settings.
harness/codex
Package codex renders OpenAI Codex CLI admin configuration.
Package codex renders OpenAI Codex CLI admin configuration.
harness/copilot
Package copilot renders GitHub Copilot CLI file-based enterprise managed settings (managed-settings.json).
Package copilot renders GitHub Copilot CLI file-based enterprise managed settings (managed-settings.json).
harness/gemini
Package gemini renders Gemini CLI system settings.
Package gemini renders Gemini CLI system settings.
harness/hutil
Package hutil holds helpers shared by harness adapters.
Package hutil holds helpers shared by harness adapters.
harness/hutil/hutiltest
Package hutiltest provides a shared rich fixture and golden-file helper for adapter tests.
Package hutiltest provides a shared rich fixture and golden-file helper for adapter tests.
identity
Package identity verifies who a gateway request is from.
Package identity verifies who a gateway request is from.
identity/identitytest
Package identitytest is a tiny OIDC issuer (discovery + JWKS + token minting + an auto-approving authorization-code/PKCE flow) for tests and the compose demo.
Package identitytest is a tiny OIDC issuer (discovery + JWKS + token minting + an auto-approving authorization-code/PKCE flow) for tests and the compose demo.
intent
Package intent turns intent-level requests ("upgrade claude-code to X", "canary this model", "enable this MCP server for 10%") into the low-level policy documents that express them, as file changes in the policy repo.
Package intent turns intent-level requests ("upgrade claude-code to X", "canary this model", "enable this MCP server for 10%") into the low-level policy documents that express them, as file changes in the policy repo.
mcpserver
Package mcpserver exposes a Halos policy repo to agents over MCP.
Package mcpserver exposes a Halos policy repo to agents over MCP.
policy
Package policy defines Halos's harness-neutral policy model: the YAML documents an org keeps in its policy repo, and the in-memory form every other package (compiler, gateway, delivery, eval) consumes.
Package policy defines Halos's harness-neutral policy model: the YAML documents an org keeps in its policy repo, and the in-memory form every other package (compiler, gateway, delivery, eval) consumes.
promote
Package promote turns experiment evidence into a rollout decision.
Package promote turns experiment evidence into a rollout decision.
release
Package release builds immutable, content-addressed release bundles: a deterministic tar holding manifest.json plus every rendered file (as blobs/<sha256>).
Package release builds immutable, content-addressed release bundles: a deterministic tar holding manifest.json plus every rendered file (as blobs/<sha256>).
rollout
Package rollout drives a policy.Rollout through its steps.
Package rollout drives a policy.Rollout through its steps.
server
Package server is the Halos console backend: fleet ingest, policy and experiment read APIs, and the embedded web console.
Package server is the Halos console backend: fleet ingest, policy and experiment read APIs, and the embedded web console.
shadow
Package shadow implements the mirror pipeline: halo-kong posts a Job for sampled first-turn requests, halo-shadow replays it against control and candidate (non-streaming) and stores the pair for later LLM-judge grading.
Package shadow implements the mirror pipeline: halo-kong posts a Job for sampled first-turn requests, halo-shadow replays it against control and candidate (non-streaming) and stores the pair for later LLM-judge grading.
stats
Package stats holds the statistics Halos uses to gate rollouts: always-valid sequential tests (mSPRT), fixed-horizon Welch tests, CUPED variance reduction, paired bootstrap for eval scorecards, and guardrail evaluation.
Package stats holds the statistics Halos uses to gate rollouts: always-valid sequential tests (mSPRT), fixed-horizon Welch tests, CUPED variance reduction, paired bootstrap for eval scorecards, and guardrail evaluation.
telemetry
Package telemetry generates the OpenTelemetry Collector configuration that receives OTLP from Claude Code, Codex and Gemini CLI, normalises their harness-specific metrics into the halo.* schema, and exports to ClickHouse and Prometheus.
Package telemetry generates the OpenTelemetry Collector configuration that receives OTLP from Claude Code, Codex and Gemini CLI, normalises their harness-specific metrics into the halo.* schema, and exports to ClickHouse and Prometheus.
telemetry/gwmetrics
Package gwmetrics is halo-proxy's per-request OTLP metrics emitter: the gateway assigns ring/variant itself, so these are the best-attributed online samples for halo.api.error_rate and halo.latency.* (and the only ones for traffic-axis experiments).
Package gwmetrics is halo-proxy's per-request OTLP metrics emitter: the gateway assigns ring/variant itself, so these are the best-attributed online samples for halo.api.error_rate and halo.latency.* (and the only ones for traffic-axis experiments).
telemetry/synth
Package synth emits synthetic OTLP/HTTP (JSON) telemetry shaped like the real harnesses, for control vs treatment cohorts with a known injected effect.
Package synth emits synthetic OTLP/HTTP (JSON) telemetry shaped like the real harnesses, for control vs treatment cohorts with a known injected effect.
toggle
Package toggle evaluates feature-toggle targeting rules and composes the per-harness settings fragments a release carries for client-axis toggles.
Package toggle evaluates feature-toggle targeting rules and composes the per-harness settings fragments a release carries for client-axis toggles.
tools/gendocs command
Command gendocs regenerates the CLI and policy reference pages:
Command gendocs regenerates the CLI and policy reference pages:
upgrade
Package upgrade watches upstream for new versions of the pinned coding CLIs and for new models in configured provider model lists, and turns each new candidate into an eval-gated pull request: it verifies the candidate's install artifacts (sha256 / npm integrity, via release.ArtifactResolver), writes the candidate pin on a branch, runs the eval suite, and opens a PR carrying the scorecard.
Package upgrade watches upstream for new versions of the pinned coding CLIs and for new models in configured provider model lists, and turns each new candidate into an eval-gated pull request: it verifies the candidate's install artifacts (sha256 / npm integrity, via release.ArtifactResolver), writes the candidate pin on a branch, runs the eval suite, and opens a PR carrying the scorecard.
yamledit
Package yamledit finds a kind/name YAML document in a policy repo (any document of a multi-document file) and edits it by byte splice, leaving comments, formatting and every other document intact.
Package yamledit finds a kind/name YAML document in a policy repo (any document of a multi-document file) and edits it by byte splice, leaving comments, formatting and every other document intact.
test
load command
Command load drives a real halo-proxy binary against mock upstreams and reports added latency, throughput, errors, memory/goroutine growth over a soak, failover + circuit-breaker behaviour, and long-lived SSE integrity.
Command load drives a real halo-proxy binary against mock upstreams and reports added latency, throughput, errors, memory/goroutine growth over a soak, failover + circuit-breaker behaviour, and long-lived SSE integrity.
uat/k8s/uatidp command
Command uatidp is the mock OIDC issuer for `make uat-k8s`: discovery, JWKS, auth-code+PKCE (/authorize auto-approves the identity set by PUT /_uat/login) and GET /mint, which hands out a gateway JWT for any user.
Command uatidp is the mock OIDC issuer for `make uat-k8s`: discovery, JWKS, auth-code+PKCE (/authorize auto-approves the identity set by PUT /_uat/login) and GET /mint, which hands out a gateway JWT for any user.
Package web exposes the built console.
Package web exposes the built console.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL