@cellstate/convex
v0.5.7
Published
Convex component for CELLSTATE — hierarchical memory for AI agents with trajectories, scopes, artifacts, notes, and multi-agent coordination
Maintainers
Readme
@cellstate/convex
Convex component for CELLSTATE — hierarchical memory for AI agents with trajectories, scopes, artifacts, notes, and multi-agent coordination.
What is CELLSTATE?
CELLSTATE is a hierarchical memory framework for AI agents that provides:
- Trajectories: Task containers that track agent work from start to completion
- Scopes: Context windows within trajectories for managing token budgets
- Turns: Ephemeral conversation messages within scopes
- Artifacts: Extracted values (code, decisions, plans) that persist beyond conversations
- Notes: Cross-trajectory knowledge that accumulates over time
- Agents: Multi-agent registration and coordination
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Your Convex App │
│ │
│ ┌─────────────────┐ ┌──────────────────────────────────┐ │
│ │ Frontend │ │ Convex Backend │ │
│ │ (React/etc) │──│ Queries, Mutations, Actions │ │
│ │ │ │ │ │
│ │ Real-time subs │ │ ┌────────────────────────────┐ │ │
│ │ via useQuery() │ │ │ @cellstate/convex │ │ │
│ └─────────────────┘ │ │ (CELLSTATE Component) │ │ │
│ │ │ │ │ │
│ │ │ Trajectories, Scopes, │ │ │
│ │ │ Turns, Artifacts, Notes, │ │ │
│ │ │ Agents, Tool Executions │ │ │
│ │ └────────────────────────────┘ │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘Data lives entirely inside Convex — no external API calls needed. You get real-time subscriptions, transactional consistency, and zero-latency reads for free.
Quick Start
1. Install
bun add @cellstate/convex2. Register the Component
// convex/convex.config.ts
import { defineApp } from "convex/server";
import cellstate from "@cellstate/convex/convex.config";
const app = defineApp();
app.use(cellstate);
export default app;3. Use in Your Code
// convex/myAgent.ts
import { CellstateMemory } from "@cellstate/convex";
import { components } from "./_generated/api";
import { internalAction } from "./_generated/server";
import { v } from "convex/values";
const memory = new CellstateMemory(components.cellstate);
export const runTask = internalAction({
args: { prompt: v.string() },
handler: async (ctx, { prompt }) => {
// Start a task (creates trajectory + scope)
const { trajectoryId, scopeId } = await memory.startTask(ctx, {
name: "User query",
description: prompt,
tokenBudget: 8000,
});
// Record the user's message
await memory.addTurn(ctx, {
scopeId,
trajectoryId,
role: "user",
content: prompt,
});
// Search existing knowledge
const notes = await memory.searchNotes(ctx, {
query: prompt,
limit: 5,
});
// ... do LLM inference with notes as context ...
// Extract valuable output as an artifact
await memory.createArtifact(ctx, {
trajectoryId,
scopeId,
name: "Analysis Result",
content: "...",
artifactType: "document",
sourceTurn: 1,
});
// Save learned knowledge as a cross-trajectory note
await memory.createNote(ctx, {
noteType: "fact",
title: "Discovered pattern",
content: "...",
sourceTrajectoryIds: [trajectoryId],
});
// Complete the task
await memory.completeTask(ctx, {
trajectoryId,
scopeId,
outcomeStatus: "success",
outcomeSummary: "Analyzed user query successfully",
});
},
});API Reference
Task Lifecycle
| Method | Description |
|--------|-------------|
| startTask({ name, description?, tokenBudget? }) | Create a trajectory + scope in one call |
| completeTask({ trajectoryId, scopeId, outcomeStatus?, outcomeSummary? }) | Close scope and mark trajectory complete |
Trajectories
| Method | Description |
|--------|-------------|
| createTrajectory({ name, description?, agentId? }) | Create a task container |
| updateTrajectoryStatus({ trajectoryId, status }) | Update status (active/completed/failed/suspended) |
| getTrajectory(trajectoryId) | Get trajectory by ID |
| listTrajectories(status?) | List trajectories, optionally filtered by status |
Scopes (Context Windows)
| Method | Description |
|--------|-------------|
| createScope({ trajectoryId, name, tokenBudget? }) | Create a new context window |
| closeScope(scopeId) | Close a scope (triggers budget reclaim) |
| getOpenScopes(trajectoryId) | Get all open scopes for a trajectory |
Turns (Conversation)
| Method | Description |
|--------|-------------|
| addTurn({ scopeId, trajectoryId, role, content }) | Add a message (auto-tracks token usage) |
| getTurns(scopeId) | Get all turns in a scope, ordered by turn number |
Artifacts (Extracted Values)
| Method | Description |
|--------|-------------|
| createArtifact({ trajectoryId, scopeId, name, content, artifactType, sourceTurn }) | Save a persistent output |
| listArtifacts(trajectoryId, artifactType?) | List artifacts, optionally filtered by type |
Artifact types: fact, code, document, data, config, log, summary, decision, plan
Notes (Cross-Trajectory Knowledge)
| Method | Description |
|--------|-------------|
| createNote({ noteType, title, content, sourceTrajectoryIds }) | Create long-term knowledge |
| searchNotes({ query, noteType?, limit? }) | Full-text search across notes |
| listNotes(noteType?, activeOnly?) | List notes by type |
| deactivateNote(noteId) | Soft-delete a note |
Note types: convention, strategy, gotcha, fact, preference, relationship, procedure, meta
Agents (Multi-Agent Coordination)
| Method | Description |
|--------|-------------|
| registerAgent({ agentType, capabilities, canDelegateTo? }) | Register an agent |
| updateAgentStatus(agentId, status) | Update status (active/idle/busy/offline) |
| agentHeartbeat(agentId) | Heartbeat ping |
| listAgents(status?) | List agents by status |
Tool Execution Audit
| Method | Description |
|--------|-------------|
| startToolExecution({ toolName, agentId?, trajectoryId? }) | Record tool invocation start |
| completeToolExecution({ executionId, status, durationMs }) | Record tool completion |
Memory Hierarchy
Tenant (your Convex app)
├── Notes (cross-trajectory knowledge, persists forever)
├── Agents (registered agents with capabilities)
└── Trajectory (task container)
├── Scope (context window with token budget)
│ └── Turns (individual messages)
├── Artifacts (extracted values from this task)
└── Tool Executions (audit trail)Best Practices
- Start with a Trajectory: Every agent task should have a trajectory
- Use Scopes for Token Management: Create new scopes when approaching token limits
- Extract Artifacts: Save important outputs (code, decisions, plans) as artifacts
- Create Notes for Patterns: When you notice recurring patterns, save them as notes
- Register Agents: Use agent registration for multi-agent coordination and delegation
Schema
The component creates 7 tables isolated within the component boundary:
| Table | Purpose | Key Indexes |
|-------|---------|-------------|
| trajectories | Task containers | by_status, by_agent, by_parent |
| scopes | Context windows | by_trajectory, by_open |
| turns | Conversation messages | by_scope, by_trajectory |
| artifacts | Persistent outputs | by_trajectory, by_type |
| notes | Cross-trajectory knowledge | by_type, by_active, search_content (full-text) |
| agents | Agent registry | by_type, by_status |
| toolExecutions | Tool audit trail | by_trajectory, by_tool, by_agent |
License
Apache-2.0 — See the main CELLSTATE repository for details.
