Documentation
¶
Index ¶
- Constants
- Variables
- func AtomicWrite(path string, data []byte) error
- func AtomicWriteExclusive(path string, data []byte) error
- func BuildPlainMeta(filename string) domain.DocMeta
- func DeleteDoc(docsDir, filename string) error
- func ExtractFrontmatter(data []byte) (fmBytes []byte, bodyBytes []byte, err error)
- func ExtractSlug(filename string) string
- func ExtractTitle(body string, filename string) string
- func FindReferencingDocs(docsDir, filename string) ([]string, error)
- func GenerateReadmeBridge(loreDir string) error
- func GenerateReleaseNotes(version string, date string, docs []ReleaseDoc, docsDir string) (string, error)
- func Marshal(meta domain.DocMeta, body string) ([]byte, error)
- func NormalizeAfter(after string) string
- func QuickHealthCheck(docsDir string) (int, error)
- func ReadDocContent(path string) (string, error)
- func RegenerateIndex(docsDir string) error
- func Unmarshal(data []byte) (domain.DocMeta, string, error)
- func UnmarshalPermissive(data []byte) (domain.DocMeta, string, error)
- func UpdateChangelog(projectDir string, version string, date string, docs []ReleaseDoc) (bool, error)
- func UpdateReleasesJSON(loreDir string, version string, date string, docFilenames []string) error
- func ValidateFilename(filename string) error
- func ValidateMeta(meta domain.DocMeta) error
- type CorpusStore
- type DiagnosticReport
- type FixReport
- type Issue
- type PlainCorpusStore
- type ReleaseDoc
- type ReleaseEntry
- type SearchResult
- type WriteResult
Constants ¶
const ( SubkindFrontmatterMissing = "missing" SubkindFrontmatterMalformed = "malformed" )
Invalid-frontmatter subkinds. Kept as constants so callers can pattern-match on stable strings.
Variables ¶
var ( ErrFrontmatterMissing = errors.New("storage: frontmatter missing") ErrFrontmatterMalformed = errors.New("storage: frontmatter malformed") )
Typed errors returned by ExtractFrontmatter. Callers use errors.Is to distinguish between a truly-absent frontmatter block and one that is present but unparseable.
Functions ¶
func AtomicWrite ¶
AtomicWrite writes data to path via a temp file + rename for crash safety. Sets explicit 0644 permissions on the resulting file. Overwrites if exists.
func AtomicWriteExclusive ¶
AtomicWriteExclusive writes data to path via a temp file + hard link. Unlike AtomicWrite, it fails if path already exists (returns an error where os.IsExist reports true). This avoids the TOCTOU race inherent in Stat-then-Rename patterns.
func BuildPlainMeta ¶ added in v1.1.0
BuildPlainMeta creates synthetic metadata from a filename for standalone mode. Exported for use in cmd/ when a single file fails front matter parsing.
func DeleteDoc ¶
DeleteDoc removes a document from docsDir and regenerates the README index. Returns an error if the file does not exist or cannot be removed. Index regeneration errors are returned separately (wrapped with context).
func ExtractFrontmatter ¶ added in v1.2.3
ExtractFrontmatter captures the frontmatter bytes verbatim and returns them alongside the body bytes. Unlike Unmarshal, it does not parse the YAML into a DocMeta struct — it returns the raw byte regions.
This is the foundation of invariant I24 (polish FM byte-identity): a caller that subsequently writes fmBytes to disk gets back the exact bytes it received, without YAML re-serialization (which would lose key ordering, comment lines, and quote styles).
CRLF normalization matches Unmarshal: if the input contains "\r\n", it is converted to "\n" before delimiter detection, and the returned byte slices reflect the normalized form. The codebase is LF-first (enforced via .gitattributes) so the normalized form is the canonical representation.
Postcondition on success: fmBytes + bodyBytes == normalized_input.
Error semantics:
- ErrFrontmatterMissing — no "---\n" opening delimiter.
- ErrFrontmatterMalformed — opening delimiter present but the YAML block is unclosed, empty, or unparseable. The underlying yaml.Unmarshal error is wrapped via fmt.Errorf("%w: %v", ...) so callers can surface the parse detail while still matching on the sentinel via errors.Is.
func ExtractSlug ¶
ExtractSlug extracts the slug from a filename with pattern {type}-{slug}-{date}.md. Example: "decision-auth-strategy-2026-03-07.md" → "auth-strategy"
func ExtractTitle ¶ added in v1.0.0
extractTitle returns the first top-level markdown heading (# ...) from body. Falls back to the slug portion of filename (e.g. "auth-strategy" from "decision-auth-strategy-2026-03-07.md") when the body has no heading. Only matches # (h1), not ## or deeper. ExtractTitle returns the first # heading from body, or a slug from filename.
func FindReferencingDocs ¶
FindReferencingDocs returns filenames of documents whose `related:` field references the given filename (compared without .md extension).
func GenerateReadmeBridge ¶ added in v1.0.0
GenerateReadmeBridge creates .lore/README.md as a discovery bridge. Skips silently if the file already exists (user may have edited it).
func GenerateReleaseNotes ¶ added in v1.0.0
func GenerateReleaseNotes(version string, date string, docs []ReleaseDoc, docsDir string) (string, error)
GenerateReleaseNotes produces a release notes Markdown document with front matter.
func NormalizeAfter ¶
NormalizeAfter converts a YYYY-MM date to YYYY-MM-01 for lexicographic comparison. YYYY-MM-DD values pass through unchanged.
func QuickHealthCheck ¶
QuickHealthCheck performs a fast health check on the docs directory. Returns the number of issues found:
- orphan .tmp files (interrupted writes)
- missing or empty README.md index
This is NOT the full diagnostic — see lore doctor for full checks.
func ReadDocContent ¶
ReadDocContent returns the full file content (front matter + body) for display. The path argument is expected to come from SearchResult.Path (produced by SearchDocs), which constructs paths via filepath.Join(dir, entry.Name()) — never from user input.
func RegenerateIndex ¶
RegenerateIndex creates or updates the README.md index in docsDir. It scans all .md files (except README.md), parses their front matter, and generates a sorted table. The result is written atomically.
func UnmarshalPermissive ¶ added in v1.1.0
UnmarshalPermissive parses front matter + body from a document WITHOUT running ValidateMeta. Used by PlainCorpusStore (standalone mode) so external docs sites can have partial front matter (e.g. just `type` and `date`, or arbitrary types like "blog-post") without being rejected and silently downgraded to a synthetic "note" meta.
Strict validation (ValidateMeta) is only appropriate for lore-managed corpora where the commit-capture workflow is guaranteed to fill every required field.
func UpdateChangelog ¶ added in v1.0.0
func UpdateChangelog(projectDir string, version string, date string, docs []ReleaseDoc) (bool, error)
UpdateChangelog updates or creates CHANGELOG.md with a new release section. Returns (headerMissing, error). headerMissing is true when an existing CHANGELOG lacks the "# Changelog" header — callers should warn on stderr.
func UpdateReleasesJSON ¶ added in v1.0.0
UpdateReleasesJSON adds a new release entry to .lore/releases.json.
func ValidateFilename ¶
ValidateFilename rejects path traversal attempts in user-supplied filenames.
func ValidateMeta ¶
ValidateMeta checks that required fields (type, date, status) are present, that type is a recognized DocType constant, and that date is in YYYY-MM-DD format.
Types ¶
type CorpusStore ¶
type CorpusStore struct {
Dir string // path to .lore/docs/
}
CorpusStore implements domain.CorpusReader for the local filesystem.
type DiagnosticReport ¶
type DiagnosticReport struct {
Issues []Issue
DocCount int // number of valid .md documents scanned
Checked int // total number of checks performed
}
DiagnosticReport holds the results of a full corpus health check.
func Diagnose ¶
func Diagnose(docsDir string) (*DiagnosticReport, error)
Diagnose performs a comprehensive health check on the docs directory. It checks for orphan .tmp files, broken references, stale index, stale cache (metadata.json), and invalid front matter.
type FixReport ¶
type FixReport struct {
Fixed int // number of issues successfully fixed
Remaining int // number of issues that still need manual attention
Errors int // number of errors during fix (permission, etc.)
Details []string // descriptions of actions taken
}
FixReport holds the results of automatic repairs.
type Issue ¶
type Issue struct {
Category string // "orphan-tmp", "broken-ref", "stale-index", "stale-cache", "invalid-frontmatter"
// Subkind narrows an issue to a precise sub-category. Currently
// only populated for Category == "invalid-frontmatter":
// - "missing" — no "---\n" delimiter; a synthesized FM is safe
// - "malformed" — "---" present but the YAML between delimiters
// is unparseable; auto-fix would destroy
// potentially recoverable authentic content
// Story 8-22 / invariant I31: `doctor --fix` never rewrites an
// FM when the source contains a "---" delimiter — the malformed
// path surfaces a restore hint rather than synthesizing.
Subkind string
File string // file concerned
Detail string // human-readable description
AutoFix bool // repairable automatically?
}
Issue represents a single diagnostic finding.
type PlainCorpusStore ¶ added in v1.1.0
type PlainCorpusStore struct {
Dir string // path to the markdown directory
}
PlainCorpusStore implements domain.CorpusReader for any directory of Markdown files. Unlike CorpusStore, it gracefully handles files without YAML front matter, making it suitable for standalone Angela usage on non-lore projects.
func (*PlainCorpusStore) ListDocs ¶ added in v1.1.0
ListDocs scans the directory recursively for .md files and returns their metadata. Files with valid YAML front matter use the parsed metadata. Files without front matter get synthetic metadata derived from the filename and file modification time.
func (*PlainCorpusStore) ReadDoc ¶ added in v1.1.0
func (s *PlainCorpusStore) ReadDoc(id string) (string, error)
ReadDoc reads a single document by relative path (e.g., "commands/angela-polish.md"). Unlike CorpusStore.ReadDoc which only accepts flat filenames, PlainCorpusStore supports subdirectory paths for recursive standalone mode.
type ReleaseDoc ¶ added in v1.0.0
type ReleaseDoc struct {
domain.DocMeta
Title string // first # heading from body, fallback: slug from filename
}
ReleaseDoc enriches DocMeta with the document title for release notes display.
func CollectReleaseDocuments ¶ added in v1.0.0
func CollectReleaseDocuments(docsDir string, commits []string) ([]ReleaseDoc, error, error)
CollectReleaseDocuments scans docsDir for documents whose front matter commit field matches one of the given commit hashes. Documents are grouped by type and sorted by date within each group. Returns matched docs alongside any non-fatal parse errors (callers should surface these as warnings).
type ReleaseEntry ¶ added in v1.0.0
type ReleaseEntry struct {
Version string `json:"version"`
Date string `json:"date"`
Documents []string `json:"documents"`
}
ReleaseEntry represents one release in releases.json.
type SearchResult ¶
type SearchResult struct {
Filename string
Path string
Meta domain.DocMeta
Title string // first # heading from body, fallback: slug from filename
}
SearchResult represents a single search hit from SearchDocs.
func FindDocByCommit ¶
func FindDocByCommit(dir string, commitHash string) (*SearchResult, error)
FindDocByCommit searches for a document whose front matter commit field matches commitHash (strict equality — caller resolves short hashes before calling). Returns nil if no match is found.
func SearchDocs ¶
SearchDocs searches documents matching keyword (case-insensitive) in filename, tags, and body, then applies type and date filters from DocFilter. Returns results sorted by date descending.
type WriteResult ¶
type WriteResult struct {
Filename string // e.g. "decision-auth-strategy-2026-03-07.md"
Path string // e.g. "/path/to/.lore/docs/decision-auth-strategy-2026-03-07.md"
// Deprecated: always nil — callers should call RegenerateIndex explicitly.
IndexErr error
}
WriteResult contains the outcome of a WriteDoc operation.
func WriteDoc ¶
WriteDoc creates a document in the given directory via AtomicWrite. subject is used for the filename slug (e.g., "add JWT middleware" → "add-jwt-middleware"). After writing, it regenerates the README index. Index errors are surfaced in WriteResult.IndexErr but do not cause WriteDoc itself to fail.