Documentation
¶
Overview ¶
Package schema loads and validates .agent-memory/meta/schema.yaml. The schema declares the categories of files the server knows about (durable decisions, modules, archive, local current/sessions, server-managed index) and the per-category policy that drives M3 approval routing and validation.
The manifest (internal/config) imports this package for ApprovalMode and references categories by name in its updates.approval block.
See docs/patterns/configuration-loading.md and design doc v0.4.1 §25.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func WriteDefault ¶
WriteDefault writes the recommended schema to schemaPath. Used by `agent-memory init` (T1.10).
func WriteSchema ¶
WriteSchema serialises s to schemaPath atomically.
Types ¶
type ApprovalMode ¶
type ApprovalMode string
ApprovalMode is the approval policy assigned to a category or (in the manifest) overridden per-operation.
const ( // ApprovalApply means writes are applied immediately after validation. ApprovalApply ApprovalMode = "apply" // ApprovalStage means writes are staged for human review via the // review/apply CLI commands. ApprovalStage ApprovalMode = "stage" // ApprovalServerOnly means agents may not write to this category at all; // the server maintains it (e.g., index.md). ApprovalServerOnly ApprovalMode = "server_only" )
func (ApprovalMode) IsValid ¶
func (m ApprovalMode) IsValid() bool
IsValid reports whether m is one of the recognised ApprovalMode values.
type Category ¶
type Category struct {
// Name is populated from the map key by populateCategoryNames() after
// load. It is NOT read from YAML directly.
Name string `yaml:"-"`
// Exactly one of File or FileGlob identifies the category's files.
File string `yaml:"file,omitempty"`
FileGlob string `yaml:"file_glob,omitempty"`
// SectionIDRequired turns on the AssignMissingIDs pass during init and
// rebuild-index for files in this category.
SectionIDRequired bool `yaml:"section_id_required,omitempty"`
// SectionSchema is the per-section structural schema (required fields,
// patterns, enums). M1 stores it verbatim; M3 will validate against it.
SectionSchema *SectionSchema `yaml:"section_schema,omitempty"`
// Approval is the default approval policy for writes to this category.
// The manifest may override per-operation in updates.approval.
Approval ApprovalMode `yaml:"approval,omitempty"`
// ServerManaged means the file is written only by the server (e.g.,
// index.md). AgentWritable must be false in this case.
ServerManaged bool `yaml:"server_managed,omitempty"`
AgentWritable bool `yaml:"agent_writable,omitempty"`
// WriteOnce means files in this category may not be modified after
// creation (e.g., archive/*.md).
WriteOnce bool `yaml:"write_once,omitempty"`
// GitTracked indicates whether agent-memory init's .gitignore should
// keep this file out of git. false here corresponds to entries in
// .agent-memory/.gitignore (current/, sessions/, etc.).
GitTracked bool `yaml:"git_tracked"`
Provenance Provenance `yaml:"provenance,omitempty"`
}
Category declares the rules for a class of memory files.
type FieldSpec ¶
type FieldSpec struct {
Name string `yaml:"name"`
Pattern string `yaml:"pattern,omitempty"`
Enum []string `yaml:"enum,omitempty"`
}
FieldSpec describes one labelled field inside a section's body (e.g., "Date: 2026-05-26").
type Provenance ¶
type Provenance struct {
Required bool `yaml:"required,omitempty"`
RequiredForNewSections bool `yaml:"required_for_new_sections,omitempty"`
AllowedSourceTypes []string `yaml:"allowed_source_types,omitempty"`
ForbiddenSourceTypes []string `yaml:"forbidden_source_types,omitempty"`
}
Provenance is the source-attribution policy for a category.
type Schema ¶
type Schema struct {
Version string `yaml:"version"`
Categories map[string]Category `yaml:"categories"`
}
Schema is the top-level deserialisation target for schema.yaml.
func DefaultSchema ¶
func DefaultSchema() *Schema
DefaultSchema returns the recommended schema from design doc v0.4.1 §25.1. The returned Schema has Category.Name populated for every entry — callers who consume *Schema directly (without going through LoadSchema) get a self-consistent struct.
func LoadSchema ¶
LoadSchema reads schema.yaml from schemaPath. The YAML is decoded into a fresh Schema, then merged INTO DefaultSchema field-by-field so partial overrides work intuitively:
- YAML mentioning one field in one category overrides only that field; the rest of the category and all other categories keep their defaults.
- User-defined categories not in defaults are accepted verbatim.
Merge semantics for individual Category fields:
- String / pointer / slice fields: empty/nil/[] in YAML means "not set"; the default is preserved.
- Bool fields: true overrides; false is treated as "not set" because Go's zero value for bool is indistinguishable from an explicit `field: false` in YAML. To flip a default-true bool to false, write the full category structure (documented limitation).
Naive yaml.v3 merge does NOT work here because it preserves only map KEYS (categories not mentioned in YAML survive), not field-level merge INTO existing map VALUES. The custom merge below handles both layers.
func (*Schema) CategoryForPath ¶
CategoryForPath returns the category whose File or FileGlob matches rel. rel must use forward slashes (the canonical form used in design and manifest examples).
Lookup order:
- Exact File match.
- FileGlob via path.Match — uses '/' as the separator on every OS, so '*' in the glob never spans directory boundaries. (path/filepath would use '\' on Windows, letting '*' eat slashes, which is wrong for our convention.)
The returned Category has Name populated from the map key, even if the Schema didn't go through populateCategoryNames() upstream. Callers can rely on Name being non-empty whenever ok == true.
Returns (Category{}, false) if no category matches.
type SectionSchema ¶
type SectionSchema struct {
RequiredTopLevelHeading bool `yaml:"required_top_level_heading,omitempty"`
PerSectionRequiredFields []FieldSpec `yaml:"per_section_required_fields,omitempty"`
PerSectionOptionalFields []FieldSpec `yaml:"per_section_optional_fields,omitempty"`
}
SectionSchema describes the required structure of an individual section within a category file. The validator that consumes these fields lands in M3; M1 only stores and round-trips them.
type SectionViolation ¶
type SectionViolation struct {
Field string // the FieldSpec.Name; empty for category-level violations
Message string // human-readable
}
SectionViolation is one rule-broken finding from ValidateSection.
func ValidateSection ¶
func ValidateSection(cat Category, sectionBody []byte) []SectionViolation
ValidateSection checks one section's body against the category's SectionSchema (required fields, patterns, enums). Returns a slice of violations; empty slice means the body conforms (or the category declares no SectionSchema, in which case anything goes).
Field parsing is intentionally simple: single-line `Name: Value` pairs. Multi-line values, indented continuations, and structured sub-fields are not supported in M3. The validator runs on the section body bytes (everything after the heading line and optional @id anchor) — the caller is responsible for slicing that out.
Examples of what gets caught for the decisions category:
## Use Postgres <!-- @id: use-postgres --> Status: active ← matched against Status enum Confidence: confirmed ← matched against Confidence enum (no Date field) ← reported as missing required field
func (SectionViolation) String ¶
func (v SectionViolation) String() string