# PulseDB: API Reference
> **Version:** 1.0.0
> **Status:** Approved
> **Last Updated:** February 2026
> **Owner:** PulseDB Team
---
## 1. Overview
This document provides the complete API reference for PulseDB. All public types, functions, and traits are documented with signatures, parameters, return types, and usage examples.
### 1.1 Crate Structure
```
pulsedb
├── lib.rs // Re-exports
├── db.rs // PulseDB struct
├── collective.rs // Collective management
├── experience.rs // Experience CRUD
├── search.rs // Search and retrieval
├── relation.rs // Relationship storage
├── insight.rs // Derived insights
├── activity.rs // Activity tracking
├── watch.rs // Real-time notifications
├── embedding.rs // Embedding service
├── substrate.rs // SubstrateProvider trait
├── types.rs // Core types
└── error.rs // Error types
```
### 1.2 Feature Flags
```toml
[features]
default = ["builtin-embeddings"]
builtin-embeddings = ["ort"] # ONNX runtime for embedding generation
```
---
## 2. Database Lifecycle
### 2.1 PulseDB
The main entry point for all database operations.
```rust
pub struct PulseDB { /* private */ }
```
#### `PulseDB::open`
Opens or creates a PulseDB database.
```rust
pub fn open(path: impl AsRef<Path>, config: Config) -> Result<PulseDB, PulseDBError>
```
**Parameters:**
| `path` | `impl AsRef<Path>` | Path to database file |
| `config` | `Config` | Configuration options |
**Returns:** `Result<PulseDB, PulseDBError>`
**Errors:**
| `PulseDBError::Io` | File system error |
| `StorageError::Corrupted` | Database file corrupted |
| `StorageError::SchemaVersionMismatch` | On-disk schema version differs from expected |
| `ValidationError::DimensionMismatch` | Config dimension doesn't match existing |
**Example:**
```rust
use pulsedb::{PulseDB, Config};
// Open with defaults
let db = PulseDB::open("./pulse.db", Config::default())?;
// Open with custom config
let db = PulseDB::open("./pulse.db", Config {
embedding_provider: EmbeddingProvider::External,
embedding_dimension: EmbeddingDimension::D768,
..Default::default()
})?;
```
---
#### `PulseDB::close`
Closes the database, flushing all pending writes.
```rust
pub fn close(self) -> Result<(), PulseDBError>
```
**Parameters:** None (consumes self)
**Returns:** `Result<(), PulseDBError>`
**Example:**
```rust
let db = PulseDB::open("./pulse.db", Config::default())?;
// ... use database ...
db.close()?; // Explicit close
// db is consumed, cannot be used after this
```
---
### 2.2 Config
Database configuration options.
```rust
#[derive(Clone, Debug)]
pub struct Config {
/// Embedding provider configuration
pub embedding_provider: EmbeddingProvider,
/// Embedding vector dimension
pub embedding_dimension: EmbeddingDimension,
/// Default collective for operations (optional)
pub default_collective: Option<CollectiveId>,
/// Cache size in megabytes
pub cache_size_mb: usize,
/// Sync mode for durability
pub sync_mode: SyncMode,
/// HNSW vector index configuration
pub hnsw: HnswConfig,
/// Agent-activity tracking configuration
pub activity: ActivityConfig,
/// Watch system configuration
pub watch: WatchConfig,
/// Temporal decay / energy configuration (per-collective default)
pub decay: DecayConfig,
/// Open the database read-only (all mutations return `PulseDBError::ReadOnly`)
pub read_only: bool,
}
impl Default for Config {
fn default() -> Self {
Config {
// Default = External provider: the caller supplies embeddings
// (NewExperience.embedding = Some(..)). Enable the `builtin-embeddings`
// feature + EmbeddingProvider::Builtin to have PulseDB generate them.
embedding_provider: EmbeddingProvider::External,
embedding_dimension: EmbeddingDimension::D384,
default_collective: None,
cache_size_mb: 64,
sync_mode: SyncMode::Normal,
hnsw: HnswConfig::default(),
activity: ActivityConfig::default(),
watch: WatchConfig::default(),
decay: DecayConfig::default(),
read_only: false,
}
}
}
```
---
### 2.3 EmbeddingProvider
```rust
#[derive(Clone, Debug)]
pub enum EmbeddingProvider {
/// PulseDB computes embeddings using built-in ONNX model
Builtin {
/// Custom model path (None = use bundled model)
model_path: Option<PathBuf>,
},
/// Consumer provides pre-computed embeddings
External,
}
```
**Usage Notes:**
- `Builtin`: PulseDB generates embeddings automatically. No embedding field needed in `NewExperience`.
- `External`: Consumer must provide `embedding` field in `NewExperience`. PulseDB only validates dimension.
---
### 2.4 EmbeddingDimension
```rust
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EmbeddingDimension {
/// 384 dimensions (all-MiniLM-L6-v2)
D384,
/// 768 dimensions (bge-base-en-v1.5)
D768,
/// Custom dimension for external providers
Custom(usize),
}
impl EmbeddingDimension {
pub fn size(&self) -> usize {
match self {
Self::D384 => 384,
Self::D768 => 768,
Self::Custom(n) => *n,
}
}
}
```
---
### 2.5 SyncMode
```rust
#[derive(Clone, Copy, Debug, Default)]
pub enum SyncMode {
/// Sync on commit (default, safe)
#[default]
Normal,
/// Async sync (faster, risk data loss on crash)
Fast,
/// Sync every write (slowest, maximum durability)
Paranoid,
}
```
---
## 3. Collective Management
### 3.1 create_collective
Creates a new isolated collective (hive mind).
```rust
impl PulseDB {
pub fn create_collective(&self, name: &str) -> Result<CollectiveId, PulseDBError>;
pub fn create_collective_with_owner(
&self,
name: &str,
owner_id: &str,
) -> Result<CollectiveId, PulseDBError>;
}
```
**Parameters:**
| `name` | `&str` | Human-readable name (max 256 chars) |
| `owner_id` | `&str` | Owner identifier |
**Returns:** `Result<CollectiveId, PulseDBError>`
**Example:**
```rust
// Simple creation
let collective_id = db.create_collective("my-project")?;
// With owner
let collective_id = db.create_collective_with_owner(
"my-project",
"user_123",
)?;
```
---
### 3.2 list_collectives
Lists all collectives, optionally filtered by owner.
```rust
impl PulseDB {
pub fn list_collectives(&self) -> Result<Vec<Collective>, PulseDBError>;
pub fn list_collectives_by_owner(
&self,
owner_id: &str,
) -> Result<Vec<Collective>, PulseDBError>;
}
```
**Returns:** `Result<Vec<Collective>, PulseDBError>`
**Example:**
```rust
// List all
let collectives = db.list_collectives()?;
// Filter by owner
let my_collectives = db.list_collectives_by_owner("user_123")?;
```
---
### 3.3 get_collective
Gets a collective by ID.
```rust
impl PulseDB {
pub fn get_collective(&self, id: CollectiveId) -> Result<Option<Collective>, PulseDBError>;
}
```
**Returns:** `Result<Option<Collective>, PulseDBError>`
- `Ok(Some(collective))` if found
- `Ok(None)` if not found
- `Err(...)` on database error
---
### 3.4 get_collective_stats
Gets statistics for a collective.
```rust
impl PulseDB {
pub fn get_collective_stats(&self, id: CollectiveId) -> Result<CollectiveStats, PulseDBError>;
}
#[derive(Clone, Debug)]
pub struct CollectiveStats {
pub experience_count: u64,
pub storage_bytes: u64,
pub oldest_experience: Option<Timestamp>,
pub newest_experience: Option<Timestamp>,
}
```
---
### 3.5 delete_collective
Deletes a collective and all its data.
```rust
impl PulseDB {
pub fn delete_collective(&self, id: CollectiveId) -> Result<(), PulseDBError>;
}
```
**⚠️ Warning:** This permanently deletes all experiences, relations, insights, and activities in the collective.
---
## 4. Experience Operations
### 4.1 record_experience
Records a new experience to the collective.
```rust
impl PulseDB {
pub fn record_experience(&self, experience: NewExperience) -> Result<ExperienceId, PulseDBError>;
}
#[derive(Clone, Debug, Default)]
pub struct NewExperience {
/// Target collective (required)
pub collective_id: CollectiveId,
/// Experience content (required)
pub content: String,
/// Experience type (required)
pub experience_type: ExperienceType,
/// Pre-computed embedding (required if External provider)
pub embedding: Option<Vec<f32>>,
/// Importance score (0.0 - 1.0)
pub importance: f32,
/// Confidence score (0.0 - 1.0)
pub confidence: f32,
/// Domain tags
pub domain: Vec<String>,
/// Related file paths
pub related_files: Vec<String>,
/// Source agent ID
pub source_agent: AgentId,
/// Source task ID (optional)
pub source_task: Option<TaskId>,
}
```
**Example:**
```rust
use pulsedb::{NewExperience, ExperienceType, Severity};
let exp_id = db.record_experience(NewExperience {
collective_id,
content: "Prisma client not available in edge runtime".into(),
experience_type: ExperienceType::Difficulty {
description: "Next.js middleware runs in edge runtime".into(),
severity: Severity::High,
},
importance: 0.9,
confidence: 1.0,
domain: vec!["prisma".into(), "nextjs".into(), "edge".into()],
source_agent: AgentId("agent_1".into()),
..Default::default()
})?;
```
---
### 4.2 get_experience
Retrieves an experience by ID.
```rust
impl PulseDB {
pub fn get_experience(&self, id: ExperienceId) -> Result<Option<Experience>, PulseDBError>;
}
```
**Returns:** `Result<Option<Experience>, PulseDBError>`
---
### 4.3 update_experience
Updates mutable fields of an experience.
```rust
impl PulseDB {
pub fn update_experience(
&self,
id: ExperienceId,
update: ExperienceUpdate,
) -> Result<(), PulseDBError>;
}
#[derive(Clone, Debug, Default)]
pub struct ExperienceUpdate {
pub importance: Option<f32>,
pub confidence: Option<f32>,
pub domain: Option<Vec<String>>,
pub related_files: Option<Vec<String>>,
}
```
**Note:** Content and embedding are immutable. Create a new experience if content changes.
---
### 4.4 archive_experience
Soft-deletes an experience (excludes from search).
```rust
impl PulseDB {
pub fn archive_experience(&self, id: ExperienceId) -> Result<(), PulseDBError>;
}
```
---
### 4.5 unarchive_experience
Restores an archived experience.
```rust
impl PulseDB {
pub fn unarchive_experience(&self, id: ExperienceId) -> Result<(), PulseDBError>;
}
```
---
### 4.6 delete_experience
Permanently deletes an experience.
```rust
impl PulseDB {
pub fn delete_experience(&self, id: ExperienceId) -> Result<(), PulseDBError>;
}
```
**⚠️ Warning:** This also deletes all relations involving this experience.
---
### 4.7 reinforce_experience
Records that an experience was useful: increments the calling instance's bucket in the per-instance application G-counter (schema v3) and refreshes `last_reinforced`, boosting the experience's temporal energy. Returns the new total application count across all instance buckets.
```rust
impl PulseDB {
pub fn reinforce_experience(&self, id: ExperienceId) -> Result<u32, PulseDBError>;
}
```
**Parameters:**
| `id` | `ExperienceId` | Experience to reinforce |
**Returns:** `u32` — the total application count after the increment (sum across all instance buckets).
---
## 5. Search & Retrieval
### 5.1 get_context_candidates
Retrieves raw context candidates for a task.
```rust
impl PulseDB {
pub fn get_context_candidates(
&self,
request: ContextRequest,
) -> Result<ContextCandidates, PulseDBError>;
}
#[derive(Clone, Debug)]
pub struct ContextRequest {
/// Target collective (must exist)
pub collective_id: CollectiveId,
/// Query embedding for similarity search and insight retrieval
pub query_embedding: Vec<f32>,
/// Max similar experiences to return (1-1000, default: 20)
pub max_similar: usize,
/// Max recent experiences to return (1-1000, default: 10)
pub max_recent: usize,
/// Include derived insights (default: true)
pub include_insights: bool,
/// Include relations for returned experiences (default: true)
pub include_relations: bool,
/// Include active (non-stale) agent activities (default: true)
pub include_active_agents: bool,
/// Filter applied to similar and recent experience queries
pub filter: SearchFilter,
/// Optional recall weights for similarity + temporal energy
/// (`None` preserves legacy similarity-only ranking)
pub recall_weights: Option<RecallWeights>,
}
// ContextRequest implements Default (nil collective, empty query, the limits/flags above).
#[derive(Clone, Debug)]
pub struct ContextCandidates {
/// Semantically similar experiences, sorted by similarity descending
pub similar_experiences: Vec<SearchResult>,
/// Most recent experiences, sorted by timestamp descending
pub recent_experiences: Vec<Experience>,
/// Derived insights similar to the query (empty if `include_insights` was false)
pub insights: Vec<DerivedInsight>,
/// Relations involving the returned experiences (deduped; empty if not requested)
pub relations: Vec<ExperienceRelation>,
/// Currently active (non-stale) agents (empty if `include_active_agents` was false)
pub active_agents: Vec<Activity>,
}
```
**Example:**
```rust
let candidates = db.get_context_candidates(ContextRequest {
collective_id,
query_embedding: embedding_model.embed("Help user with auth")?,
max_recent: 5,
max_similar: 20,
..Default::default()
})?;
for result in candidates.similar_experiences {
println!("Score {:.3}: {}", result.similarity, result.experience.content);
}
```
---
### 5.2 search_similar
Vector similarity search for experiences.
```rust
impl PulseDB {
pub fn search_similar(
&self,
collective_id: CollectiveId,
query_embedding: &[f32],
k: usize,
) -> Result<Vec<SearchResult>, PulseDBError>;
pub fn search_similar_filtered(
&self,
collective_id: CollectiveId,
query_embedding: &[f32],
k: usize,
filter: SearchFilter,
) -> Result<Vec<SearchResult>, PulseDBError>;
}
/// A search result pairing an experience with its similarity score.
#[derive(Clone, Debug)]
pub struct SearchResult {
/// The full experience record.
pub experience: Experience,
/// Similarity score (1.0 - cosine_distance). Higher is more similar.
pub similarity: f32,
}
#[derive(Clone, Debug)]
pub struct SearchFilter {
/// Filter by domains (experience must have at least one)
pub domains: Option<Vec<String>>,
/// Experience types to include (matched on the type discriminant)
pub experience_types: Option<Vec<ExperienceType>>,
/// Minimum importance threshold
pub min_importance: Option<f32>,
/// Minimum confidence threshold
pub min_confidence: Option<f32>,
/// Only include experiences created at or after this timestamp
pub since: Option<Timestamp>,
/// Whether to exclude archived experiences (default: `true`)
pub exclude_archived: bool,
}
// SearchFilter implements Default manually: all `Option` fields are `None`
// and `exclude_archived` defaults to `true`.
```
**Returns:** `Vec<SearchResult>` sorted by `similarity` descending. Each result exposes
`result.experience` (the full `Experience`) and `result.similarity` (the score).
---
### 5.3 get_recent_experiences
Gets most recent experiences by timestamp.
```rust
impl PulseDB {
pub fn get_recent_experiences(
&self,
collective_id: CollectiveId,
limit: usize,
) -> Result<Vec<Experience>, PulseDBError>;
pub fn get_recent_experiences_filtered(
&self,
collective_id: CollectiveId,
limit: usize,
filter: SearchFilter,
) -> Result<Vec<Experience>, PulseDBError>;
}
```
---
## 6. Relationship Storage
### 6.1 store_relation
Stores a relationship between experiences.
```rust
impl PulseDB {
pub fn store_relation(&self, relation: NewExperienceRelation) -> Result<RelationId, PulseDBError>;
}
#[derive(Clone, Debug)]
pub struct NewExperienceRelation {
pub source_id: ExperienceId,
pub target_id: ExperienceId,
pub relation_type: RelationType,
pub strength: f32,
pub metadata: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RelationType {
Supports,
Contradicts,
Elaborates,
Supersedes,
Implies,
RelatedTo,
}
```
**Example:**
```rust
let relation_id = db.store_relation(NewExperienceRelation {
source_id: solution_exp_id,
target_id: problem_exp_id,
relation_type: RelationType::Elaborates,
strength: 0.9,
metadata: None,
})?;
```
---
### 6.2 get_related_experiences
Gets experiences related to a given experience.
```rust
impl PulseDB {
pub fn get_related_experiences(
&self,
experience_id: ExperienceId,
direction: RelationDirection,
) -> Result<Vec<(Experience, ExperienceRelation)>, PulseDBError>;
pub fn get_related_experiences_filtered(
&self,
experience_id: ExperienceId,
direction: RelationDirection,
relation_type: Option<RelationType>,
) -> Result<Vec<(Experience, ExperienceRelation)>, PulseDBError>;
}
#[derive(Clone, Copy, Debug)]
pub enum RelationDirection {
Outgoing, // source_id = experience_id
Incoming, // target_id = experience_id
Both,
}
```
---
### 6.3 delete_relation
Deletes a specific relation.
```rust
impl PulseDB {
pub fn delete_relation(&self, id: RelationId) -> Result<(), PulseDBError>;
}
```
---
## 7. Insight Storage
### 7.1 store_insight
Stores a derived insight (synthesized by consumer).
```rust
impl PulseDB {
pub fn store_insight(&self, insight: NewDerivedInsight) -> Result<InsightId, PulseDBError>;
}
#[derive(Clone, Debug)]
pub struct NewDerivedInsight {
pub collective_id: CollectiveId,
pub content: String,
/// Pre-computed embedding (required for External provider)
pub embedding: Option<Vec<f32>>,
pub source_experience_ids: Vec<ExperienceId>,
pub insight_type: InsightType,
pub confidence: f32,
pub domain: Vec<String>,
}
```
---
### 7.2 get_insights
Gets insights similar to a query.
```rust
impl PulseDB {
pub fn get_insights(
&self,
collective_id: CollectiveId,
query_embedding: &[f32],
limit: usize,
) -> Result<Vec<(DerivedInsight, f32)>, PulseDBError>;
}
```
---
### 7.3 delete_insight
Deletes an insight.
```rust
impl PulseDB {
pub fn delete_insight(&self, id: InsightId) -> Result<(), PulseDBError>;
}
```
---
## 8. Activity Tracking
### 8.1 register_activity
Registers an agent's current activity.
```rust
impl PulseDB {
pub fn register_activity(&self, activity: NewActivity) -> Result<(), PulseDBError>;
}
#[derive(Clone, Debug)]
pub struct NewActivity {
pub agent_id: String,
pub collective_id: CollectiveId,
pub current_task: Option<String>,
pub context_summary: Option<String>,
}
```
---
### 8.2 update_heartbeat
Updates activity heartbeat.
```rust
impl PulseDB {
pub fn update_heartbeat(&self, agent_id: &str, collective_id: CollectiveId) -> Result<(), PulseDBError>;
}
```
---
### 8.3 end_activity
Ends an agent's activity.
```rust
impl PulseDB {
pub fn end_activity(&self, agent_id: &str, collective_id: CollectiveId) -> Result<(), PulseDBError>;
}
```
---
### 8.4 get_active_agents
Gets currently active agents.
```rust
impl PulseDB {
pub fn get_active_agents(&self, collective_id: CollectiveId) -> Result<Vec<Activity>, PulseDBError>;
}
```
**Note:** The staleness window (activities with no heartbeat newer than
`now - stale_threshold` are excluded) is configured globally via
`Config.activity.stale_threshold` (default: 5 minutes), not passed per call.
---
## 9. Real-Time Watch
### 9.1 watch_experiences
Subscribes to new experiences.
```rust
impl PulseDB {
pub fn watch_experiences(
&self,
collective_id: CollectiveId,
) -> Result<WatchStream, PulseDBError>;
pub fn watch_experiences_filtered(
&self,
collective_id: CollectiveId,
filter: WatchFilter,
) -> Result<WatchStream, PulseDBError>;
}
#[derive(Clone, Debug, Default)]
pub struct WatchFilter {
pub domains: Option<Vec<String>>,
pub experience_types: Option<Vec<ExperienceType>>,
pub min_importance: Option<f32>,
}
```
`WatchStream` implements `futures_core::Stream<Item = WatchEvent>`. Subscription is
synchronous (no `.await` to subscribe); the resulting stream is consumed
asynchronously.
```rust
#[derive(Clone, Debug)]
pub struct WatchEvent {
pub experience_id: ExperienceId,
pub collective_id: CollectiveId,
pub event_type: WatchEventType,
pub timestamp: Timestamp,
/// Full experience data for `Created`/`Updated`; `None` for `Deleted`.
pub experience: Option<Experience>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WatchEventType {
Created,
Updated,
Archived,
Deleted,
}
```
**Example:**
```rust
use futures::StreamExt;
use pulsedb::WatchEventType;
let mut stream = db.watch_experiences(collective_id)?;
while let Some(event) = stream.next().await {
match event.event_type {
WatchEventType::Created => {
if let Some(exp) = event.experience {
println!("New experience: {}", exp.content);
}
}
WatchEventType::Deleted => println!("Removed: {}", event.experience_id),
_ => {}
}
}
```
---
### 9.2 WatchConfig
```rust
#[derive(Clone, Debug)]
pub struct WatchConfig {
/// Use in-process channels (crossbeam)
pub in_process: bool,
/// Poll interval for cross-process (ms)
pub poll_interval_ms: u64,
/// Buffer size for watch channel
pub buffer_size: usize,
}
impl Default for WatchConfig {
fn default() -> Self {
Self {
in_process: true,
poll_interval_ms: 100,
buffer_size: 1000,
}
}
}
```
---
## 10. SubstrateProvider Trait
The trait for PulseHive integration.
```rust
#[async_trait]
pub trait SubstrateProvider: Send + Sync {
// ─────────────────────────────────────────────────────────────
// Experience Operations
// ─────────────────────────────────────────────────────────────
async fn store_experience(&self, exp: NewExperience) -> Result<ExperienceId, PulseDBError>;
async fn get_experience(&self, id: ExperienceId) -> Result<Option<Experience>, PulseDBError>;
async fn search_similar(
&self,
collective: CollectiveId,
embedding: &[f32],
k: usize,
) -> Result<Vec<(Experience, f32)>, PulseDBError>;
async fn get_recent(
&self,
collective: CollectiveId,
limit: usize,
) -> Result<Vec<Experience>, PulseDBError>;
// ─────────────────────────────────────────────────────────────
// Relation Operations
// ─────────────────────────────────────────────────────────────
async fn store_relation(&self, rel: NewExperienceRelation) -> Result<RelationId, PulseDBError>;
async fn get_related(
&self,
exp_id: ExperienceId,
) -> Result<Vec<(Experience, ExperienceRelation)>, PulseDBError>;
// ─────────────────────────────────────────────────────────────
// Insight Operations
// ─────────────────────────────────────────────────────────────
async fn store_insight(&self, insight: NewDerivedInsight) -> Result<InsightId, PulseDBError>;
async fn get_insights(
&self,
collective: CollectiveId,
embedding: &[f32],
k: usize,
) -> Result<Vec<(DerivedInsight, f32)>, PulseDBError>;
// ─────────────────────────────────────────────────────────────
// Activity Operations
// ─────────────────────────────────────────────────────────────
async fn get_activities(&self, collective: CollectiveId) -> Result<Vec<Activity>, PulseDBError>;
// ─────────────────────────────────────────────────────────────
// Watch Operations
// ─────────────────────────────────────────────────────────────
async fn watch(
&self,
collective: CollectiveId,
) -> Result<Pin<Box<dyn Stream<Item = WatchEvent> + Send>>, PulseDBError>;
}
```
> **Note:** The trait declares additional methods (e.g. `get_context_candidates`,
> `create_collective`, `get_or_create_collective`, `list_collectives`) and several
> defaulted methods; only the core surface is shown here.
**Implementation:**
```rust
pub struct PulseDBSubstrate {
db: Arc<PulseDB>,
}
impl PulseDBSubstrate {
/// Wraps a shared `PulseDB` reference.
pub fn new(db: Arc<PulseDB>) -> Self {
Self { db }
}
/// Wraps an owned `PulseDB` in an `Arc`.
pub fn from_db(db: PulseDB) -> Self {
Self { db: Arc::new(db) }
}
}
#[async_trait]
impl SubstrateProvider for PulseDBSubstrate {
// Each async method delegates to PulseDB's sync API via spawn_blocking.
async fn store_experience(&self, exp: NewExperience) -> Result<ExperienceId, PulseDBError> {
let db = self.db.clone();
// (runs on the blocking thread pool)
db.record_experience(exp)
}
// ... other implementations
}
```
---
## 11. Error Types
### 11.1 PulseDBError
```rust
#[derive(Debug, thiserror::Error)]
pub enum PulseDBError {
#[error("Storage error: {0}")]
Storage(#[from] StorageError),
#[error("Validation error: {0}")]
Validation(#[from] ValidationError),
#[error("Configuration error: {reason}")]
Config { reason: String },
#[error("{0}")]
NotFound(#[from] NotFoundError),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Embedding error: {0}")]
Embedding(String),
#[error("Vector index error: {0}")]
Vector(String),
#[error("Watch error: {0}")]
Watch(String),
#[error("Internal error: {0}")]
Internal(String),
#[error("Database is in read-only mode")]
ReadOnly,
/// Only available when the `sync` feature is enabled.
#[cfg(feature = "sync")]
#[error("Sync error: {0}")]
Sync(#[from] SyncError),
}
```
### 11.2 StorageError
```rust
#[derive(Debug, thiserror::Error)]
pub enum StorageError {
#[error("Database corrupted: {0}")]
Corrupted(String),
#[error("Database not found: {0}")]
DatabaseNotFound(PathBuf),
#[error("Database is locked by another writer")]
DatabaseLocked,
#[error("Transaction failed: {0}")]
Transaction(String),
#[error("Serialization error: {0}")]
Serialization(String),
#[error("Storage engine error: {0}")]
Redb(String),
#[error("Schema version mismatch: expected {expected}, found {found}")]
SchemaVersionMismatch { expected: u32, found: u32 },
#[error("Table not found: {0}")]
TableNotFound(String),
}
```
### 11.3 ValidationError
```rust
#[derive(Debug, thiserror::Error)]
pub enum ValidationError {
#[error("Embedding dimension mismatch: expected {expected}, got {got}")]
DimensionMismatch { expected: usize, got: usize },
#[error("Invalid field '{field}': {reason}")]
InvalidField { field: String, reason: String },
#[error("Content too large: {size} bytes (max: {max} bytes)")]
ContentTooLarge { size: usize, max: usize },
#[error("Required field missing: {field}")]
RequiredField { field: String },
#[error("Too many items in '{field}': {count} (max: {max})")]
TooManyItems { field: String, count: usize, max: usize },
}
```
### 11.4 Error Handling Example
```rust
use pulsedb::{PulseDB, PulseDBError, ValidationError, NotFoundError};
match db.record_experience(exp) {
Ok(id) => println!("Recorded: {:?}", id),
Err(PulseDBError::Validation(ValidationError::DimensionMismatch { expected, got })) => {
eprintln!("Wrong embedding dimension: expected {}, got {}", expected, got);
}
Err(PulseDBError::NotFound(NotFoundError::Collective(id))) => {
eprintln!("Collective {} does not exist", id);
}
Err(e) => eprintln!("Unexpected error: {}", e),
}
```
---
## 12. Type Reference
### 12.1 Identifiers
```rust
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct CollectiveId(pub Uuid);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ExperienceId(pub Uuid);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RelationId(pub Uuid);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InsightId(pub Uuid);
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct UserId(pub String);
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AgentId(pub String);
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct TaskId(pub String);
```
### 12.2 Timestamp
```rust
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Timestamp(pub i64); // Unix millis
impl Timestamp {
pub fn now() -> Self {
Self(SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as i64)
}
}
```
---
## 13. Complete Example
```rust
use pulsedb::{
PulseDB, Config, EmbeddingProvider, EmbeddingDimension,
NewExperience, ExperienceType, Severity,
ContextRequest, NewExperienceRelation, RelationType,
AgentId,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// ─────────────────────────────────────────────────────────────
// 1. Open database
// ─────────────────────────────────────────────────────────────
let db = PulseDB::open("./pulse.db", Config::default())?;
// ─────────────────────────────────────────────────────────────
// 2. Create collective
// ─────────────────────────────────────────────────────────────
let collective_id = db.create_collective("my-project")?;
// ─────────────────────────────────────────────────────────────
// 3. Record experiences
// ─────────────────────────────────────────────────────────────
let problem_id = db.record_experience(NewExperience {
collective_id,
content: "Prisma client fails in edge runtime".into(),
experience_type: ExperienceType::Difficulty {
description: "Next.js middleware uses edge".into(),
severity: Severity::High,
},
importance: 0.9,
domain: vec!["prisma".into(), "nextjs".into()],
source_agent: AgentId("agent_1".into()),
// Config::default() uses the External embedding provider, so callers must
// supply the embedding (matching the collective's dimension). Builtin
// provider (feature `builtin-embeddings`) generates it automatically.
embedding: Some(vec![0.1; 384]),
..Default::default()
})?;
let solution_id = db.record_experience(NewExperience {
collective_id,
content: "Use Prisma adapter pattern for edge".into(),
experience_type: ExperienceType::Solution {
problem_ref: Some(problem_id),
approach: "adapter pattern".into(),
worked: true,
},
importance: 0.95,
domain: vec!["prisma".into(), "nextjs".into()],
source_agent: AgentId("agent_1".into()),
embedding: Some(vec![0.1; 384]), // External provider — supply the embedding
..Default::default()
})?;
// ─────────────────────────────────────────────────────────────
// 4. Store relation
// ─────────────────────────────────────────────────────────────
db.store_relation(NewExperienceRelation {
source_id: solution_id,
target_id: problem_id,
relation_type: RelationType::Elaborates,
strength: 1.0,
metadata: None,
})?;
// ─────────────────────────────────────────────────────────────
// 5. Get context candidates (another agent)
// ─────────────────────────────────────────────────────────────
let candidates = db.get_context_candidates(ContextRequest {
collective_id,
query_embedding: vec![0.0; 384], // Would be a real query embedding
max_similar: 10,
..Default::default()
})?;
println!("Found {} similar experiences", candidates.similar_experiences.len());
// ─────────────────────────────────────────────────────────────
// 6. Clean up
// ─────────────────────────────────────────────────────────────
db.close()?;
Ok(())
}
```
---
## Changelog
| 1.0.0 | February 2026 | PulseDB Team | Initial API reference |