Documentation
¶
Overview ¶
Package config loads and writes the consumer repo's `aiwf.yaml`.
The file is small and deliberately so — see docs/pocv3/design/design-decisions.md §"aiwf.yaml config". The fields are:
hosts: [claude-code] # optional; PoC default and only supported value status_md: # optional; opt-out for the STATUS.md auto-update auto_update: false # default true — see StatusMdAutoUpdate
Identity is runtime-derived (per `provenance-model.md`):
- `--actor <role>/<id>` flag on the verb wins.
- else `git config user.email` → `human/<localpart>`.
- else verb refuses with a usage error.
Two legacy fields are tolerated on read for the migration window:
- `actor:` (pre-I2.5) — captured into LegacyActor; ignored for identity. Stripped on `aiwf update`. See StripLegacyActor.
- `aiwf_version:` (pre-G47) — captured into LegacyAiwfVersion; was a set-once pin that never auto-maintained itself, producing chronic doctor noise. Stripped on `aiwf update`. See StripLegacyAiwfVersion.
Validation rules:
- ActorPattern is the published regex for `<role>/<id>`; callers that resolve identity at runtime (cmd/aiwf, initrepo) consult it.
Index ¶
Constants ¶
const DefaultAllocateTrunk = "refs/remotes/origin/main"
DefaultAllocateTrunk is the trunk ref the allocator falls back to when aiwf.yaml.allocate.trunk is unset. Mirrors what `git clone` produces for a standard upstream project.
const DefaultEntityTitleMaxLength = 80
DefaultEntityTitleMaxLength is the kernel-default cap on entity title (and slug) length. 80 chars matches the Conventional Commits subject-line convention so an entity-touching commit subject that quotes the title verbatim still fits within typical commit-subject guidelines.
const DefaultHTMLOutDir = "site"
DefaultHTMLOutDir is the path the renderer falls back to when aiwf.yaml.html.out_dir is unset.
const FileName = "aiwf.yaml"
FileName is the canonical filename at the consumer repo root.
Variables ¶
var ActorPattern = regexp.MustCompile(`^[^\s/]+/[^\s/]+$`)
ActorPattern enforces the actor format documented in docs/pocv3/design/design-decisions.md: `<role>/<identifier>`, exactly one '/', no whitespace, neither side empty.
var ErrNotFound = errors.New("aiwf.yaml not found")
ErrNotFound reports that aiwf.yaml does not exist in the queried directory. Callers (notably resolveActor) handle this gracefully, since the file is optional pre-`aiwf init`.
Functions ¶
func StripLegacyActor ¶
StripLegacyActor removes any top-level `actor:` line from root/aiwf.yaml and rewrites the file in place. The strip is textual (line-based) rather than a YAML round-trip so user comments and key ordering survive — the legacy `actor:` key is the only field we know to be dead, and a re-marshal would regenerate the file in the marshaler's preferred shape.
Returns (false, nil) when no `actor:` line is present (file stays byte-identical), (true, nil) when one was removed, or an error when the file is unreadable / unwritable. Idempotent: callers may invoke on every `aiwf update` without churn.
`actor:` only matches at column 0 (i.e. a top-level YAML key). A nested key with an actor field name in some hypothetical future block would not be touched.
func StripLegacyAiwfVersion ¶
StripLegacyAiwfVersion removes any top-level `aiwf_version:` line from root/aiwf.yaml and rewrites the file in place. Same shape as StripLegacyActor: textual line-based strip so user comments and key ordering survive.
Returns (false, nil) when no line is present, (true, nil) when one was removed. Idempotent — callers may invoke on every `aiwf update` without churn.
Filed under G47: the field was historically required and stamped at init time, but never auto-maintained, producing chronic doctor noise. The information is now reachable via `aiwf version` (the running binary) and `aiwf doctor --check-latest` (newer release available); the stored pin is dead weight.
Types ¶
type Allocate ¶
type Allocate struct {
Trunk string `yaml:"trunk,omitempty"`
}
Allocate carries the consumer's id-allocator configuration. Trunk names the git ref the trunk-aware allocator unions into its view of existing ids; an empty value means "use the default trunk ref" and AllocateTrunkRef returns DefaultAllocateTrunk in that case.
See docs/pocv3/design/id-allocation.md for the full model.
type Archive ¶ added in v0.8.0
type Archive struct {
SweepThreshold *int `yaml:"sweep_threshold,omitempty"`
}
Archive carries the consumer's drift-control configuration for the per-kind archive convention (ADR-0004). SweepThreshold is a tristate via *int: nil means "not specified, take the default (no threshold — `archive-sweep-pending` stays advisory)", &N is an explicit hard threshold past which the aggregate finding escalates from warning to error. Mirrors the StatusMd.AutoUpdate tristate so "unset" is always distinguishable from a meaningful zero. Use the getter Config.ArchiveSweepThreshold rather than reading the pointer directly so callers don't have to repeat the default.
Default behavior (empty Archive block, or absent archive.sweep_threshold): `archive-sweep-pending` stays advisory regardless of count. Teams choose their own discipline; the kernel does not nag.
type Config ¶
type Config struct {
LegacyAiwfVersion string `yaml:"aiwf_version,omitempty"`
LegacyActor string `yaml:"actor,omitempty"`
Hosts []string `yaml:"hosts,omitempty"`
StatusMd StatusMd `yaml:"status_md,omitempty"`
TDD TDD `yaml:"tdd,omitempty"`
HTML HTML `yaml:"html,omitempty"`
Allocate Allocate `yaml:"allocate,omitempty"`
Tree Tree `yaml:"tree,omitempty"`
Doctor Doctor `yaml:"doctor,omitempty"`
Archive Archive `yaml:"archive,omitempty"`
Entities Entities `yaml:"entities,omitempty"`
}
Config is the in-memory shape of aiwf.yaml. Hosts is omitted when the on-disk file leaves it absent (which is the typical case).
StatusMd is the opt-out surface for the pre-commit hook that keeps `STATUS.md` in sync with the entity tree. Default behavior (block absent, or block present with `auto_update` absent) is on; an explicit `auto_update: false` opts out. See StatusMdAutoUpdate.
LegacyActor captures any pre-I2.5 `actor:` key still present in the on-disk file. The value is ignored for identity resolution (which is runtime-derived); the field exists so `aiwf doctor` can surface a deprecation note pointing the user at `git config user.email`.
func Load ¶
Load reads aiwf.yaml from root. Returns ErrNotFound when the file is absent so callers can distinguish "missing config" (acceptable pre-init) from "malformed config" (always an error).
func (*Config) AllocateTrunkRef ¶
AllocateTrunkRef returns the configured trunk ref (or the default) and whether the value was explicitly set in aiwf.yaml. The "explicit" bit drives the missing-ref policy: an explicitly-named ref that doesn't resolve is a hard error; an unconfigured default that doesn't resolve falls back to working-tree-only when the repo also has no remotes.
func (*Config) ArchiveSweepThreshold ¶ added in v0.8.0
ArchiveSweepThreshold returns the configured threshold and a bool indicating whether the consumer explicitly set one. When set=false, `aiwf check` does not escalate `archive-sweep-pending` regardless of count (the default-permissive behavior per ADR-0004 §"Drift control" layer 2). Tolerant of a nil receiver so callers in `cmd/aiwf/main.go` can invoke before / without a loaded Config.
func (*Config) EntityTitleMaxLength ¶ added in v0.8.0
EntityTitleMaxLength returns the configured title-length cap or the kernel default when unset. A non-positive configured value is treated as the default — the cap exists to prevent filesystem and table-layout pathologies, not to enable disabling them.
func (*Config) HTMLOutDir ¶
HTMLOutDir returns the configured output directory or the default when unset. Callers should resolve to an absolute path against the repo root before passing to the renderer.
func (*Config) StatusMdAutoUpdate ¶
StatusMdAutoUpdate returns whether the consumer wants the pre-commit hook installed and `STATUS.md` regenerated on every commit. Default true: the framework's opt-out, not opt-in. The committed `STATUS.md` is the user's content once tracked; flipping the flag controls whether the *hook* is installed, not whether the file is deleted.
func (*Config) Validate ¶
Validate enforces the documented constraints. Called by Load and expected to be called by Write before serialization.
Identity (the actor field) is no longer stored — it's runtime- derived per `provenance-model.md`. Any incoming `actor:` key is captured by LegacyActor for the deprecation note in `aiwf doctor`, but is not validated here (a malformed legacy value is harmless since runtime resolution doesn't consult it).
`aiwf_version:` is no longer required (G47). Pre-G47 yamls still load fine; the legacy value is captured into LegacyAiwfVersion and stripped on `aiwf update` via StripLegacyAiwfVersion.
type Doctor ¶
type Doctor struct {
RecommendedPlugins []string `yaml:"recommended_plugins,omitempty"`
}
Doctor carries opt-in configuration consumed by `aiwf doctor`. RecommendedPlugins is a list of Claude Code plugin identifiers, each shaped `<name>@<marketplace>` (the same string a user types into `claude /plugin install`). Doctor warns once per entry that is not present in `~/.claude/plugins/installed_plugins.json` for the consumer repo's project scope.
Default behavior (empty Doctor block, or absent doctor.recommended_plugins): the check makes zero observations — the kernel makes no assumption about which plugins a consumer "should" have. See M-070 for the detection rules and M-071 for this repo's own declared list.
type Entities ¶ added in v0.8.0
type Entities struct {
TitleMaxLength *int `yaml:"title_max_length,omitempty"`
}
Entities carries the consumer's policy for entity-shape constraints the kernel applies when writing new entity files. TitleMaxLength caps the length of `--title` accepted by mutating verbs that write titles (`aiwf add`, `aiwf retitle`, `aiwf import`) and the length of `<new-slug>` accepted by `aiwf rename`. Title and slug share the same budget so on-disk filenames and frontmatter titles stay in sync — every kernel render surface (CLI tables, HTML render, git-log subjects, `aiwf history`, filesystem) degrades uniformly rather than diverging.
Default behavior (empty Entities block, or absent entities.title_max_length): the cap is DefaultEntityTitleMaxLength (80 chars — the Conventional Commits subject-line convention). Consumers who want longer or shorter caps override here per G-0102.
type HTML ¶
type HTML struct {
OutDir string `yaml:"out_dir,omitempty"`
CommitOutput bool `yaml:"commit_output,omitempty"`
}
HTML holds the consumer's settings for the static-site render produced by `aiwf render --format=html`. OutDir is the directory the renderer writes into (relative to the repo root unless given as an absolute path); CommitOutput records the consumer's intent to commit the rendered files. The gitignore block managed by `aiwf init` / `aiwf update` is *derived* from CommitOutput — the consumer expresses intent here, and the framework reconciles the gitignore on the next admin verb run.
Default OutDir: "site" — the standard SSG convention. Default CommitOutput: false — gitignore the output and publish via CI.
type StatusMd ¶
type StatusMd struct {
AutoUpdate *bool `yaml:"auto_update,omitempty"`
}
StatusMd carries the opt-out for the pre-commit hook that regenerates `STATUS.md`. AutoUpdate is a tristate via *bool: nil means "not specified, take the default (true)", &false is an explicit opt-out, &true is an explicit opt-in. Use the getter Config.StatusMdAutoUpdate rather than reading the pointer directly so callers don't have to repeat the default.
type TDD ¶
type TDD struct {
RequireTestMetrics bool `yaml:"require_test_metrics,omitempty"`
Strict bool `yaml:"strict,omitempty"`
}
TDD carries opt-in governance for the TDD model. RequireTestMetrics gates the `acs-tdd-tests-missing` warning emitted by `aiwf check`: when true, every AC at `tdd_phase: done` under a `tdd: required` milestone must have at least one commit in its history carrying an `aiwf-tests:` trailer or the check warns. Default false — the trailer is informational metadata; consumers who want stricter governance opt in at the project level.
Strict promotes a defined set of TDD-related findings from warning to error so the pre-push hook blocks the push. Today the bumper covers `entity-body-empty` (M-066/AC-2); M-065's `milestone-tdd-undeclared` will join the same bumper when its rule lands. Single source of truth for the project's TDD strictness posture — no parallel field, no second config knob. Default false. See check.ApplyTDDStrict for the precise set of codes covered.
type Tree ¶
type Tree struct {
AllowPaths []string `yaml:"allow_paths,omitempty"`
Strict bool `yaml:"strict,omitempty"`
}
Tree is the consumer's policy for what may live under `work/`. AllowPaths is a list of repo-relative glob patterns (filepath.Match semantics) that exempt files from the tree-discipline check — useful for project-specific scratch dirs or templates the consumer genuinely wants alongside the entity tree. Strict promotes the `unexpected-tree-file` finding from a warning to an error so the pre-push hook blocks the push.
Default behavior (empty Tree block): contract artifact dirs are auto-exempt; everything else under work/ is reported as a warning. See docs/pocv3/design/tree-discipline.md.