config

package
v0.0.0-...-5be0be7 Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package config resolves Coop settings from environment variables and an optional conf file, with XDG-based defaults. Every COOP_* setting follows the same precedence: environment variable, then conf file, then built-in default.

Index

Constants

View Source
const (
	DefaultProfile = "default"
)

DefaultProfile is the credential profile used when none is selected; profilesSubdir is the folder under an agent dir that holds the named profiles.

Variables

This section is empty.

Functions

func EnsurePrivateDir

func EnsurePrivateDir(path string) error

EnsurePrivateDir creates or tightens one host-owned directory without following a final link. It deliberately does not walk descendants: a private ancestor protects provider-owned state without changing the provider's own file modes.

func RegisterAdapterConfig

func RegisterAdapterConfig(name string)

RegisterAdapterConfig registers the two coop.conf keys owned by an agent adapter. The agent registry calls it from its existing single registration point, so adding an adapter does not require a second provider list in config.

func RootDir

func RootDir() string

RootDir is Coop's per-user configuration root.

func ShellSplit

func ShellSplit(s string) []string

ShellSplit exposes shellSplit so other packages can split a committed command setting (e.g. the .agent/project.yaml gate:) into argv exactly as Load splits COOP_GATE — one splitter, one rule.

func WithLock

func WithLock(path string, fn func() error) error

WithLock runs fn while holding an exclusive advisory lock (flock) on a sibling <path>.lock, so a load→modify→write of path can't lose a concurrent process's update. Fails CLOSED: when the lock file can't be opened or flocked, fn does NOT run and the caller gets an error naming the lock — these files pick which credential an unattended run uses, so a silently lost update is worse than a refused command (on a healthy system flock on a local file effectively never fails, so this costs nothing in normal operation). Linux/darwin only — coop's only targets.

func WriteFileAtomic

func WriteFileAtomic(path string, data []byte) error

WriteFileAtomic writes data to path via a uniquely-named temp file in the same dir, fsyncs it, then renames it into place and fsyncs the parent dir. The rename is atomic (no truncated file on a crash) and a UNIQUE temp name means concurrent writers don't clobber a shared "<path>.tmp" mid-write; the two fsyncs mean a power loss leaves either the old contents or the new ones — never a live-but-empty file, which for a credential pointer reads back as "unset" and silently changes which account the next run picks.

func WriteFileAtomicMode

func WriteFileAtomicMode(path string, data []byte, perm os.FileMode) error

WriteFileAtomicMode is WriteFileAtomic with an explicit mode for a newly created file. Replacing an existing regular file preserves its mode; links and unsupported file types are never replaced.

Types

type Config

type Config struct {
	BaseImage string // COOP_BASE_IMAGE — shared base image tag
	Workdir   string // COOP_WORKDIR — where the repo mounts in the box (empty = its real host path)
	HomeInBox string // COOP_HOME_IN_BOX — the box user's home
	Shell     string // COOP_SHELL — `coop shell`'s shell

	ConfigDir string // COOP_CONFIG_DIR — per-agent auth + settings folder

	MCPFile  string // COOP_MCP_FILE — the one MCP source of truth
	MCPInBox string // where MCPFile mounts in the box (Claude's --mcp-config)

	RuntimeName   string // COOP_RUNTIME — "" means autodetect
	RepoOverride  string // COOP_REPO — overrides git-toplevel detection
	ImageOverride string // COOP_IMAGE — overrides image selection

	Homes         bool // COOP_HOMES — mount the per-agent home dirs
	Network       bool // COOP_NETWORK — join the sibling-services network
	AutoUp        bool // COOP_AUTO_UP — auto-start sibling services (compose up) before a box when a compose file is present
	Cache         bool // COOP_CACHE — mount the shared dependency cache volume
	Caffeinate    bool // COOP_CAFFEINATE — hold a system sleep inhibitor (caffeinate on macOS) while a loop runs
	NoUpdateCheck bool // COOP_NO_UPDATE_CHECK — opt out of the once-a-day update-available check
	StreamTrace   bool // COOP_STREAM_TRACE — persist raw and rendered output for streaming loop attempts
	ACPWarm       bool // COOP_ACP_WARM — keep alternate ACP providers warm (environment only)
	// EvalDisableWebTools is internal trial state, also carried to a loop subprocess.
	// It disables ordinary native search/fetch, not arbitrary authenticated requests.
	EvalDisableWebTools bool

	ServicesNet    string   // COOP_SERVICES_NET — override the services network name
	ACPCarryTokens int      // COOP_ACP_CARRY_TOKENS — per-session budget (≈tokens, ~4 bytes each) for the conversation carried across an ACP provider switch (default 200000)
	TasksFiles     []string // COOP_TASKS — explicit task queue(s) override; empty = derive from .agent/project.yaml (subprojects) else .agent/tasks
	Gate           []string // COOP_GATE — revalidation gate run in the box before a fork merge lands
	ExtraRunArgs   []string // COOP_RUN_ARGS — extra args passed to the container runtime

	// Box resource/privilege caps (docker; skipped on Apple `container`).
	Memory          string // COOP_MEMORY — memory cap, e.g. "4g" (empty = unset)
	CPUs            string // COOP_CPUS — cpu cap, e.g. "2" (empty = unset)
	Pids            string // COOP_PIDS — pids-limit (fork-bomb cap), default 4096; "0"/"unlimited"/"" = off
	NoNewPrivileges bool   // COOP_NO_NEW_PRIVILEGES — pass --security-opt no-new-privileges (default on)
	Egress          string // COOP_EGRESS — open, filtered (host-qualified), or none

	ConsultTimeout string // COOP_CONSULT_TIMEOUT — per-peer coop-consult timeout in seconds (empty/0 = unlimited)

	// ProviderTimeouts is the INTERNAL provider-attempt watchdog override
	// ("start=2s,idle=3s,tool=6s"), read only so deterministic fixture tests can shorten the
	// fixed deadlines; it is deliberately not a documented user knob.
	ProviderTimeouts string // COOP_PROVIDER_TIMEOUTS

	Editor    string // COOP_EDITOR — editor for `coop fork review --open` (else $VISUAL/$EDITOR or a detected GUI editor)
	ReviewCmd string // COOP_REVIEW_CMD — full override for `coop fork review` (run via sh -c; gets $COOP_FORK_PATH/$COOP_FORK_NAME/$COOP_REVIEW_REF)

	// BoxHome is ~/.config/coop: the home for conf, mcp.json, and agents/.
	BoxHome string
	// contains filtered or unexported fields
}

Config is the fully-resolved settings for one invocation. It is computed once in Load and passed down; process-only presentation settings are the narrow exception because the leaf ui package cannot import config.

func Load

func Load() (*Config, error)

Load resolves the configuration from the environment and conf file. A genuinely absent default file is optional; an explicitly selected file or a present invalid file is an operator error.

func (*Config) ACPCarryBytes

func (c *Config) ACPCarryBytes() int

ACPCarryBytes is the per-session budget, in bytes, for the conversation carried across an ACP provider switch — COOP_ACP_CARRY_TOKENS at ~4 bytes per token, defaulting here too so a Config built directly (tests) doesn't silently zero the budget.

func (*Config) ActiveEffort

func (c *Config) ActiveEffort(agent string) string

ActiveEffort returns the run's EXPLICIT top-tier effort for agent ("" when none), so a caller that temporarily overrides it (the review pass) can snapshot and restore it.

func (*Config) ActiveModel

func (c *Config) ActiveModel(agent string) string

ActiveModel returns the run's EXPLICIT top-tier model for agent ("" when none), so a caller that temporarily overrides it (the loop swapping in a step's loop.yaml model for the review pass) can snapshot and restore the prior value.

func (*Config) ActiveProfile

func (c *Config) ActiveProfile(agent string) string

ActiveProfile is the exported reader for activeProfile — the profile a run of agent resolves to right now. Used for display (the run/loop banner names which profile is in play).

func (*Config) AgentDir

func (c *Config) AgentDir(agent string) string

AgentDir is the host folder mounted at the box's ~/.<agent>: the active profile's credential + session dir (see AgentProfileDir). Defaults to the "default" profile.

func (*Config) AgentEffortDefault

func (c *Config) AgentEffortDefault(agent string) string

AgentEffortDefault is the agent-wide default reasoning effort — the effort part of COOP_<AGENT>_MODEL (its shape is model[/effort], e.g. "opus/high"), or "". One var carries both axes, so there is no separate COOP_<AGENT>_EFFORT.

func (*Config) AgentModelDefault

func (c *Config) AgentModelDefault(agent string) string

AgentModelDefault is the agent-wide default model — the model part of COOP_<AGENT>_MODEL (model[/effort]), or "". Resolved late (not in Load) because config doesn't know the agent set.

func (*Config) AgentProfileDir

func (c *Config) AgentProfileDir(agent, name string) string

AgentProfileDir is the host folder for one named credential profile of an agent: <ConfigDir>/<agent>/profiles/<name>/. "default" is just the profile named "default" — every login lives under profiles/, so this always resolves there.

func (*Config) Clone

func (c *Config) Clone() *Config

Clone returns a copy that can be mutated without touching the original. A plain `*cfg` is NOT enough: Config carries per-run maps (the explicitly-set keys, and the per-agent profile, model and effort tiers), and a shallow copy shares them — so a caller that "copied the config" to change one run's model would silently change every other holder's too, and a concurrent one would race. Callers that run several configurations side by side (coop eval) rely on this.

func (*Config) Cmd

func (c *Config) Cmd(env, def string) []string

Cmd resolves a command setting (COOP_<NAME>_CMD) the same way Load resolves every other: environment variable, then conf file, then the built-in default — then splits it into words. It lets an agent adapter own its own default command without config knowing the agent set.

func (*Config) DefaultProfileOf

func (c *Config) DefaultProfileOf(agent string) string

DefaultProfileOf returns the profile marked default for agent, or the built-in DefaultProfile when none is marked.

func (*Config) DefaultsFile

func (c *Config) DefaultsFile() string

DefaultsFile marks each agent's default profile (KEY=VALUE, agent=profile): the profile an interactive run uses when none is given on the CLI. Managed by `coop credentials <agent> <credential> default`.

func (*Config) EffortFor

func (c *Config) EffortFor(agent string) string

EffortFor resolves the reasoning effort a run of agent should use, most specific first:

  1. the explicit per-run choice (target /effort),
  2. the active rotation target's effort,
  3. the agent-wide COOP_<AGENT>_MODEL's /effort.

Like the model, effort is its own axis — never a property of a credential. "" means no coop-level choice, so the agent CLI's own default applies (see agent.withEffort).

func (*Config) EnvFile

func (c *Config) EnvFile() string

EnvFile is the optional file of KEY=VALUE pairs passed into every box.

func (*Config) Explicit

func (c *Config) Explicit(key string) bool

Explicit reports whether the user explicitly set key (env var or conf file) — false when the loaded value is just the built-in default. The .agent/project.yaml box: overlay (box.Run) uses it so a committed repo policy fills only the slots the user left unset: an explicit setting always wins, and — since the built-in egress default is the loosest — a repo can only tighten.

func (*Config) GlobalPresetsDir

func (c *Config) GlobalPresetsDir() string

GlobalPresetsDir is the per-user presets root (~/.config/coop/presets): a second location `coop <preset>` and `coop presets` load from when the repo doesn't define the name (a repo preset wins a collision). COOP_PRESETS_DIR overrides the path — free testability, and it lets a user relocate the folder.

func (*Config) Instructions

func (c *Config) Instructions() string

Instructions is the optional shared instruction file wired into each agent.

func (*Config) ModelFor

func (c *Config) ModelFor(agent string) string

ModelFor resolves the model a run of agent should use, most specific first:

  1. the explicit per-run choice,
  2. the active rotation target's model (a loop's `opus@work` — re-set on each rotation),
  3. the agent-wide COOP_<AGENT>_MODEL.

The model is its own axis — never a property of a credential (a credential is just an account). "" means no coop-level choice — the agent CLI's own default runs (including a model baked into COOP_<AGENT>_CMD, which the adapters never override; see agent.withModel).

func (*Config) Profiles

func (c *Config) Profiles(agent string) []string

Profiles lists agent's credential profile names from its profiles/ dir, or nothing when the agent has never been used (or has no profiles/ dir yet).

func (*Config) SetActiveEffort

func (c *Config) SetActiveEffort(agent, effort string)

SetActiveEffort selects the reasoning effort a run of agent uses, overriding every other tier — only an EXPLICIT target /effort lands here. Empty clears it, falling back to the lower tiers.

func (*Config) SetActiveModel

func (c *Config) SetActiveModel(agent, model string)

SetActiveModel selects the model a run of agent uses, overriding every other tier — only an explicit one-off choice lands here. Empty clears the selection, falling back to the lower tiers.

func (*Config) SetActiveProfile

func (c *Config) SetActiveProfile(agent, name string)

SetActiveProfile selects which credential profile of agent AgentDir resolves to — and therefore which one the box mounts and the adapters read. The loop calls this to rotate between subscriptions; an empty name resets to the default.

func (*Config) SetDefaultProfile

func (c *Config) SetDefaultProfile(agent, name string) error

SetDefaultProfile marks name as agent's default profile, persisting it to DefaultsFile and updating the in-memory view. The load→modify→write runs under WithLock so concurrent writers (e.g. two `coop credentials default` for different agents) don't lose each other's edit.

func (*Config) SetEgress

func (c *Config) SetEgress(mode string)

SetEgress records the posture the host resolved for this launch (network admission folds the repo's request, the remembered approval and the operator's flags into one decision). Marking it explicit keeps a later project-policy overlay from deciding the mode a second time.

func (*Config) SetRuntimeLimits

func (c *Config) SetRuntimeLimits(cpus, memory, pids string)

SetRuntimeLimits fixes one admitted launch's caps without changing the operator config. Marking them explicit also carries them through a supervised ACP child.

func (*Config) SetTargetEffort

func (c *Config) SetTargetEffort(agent, effort string)

SetTargetEffort selects the active rotation target's effort — applied at loop start and on every rotation, below an explicit target /effort and above every static default. Empty clears it.

func (*Config) SetTargetModel

func (c *Config) SetTargetModel(agent, model string)

SetTargetModel selects the active rotation target's model — a loop applies it at start and on every rotation, so an `opus@work` target runs opus until the rotation moves on. It ranks below an explicit one-off target and above every static default. Empty clears it (a bare credential target), so resolution falls through to the agent-wide default.

type Failure

type Failure struct {
	Headline string
	Where    string
	Problem  string
	Action   string
}

Failure is a settings problem this package could not work around, kept as the PARTS a person needs — where it is, what is wrong, and the one change that fixes it — rather than as a rendered block: config is a leaf library, and the CLI owns the terminal (internal/importdag_test.go). Where is empty when no file carries the problem, Action when there is nothing useful to add.

func (*Failure) Error

func (f *Failure) Error() string

Jump to

Keyboard shortcuts

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