config

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: May 21, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

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

View Source
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.

View Source
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.

View Source
const DefaultHTMLOutDir = "site"

DefaultHTMLOutDir is the path the renderer falls back to when aiwf.yaml.html.out_dir is unset.

View Source
const FileName = "aiwf.yaml"

FileName is the canonical filename at the consumer repo root.

Variables

View Source
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.

View Source
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

func StripLegacyActor(root string) (changed bool, err error)

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

func StripLegacyAiwfVersion(root string) (changed bool, err error)

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.

func Write

func Write(root string, cfg *Config) error

Write marshals cfg to root/aiwf.yaml. Refuses to overwrite an existing file — callers (notably `aiwf init`) decide what to do when one is already there.

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

func Load(root string) (*Config, error)

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

func (c *Config) AllocateTrunkRef() (ref string, explicit bool)

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

func (c *Config) ArchiveSweepThreshold() (n int, set bool)

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

func (c *Config) EntityTitleMaxLength() int

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

func (c *Config) HTMLOutDir() string

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

func (c *Config) StatusMdAutoUpdate() bool

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

func (c *Config) Validate() error

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.

Jump to

Keyboard shortcuts

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