Schema-driven framework for context management
Overcontext provides infrastructure for defining and managing custom entity schemas. Unlike a library with predefined types, overcontext lets you define your own entity schemas using Zod and provides the storage, validation, discovery, and CLI building blocks to work with them.
- Schema-Driven: Register any Zod schema, get type-safe CRUD operations
- Storage Agnostic: Filesystem and in-memory providers included
- Hierarchical Discovery: Walk directory trees to find context at multiple levels
- Namespace Support: Organize entities across multiple namespaces
- CLI Framework: Reusable command builders for creating CLIs
- Type-Safe: Full TypeScript type inference from schemas
- Observable: Event-driven patterns with storage events
npm install @utilarium/overcontext zodimport { z } from 'zod';
import { discoverOvercontext, BaseEntitySchema } from '@utilarium/overcontext';
// Define your schemas
const PersonSchema = BaseEntitySchema.extend({
type: z.literal('person'),
company: z.string().optional(),
email: z.string().email().optional(),
});
const TermSchema = BaseEntitySchema.extend({
type: z.literal('term'),
expansion: z.string().optional(),
});
// Discover context directories and create API
const ctx = await discoverOvercontext({
schemas: {
person: PersonSchema,
term: TermSchema,
},
pluralNames: {
person: 'people', // Optional: custom directory names
},
});
// Type-safe operations
const person = await ctx.create('person', {
name: 'John Doe',
company: 'Acme Corp',
email: 'john@acme.com',
});
// Search and query
const results = await ctx.search({
type: 'person',
search: 'acme',
searchFields: ['company'],
});
// Get all entities
const allPeople = await ctx.getAll('person');You define entity types using Zod schemas. Overcontext provides the infrastructure:
// You define the schema
const ProjectSchema = BaseEntitySchema.extend({
type: z.literal('project'),
status: z.enum(['active', 'completed', 'archived']),
owner: z.string(),
});
// Overcontext handles storage, validation, and operations
const ctx = await discoverOvercontext({
schemas: { project: ProjectSchema },
});Context can exist at multiple directory levels. Closer context overrides distant:
/workspace/context/ # Workspace-wide entities
/workspace/project/context/ # Project-specific (overrides workspace)
// Automatically discovers and merges context from multiple levels
const ctx = await discoverOvercontext({
schemas: { person: PersonSchema },
startDir: process.cwd(), // Starts here, walks up
});Organize entities by domain:
// Work-related entities
await ctx.create('person', { name: 'Colleague' }, { namespace: 'work' });
// Personal entities
await ctx.create('person', { name: 'Friend' }, { namespace: 'personal' });
// Query specific namespace
const workPeople = await ctx.getAll('person', 'work');- Filesystem: YAML files in directory structure
- Memory: In-memory for testing
- Hierarchical: Multi-level discovery with override behavior
- Custom: Implement your own
// Create
const entity = await ctx.create('person', {
name: 'John Doe',
company: 'Acme',
});
// Read
const person = await ctx.get('person', 'john-doe');
const allPeople = await ctx.getAll('person');
// Update
await ctx.update('person', 'john-doe', {
company: 'NewCo',
});
// Delete
await ctx.delete('person', 'john-doe');// Simple search
const results = await ctx.quickSearch('john');
// Advanced query
const results = await ctx.search({
type: ['person', 'term'],
search: 'api',
searchFields: ['company', 'expansion'],
limit: 20,
sort: [{ field: 'name', direction: 'asc' }],
});
// Query builder
import { query } from '@utilarium/overcontext';
const q = query()
.type('person')
.search('acme', ['company'])
.sortBy('name', 'desc')
.limit(10)
.build();
const results = await ctx.search(q);import { createCLIBuilder } from '@utilarium/overcontext';
const cli = createCLIBuilder({ api: ctx });
// List entities
const output = await cli.list({
type: 'person',
format: 'table',
});
console.log(output);
// Get entity
const entity = await cli.get({
type: 'person',
id: 'john-doe',
format: 'yaml',
});Full documentation: https://utilarium.github.io/overcontext/
import { z } from 'zod';
import { discoverOvercontext, BaseEntitySchema } from '@utilarium/overcontext';
// Define your domain
const PersonSchema = BaseEntitySchema.extend({
type: z.literal('person'),
company: z.string().optional(),
role: z.string().optional(),
email: z.string().email().optional(),
});
const ProjectSchema = BaseEntitySchema.extend({
type: z.literal('project'),
status: z.enum(['active', 'completed', 'archived']),
owner: z.string().optional(),
repository: z.string().url().optional(),
});
const TermSchema = BaseEntitySchema.extend({
type: z.literal('term'),
expansion: z.string(),
category: z.string().optional(),
});
// Create context
const ctx = await discoverOvercontext({
schemas: {
person: PersonSchema,
project: ProjectSchema,
term: TermSchema,
},
pluralNames: {
person: 'people',
},
});
// Use it
await ctx.create('person', {
name: 'Alice Johnson',
company: 'Acme Corp',
role: 'Engineering Manager',
email: 'alice@acme.com',
});
await ctx.create('project', {
name: 'Overcontext',
status: 'active',
owner: 'alice-johnson',
repository: 'https://github.com/utilarium/overcontext',
});
await ctx.create('term', {
name: 'API',
expansion: 'Application Programming Interface',
category: 'technology',
});
// Search across types
const results = await ctx.search({
search: 'acme',
searchFields: ['company', 'owner'],
});- Node.js >= 24.0.0
- TypeScript >= 5.0.0 (for type safety)
Apache-2.0 © Tim O'Brien