Repository navigation
v0.1.0
The first general-availability release. Everything in this section and in the two release candidates ships here. Verified in CI on every change, and run end to end before this tag: Linux, macOS and Windows builds; the installers, halod as a launchd daemon and as a Windows SYSTEM scheduled task; the GitHub Action, the GitLab template and the dev container Feature; Helm on a kind cluster with pod-kill, rolling-upgrade and eviction fault injection under load; halo-kong in open-source Kong 3.9.3; the real pinned Claude Code, Codex, Gemini CLI and Copilot CLI driven headlessly through halo-proxy; halo-proxy against the real Anthropic and OpenAI APIs nightly; a headless browser click-through of every console page.
GA scope. Linux and macOS hosts, dev containers, the four CLIs' managed configuration, halo-proxy with Anthropic and OpenAI upstreams, and halo-kong on open-source Kong are GA. Windows hosts, MDM-delivered laptops (Jamf, Kandji, Intune), Codespaces and Coder, the Codex and Copilot CLI onboarding entry points, and the Bedrock, Vertex and Azure OpenAI upstreams are supported but not yet field-verified: each is built, unit- and fixture-tested, and exercised in CI as far as a hosted runner can, but has not run against a real tenant, device fleet or cloud account. See Known gaps.
Added
- Device posture gate (
Ring.posture: off|warn|enforce, defaultwarn):halo-proxyandhalo-kongaskhalo-server(GET /api/v1/gateway/posture, gateway token, rate-limited) whether the calling device'shalodreported it stale, drifted or off its ring's release, and refuse model calls inenforce. Verdicts are cached (1 m) and the last verdict serves for a 15 m grace window whenhalo-serveris unreachable, after which requests pass and are countedoutcome="unknown".halo_proxy_gate_totalmetrics. ADR-0011. - CLI version gate (
Ring.versionGate: off|warn|enforce, defaultwarn): the gateway reads the CLI version from theUser-Agentand compares it with the ring's pinned versions (ring profile and the variant profiles of running client-axis experiments). This covers Codex, Gemini CLI and Copilot CLI, which do not enforce a pin themselves. User-Agent formats come from recorded headers and vendor source, cited in ADR-0011. - Immutable managed files:
halod.yamlimmutable: truesetschflags schg(macOS) /chattr +i(Linux) after each atomic write and clears it before a rewrite; a missing tool or permission is logged once and skipped. - Policy API v1:
apiVersion: halos.dev/v1is the stable document version; every kind and field is frozen as it was in v1alpha1.halo migrate --policy-dir DIR [--dry-run]rewrites v1alpha1 documents in place, keeping comments and formatting (idempotent).halo initand the intent commands write v1;schemas/*.schema.jsondescribe v1 andschemas/v1alpha1/keeps the old ones. Compatibility states the v1 guarantees, the deprecation policy and the supported version skew acrosshalo,halod,halo-serverandhalo-proxy. ADR-0012. - Agentic onboarding from whichever AI CLI you have.
halo quickstartbrings up the demo and prints a tour.halo doctorreports installed CLIs and versions, tools, which credential variables are set (never their values), policy validity and gateway reachability, with a fix per problem.halo onboard local|install|proxy|verifytakes a machine from nothing to a validatedhalos.yaml, a dry-run (then--apply) install of the managed config, an optional loopbackhalo-proxy, and a realclaude -p/codex exec/gemini -p/copilot -pround trip.halo onboard companyinterviews an admin (IdP, gateway, provider, delivery) and generates the policy repo, Helm values, OIDC client, enrollment config, CI workflow and smoke eval, then stops before anything outward. All--output json, idempotent, dry-run by default. MCP tools of the same names plus anonboardprompt; entry points for Claude Code (/halos:halo-onboard), Codex ($halos-onboard), Gemini CLI (extension) and Copilot CLI (.github/mcp.json). New Start here page. - Helm HA:
halo-proxyruns with probes, a PodDisruptionBudget, topology spread, an optional HPA, a hardenedsecurityContextand an optional NetworkPolicy;values.schema.jsonpinshalo-serverandhalo-shadowto one replica because each is a single writer over local JSONL files (documented in the chart).make uat-k8snow kills a proxy pod mid-traffic, performs a rolling upgrade and tests the PDB under 200 rps with zero client-visible errors required. - Operations docs: Operations (HA model, SLOs, Prometheus alert rules on the real metric names, backup and restore of every
--data-dirfile and key, runbook for killing a change, rolling back a ring, rotating release and kill-switch keys, a lost signer state file, gateway or server down) and Support policy (SemVer scope per surface, supported versions, upgrade orderhalo-server → halo-shadow → halo-proxy/kong → halod → halo, EOL). - Nightly soak (
soak.yml): 60 minutes oftest/loadagainst a realhalo-proxy, failing on errors, cut SSE streams, goroutine or heap growth, and p99 regression against a committed baseline (records only untiltest/load/baseline.jsonis committed). - Fuzzing: 16 native Go fuzz targets over every parser of untrusted input (policy YAML, JWTs, ring pointers, bundle tar and manifest, kill lists, SSE, identity headers, webhook signatures, server JSON, audit chain, shadow replay,
halodpaths andhalod.yaml), run briefly on every PR and for 10 minutes per target nightly. An OpenSSF Scorecard workflow and aSECURITY.mdwith the disclosure process and supported versions. - Security model, bound to tests: every claim in the security model names the test that proves it, and
TestSecurityModelClaimsBoundfails if a named test disappears. - CI verifies every delivery path on every PR:
install.ps1,enroll.ps1andhalod service installon Windows;install.sh,enroll.shand launchd on macOS; the composite Action on three OSes; the GitLab template undergitlab-ci-local; the dev container and the Feature under the devcontainer CLI; Playwright clicks through every console page and button (make demo-e2e). - One-command releases:
scripts/release.sh [--dry-run] [--yes] <tag>runs the preflight (main, clean, HEAD == origin/main, SemVer, CHANGELOG section, green CI,go test,goreleaser check) and pushes the tag;release.ymlgates, builds, attests provenance and then verifies the published artifacts (cosign bundle, checksums, attestation, image signatures,install.sh, tap and bucket);release-drift.ymlfails daily if the tap or bucket drift from the latest release. RELEASING.md. - Demo kiosk:
make demoserves a pinnedhalodwith its checksum and configures every launcher, so "Set up my laptop" and the dev container launcher work end to end locally. Unconfigured launchers never show a raw server error:GET /api/v1/capabilitiesreports each launcher's availability, the kiosk shows only usable ones, and admins see what to set. Harness cards list only the model aliases that harness can use (the same wire check ashalo validate). halo eval onlinereports per-arm error rate, mean latency and output tokens over every shadow pair, errored ones included, and exportshalo.eval.shadow.*(ADR-0004: regressions in refusal rate, latency and cost are now caught, not only judge scores).- Guardrails
guardSandboxEgress(a ring profile withpermissions.sandboxRequiredmust set a non-emptyegress.allowedDomains) andguardGARing(a default ring that ships hooks must make them managed-only);guardNoBypassnow also scans profileenvand harness overrides.ExtraGuardrailslets an org add checks that can only add issues.halo release publishrefuses a ring pinned to a differentrelease:digest. Every ADR 0001–0010 carries an Implementation status table mapping each commitment to code and a test, with dated addenda where a decision was superseded. halo planno longer requires--against: a first release has no baseline.
Changed
halo initand the intent commands writehalos.dev/v1.- Release candidates are published as GitHub prereleases and never move the
:latestimage tag or the Homebrew and Scoop manifests; only a finalvX.Y.Ztag does. - The Scoop manifest is
halo.json; the Homebrew formula lives in the tap'sFormula/directory.
Deprecated
apiVersion: halos.dev/v1alpha1still loads with identical semantics and a validation warning per file. It is removed only inhalos.dev/v2.
Fixed
halodon Windows:state.jsonis written with the managedvardirectory's DACL instead of an owner-only one, so the SYSTEM scheduled task no longer rejects a state file first written by an admin during enrollment.- GitLab template:
.halosno longer sets a job-levelHALOS_VERSIONdefault that shadowed the pipeline-level pin. halo exp analyzecould fail withjson: unsupported value: -Infwhen a guardrail's two arms had no variance yet; the sequential guardrail now reports the exact estimate instead of an unbounded interval.halo-proxyno longer logs a spurious export error when a telemetry flush is cut short by shutdown.test/loadpaces requests with-rps; an unthrottled run exhausted the kind ingress's ephemeral ports and reported harness 502s as chart failures.
Security
Each finding below has a regression test; none changed an invariant.
- Policy:
bypassPermissions/danger-full-accessin profileenvor harness overrides is now ahalo validateerror, not only a release-build backstop. - Bundles:
halo release buildrefuses any rendered file carrying a literal credential (Anthropic, GitHub, AWS keys, private keys), without echoing it. halodarchive extraction accepts only regular files and no entry larger than the tar itself (PAX/GNU sparse bombs and symlink or hardlink entries are refused); managed files owned by another user, group- or world-writable, or with a loose DACL are replaced rather than adopted; Windows paths are normalised and DOS device names refused.- Gateway: JSON bodies are re-encoded with duplicate and case-variant
"model"keys dropped (an alias could otherwise be smuggled past the allowlist); request trailers are not forwarded; upstream event-stream chunks are compacted and event names with line breaks refused;halo-konghandles Kong's header-list cap. halo-shadowand the kill-switch fetch never follow redirects.halo-server: login and enrollment are rate-limited; CSRF checks no longer rely onOriginalone; promotion branch names are validated; invalid UTF-8 no longer breaks the audit chain.- Docker base images are pinned by digest.
Known gaps
- Not field-verified (built and tested, never run against the real thing): Jamf, Kandji and Intune tenants; real Codespaces and Coder; Codex and Copilot CLI onboarding entry points (their formats follow the vendors' docs); Bedrock, Vertex, Azure OpenAI and Kong Enterprise/Konnect; the Helm chart on a managed cloud cluster (it runs on kind); kill-switch key rotation on a live cluster (the runbook is derived from code).
- The nightly fuzz, Scorecard and soak workflows ship here and have not yet had a scheduled run. The soak's p99 gate arms once a reviewed
test/load/baseline.jsonis committed. halodon Windows is a SYSTEM scheduled task, not an SCM service (ADR-0006 addendum). The immutable-file flag has no Windows equivalent.- The posture gate has no hardware attestation and the version gate trusts a client-controlled
User-Agent; both are honest-client controls, documented in ADR-0011. - The support window in the support policy is a stated commitment, not something the code enforces.
- The CI jobs that install a released
halovalidate a v1alpha1 copy of the example policy (test/ci/policy-v1alpha1) because the previous release predateshalos.dev/v1; they return toexamples/acme-corpwith the first release after this one.