Cross-Agent Context Sharing
SQLite-backed context sharing between agents with versioning, channels, encryption, and pub/sub transport.
When multiple agents work on the same project, they need to share decisions, assumptions, and constraints. Nella’s context sharing system provides a SQLite-backed store with versioning, channels, visibility controls, and real-time pub/sub — so agents stay coordinated without stepping on each other.
How It Works
- Agent A publishes a decision: “Using JWT with RS256 for API auth”
- Agent B queries the context channel and sees the decision before writing auth code
- If Agent B tries to contradict the decision, Nella flags the conflict
import { createContextManager } from '@usenella/core';
const ctx = createContextManager({
workspaceId: 'my-project',
agentId: 'agent-alpha',
transport: 'local', // or 'supabase' for cross-machine
});
// Share a decision
await ctx.setDecision('jwt-auth', 'Use JWT with RS256 for all API endpoints');
// Another agent reads it
const decisions = await ctx.getDecisions();
// → [{ key: 'jwt-auth', value: 'Use JWT with RS256...', sourceAgentId: 'agent-alpha' }]
Context Types
Every context entry has a type that determines how it’s used:
| Type | Description | Example |
|---|---|---|
string | Free-form text | Notes, comments |
number | Numeric value | Version numbers, thresholds |
boolean | Flag | Feature toggles |
object | Structured data | Configuration objects |
array | List data | File lists, dependency lists |
code | Code snippet | Implementation references |
snippet | Short code excerpt | Pattern examples |
decision | Architectural decision | ”Use PostgreSQL over MySQL” |
dependency | Dependency info | ”Requires zod ^3.22” |
preference | Coding preference | ”Use early returns” |
Convenience Methods
// Type-specific setters
await ctx.setSnippet('auth-pattern', 'const token = jwt.sign(...)');
await ctx.setDecision('db-choice', 'PostgreSQL for JSONB support');
await ctx.setDependency('zod', '{ version: "^3.22", reason: "Schema validation" }');
await ctx.setPreference('error-handling', 'Use Result types over try/catch');
// Type-specific getters
const snippets = await ctx.getSnippets();
const decisions = await ctx.getDecisions();
const dependencies = await ctx.getDependencies();
Visibility Levels
Control who can see each context entry:
| Level | Scope | Use Case |
|---|---|---|
private | Only the publishing agent | Internal working notes |
workspace | All agents in the workspace | Project-level decisions |
shared | All agents on the channel | Cross-team coordination |
global | All agents everywhere | Organization-wide standards |
Channels
Channels partition context into logical groups. Each channel has its own settings:
// Create a channel
await ctx.createChannel({
name: 'backend-team',
description: 'Backend API development context',
allowedAgents: ['agent-alpha', 'agent-beta'],
settings: {
maxEntries: 1000, // Max entries per channel
defaultTtl: 3600, // Default TTL in seconds (0 = no expiry)
autoCleanup: true, // Remove expired entries automatically
},
});
// Publish to a channel
await ctx.set('rate-limit-decision', 'Token bucket at 100 req/min', {
type: 'decision',
channel: 'backend-team',
visibility: 'shared',
});
// Query a channel
const entries = await ctx.query({
channelId: 'backend-team',
types: ['decision', 'dependency'],
limit: 20,
});
Versioning
Every update creates a new version. You can inspect history and roll back:
// Get version history
const versions = await ctx.getVersions('jwt-auth');
// → [{ version: 3, value: '...', updatedAt: '...' }, ...]
// Rollback to a previous version
await ctx.rollback('jwt-auth', 1); // Roll back to version 1
- Max versions: 50 per entry (configurable)
- Pruning: Oldest versions are automatically pruned when the limit is reached
Optimistic Concurrency
Context entries use ETags (SHA-256 of the serialized value) for conflict detection:
try {
await ctx.set('api-design', 'REST with versioned paths', { etag: 'abc123' });
} catch (err) {
if (err instanceof ContextConflictError) {
// Another agent updated this entry since you last read it
const latest = await ctx.get('api-design');
// Resolve conflict and retry...
}
}
Search
Three search modes for finding context entries:
| Mode | Description | Use Case |
|---|---|---|
substring | Case-insensitive LIKE search | Exact phrase matching |
regex | Regular expression matching | Pattern matching |
fuzzy | Jaro-Winkler similarity (threshold: 0.8) | Typo-tolerant search |
const results = await ctx.search('authentication', { mode: 'fuzzy' });
Encryption
Sensitive context entries can be encrypted at rest using AES-256-GCM:
await ctx.set('api-secret', 'sk_live_abc123', {
encrypted: true,
});
// Stored as: iv:authTag:encryptedData (base64)
Transport Layer
The pub/sub system supports pluggable transports:
Local Transport (default)
In-process Map<channel, Set<handler>>. Best for single-machine setups where multiple agents run in the same process or connect via MCP.
Supabase Transport
Uses Supabase Realtime broadcast for cross-machine context sharing. Agents on different machines can share context in real-time.
const ctx = createContextManager({
workspaceId: 'my-project',
agentId: 'agent-remote',
transport: 'supabase',
supabaseUrl: process.env.SUPABASE_URL,
supabaseKey: process.env.SUPABASE_KEY,
});
Database
Context is stored in SQLite (via better-sqlite3) with WAL mode for concurrent reads:
- Tables:
context_entries,context_versions,context_channels,context_meta - Indexes: 7 covering workspace_id, key, channel_id, expires_at, type, entry_id
- Prepared statements: 18 pre-compiled for performance
MCP Integration
The shipped @getnella/mcp package exposes session-oriented context tools, not the full channel publishing surface from the core library.
Today the public MCP surface includes:
nella_get_context— Inspect the current session context, assumptions, dependency snapshot, and trust-chain challengenella_add_assumption— Record an assumption during the current tasknella_check_assumptions— Review assumption validitynella_check_dependencies— Detect dependency drift
If you need multi-agent channel publishing, use SharedContextManager programmatically from @usenella/core in your own runtime. See the MCP Tools Overview for the shipped tool reference.
Events
The context manager emits 11 event types for real-time monitoring:
| Event | Description |
|---|---|
entry:created | New context entry added |
entry:updated | Context entry modified |
entry:deleted | Context entry removed |
entry:expired | TTL reached, entry cleaned up |
entry:expiring | Warning: entry expires in < 60 seconds |
version:created | New version snapshot saved |
version:pruned | Old versions pruned past limit |
channel:created | New channel created |
channel:deleted | Channel removed |
conflict:detected | Optimistic concurrency conflict |
transport:error | Pub/sub transport failure |
Import / Export
Context snapshots can be exported and imported for workspace migration:
// Export everything
const snapshot = await ctx.export();
// { entries, versions, channels, schemaPatterns }
// Import with merge strategy
await ctx.import(snapshot, { strategy: 'merge' });
// Strategies: 'merge' | 'replace' | 'skip-existing'
Tip
Combine context sharing with Cloud Sync to persist context across machines automatically.