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 · traverseusing 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 conceptsBundle.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.
| Member | Description |
|---|
| Load(string root) → Bundle | Walk a directory and build the graph. Throws BundleLoadException only when the root itself is unreadable. |
| Root → string | The bundle's root path. |
| Concepts → IReadOnlyList<Concept> | All parsed concepts, in component-wise walk order. |
| Count → int · IsEmpty → bool | Number of concepts. |
| Get(ConceptId) → Concept? | Look up one concept; null if absent. |
| Contains(ConceptId) → bool | Whether 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. |
| Concept | Record: Id, Path, Document. |
##
ConceptId
§2 — id ↔ pathA concept id is the file path with .md removed, as ordered segments. Sortable and value-equal.
| Member | Description |
|---|
| Parse(string) → ConceptId | Parse "tables/orders"; throws ConceptIdException on an invalid segment. |
| TryParse(string, out ConceptId?) → bool | Non-throwing parse. |
| FromPath(root, path) → ConceptId | Derive an id from a file path under a bundle root. |
| ToPath(root) → string | Inverse: 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) → string | Derive a spec-legal segment from a free-form title, for a producer minting new concept ids. |
##
OkfDocument & Frontmatter
§4 — one conceptFrontmatter 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).
| OkfDocument | Description |
|---|
| Parse(string) → OkfDocument | Parse frontmatter + body; throws DocumentParseException. |
| TryParse(string, out doc, out error) → bool | Non-throwing parse. |
| Serialize() → string | Re-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 → string | The two halves of the document. |
| OkfDocumentBuilder.ForType(string) → …→ Build() → OkfDocument | A 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. |
| Frontmatter | Description |
|---|
| 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() → YamlMapping | The 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 → TrustTier | Derived from Verified (§5.3) — see the provenance, trust & lifecycle chapter below. |
| Lifecycle → Lifecycle | The §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.2Five 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.
| Type | Description |
|---|
| 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) · TrustTier | One { 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>) → YamlSequence | The 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 status ⇒ Stable; 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 · FixedClock | DateTimeOffset 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| Type | Description |
|---|
| BundleConceptWriter | Atomic, 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. |
| ConceptSearch | Search(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 · AuditVocabulary | Run(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 onlyA 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.
| Member | Description |
|---|
| YamlValue.Parse(string) → YamlValue | Parse the subset; throws YamlParseException (with a line number). |
| YamlEmitter.Emit(YamlValue) → string | Serialize back to the same subset. |
| AsString() · AsBool() · AsSequence() · AsMapping() | Typed views; null if the node is another kind. |
| ToYamlString() → string | Emit a single value. |
| YamlMapping: Get · ContainsKey · Entries · Keys · Count | Order-preserving map access. |
##
Links & citations
§6, §13.1 — the graph edges| Member | Description |
|---|
| LinkScanner.ExtractLinks(body) → IReadOnlyList<ConceptLink> | Markdown links, classified by LinkKind. |
| LinkScanner.ExtractCitations(body) → IReadOnlyList<Citation> | Numbered [n] citations. |
| ConceptLink(Text, Target, Kind) | A link; Resolve(source) → ConceptId? turns it into a target id. |
| ResolvedLink(Target, Exists, Text, Raw) | A link resolved against the bundle — Exists tells you if the target is real. |
| Citation(Number, Text, Target, Raw) | One numbered citation. |
| LinkKind | Enum: absolute vs relative link classification. |
##
IndexGenerator & ChangeLog
§8, §9 — reserved files| Member | Description |
|---|
| IndexGenerator.RegenerateIndexes(root) → IReadOnlyList<string> | Write every index.md; returns the paths written. |
| RegenerateIndexesWith(root, Synthesize) | Same, with a custom description synthesizer. |
| BuildIndexText(entries) → string | Render 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| Member | Description |
|---|
| BundleValidator.Validate(Bundle) → ValidationReport | Run the §11 conformance check. |
| ValidationReport.IsConformant → bool | True when there are no Error diagnostics. |
| Diagnostics → IReadOnlyList<Diagnostic> | Every finding; Of(severity) filters. |
| ErrorCount · WarningCount → int | Tallies by severity. |
| Diagnostic(Severity, Path, Concept, Message) | One finding; ToString() is the CLI line. |
| Severity | Enum: Error, Warning, Info. |
| OkfSpec.Version → string | The implemented spec version ("0.2"). |
##
Errors
one base exceptionEvery 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.
| Exception | Thrown by |
|---|
| OkfException | Base type for all of the below. |
| ConceptIdException | ConceptId.Parse / ValidateSegment. |
| BundleLoadException | Bundle.Load, when the root is unreadable. |
| DocumentParseException | OkfDocument.Parse. |
| DocumentValidationException | Validate / ValidateConformance. |
| YamlParseException | The YAML subset parser (carries a Line). |
→ cli.md — the same engine as a binary · getting-started.md