@subcortex-ai/sdk
v0.21.0
Published
Cognitive infrastructure for AI agents. A persistent, portable cognitive layer that travels with your agents — provenance, confidence, and temporal awareness baked into every assertion.
Downloads
3,360
Maintainers
Readme
@subcortex-ai/sdk
SubCortex — Cognitive infrastructure for AI agents. A persistent, portable cognitive layer that travels with your agents. More than memory — provenance, confidence, and temporal awareness baked into every assertion. Ship personality without deploys. Every session builds on every session before it.
Install
npm install @subcortex-ai/sdkQuick Start
import { SubCortexClient } from '@subcortex-ai/sdk'
const subcortex = new SubCortexClient({
endpoint: 'https://your-subcortex-instance.com',
tenantId: 'your-tenant-id',
apiKey: 'scx_live_...',
})
// Store a fact about a user
await subcortex.assertions.create({
subject: 'user:alice',
predicate: 'role',
value: 'Engineering Manager',
confidence: 0.99,
})
// Query everything known about a subject
const facts = await subcortex.assertions.query('user:alice')
// Identify a returning user — memories, reminders, conflicts, signals, all in one call
const user = await subcortex.users.identify({ userId: 'alice', displayName: 'Alice Smith' })
// Record an emotional signal
await subcortex.signals.record({
userId: 'alice',
type: 'frustration',
content: 'Frustrated about the hiring timeline slipping',
intensity: 0.8,
resolveConflicting: false,
})
// Record a positive signal and automatically resolve prior negative ones on the same subject
await subcortex.signals.record({
userId: 'alice',
type: 'satisfaction',
content: 'Excited — found a great candidate',
intensity: 0.85,
resolveConflicting: true,
})
// Check server health
const health = await subcortex.health()API Reference
new SubCortexClient(options)
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| endpoint | string | Yes | — | Base URL of the SubCortex REST API |
| tenantId | string | Yes | — | Tenant ID for all operations |
| apiKey | string | No* | — | API key (scx_live_...) |
| token | string | No* | — | JWT token (alternative to apiKey) |
| retry | object | No | { maxRetries: 3, baseDelayMs: 500, maxDelayMs: 10000 } | Retry config |
| timeoutMs | number | No | 30000 | Request timeout in ms |
| fetch | typeof fetch | No | globalThis.fetch | Custom fetch (for testing / Cloudflare Workers) |
| headers | Record<string, string> | No | {} | Custom headers added to every request |
| agentScope | string | No | — | Act as one agent: reads see shared knowledge plus this agent's private beliefs |
| userScope | string | No | — | Act for one user: reads become default-deny to that user's subjects |
*At least one of apiKey or token should be provided for authenticated requests.
The API key decides the tenant. tenantId names it in request paths; a client configured with another tenant's id still reaches only the key's tenant. agentScope and userScope narrow what a client sees inside that tenant; without them a client sees the whole tenant.
Assertions
subcortex.assertions.create({ subject, predicate, value, confidence? })
subcortex.assertions.get(assertionId)
subcortex.assertions.query(subject)
subcortex.assertions.list()
subcortex.assertions.supersede({ originalAssertionId, subject, predicate, value })
subcortex.assertions.retract(assertionId)Relationships
subcortex.relationships.create({ fromSubject, toSubject, relationshipType, confidence? })
subcortex.relationships.query(subject)
subcortex.relationships.list()Agents
subcortex.agents.create({ name, description, personality, instructions, model, capabilities, memoryPolicy })
subcortex.agents.get(agentId)
subcortex.agents.update(agentId, input)
subcortex.agents.delete(agentId)
subcortex.agents.list()
subcortex.agents.getInstructions(agentId) // returns composed system promptMemory
// Routes through Thalamus pipeline (dedup, conflict detection) by default
subcortex.memory.store({ subject, predicate, value, agentId })
// Bypass Thalamus for bulk imports
subcortex.memory.store({ subject, predicate, value, raw: true })
subcortex.memory.recall(subject)
subcortex.memory.forget(assertionId)Users
// Full user context in one call — memories, reminders, conflicts, signals, connected people
const user = await subcortex.users.identify({ userId, displayName?, agentId? })
// Register a person the user mentioned, with role and bidirectional relationships
await subcortex.users.registerPerson({ name, userId, relationship, role?, confidence? })
// Record a rapport signal about the user (legacy — prefer signals.record)
await subcortex.users.recordRapport({ userId, type, value, aboutPerson? })
// Dismiss a surfaced reminder
await subcortex.users.dismissReminder(userId, reminderContent)Signals
// Record an emotional signal
await subcortex.signals.record({
userId,
type, // 'frustration' | 'excitement' | 'concern' | 'satisfaction' | 'confusion' | 'gratitude' | 'tension' | 'sentiment'
content,
intensity?, // 0–1, default 0.7
aboutSubject?, // e.g. 'person:sarah-johnson', 'context:hiring'
resolveConflicting?, // true = auto-resolve prior negative signals on the same subject
})
// Query signals for a user with decay and trajectory
const snapshot = await subcortex.signals.query('user:alice', { windowHours: 72, type?: 'frustration' })
// snapshot.signals, snapshot.trajectory ('warming'|'cooling'|'stable'|'neutral'), snapshot.aggregateIntensity
// Manually resolve a signal
await subcortex.signals.resolve({ signalId, resolvedBySignalId })Intake (Thalamus)
// Submit candidate assertions for pipeline processing
const result = await subcortex.intake.submit({ correlationId, agentId, candidates, context? })
// result.accepted, result.reinforced, result.conflicts, result.rejected, result.items
// Poll for pending results (conflicts, clarification requests)
const pending = await subcortex.intake.pending(agentId, { status?, limit? })
subcortex.intake.acknowledge(itemId)
subcortex.intake.acknowledgeAll(agentId)
subcortex.intake.stats(agentId)Decisions
The decision corpus: the typed judgments a host asked for and what each turned out to be, written once and never changed. Outcomes are their own rows pointing at a decision by id; calibration is the join.
// Append at a turn boundary. Ids are host-minted; a retried batch is skipped, never duplicated.
await subcortex.decisions.record({ decisions: [...], outcomes: [...] })
// Read back, newest first — for review, or for compiling a policy.
const rows = await subcortex.decisions.list({ question: 'interaction.turn-complete', policy: 'baseline/v1' })
const outcomes = await subcortex.decisions.outcomes({ policy: 'baseline/v1' })The engine stamps this client's userScope and agentScope onto every row it writes and applies the same visibility rule as beliefs on reads. The scope inside each record is the host's own partition key: stored verbatim, never used to authorize.
// The reliability curve, computed by the engine — no rows leave it.
const curve = await subcortex.decisions.calibration({ question: 'interaction.turn-complete' })
// The compiled reflex policy for this client's scope (Striatum). Fetch at session start, cache it.
const policy = await subcortex.decisions.reflexPolicy()A threshold in the policy is measured from the corpus or it is the conservative baseline; the version is baseline/v1 until the corpus earns a measured one.
Schema Helpers
import {
SubjectPrefix, subject,
ConfidenceLevel, ConfidenceScores, confidenceToScore, scoreToConfidence,
Predicates, OrgRelationship, EntityRelationship,
POSITIVE_SIGNALS, NEGATIVE_SIGNALS,
SYSTEM_SIGNAL_TYPES,
} from '@subcortex-ai/sdk'
// Build subject strings
subject(SubjectPrefix.USER, 'alice') // → 'user:alice'
subject(SubjectPrefix.PERSON, 'Sarah Johnson') // → 'person:sarah-johnson'
// Confidence levels
confidenceToScore(ConfidenceLevel.CONFIRMED) // → 0.99
confidenceToScore('high') // → 0.85
scoreToConfidence(0.72) // → ConfidenceLevel.MODERATEContext Formatting
import { toContextXml } from '@subcortex-ai/sdk'
const user = await subcortex.users.identify({ userId })
const xml = toContextXml(user) // Inject into LLM system promptError Handling
import {
SubCortexNotFoundError,
SubCortexValidationError,
SubCortexConflictError,
SubCortexRateLimitError,
SubCortexServerError,
SubCortexNetworkError,
SubCortexTimeoutError,
} from '@subcortex-ai/sdk'
try {
await subcortex.assertions.get('nonexistent-id')
} catch (error) {
if (error instanceof SubCortexNotFoundError) {
console.log('Not found')
} else if (error instanceof SubCortexRateLimitError) {
console.log(`Rate limited — retry after ${error.retryAfter}s`)
} else if (error instanceof SubCortexNetworkError) {
console.log('SubCortex unreachable')
}
}All errors extend SubCortexError with:
statusCode— HTTP status (0 for network/timeout errors)requestId— server-assigned ID for debuggingretryable— whether the SDK will retry automatically
Retry & Timeout
Requests automatically retry on 5xx errors and network failures with exponential backoff + jitter. 429 respects the Retry-After header. 4xx errors are never retried.
const subcortex = new SubCortexClient({
endpoint: 'https://api.subcortex.example.com',
tenantId: 'my-tenant',
apiKey: 'scx_live_...',
retry: { maxRetries: 5, baseDelayMs: 1000, maxDelayMs: 30000 },
timeoutMs: 60000,
})Framework Integration
Next.js (App Router)
Next.js patches globalThis.fetch with aggressive caching. GET requests — including assertion queries, user identification, and signal snapshots — will return stale data unless you bypass the cache. This is critical for cognitive data that changes between sessions.
// app/api/my-agent/route.ts
const noCacheFetch: typeof fetch = (input, init) =>
fetch(input, { ...init, cache: 'no-store' })
const subcortex = new SubCortexClient({
endpoint: process.env.SUBCORTEX_ENDPOINT!,
tenantId: process.env.SUBCORTEX_TENANT_ID!,
apiKey: process.env.SUBCORTEX_API_KEY,
fetch: noCacheFetch, // ← Required in Next.js
})Without this, users.identify(), assertions.query(), and signals.query() may return cached results — meaning new assertions added between sessions (by other agents, users, or the SubCortex console) will be invisible until a hard page refresh.
What is SubCortex?
SubCortex is a purpose-built cognitive engine for AI agents — persistent memory, identity, emotional signals, and knowledge graph in one system.
| Concept | Description | |---------|-------------| | Assertion | An atomic fact: subject + predicate + value, with confidence and temporal bounds | | Relationship | A directional edge between two subjects | | Signal | An emotional/rapport data point that decays over time and has a trajectory | | Thalamus | The intake pipeline — classifies, deduplicates, and detects contradictions | | Agent | A named AI identity with composable instructions, capabilities, and memory policy |
License
Apache-2.0
