Skip to main content

Overview

The workspace provides persistent memory for agents with a flexible filesystem-like structure. Agents can create arbitrary markdown file hierarchies that get indexed for full-text and semantic search. Inspired by OpenClaw, the workspace gives agents long-term memory across sessions.

Filesystem-like Structure

Core Types

Workspace

Database-backed memory storage scoped to a user and optionally an agent.
String
User identifier from the channel
Option<Uuid>
Optional agent ID for multi-agent isolation
Option<Arc<dyn EmbeddingProvider>>
Embedding provider for semantic search

Constructors

fn(user_id: impl Into<String>, pool: Pool) -> Self
Create a new workspace backed by PostgreSQL (requires postgres feature)
fn(user_id: impl Into<String>, db: Arc<dyn Database>) -> Self
Create a workspace with any Database implementation (libSQL, etc.)
fn(self, agent_id: Uuid) -> Self
Set a specific agent ID for multi-agent isolation
fn(self, provider: Arc<dyn EmbeddingProvider>) -> Self
Set the embedding provider for semantic search

Example

File Operations

Workspace provides a simple filesystem-like API for document management.

read

async fn(&self, path: &str) -> Result<MemoryDocument>
Read a file by path. Returns error if file doesn’t exist.

write

async fn(&self, path: &str, content: &str) -> Result<MemoryDocument>
Create or update a file. Creates parent directories implicitly. Re-indexes for search.

append

async fn(&self, path: &str, content: &str) -> Result<()>
Append content to a file. Creates the file if it doesn’t exist. Adds newline separator.

exists

async fn(&self, path: &str) -> Result<bool>
Check if a file exists at the given path.

delete

async fn(&self, path: &str) -> Result<()>
Delete a file and its associated search chunks.

list

async fn(&self, directory: &str) -> Result<Vec<WorkspaceEntry>>
List files and directories at a path. Returns immediate children (not recursive). Use empty string or ”/” for root.

list_all

async fn(&self) -> Result<Vec<String>>
List all files recursively as a flat list of paths.

Convenience Methods

memory

async fn(&self) -> Result<MemoryDocument>
Get the main MEMORY.md document (long-term curated memory). Creates if it doesn’t exist.

today_log

async fn(&self) -> Result<MemoryDocument>
Get today’s daily log (append-only, keyed by date).

daily_log

async fn(&self, date: NaiveDate) -> Result<MemoryDocument>
Get a daily log for a specific date.

append_memory

async fn(&self, entry: &str) -> Result<()>
Append an entry to MEMORY.md with double newline separation. For important facts and decisions.

append_daily_log

async fn(&self, entry: &str) -> Result<()>
Append a timestamped entry to today’s daily log.

heartbeat_checklist

async fn(&self) -> Result<Option<String>>
Get the HEARTBEAT.md checklist for periodic background tasks. Returns seed template if not yet created.

System Prompt

system_prompt

async fn(&self) -> Result<String>
Build the system prompt from identity files (AGENTS.md, SOUL.md, USER.md, IDENTITY.md, MEMORY.md). Includes last 2 days of daily logs.

system_prompt_for_context

async fn(&self, is_group_chat: bool) -> Result<String>
Build system prompt with option to exclude MEMORY.md for group chats (privacy protection).

search

Hybrid search combining full-text (BM25) and semantic (vector) search using Reciprocal Rank Fusion.

search_with_config

async fn(&self, query: &str, config: SearchConfig) -> Result<Vec<SearchResult>>
Search with custom configuration for ranking weights and limits.

Seeding

seed_if_empty

async fn(&self) -> Result<usize>
Seed missing core identity files (README, MEMORY, IDENTITY, SOUL, AGENTS, USER, HEARTBEAT). Only creates files that don’t exist - never overwrites. Returns number of files created.

backfill_embeddings

async fn(&self) -> Result<usize>
Generate embeddings for chunks that don’t have them yet. Useful after enabling embedding provider. Returns number of chunks processed.

Data Types

MemoryDocument

A document stored in the workspace.
Uuid
Unique document identifier
String
Owner user identifier
Option<Uuid>
Optional agent ID for isolation
String
File path (e.g., “context/vision.md”)
String
Full document content
DateTime<Utc>
Creation timestamp
DateTime<Utc>
Last update timestamp

WorkspaceEntry

An entry in a directory listing.
String
Relative path from listing directory
bool
True if this entry has children
Option<DateTime<Utc>>
Last update time (latest among children for directories)
Option<String>
First ~200 characters (None for directories)

SearchResult

A search result with ranking score.
String
Document path
String
Matched chunk content
f32
Combined relevance score (0.0 to 1.0)
String
Preview text with context

SearchConfig

Configuration for hybrid search ranking.
usize
default:"10"
Maximum results to return
f32
default:"0.5"
Weight for semantic similarity (0.0 to 1.0)
f32
default:"0.5"
Weight for BM25 full-text score (0.0 to 1.0)
usize
default:"60"
RRF constant (higher = less aggressive fusion)

Embedding Providers

Workspace supports multiple embedding providers for semantic search.

OpenAiEmbeddings

OllamaEmbeddings

NearAiEmbeddings

MockEmbeddings

For testing without external dependencies.

Key Patterns

  1. Memory is persistence: If you want to remember something, write it to the workspace
  2. Flexible structure: Create any directory/file hierarchy you need
  3. Self-documenting: Use README.md files to describe directory structure
  4. Hybrid search: Vector similarity + BM25 full-text via RRF for best results
  5. Privacy boundaries: Use system_prompt_for_context(true) to exclude personal memory in group chats

Agent Module

Core agent orchestration and session management

LLM Module

Language model integration for reasoning