Documentation
¶
Overview ¶
Package policy is memcode's user-authored behavior layer: typed settings on named decision points, resolved deterministically at runtime.
The rule the whole package exists to enforce:
Policy chooses behavior. The model may not synthesize policy.
A user says "always review plans with grok"; the model translates that into one Set call; the runtime reads the result. What must never happen is a model deciding on its own that some task deserves a different model — that is the automatic routing memcode deleted, and it is not allowed back in through a settings API.
Two consequences run through the design. Policies are UNCONDITIONAL: every one applies every time, and nothing inspects or classifies a task to decide whether a policy fires. And fallbacks are OPERATIONAL only: a declared fallback exists for a provider that cannot be reached, never for a result that looked weak.
This is deliberately NOT internal/prefs. That system infers standing preferences from repeated signals and injects advisory prose into the prompt. This one is explicit, immediate, programmatic, and never inferred. Neither writes to the other.
Index ¶
- Constants
- Variables
- func Save(path string, s Set) error
- func SetField(path string, t Target, field string, raw any) error
- func UnsetTarget(path string, t Target) error
- func UserPath() string
- func Validate(t Target, field string, raw any) (any, error)
- func WorkspacePath(root string) string
- type Field
- type Kind
- type Option
- type Resolved
- type Resolver
- type Schema
- type Scope
- type Set
- type Target
- type Value
Constants ¶
const ( // ModeOff / ModeOffer / ModeAlways are the shared vocabulary for a step // that can be disabled, offered, or run every time. They are an enum rather // than a bool because "never review", "offer review" and "always review // with X" are three independent things, and a bool plus a nil model can // only express two of them. ModeOff = "off" ModeOffer = "offer" ModeAlways = "always" )
Variables ¶
var PersistedScopes = []Scope{ScopeWorkspace, ScopeUser}
PersistedScopes are the scopes backed by a file. Session and override are deliberately absent: they are held in memory by whoever owns them.
Functions ¶
func UnsetTarget ¶
UnsetTarget removes a whole target from one scope, leaving every other scope untouched — resetting "how explore agents behave" in this repo must not disturb what was set everywhere.
func UserPath ¶
func UserPath() string
UserPath is $XDG_CONFIG_HOME/memcode/policy.json, else ~/.config/memcode/policy.json. "" when no home directory can be determined.
func Validate ¶
Validate normalises and checks a value against its field's kind. It runs at SET time so a bad policy is refused where the user can see it, not two turns later inside a failing call.
func WorkspacePath ¶
WorkspacePath is <root>/.memcode/policy.json.
Types ¶
type Field ¶
type Field struct {
Name string
Kind Kind
Enum []string // KindEnum / KindStrategy: the permitted values
Min int // KindInt
Max int // KindInt
Def any // the component default — what applies when nothing is set anywhere
Doc string // shown in `/policy` and in the tool description
}
Field is one typed knob on a target.
type Kind ¶
type Kind string
Kind is the closed set of field types. Values are validated against their kind at SET time, so a malformed policy is refused where the user can see the refusal, rather than surfacing as a broken turn later.
const ( KindModel Kind = "model" // a pinnable catalog label KindModelList Kind = "model_list" // an ordered list of pinnable labels KindEnum Kind = "enum" // one of Field.Enum KindInt Kind = "int" // an integer within [Min,Max] KindStrategy Kind = "strategy" // an enum that selects HOW a value is produced )
type Option ¶
type Option func(*resolveOpts)
Option customises one Resolve call.
func Override ¶
Override supplies values scoped to THIS operation. It is passed in by whoever owns the operation and is never stored: "review this plan with kimi" belongs to that plan and disappears when the plan does. There is no global consume-on-next-use state that could leak into an unrelated later operation.
type Resolved ¶
Resolved is a target's effective policy.
type Resolver ¶
type Resolver struct {
Session Set
Workspace Set
User Set
// Primary is the session's primary model pin — where a model chain ends
// for a schema that declares InheritsPrimaryModel.
Primary string
}
Resolver holds the layers and answers Resolve. One per session.
func (*Resolver) Resolve ¶
Resolve computes a target's effective policy, field by field.
Per field: override -> session -> workspace -> user -> parent target -> primary pin (if the schema ends there) -> the schema default. Per-field rather than per-target means a user-level model and a workspace-level fallback list compose instead of one silently replacing the other.
type Schema ¶
type Schema struct {
Target Target
Doc string
Fields []Field
// Parent is the target an unset field falls through to. Inheritance is
// DECLARED here, never special-cased in the resolver: agent.explore names
// agent.delegated as its parent, and a future agent.research or plan.scout
// does the same and needs no resolution code of its own.
Parent Target
// InheritsPrimaryModel ends a model chain at the session's primary pin.
// This is how "unset delegated means run everything on the user's own
// model" is expressed as schema rather than as a hand-written chain.
InheritsPrimaryModel bool
}
Schema declares a target's fields and where it inherits from.
type Scope ¶
type Scope string
Scope names where a resolved value came from. Every resolved field reports one, because per-field resolution across four layers is only comprehensible if the user can ask "why is it that, and who set it?".
const ( ScopeOverride Scope = "override" // this operation only ScopeSession Scope = "session" // this session ScopeWorkspace Scope = "workspace" // this repo ScopeUser Scope = "user" // everywhere ScopeInherited Scope = "inherited" // a parent target, or the primary pin ScopeDefault Scope = "default" // the schema's declared default )
type Set ¶
Set is one scope's contents: target -> field -> value.
func Load ¶
Load reads a policy file. A missing or corrupt file is "no policy", never an error: a settings file that fails to parse must not stop a session starting.
type Target ¶
type Target string
Target names a stable decision point. Adding a controllable behavior means registering a Target with a schema and calling Resolve where the decision is made — there is no other extension mechanism, and no target-specific resolution code anywhere.
const ( // AgentDelegated is the model for delegated work: agent-tool workers, // scouts, plan research. Unset inherits the session's primary pin. AgentDelegated Target = "agent.delegated" // AgentExplore narrows AgentDelegated for read-only explore/scout agents. AgentExplore Target = "agent.explore" // PlanReview governs the second-model plan critique. PlanReview Target = "plan.review" // PlanAdvisor governs the plan-mode advisor. PlanAdvisor Target = "plan.advisor" // StartupModel governs how a session picks its primary model at launch. StartupModel Target = "startup.model" // UITheme governs the colour theme. UITheme Target = "ui.theme" // SessionEffort governs the default thinking depth. SessionEffort Target = "session.effort" )