MCP Hub
Back to servers

kalairos

Durable, private, time-aware memory engine for long-running AI agents

npm99/wk
Updated
Apr 20, 2026

Quick Install

npx -y kalairos

Kalairos

Your AI agent forgot what it knew yesterday. That's not a bug — your database just doesn't care about time.

Vector databases store embeddings. Kalairos remembers.

Your agent stores a fact. Updates it. Then asks "what was true last week?" Your vector database returns nothing — the old embedding is gone. Kalairos returns the right answer, with a full version trail showing when and why it changed.

npm install kalairos

See it work — 30 seconds, no API key

npx kalairos demo

Runs a live agent memory demo in your terminal. Zero config. Nothing written to disk.


Quick start

const kalairos = require('kalairos');

async function main() {
	await kalairos.init({
		// Bring your own embedder — any function that returns a number[]
		embedFn: async (text) => {
			const res = await fetch('https://api.openai.com/v1/embeddings', {
				method: 'POST',
				headers: {
					Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
					'Content-Type': 'application/json',
				},
				body: JSON.stringify({ model: 'text-embedding-3-small', input: text }),
			});
			return (await res.json()).data[0].embedding;
		},
	});

	const agent = kalairos.createAgent({ name: 'analyst' });

	// Store a fact
	const id = await agent.remember('Revenue target is $10M for Q3');

	// Update it — version detection is automatic, no ID needed
	await agent.remember('Revenue target revised to $12M for Q3');

	// What's current?
	const now = await agent.recall('revenue target');
	// → "Revenue target revised to $12M for Q3"

	// What was true BEFORE the revision?
	const then = await agent.recall('revenue target', {
		asOf: Date.now() - 7 * 24 * 60 * 60 * 1000, // one week ago
	});
	// → "Revenue target is $10M for Q3"

	// What changed?
	const history = await agent.getHistory(id);
	// → v1: "$10M" → v2: "$12M", delta: "Value changed: [$10m] → [$12m]"

	// Spot contradictions
	const { contradictions } = await agent.getContradictions(id);

	await kalairos.shutdown();
}

main();

Why not just use a vector database?

Vector DBKalairos
UpdatesOverwrite or duplicateAutomatic versioning
HistoryNoneFull version trail with deltas
"What was true on Jan 15?"Can't answerasOf any timestamp
ContradictionsInvisibleAuto-detected between versions
ProvenanceNot trackedWho stored it, when, from where
RetrievalCosine similaritySemantic + graph + keyword + recency
DeploymentCloud SDKLocal-first, zero cloud dependency
Embedding modelBundled or locked inBYO — any provider, any model

Benchmarks

All numbers from npm run bench — deterministic bag-of-words embedder, no API key needed. Reproducible on any machine.

MetricScoreWhat it measures
Recall@575% (finance), 50% (engineering)Fraction of relevant items in top-5 results
Precision@3100% (health)Fraction of top-3 results that are relevant
MRR1.0First relevant result appears at rank 1
Temporal accuracy100%asOf time-travel returns correct historical version
Contradiction detection100%Value changes flagged across all scenarios
Cross-session recall100%Agent B finds Agent A's memories
Noise separation3/5 finance in top-5Relevant entities ranked above unrelated noise

Constitution Goal Scorecard: 10/10 goals, 53/53 assertions passing (100%)

These numbers use a bag-of-words embedder (no neural model). With OpenAI text-embedding-3-small or Cohere embeddings, expect recall@5 > 90%. See bench/agent-memory/bench-eval-real.js for a variant that uses real embeddings.

npm run bench          # full suite (53 tests, ~300ms)
npm run bench:real     # real embeddings (requires OPENAI_API_KEY)

Agent API

createAgent() is the recommended interface. It wraps the core engine with agent identity, default classification, default tags, and a clean remember / recall / update surface.

const agent = kalairos.createAgent({
	name: 'budget-planner',
	defaultClassification: 'confidential',
	defaultTags: ['finance'],
});

await agent.remember('Q2 budget is 2.4M');
await agent.update('Q2 budget is now 2.7M');

const results = await agent.recall('Q2 budget');
const past = await agent.recall('Q2 budget', {
	asOf: Date.now() - 7 * 24 * 60 * 60 * 1000,
});

const history = await agent.getHistory(id);
const { contradictions } = await agent.getContradictions(id);
MethodWhat it does
agent.remember(text, opts?)Store or update a fact (version detection is automatic)
agent.update(text, opts?)Alias for remember — makes update intent explicit
agent.recall(text, opts?)Query memories (supports asOf for time-travel)
agent.getHistory(id)Full version history with provenance trail
agent.getContradictions(id)Versions flagged as contradictory

Agent memory workflow — token-budgeted context

Feed Kalairos memories into your agent's prompt with a token budget. This is the recommended integration pattern for production agents:

const kalairos = require('kalairos');

await kalairos.init({ embedFn: myEmbedder });
const agent = kalairos.createAgent({ name: 'assistant' });

// Store facts over time
await agent.remember('User prefers dark mode');
await agent.remember('Last deployment was v2.3.1 on March 15');

// At inference time: retrieve within a token budget
const { results, tokenUsage } = await agent.recall('user preferences', {
	maxTokens: 2000,
});
const context = results.map((r) => r.text).join('\n');
// → Feed `context` into your agent prompt

console.log(tokenUsage);
// → { budget: 2000, used: 847, resultsDropped: 0 }

For agent boot (no query needed — just the most important memories):

const { items } = await agent.boot({ maxTokens: 1000, depth: 'essential' });
const bootContext = items.map((i) => i.text).join('\n');
// → Prepend to system prompt for session continuity

Core capabilities

Versioned memory

Every update creates a version, never an overwrite. Each version records the new content, a delta summary describing the change, a timestamp, source provenance, classification, and a snapshot of graph edges at that point in time.

Time-travel queries

Use queryAt(text, timestamp) for a point-in-time snapshot, or queryRange(text, since, until) for entities whose version timeline overlaps a range. Entities that didn't exist yet are skipped. Each entity is scored against the version current at that timestamp.

// Point-in-time snapshot
const snapshot = await kalairos.queryAt(
	'raw material cost',
	new Date('2026-01-15').getTime(),
);

// Range query — entities active between these bounds
const window = await kalairos.queryRange(
	'raw material cost',
	new Date('2026-01-01').getTime(),
	new Date('2026-01-31').getTime(),
);

Contradiction detection

When a version contradicts a previous one (e.g. a price changes from $200 to $250), the delta is flagged. Agents can inspect contradictions and decide how to act.

Provenance and classification

Every entity tracks source (who created it) and classification (how sensitive it is). Query results include both so downstream systems can make trust decisions.

await kalairos.ingest('Customer requested a refund', {
	source: { type: 'tool', uri: 'support-ticket-1234' },
	classification: 'confidential',
	tags: ['support', 'billing'],
});

Retention and deletion

  • Soft delete: remove(id, { deletedBy }) — excluded from queries, preserved for audit
  • Hard delete: purge(id) — permanent erasure for right-to-erasure workflows (GDPR)
  • Retention policy: { policy: "keep" | "expire", expiresAt } per entity

Memory types and workspaces

Tag entities with memoryType ("short-term", "long-term", "working") and workspaceId for tenant isolation. Both are filterable in queries.

await kalairos.remember('Meeting notes from standup', {
	memoryType: 'short-term',
	workspaceId: 'team-alpha',
});

Hybrid scoring

Queries combine multiple signals into a final score:

  • Semantic similarity — cosine distance between embeddings
  • Graph boost — related entities via automatically discovered links
  • Keyword boost — exact term overlap
  • LLM keyword boost — when useLLM enrichment is enabled
  • Importance boost — explicit importance (0-1), LLM-derived, or auto-heuristic from version count + connectivity + contradictions
  • Recency boost — configurable half-life, disabled in asOf mode

Set importance explicitly to prioritize critical memories in tight token budgets:

await agent.remember('API key rotation policy: every 90 days', {
	importance: 0.9,
});
await agent.remember('Office wifi password is "guest123"', { importance: 0.2 });

Error signals

Structured errors that agents can subscribe to for adaptive behavior:

kalairos.onSignal('ERR_EMBEDDING_FAILED', (err) => {
	console.warn(err.message, '—', err.suggestion);
});

LLM enrichment

Pass llmFn to init() for optional metadata extraction on ingest. When useLLM: true is set, the LLM extracts keywords, context, semantic tags, and importance scores. Off by default. Failures are non-blocking.

await kalairos.init({
	embedFn: myEmbedder,
	llmFn: async (text, type) => ({
		keywords: ['budget', 'Q2'],
		context: 'Quarterly budget update',
		llmTags: ['finance', 'planning'],
		importance: 0.8,
	}),
});

await kalairos.remember('Q2 budget is 2.4M', { useLLM: true });

API reference

Lifecycle

await kalairos.init({ embedFn, llmFn?, embeddingDim?, dataFile?, ...overrides })
await kalairos.shutdown()

Write

await kalairos.remember(text, opts?)
await kalairos.ingest(text, opts?)
await kalairos.ingestBatch(items)
await kalairos.ingestFile(filePath, opts?)
await kalairos.ingestTimeSeries(label, points, opts?)

Options: { type, timestamp, metadata, tags, source, classification, retention, memoryType, workspaceId, useLLM, importance }

Read

await kalairos.query(text, { limit?, maxTokens?, filter? })
await kalairos.queryAt(text, timestamp, { limit?, maxTokens?, filter? })
await kalairos.queryRange(text, since, until, { limit?, maxTokens?, filter? })
await kalairos.get(id)
await kalairos.getMany(ids)
await kalairos.getHistory(id)
await kalairos.listEntities({ page?, limit?, type?, since?, until?, tags?, memoryType?, workspaceId? })
await kalairos.getGraph()
await kalairos.traverse(id, depth?)
await kalairos.getStatus()

Delete

await kalairos.remove(id, { deletedBy? })    // soft delete
await kalairos.purge(id)                      // permanent hard delete

Agent

const agent = kalairos.createAgent({ name, defaultClassification?, defaultTags?, useLLM? })

Signals

kalairos.onSignal(code, callback)
kalairos.getSignals(code?)

HTTP server

npx kalairos          # starts on localhost:3000

Core endpoints

MethodPathDescription
POST/ingestIngest with full options
POST/rememberAgent-facing write
POST/ingest/batchBatch ingest
POST/ingest/timeseriesTime series data
POST/ingest/fileFile ingest
POST/queryQuery with { text, limit?, filter?, asOf? }
GET/entity/:idGet entity
DELETE/entity/:idSoft delete
DELETE/entity/:id/purgePermanent hard delete
POST/entities/batchGet multiple by ID
GET/entitiesList with filters
GET/history/:idVersion history
GET/graphFull graph
GET/traverse/:idTraverse from entity
GET/statusSystem status

Agent endpoints

MethodPathDescription
POST/agent/createCreate agent { name, defaultClassification?, defaultTags?, useLLM? }
POST/agent/:agentId/rememberStore via agent
POST/agent/:agentId/updateUpdate via agent
POST/agent/:agentId/recallQuery via agent (supports asOf)
GET/agent/:agentId/history/:entityIdVersion history
GET/agent/:agentId/contradictions/:entityIdContradiction inspection

Configuration

VariableDefaultDescription
KALAIROS_LINK_THRESHOLD0.72Similarity threshold for graph linking
KALAIROS_VERSION_THRESHOLD0.82Similarity threshold for version detection
KALAIROS_GRAPH_BOOST0.01Graph relationship boost weight
KALAIROS_LLM_BOOST0.08LLM keyword boost weight
KALAIROS_IMPORTANCE_WEIGHT0.05Importance boost weight in query scoring
KALAIROS_RECENCY_WEIGHT0.10Recency boost weight
KALAIROS_RECENCY_HALFLIFE_DAYS30Recency half-life in days
KALAIROS_MIN_SCORE0.45Minimum final score for results
KALAIROS_MIN_SEMANTIC0.35Minimum semantic similarity
KALAIROS_MAX_VERSIONS0Max versions per entity (0 = unlimited)
KALAIROS_STRICT_EMBEDDINGS1Require embedder (0 to disable)
KALAIROS_PORT3000HTTP server port

Storage

  • Persisted locally to data.kalairos (configurable via dataFile)
  • Atomic writes to reduce corruption risk
  • Pass dataFile: ":memory:" for in-memory-only mode

Feedback

We'd love to hear how you're using Kalairos — what works, what's missing, what you'd build on top of it.

Reach us at main@krishnalabs.ai


License

MIT — KrishnaLabs

Reviews

No reviews yet

Sign in to write a review