okf-tool
v0.2.0
Published
Open Knowledge Format (OKF) library for TypeScript — parse, write, search, and validate OKF knowledge bundles
Maintainers
Readme
OKF Tool
A TypeScript library for working with Open Knowledge Format (OKF) knowledge bundles. Parse, write, search, and validate OKF bundles with full v0.1 specification conformance.
OKF is an open, human- and agent-friendly format for representing knowledge — combining markdown files with YAML frontmatter into a hierarchical directory tree. Read the spec →
Features
- Parse — Read OKF concept files (
.mdwith YAML frontmatter), index files, and log files - Write — Serialize concepts, indices, and logs back to valid markdown
- Search — Full-text keyword search with type/tag filtering and relevance ranking
- Validate — Check bundle conformance against the OKF v0.1 specification
- Bundle CRUD — Load, create, update, delete, and save concepts within a bundle
- Pluggable Filesystem — Works with Node.js
fs/promises(default) or in-memory storage for browsers/testing - Minimal Dependencies — Only
gray-matter(parse) andjs-yaml(serialize) at runtime
Installation
npm install okf-toolQuick Start
import { OKFBundle, createNodeFileSystem } from 'okf-tool';
// Load a bundle from disk
const fs = createNodeFileSystem();
const bundle = await OKFBundle.load('./my-knowledge-bundle', { fs });
// Read bundle info
console.log(bundle.manifest);
// { rootPath: './my-knowledge-bundle', okfVersion: '0.1', conceptCount: 42 }
// Get a specific concept
const orders = bundle.getConcept('tables/orders');
console.log(orders?.frontmatter.title); // "Customer Orders"
console.log(orders?.frontmatter.type); // "BigQuery Table"
// List concepts by type
const tables = bundle.listConcepts({ type: 'BigQuery Table' });
console.log(`${tables.length} tables found`);
// List all unique types and tags
console.log(bundle.types); // ['BigQuery Dataset', 'BigQuery Table', 'Playbook']
console.log(bundle.tags); // ['customers', 'orders', 'revenue', 'sales', ...]
// Search — keyword + filters
const results = bundle.search({
keyword: 'customer',
type: 'BigQuery Table',
tags: ['sales']
});
for (const { concept, score } of results) {
console.log(`[${score}] ${concept.frontmatter.title}`);
}
// Add a new concept
await bundle.addConcept({
id: 'tables/inventory',
filePath: 'tables/inventory.md',
frontmatter: {
type: 'BigQuery Table',
title: 'Inventory',
description: 'Warehouse inventory levels.',
tags: ['logistics', 'inventory'],
timestamp: '2026-06-22T10:00:00Z',
},
body: '# Schema\n\n| Column | Type |\n|--------|------|\n| item_id | STRING |\n',
});
// Update an existing concept
await bundle.updateConcept('tables/orders', {
frontmatter: { description: 'Updated description.' },
});
// Remove a concept
await bundle.removeConcept('tables/old_table');
// Validate the bundle
const validation = await bundle.validate();
if (!validation.isValid) {
for (const err of validation.errors) {
console.error(`${err.file}: ${err.message}`);
}
}
// Persist all changes to disk
await bundle.save();Using In-Memory Filesystem (Browser / Testing)
import { OKFBundle, MemoryFileSystem } from 'okf-tool';
const fs = new MemoryFileSystem();
// Set up a bundle in memory
await fs.writeFile('index.md', `# Concepts\n\n* [My Concept](concepts/my-concept.md)\n`);
await fs.mkdir('concepts');
await fs.writeFile('concepts/my-concept.md', `---
type: Note
title: My Concept
tags: [example]
---
# Content
This is a concept stored entirely in memory.
`);
const bundle = await OKFBundle.load('.', { fs });
const concept = bundle.getConcept('concepts/my-concept');
console.log(concept?.frontmatter.title); // "My Concept"API Reference
OKFBundle (main entry point)
class OKFBundle {
static load(rootPath: string, options?: LoadOptions): Promise<OKFBundle>;
// Reading
getConcept(id: string): Concept | undefined;
listConcepts(filter?: { type?: string; tags?: string[] }): Concept[];
conceptsByType(type: string): Concept[];
get types(): string[];
get tags(): string[];
get manifest(): BundleManifest;
// Writing (in-memory, call save() to persist)
addConcept(concept: Concept): Promise<void>;
updateConcept(id: string, updates: Partial<Pick<Concept, 'frontmatter' | 'body'>>): Promise<void>;
removeConcept(id: string): Promise<void>;
save(): Promise<void>;
saveConcept(id: string): Promise<void>;
// Search
search(query: SearchQuery): SearchResult[];
searchSimple(query: SearchQuery): Concept[];
// Index management
getIndex(dirPath?: string): IndexFile | undefined;
setIndex(dirPath: string | undefined, index: IndexFile): void;
generateIndex(dirPath?: string): IndexFile;
// Log management
getLog(dirPath?: string): LogEntry[] | undefined;
setLog(dirPath: string | undefined, entries: LogEntry[]): void;
appendLog(action: string, description: string, dirPath?: string): void;
// Validation
validate(): Promise<ValidationResult>;
// Reload from disk
reload(): Promise<void>;
}SearchQuery
| Field | Type | Description |
|-------|------|-------------|
| type | string \| string[] | Filter by exact concept type |
| tags | string[] | Filter by tags (AND — all must match) |
| keyword | string | Case-insensitive search across title, description, and body |
| titlePattern | string \| RegExp | Match concept titles |
| resource | string | Exact match on resource URI |
Standalone Functions
// Parse individual files
import { parseConcept, parseIndex, parseLog } from 'okf-tool';
//Serialize to markdown strings
import { serializeConcept, serializeIndex, serializeLog } from 'okf-tool';
// Search an array of concepts directly
import { searchConcepts, searchConceptsSimple } from 'okf-tool';
// Validate without loading a full bundle
import { validateBundle } from 'okf-tool';
// Utilities
import {
conceptIdFromPath, conceptPathFromId,
isReservedFilename, titleFromFilename,
dirname, basename, joinPath
} from 'okf-tool';OKF v0.1 Specification Summary
Each OKF bundle is a directory tree:
my-bundle/
├── index.md # Optional: directory listing / version declaration
├── log.md # Optional: chronological update history
├── datasets/
│ ├── index.md
│ └── sales.md # Concept file
└── tables/
├── index.md
├── orders.md # Concept file
└── customers.md # Concept fileConcept files (.md) have:
- YAML frontmatter between
---delimiters —typeis the only required field - Markdown body — schema, examples, citations, and cross-references
Reserved filenames (not concepts): index.md, log.md
See the full specification for details.
License
Apache-2.0
