intent

package
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

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. It writes nothing itself beyond Change.Apply, never publishes and never merges: the change is reviewed and merged by a human like any other policy edit.

Index

Constants

View Source
const ArtifactAttrLine = "artifacts/** -text"

ArtifactAttrLine keeps artifact files byte-exact in every checkout.

Variables

This section is empty.

Functions

func GitAttributes added in v0.4.0

func GitAttributes(dir string) (content []byte, ok bool, err error)

GitAttributes returns the .gitattributes content a new policy repo in dir needs: the existing file with ArtifactAttrLine appended, or a new file. ok is false when the line is already there. An existing file is never replaced, only extended.

func InitFile

func InitFile(o InitOptions) []byte

InitFile renders a simple-mode halos.yaml. It is validated by the caller (Load + Validate on the written repo) like any other change.

Types

type Candidate

type Candidate struct {
	Profile, Ring, Label                string
	Experiment, Variant, ExperimentRing string
}

Candidate is what to build for an upgrade: Profile (pinning the new version) rendered for Ring, labelled Label. When Experiment is set, the treatment variant Variant is also built for ExperimentRing and served on its client-axis channel, so the canary has a release before any ring moves.

type Change

type Change struct {
	Dir   string
	Files map[string][]byte
	// Notes are follow-ups for the human (printed after the file list).
	Notes []string
	// Done lists side effects already performed, e.g. a published release.
	Done []string
}

Change is a set of whole-file writes under Dir (repo-relative, slash paths).

func Migrate

func Migrate(dir string) (*Change, error)

Migrate rewrites every document's top-level apiVersion from policy.APIVersionV1Alpha1 to policy.APIVersion, in place: each value is spliced byte for byte (yamledit), so comments, formatting, quoting and the other documents of a file are untouched. A repo already on v1 yields an empty Change, so running it twice is a no-op. It walks the files the loader reads (*.yaml/*.yml, halos.yaml included, dot-directories and tests/ skipped).

func (*Change) Apply

func (c *Change) Apply() error

Apply writes every file atomically.

func (*Change) Load

func (c *Change) Load() (*policy.Org, error)

Load loads the policy as it would be after Apply, from a scratch copy of the repo (the repo itself is untouched). Every regular file is copied, not just YAML: supply-chain artifacts and their keys and signatures (ADR-0028) are validated too. ponytail: copies the whole repo; restrict to YAML plus declared artifact paths if policy repos grow large.

func (*Change) Patch

func (c *Change) Patch() string

Patch is the change as a unified diff.

func (*Change) Paths

func (c *Change) Paths() (created, changed []string)

Paths splits the change's files into created and changed, sorted.

func (*Change) Validate

func (c *Change) Validate() ([]policy.Issue, error)

Validate loads and validates the policy as it would be after Apply.

type Doc

type Doc struct {
	Kind policy.Kind
	Name string
	Path string // canonical repo-relative path
	// contains filtered or unexported fields
}

Doc is one low-level policy document and the file it belongs in.

func Docs

func Docs(org *policy.Org) []Doc

Docs lists every document of the loaded (expanded and overlaid) policy in a stable order: gateway, profiles, rings, experiments, toggles, rollouts, units.

func (Doc) YAML

func (d Doc) YAML() ([]byte, error)

YAML marshals the document.

type Enable

type Enable struct {
	MCP  *policy.MCPServer
	Hook *policy.Hook
	// Name of the toggle (defaults to the MCP server name; required for hooks).
	Name string
	// For is who gets it: "all" (a profile change), a ring name, "N%",
	// "group:<g>" or "user:<id>" (a client-axis Toggle).
	For     string
	Owner   string
	Expires string // YYYY-MM-DD; default 90 days from Now
	Now     time.Time
}

Enable is `halo enable mcp|hook`: exactly one of MCP or Hook is set.

type Explained

type Explained struct {
	Kind   policy.Kind `json:"kind"`
	Name   string      `json:"name"`
	Source string      `json:"source"`
	YAML   string      `json:"yaml"`
}

Explained is one document as `halo explain` shows it.

type InitOptions

type InitOptions struct {
	Org      string
	Tools    map[string]string // tool -> version
	Provider string
	Project  string            // Google Cloud project, provider vertex
	Models   map[string]string // alias -> model id
	// ToolModels maps a tool to the alias it starts on instead of default (set by Complete).
	ToolModels map[string]string
	Gateway    string
	// GatewayEngine: "" (halo-proxy), kong, or external (your own API gateway).
	GatewayEngine string
	Issuer        string
	ClientID      string   // OIDC client id (portal login); optional
	Admins        []string // identity.adminGroups (ring0 team and portal admins); optional
	Safety        string
	Rollout       string
}

InitOptions shape a new simple-mode halos.yaml.

func (*InitOptions) Complete

func (o *InitOptions) Complete(ask func(question, def string) (string, error)) ([]string, error)

Complete fills what init must not leave to the user: the default alias's model for the provider and, for each tool whose wire the default model's provider cannot answer (codex needs OpenAI Responses, gemini-cli Gemini), a model alias named after the tool on its vendor's provider. A --model <tool>=<id> the user gave wins (an unprefixed id runs on the tool's vendor); ask, if set, is offered the default and may change it. It returns one note per alias it added.

type ModelSwitch

type ModelSwitch struct {
	Alias, Model string
	Canary       bool
}

ModelSwitch is `halo model switch`: point alias at model.

type Repo

type Repo struct {
	Dir  string
	Root *policy.Root
	Org  *policy.Org
}

Repo is a loaded policy repo plus its root document.

func Open

func Open(dir string) (*Repo, error)

Open loads dir.

func (*Repo) CandidateOf

func (r *Repo) CandidateOf(ro *policy.Rollout) (Candidate, error)

CandidateOf is the Candidate a rollout written by `halo upgrade start` names: its treatment profile (same name as the rollout) for the GA ring, labelled change.version, plus the experiment's treatment variant.

func (*Repo) Eject

func (r *Repo) Eject() (*Change, error)

Eject writes the documents simple mode generates, merged with any explicit overlay, as ordinary files, and strips the simple keys from halos.yaml. The policy it leaves loads to the same Org. An overlay document is replaced in place when it is alone in its file; a file holding other documents, or an unrelated file at the canonical path, is an error (nothing is clobbered).

func (*Repo) Enable

func (r *Repo) Enable(e Enable) (*Change, error)

Enable adds an MCP server or hook. For "all" it appends to the GA ring's profile (a stub profile document in simple mode); otherwise it writes a client-axis Toggle for the targeted cohort, killable with `halo kill`.

func (*Repo) Explain

func (r *Repo) Explain(kind string) ([]Explained, error)

Explain lists the effective policy, optionally only kind (case-insensitive). Generated documents show their merged form; explicit ones their source text.

func (*Repo) GA

func (r *Repo) GA() (*policy.Ring, error)

GA is the default ring.

func (*Repo) Generated

func (r *Repo) Generated() (map[string]bool, error)

Generated reports which kind/name documents simple mode expands halos.yaml into (before any explicit overlay).

func (*Repo) PlanUpgrade

func (r *Repo) PlanUpgrade(u Upgrade) (*UpgradePlan, error)

PlanUpgrade lays out a client-axis Rollout from the rollout preset: ring0 ring-wide, a canary ramp on the first percent ring (backed by a client-axis experiment whose treatment profile pins the new version), then ring by ring to GA, each later ring behind a human approval. Rings that exist only in halos.yaml get a stub document so the rollout's PRs can move their release pointer. The Rollout itself is written by Finish once the digests are known.

func (*Repo) Simple

func (r *Repo) Simple() bool

Simple reports whether halos.yaml uses simple mode.

func (*Repo) SwitchModel

func (r *Repo) SwitchModel(m ModelSwitch) (*Change, error)

SwitchModel re-points a gateway alias. Without Canary it edits the route in place (halos.yaml models.<alias> in simple mode, else the Gateway document). With Canary it writes a traffic-axis Rollout from the preset's canary ramp plus its two-arm experiment; completing the rollout re-points the alias.

func (*Repo) UpgradeStart

func (r *Repo) UpgradeStart(u Upgrade) (*Change, error)

UpgradeStart is PlanUpgrade then Finish with u's digests.

type Upgrade

type Upgrade struct {
	Tool, Version string
	// Release is the digest of the release carrying the new pin; Baseline the
	// digest rings return to on rollback. Both may be left empty for PlanUpgrade
	// (the caller builds and publishes the candidate, then calls Finish).
	Release, Baseline string
	// Label is the candidate release's version label (default "<tool>-<version>").
	Label string
}

Upgrade is `halo upgrade start`: roll tool out at version.

type UpgradePlan

type UpgradePlan struct {
	Name      string
	Candidate Candidate
	// Change holds the treatment profile, the experiment and ring stubs;
	// Change.Load() gives the policy to build the candidate from.
	Change *Change
	// contains filtered or unexported fields
}

UpgradePlan is an upgrade with every document but the Rollout rendered.

func (*UpgradePlan) Finish

func (p *UpgradePlan) Finish(release, baseline string) (*Change, error)

Finish writes the Rollout with the candidate (release) and rollback (baseline) digests and returns the whole change.

Jump to

Keyboard shortcuts

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