Documentation
¶
Overview ¶
Package copilot is Halos Copilot (ADR-0035): a language model drafts policy changes, experiment designs and explanations; Halos' deterministic checks (validation, plan, impact preview, the invariant-1 bypass-token scan and internal/stats) verify them; a human approves every write. Nothing here publishes, pushes, opens a PR, merges or promotes.
Index ¶
- Constants
- Variables
- func ReadJSON(path string, v any) error
- func Slug(s string) string
- type Budget
- type BudgetState
- type Check
- type Client
- func (c *Client) Draft(ctx context.Context, dir, intent string) (*DraftResult, error)
- func (c *Client) Experiment(ctx context.Context, dir, hypothesis string, offline *Design, s Sizing) (*ExperimentResult, error)
- func (c *Client) Explain(ctx context.Context, subject string, facts []Fact) (*Explanation, error)
- func (c *Client) Offline() bool
- func (c *Client) Spend() Spend
- type Design
- type DraftReply
- type DraftResult
- type ExperimentResult
- type Explanation
- type Fact
- type File
- type NextInput
- type Point
- type RingPlan
- type Sizing
- type Spend
- type Stats
- type Suggestion
- type Verdict
Constants ¶
const DefaultModel = "claude-opus-5-5"
DefaultModel is the pinned model the copilot asks unless configured.
const OfflineTemplates = `set <harness> version|model [to] <value> in profile <name> e.g. "set claude-code version 2.1.300 in profile engineering"`
OfflineTemplates documents what offlineDraft understands.
Variables ¶
var ( // ErrBudget stops a run that would cross a ceiling. The result so far // is still returned; nothing past the ceiling is spent. ErrBudget = errors.New("copilot: run ceiling reached") // ErrSchema marks a model reply that failed the Go-side schema: it is // never used, only fed back. ErrSchema = errors.New("copilot: reply failed schema validation") )
Functions ¶
Types ¶
type Budget ¶
type Budget struct {
MaxIterations int // model calls per run (default 3)
MaxTokens int // input + output tokens per run (default 60000)
MaxCostUSD float64 // estimated spend per run (default 2)
// Prices per million tokens, for the cost estimate (default 5 / 25).
PriceInPerMTok, PriceOutPerMTok float64
MaxOutputTokens int // per call (default 8192)
}
Budget is the hard per-run ceiling. Zero fields take the defaults.
type BudgetState ¶
type BudgetState struct {
Budget string `json:"budget"`
Key string `json:"key"`
Utilization float64 `json:"utilization"`
Exceeded bool `json:"exceeded"`
Alert bool `json:"alert"`
}
BudgetState is one budget counter (halo-server `GET /api/v1/budgets`).
type Check ¶
type Check struct {
OK bool `json:"ok"`
Errors []string `json:"errors"`
Warnings []string `json:"warnings"`
Diff string `json:"diff"` // unified diff of the policy files
Plans []RingPlan `json:"plans"`
Impact *impact.Report `json:"impact,omitempty"`
Risks []string `json:"risks"` // deterministic risk notes
}
Check is the deterministic verdict on a candidate policy. OK means no errors: it is the only thing that lets a draft be applied.
func Apply ¶
func Apply(ctx context.Context, run promote.RunFunc, dir string, files []File, slug, subject, body string) (branch, commit string, chk *Check, err error)
Apply re-runs Verify and, only when it passes, commits files to a new local halos/copilot-<slug>-<random> branch (promote.CommitOnBranch: a temporary worktree, so the user's checkout is untouched). It refuses a file with uncommitted changes: the draft was made against the working tree, the commit is made against HEAD. It never pushes or opens a PR.
func Verify ¶
Verify writes files over a copy of the policy at dir and runs every check a human change faces: the invariant-1 bypass-token scan over every byte written (comments included), load and validation, a release build and diff per ring against the current policy, and the impact preview. Check errors are findings (fed back to the model); the error return is for failures to run the checks at all.
type Client ¶
type Client struct {
LLM *eval.HTTPLLM
Model string
Budget Budget
Log io.Writer // one line per call: token counts only (nil = discard)
Debug bool // also log prompts and replies
// contains filtered or unexported fields
}
Client asks the model. LLM nil means offline: every command then uses its deterministic template and never calls out.
func (*Client) Draft ¶
Draft turns intent into a verified policy change: the model drafts whole files, Verify checks them, and errors go back to the model until the draft passes or a ceiling stops the run. Offline, a deterministic template drafts instead (see offlineDraft). It never writes to dir.
func (*Client) Experiment ¶
func (c *Client) Experiment(ctx context.Context, dir, hypothesis string, offline *Design, s Sizing) (*ExperimentResult, error)
Experiment designs an experiment for hypothesis: the model (or, offline, the given design) proposes the shape, Size computes the numbers, Halos renders the YAML and Verify checks it. A design that fails is fed back to the model within the run's ceilings. It never writes to dir.
func (*Client) Explain ¶
Explain explains facts in plain language. A point citing a key that is not among facts is rejected and fed back. Offline, the explanation is a deterministic template over the same facts.
type Design ¶
type Design struct {
Name string `json:"name"`
Axis policy.Axis `json:"axis"`
Rings []string `json:"rings"`
Variants []policy.Variant `json:"variants"`
Primary policy.MetricGoal `json:"primary"`
Guardrails []policy.MetricGoal `json:"guardrails"`
Rationale string `json:"rationale"`
}
Design is an experiment's shape: what the model (or the offline flags) proposes. It carries no numbers that need statistics; Sizing does.
type DraftReply ¶
type DraftReply struct {
Files []File `json:"files"`
Summary string `json:"summary"`
Risks []string `json:"risks"`
}
DraftReply is a model's draft.
type DraftResult ¶
type DraftResult struct {
Intent string `json:"intent"`
OK bool `json:"ok"`
Offline bool `json:"offline"`
Iterations int `json:"iterations"`
Summary string `json:"summary,omitempty"`
Files []File `json:"files"`
Check *Check `json:"check,omitempty"`
ModelRisks []string `json:"modelRisks"`
Stopped string `json:"stopped,omitempty"`
Spend Spend `json:"spend"`
}
DraftResult is the outcome of `halo copilot draft`. OK means the last draft passed every check; Stopped says why a run ended without one.
type ExperimentResult ¶
type ExperimentResult struct {
Hypothesis string `json:"hypothesis"`
OK bool `json:"ok"`
Offline bool `json:"offline"`
Design *Design `json:"design,omitempty"`
Sizing Sizing `json:"sizing"`
Stats *Stats `json:"stats,omitempty"`
File *File `json:"file,omitempty"`
Check *Check `json:"check,omitempty"`
Notes []string `json:"notes"`
Stopped string `json:"stopped,omitempty"`
Spend Spend `json:"spend"`
}
ExperimentResult is the outcome of `halo copilot experiment`.
type Explanation ¶
type Explanation struct {
Subject string `json:"subject"`
Offline bool `json:"offline"`
Summary string `json:"summary"`
Points []Point `json:"points"`
Used []Fact `json:"factsUsed"`
Stopped string `json:"stopped,omitempty"`
Spend Spend `json:"spend"`
}
Explanation is the outcome of `halo copilot explain`. Used lists the facts the points cite, so every claim can be checked against Halos output.
type Fact ¶
Fact is one keyed value Halos computed (a plan field, a diff, an experiment setting, a verdict). Explanations may cite only these.
func DiffFacts ¶
DiffFacts are the policy change from baseDir to dir: the changed YAML files, each ring's plan and the impact preview.
type NextInput ¶
type NextInput struct {
Org *policy.Org
PolicyDir string // added to commands as --policy-dir when not "."
Verdicts []Verdict
Scorecards map[string]*eval.Scorecard // by file path
ROI *roi.Report
Budgets []BudgetState
}
NextInput is the data `halo copilot next` reads. Only Org is required.
type RingPlan ¶
type RingPlan struct {
Ring string `json:"ring"`
Changed bool `json:"changed"`
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
Diff string `json:"diff,omitempty"`
}
RingPlan is one ring's release change, as `halo plan` reports it.
type Sizing ¶
type Sizing struct {
Baseline float64 `json:"baseline"` // primary metric's current mean
SD float64 `json:"sd,omitempty"` // per-unit sd; 0 = sqrt(p(1-p)) for a rate in (0,1)
MDE float64 `json:"mde"` // relative minimum detectable effect, e.g. 0.05
Alpha float64 `json:"alpha"` // default 0.05
Power float64 `json:"power"` // default 0.8
DailyUnits float64 `json:"dailyUnits,omitempty"` // users entering the experiment per day; 0 = no duration
}
Sizing is the human's input to the statistics: never the model's.
type Spend ¶
type Spend struct {
Calls int `json:"calls"`
InputTokens int `json:"inputTokens"`
OutputTokens int `json:"outputTokens"`
CostUSD float64 `json:"estCostUSD"`
}
Spend is what a run used.
type Stats ¶
type Stats struct {
SD float64 `json:"sd"`
SDDerived bool `json:"sdDerived,omitempty"` // sqrt(p(1-p)) from the baseline
AbsoluteMDE float64 `json:"absoluteMDE"`
PerArm int `json:"perArm"` // min units in the smallest arm
Total int `json:"total"` // all arms at their weights
Days int `json:"days,omitempty"`
MaxDays int `json:"maxDays"`
Formula string `json:"formula"`
}
Stats is what internal/stats computed.
type Suggestion ¶
type Suggestion struct {
Title string `json:"title"`
Evidence []string `json:"evidence"`
Command string `json:"command"`
HumanGate bool `json:"humanGate"`
}
Suggestion is one next step, with the evidence it rests on and the exact command. HumanGate marks a command that changes state: a human runs it.
func Next ¶
func Next(in NextInput) ([]Suggestion, error)
Next derives suggestions from existing data by fixed rules: no model.