Documentation
¶
Overview ¶
Package project reads a repo's .agent/project.yaml — coop's per-project config, committed with the repo (unlike the git-ignored rest of .agent/). It carries:
- subprojects: for a monorepo, the member project dirs whose .agent/tasks queues coop aggregates automatically, so you don't hand-maintain COOP_TASKS.
- serve.ports: container ports coop publishes so a dev server running in the box is reachable from the host browser, each mapped to a stable host port.
- box: the committed box policy and literal environment defaults every run in this repo inherits — applied below explicit user/runtime settings (box.Run overlays it).
- gate: the revalidation command `coop fork merge` runs in the box (an explicit COOP_GATE wins).
SECURITY: this file is committed and read on the HOST from a repo you may not fully trust, so it must never be able to LOOSEN the user's posture. The precedence (explicit env/conf > this file > built-in default) makes egress tighten-only by construction — its built-in default is already the loosest value ("open") — and no_new_privileges is deliberately NOT a key here (its default is on; a committed switch could only turn it off). box.env reaches only the container, rejects Coop's reserved COOP_ namespace, and stays below the user's agents/env and runtime-generated values.
Index ¶
Constants ¶
const ( DefaultDockerfile = ".agent/Dockerfile" DefaultCompose = ".agent/compose.yml" )
Default box-input paths when project.yaml doesn't set box.dockerfile / box.compose. Both live under .agent/ (coop's committed home) — the Dockerfile alongside the sidecar compose file.
const File = ".agent/project.yaml"
File is the repo-relative path of the project config.
Variables ¶
This section is empty.
Functions ¶
func ComposePath ¶
ComposePath returns the repo-relative path to the sidecar compose file — box.compose from project.yaml, else DefaultCompose. Best-effort, like DockerfilePath.
func DockerfilePath ¶
DockerfilePath returns the repo-relative path to the box's Dockerfile — box.dockerfile from project.yaml, else DefaultDockerfile. Best-effort: a project.yaml that won't load (which the build/run paths surface loudly on their own Load) falls back to the default here rather than erroring, so path-existence checks stay total.
func HostPort ¶
HostPort maps a repo + container port to a host port deterministically: the same project always publishes to the same host port (bookmarkable, and stable across box restarts), while two different projects almost never collide. Deterministic rather than first-come so the URL reporter and the box itself agree on the mapping without having to coordinate.
func HostPortFor ¶
HostPortFor maps a repo + an arbitrary key to a host port deterministically — the same key always publishes to the same host port, two different keys almost never collide. HostPort is the port-only case (key = the port); sidecars key on "<service>:<port>" so two services sharing a container port — or a sidecar port equal to a serve.port — still get distinct host ports.
func TaskDirs ¶
TaskDirs returns the repo-relative .agent/tasks queue(s) for repo, aggregating a monorepo's subprojects so no one has to hand-maintain COOP_TASKS. A single repo (no subprojects) yields just ".agent/tasks". A monorepo yields each subproject's queue, plus the root's own if it has one. A missing project.yaml falls back to ".agent/tasks"; an invalid one returns the error.
Types ¶
type Box ¶
type Box struct {
Dockerfile string `yaml:"dockerfile"` // box image definition, repo-relative ("" ⇒ .agent/Dockerfile)
Compose string `yaml:"compose"` // sidecar services compose file, repo-relative ("" ⇒ .agent/compose.yml)
Env map[string]string `yaml:"env"` // literal box-only environment defaults
Egress string `yaml:"egress"` // "" (unset) | "open" | "none" — anything else fails Load
AutoUp *bool `yaml:"auto_up"` // auto-start .agent/compose.yml services (default true)
Network *bool `yaml:"network"` // join the sibling-services network (default true)
Memory string `yaml:"memory"` // docker --memory syntax, passed through (e.g. 4g)
CPUs string `yaml:"cpus"` // docker --cpus value
Pids string `yaml:"pids"` // --pids-limit: a positive integer, or ""/0/unlimited for none
}
Box is the committed per-repo box policy. Every field is optional; an unset field keeps the user's own setting (env/conf) or coop's built-in default. The booleans are pointers because absent must stay distinguishable from false (their defaults are true).
type Context ¶
type Context struct {
Routes []Route `yaml:"routes"`
}
Context is the path-routed context configuration: which committed docs to compile for a given scope (touched paths). See internal/contextc for the compiler; canonical AGENTS.md/CLAUDE.md are always included regardless of routes.
type Project ¶
type Project struct {
Subprojects []string `yaml:"subprojects"` // monorepo member dirs (repo-relative), each its own coop project
Serve Serve `yaml:"serve"`
Box Box `yaml:"box"` // committed box policy (below an explicit COOP_* setting)
Review Review `yaml:"review"` // publication-review-only services and literal environment
Context Context `yaml:"context"` // path-routed instruction/rule/KB compilation (coop context)
Gate string `yaml:"gate"` // fork-merge revalidation command (an explicit COOP_GATE wins)
}
Project is the parsed .agent/project.yaml.
func Load ¶
Load reads <repo>/.agent/project.yaml. A missing file is not an error — it returns an empty Project, the common single-repo case. A present-but-invalid file (bad YAML, an unknown key, an out-of-range port, a bad box value, or a subproject path that escapes the repo) IS an error, so a typo surfaces instead of silently doing nothing. Subproject paths are cleaned in place.
func (*Project) ComposeRel ¶
func (*Project) DockerfileRel ¶
DockerfileRel / ComposeRel project the box-input paths off a loaded Project: the configured value, else the default. Callers that already hold a *Project (e.g. Build, which Loads to fail loudly on a bad file) use these; the package-level helpers below are for the path-check sites.
type Review ¶
Review is the trusted, committed environment used only for a disposable review candidate. It lets a repository use a minimal CI-like dependency stack instead of copying ignored local development state into the scratch clone.
type Route ¶
type Route struct {
Paths []string `yaml:"paths"` // repo-relative globs (e.g. "portal/**", "**/*.ex")
Include []string `yaml:"include"` // repo-relative docs to compile when a path matches
}
Route includes its Docs whenever any of its Paths globs matches a scope path. Both are repo-relative (validated in Load); Paths support `*` within a segment and `**` across segments.