docs/library.mdtype: Reference

One type per spec concern.

The OKF4net namespace mirrors the spec: Bundle (§3), ConceptId (§2), OkfDocument/Frontmatter (§4), links (§6, §13.1), IndexGenerator (§8), ChangeLog (§9), BundleValidator (§11). Zero third-party dependencies — the YAML subset and link scanner are the library's own.

##

At a glance

load · validate · traverse
using OKF4net;

var bundle = Bundle.Load("./my_bundle");           // §3 — permissive walk
var report = BundleValidator.Validate(bundle);      // §11 — diagnostics
Console.WriteLine(report.IsConformant
    ? $"conformant with OKF v{OkfSpec.Version}" : $"{report.ErrorCount} error(s)");

var id = ConceptId.Parse("tables/orders");        // §2
foreach (var link in bundle.LinksFrom(id))          // §6
    Console.WriteLine($"{id} -> {link.Target} (exists: {link.Exists})");
foreach (var back in bundle.Backlinks(id))
    Console.WriteLine($"cited by {back}");
##

Bundle

§3 — a directory of concepts

Bundle.Load walks the tree, parses every concept, and builds the cross-link graph. It is permissive: a bad file lands in ParseErrors and never aborts the load.

MemberDescription
Load(string root) → BundleWalk a directory and build the graph. Throws BundleLoadException only when the root itself is unreadable.
Root → stringThe bundle's root path.
Concepts → IReadOnlyList<Concept>All parsed concepts, in component-wise walk order.
Count → int · IsEmpty → boolNumber of concepts.
Get(ConceptId) → Concept?Look up one concept; null if absent.
Contains(ConceptId) → boolWhether the id resolves.
LinksFrom(ConceptId) → IReadOnlyList<ResolvedLink>Outgoing links, each flagged Exists.
Backlinks(ConceptId) → IReadOnlyList<ConceptId>Concepts that link to this one.
BrokenLinks() → IReadOnlyList<(ConceptId, string)>Every edge to a missing concept.
IndexFiles · LogFiles → IReadOnlyList<string>Reserved index.md / log.md paths found.
ParseErrors → IReadOnlyList<(string Path, string Error)>Files that failed to parse, with why.
ConceptRecord: Id, Path, Document.
##

ConceptId

§2 — id ↔ path

A concept id is the file path with .md removed, as ordered segments. Sortable and value-equal.

MemberDescription
Parse(string) → ConceptIdParse "tables/orders"; throws ConceptIdException on an invalid segment.
TryParse(string, out ConceptId?) → boolNon-throwing parse.
FromPath(root, path) → ConceptIdDerive an id from a file path under a bundle root.
ToPath(root) → stringInverse: the .md file path under a root.
Segments → IReadOnlyList<string>The path components.
Name → string · Parent → ConceptId?Last segment; id of the containing directory.
ValidateSegment(string)Throw if a single segment is not spec-legal.
Slugify(string) → stringDerive a spec-legal segment from a free-form title, for a producer minting new concept ids.
##

OkfDocument & Frontmatter

§4 — one concept

Frontmatter keeps the full ordered mapping and layers typed getters on top, so producer-defined keys survive round-trips. Two validation levels: ValidateConformance() enforces only §11 (non-empty type); Validate() is the stricter producer check (type, title, description, timestamp).

OkfDocumentDescription
Parse(string) → OkfDocumentParse frontmatter + body; throws DocumentParseException.
TryParse(string, out doc, out error) → boolNon-throwing parse.
Serialize() → stringRe-emit; preserves key order and unknown keys.
Validate() · ValidateConformance()Producer check / §11 check; throw DocumentValidationException.
Links() → IReadOnlyList<ConceptLink>Markdown links in the body.
Citations() → IReadOnlyList<Citation>Numbered citations in the body.
Frontmatter → Frontmatter · Body → stringThe two halves of the document.
OkfDocumentBuilder.ForType(string) → …→ Build() → OkfDocumentA fluent, in-memory builder (Title/Description/Resource/Tags/AddSource/Extension/Body) for a producer constructing a concept from scratch, without a serialize/re-parse round trip through YAML text.
FrontmatterDescription
Type · Title · Description · Resource · Timestamp → string?Typed getters over the mapping.
Tags → IReadOnlyList<string>The tags sequence, or empty.
ExtensionKeys → IReadOnlyList<string>Producer-defined keys beyond the reserved set.
AsMapping() → YamlMappingThe underlying ordered mapping.
Set(string, YamlValue) · FromMapping(YamlMapping)Mutate a key / wrap an existing mapping.
Sources → IReadOnlyList<Source> · UsageWindow → UsageWindow?The §5.1 sources list and its shared sibling usage_window.
EffectiveUsageWindow(Source) → UsageWindow?The §5.1 window framing one entry's usage_count: that entry's own usage_window if it has one, else the shared sibling — the entry wins whole-object, never per-bound.
Generated → Stamp? · Verified → IReadOnlyList<Stamp>The §5.2 generated/verified stamps.
TrustTier → TrustTierDerived from Verified (§5.3) — see the provenance, trust & lifecycle chapter below.
Lifecycle → LifecycleThe §5.4/§5.5 status/stale_after pair, as one value.
GeneratedAt → string? · LastChangedAt → string?Generated?.At, and its §13.1 fallback to the legacy Timestamp.
##

Provenance, trust & lifecycle

§5 — new in v0.2

Five small, dependency-free value types, added for v0.2 and shared by the core, Agents, and Catalog. Every accessor is lenient: a malformed field yields a default or empty value rather than throwing — judgment is left entirely to BundleValidator (§11), never made at parse time.

TypeDescription
Actor(Raw, Kind, Id, Producer, Version, IsWellFormed)The §7 actor convention. Actor.Parse(string) reads human:<id>/process:<id>/<producer>/<version>, never throws; IsHuman drives trust.
Stamp(By, At) · TrustTierOne { by, at } stamp (§5.2), and the derived tier (§5.3): Unverified / MachineConfirmed / HumanReviewed — human iff any verifier's By.IsHuman.
Source(Id, Resource, Title, Author, UsageCount, LastModified, UsageWindow) · UsageWindow(From, To)One §5.1 sources[] entry, and the usage_window that frames usage_count — shared as a sibling of sources, or carried by a single entry as its own override. The override replaces the shared window whole, so read it through Frontmatter.EffectiveUsageWindow.
Provenance.ToYaml(IEnumerable<Source>) → YamlSequenceThe serialize direction of Frontmatter.Sources' parse — for a producer building sources from scratch rather than editing an existing document.
Lifecycle(Status, StatusIsKnown, StaleAfterRaw, StaleAfter) · ConceptStatus§5.4/§5.5. Absent statusStable; IsStale(DateTimeOffset) is now >= stale_after. §5 makes stale_after an absolute instant, so StaleAfter is a DateTimeOffset?; the legacy date-only form is still read, normalized to midnight UTC and flagged by StaleAfterIsLegacyDate.
StalePolicy(Mode, GraceDays)A consumer's policy for stale concepts: Use (admit everything, the default), Strict (exclude), Tolerate(graceDays). Admits(Lifecycle, DateTimeOffset) is the one method both Agents and Catalog call.
IOkfClock · SystemClock · FixedClockDateTimeOffset Now and DateOnly Today, injected wherever "now" matters. Staleness compares Now (§5 makes stale_after an instant); Today is for display, such as an audit report's stamp. Now is a default interface member derived from Today, so a clock written before it existed still compiles. SystemClock for real time, FixedClock to pin it — it takes either a DateTimeOffset or a DateOnly (which pins midnight UTC). Every API taking a clock (BundleValidator.Validate, ConceptAudit.Run) exists so staleness (§5.5) can be made reproducible, in your own code as much as in ours.
##

Shared with Agents & Catalog

one implementation, three consumers
TypeDescription
BundleConceptWriterAtomic, per-path-locked, reparse-guarded concept writes — WriteConcept/AppendToConceptAtomic, plus a Frontmatter-typed WriteConcept overload for a caller building a document programmatically (e.g. with OkfDocumentBuilder), no YAML text round trip. The primitive behind okf_write_concept and the scoped memory store; see docs/agents.md.
ConceptSearchSearch(concepts, query, tag?) — title ×3, tags/description ×2, body ×1. The one scorer behind okf_search and the local catalog resolver; see docs/catalog.md.
ConceptAudit · AuditVocabularyRun(bundle, query?, clock?) — the corpus-level query over §5.3–§5.5 signals behind both okf audit and the okf_audit tool. Counts describe the whole bundle, findings describe the selection; AuditVocabulary is the one spelling of the trust, status and freshness labels every surface renders.
##

The YAML subset

Yaml — frontmatter only

A documented subset: scalars, sequences, shallow maps, block and flow styles, |/> block scalars. It rejects anchors, tags, and multi-document streams with clear errors — frontmatter never needs them.

MemberDescription
YamlValue.Parse(string) → YamlValueParse the subset; throws YamlParseException (with a line number).
YamlEmitter.Emit(YamlValue) → stringSerialize back to the same subset.
AsString() · AsBool() · AsSequence() · AsMapping()Typed views; null if the node is another kind.
ToYamlString() → stringEmit a single value.
YamlMapping: Get · ContainsKey · Entries · Keys · CountOrder-preserving map access.
##

IndexGenerator & ChangeLog

§8, §9 — reserved files
MemberDescription
IndexGenerator.RegenerateIndexes(root) → IReadOnlyList<string>Write every index.md; returns the paths written.
RegenerateIndexesWith(root, Synthesize)Same, with a custom description synthesizer.
BuildIndexText(entries) → stringRender one listing without touching disk.
IndexEntry(Type, Title, Link, Description)One row of a generated index.
ChangeLog: Days · Title · ToMarkdown() · InvalidDates()Parse / render a log.md (§9); IsIsoDate(s) validates a date.
LogDay(Date, Entries) · LogEntry(Kind, Text)A day's block and one entry.
##

Validation

§11 — conformance
MemberDescription
BundleValidator.Validate(Bundle) → ValidationReportRun the §11 conformance check.
ValidationReport.IsConformant → boolTrue when there are no Error diagnostics.
Diagnostics → IReadOnlyList<Diagnostic>Every finding; Of(severity) filters.
ErrorCount · WarningCount → intTallies by severity.
Diagnostic(Severity, Path, Concept, Message)One finding; ToString() is the CLI line.
SeverityEnum: Error, Warning, Info.
OkfSpec.Version → stringThe implemented spec version ("0.2").
##

Errors

one base exception

Every library exception derives from OkfException, so one catch covers the surface. Loading is permissive, so most day-to-day work throws nothing — failures accumulate in ParseErrors instead.

ExceptionThrown by
OkfExceptionBase type for all of the below.
ConceptIdExceptionConceptId.Parse / ValidateSegment.
BundleLoadExceptionBundle.Load, when the root is unreadable.
DocumentParseExceptionOkfDocument.Parse.
DocumentValidationExceptionValidate / ValidateConformance.
YamlParseExceptionThe YAML subset parser (carries a Line).

cli.md — the same engine as a binary · getting-started.md