Architecture
Deep dive into textrawl's technical architecture
This section covers the technical details of how textrawl works under the hood.
Architecture Overview
textrawl is built on a modern stack optimized for semantic search:
- Runtime: Node.js 22+ with ES modules
- Database: Neon PostgreSQL with pgvector extension (any Postgres with pgvector works)
- Transport: HTTP (REST API, MCP over StreamableHTTP, WebSocket events)
- Embeddings: OpenAI, Google AI, or Ollama (configurable)
Request Flow
Core Components
Hybrid Search
The search system combines full-text keyword matching with semantic vector similarity using Reciprocal Rank Fusion (RRF).
Text Chunking
Documents are split into overlapping chunks to fit within embedding model context limits while preserving semantic coherence.
- 512 tokens (~2048 characters) per chunk
- 50 token overlap for context preservation
- Paragraph-aware splitting on
\n\n
Embeddings
Vector representations that capture semantic meaning, enabling similarity search.
| Provider | Model | Dimensions |
|---|---|---|
| OpenAI | text-embedding-3-small | 1536 |
| Google AI | gemini-embedding-2-preview | 3072 |
| Ollama | nomic-embed-text | 1024 |
| Ollama | nomic-embed-text-v2-moe | 768 |
Database Schema
Core Tables
| Table | Purpose |
|---|---|
documents | Document metadata, content, tags |
chunks | Text chunks with embeddings and FTS vectors |
Memory Tables (Optional)
| Table | Purpose |
|---|---|
memory_entities | Named entities (people, projects, concepts) |
memory_observations | Facts about entities with embeddings |
memory_relations | Directed relationships between entities |
Key Indexes
| Index | Type | Purpose |
|---|---|---|
chunks.search_vector | GIN | Full-text search |
chunks.embedding | HNSW | Vector similarity |
memory_observations.embedding | HNSW | Memory search |
Transport Layer
textrawl exposes four transport interfaces: MCP (for AI assistants), REST API (for programmatic access), WebSocket (for real-time events), and the A2A protocol (for agent-to-agent discovery).
MCP
Uses StreamableHTTPServerTransport for stateless HTTP operation:
- Stateless: Each request creates a fresh MCP server instance
- Serverless-compatible: Works with Cloud Run, Lambda, etc.
- Single endpoint:
POST /mcphandles all MCP operations
REST API
Standard HTTP endpoints for direct integration:
- Search:
GET /api/search?q=query&limit=10 - Documents:
GET /api/documents,GET /api/documents/:id - Upload:
POST /api/upload
WebSocket
Real-time event streaming for document ingestion, insight discovery, and other background operations.
A2A Protocol
Agent-to-agent discovery via a public agent card at GET /.well-known/agent.json, letting orchestrator agents find the server and its capabilities.
Learn about the A2A protocol →
Rate Limiting
| Endpoint | Limit |
|---|---|
/mcp (API) | 100 requests/minute |
/api/upload | 10 requests/minute |
Security
- Bearer token authentication (
API_BEARER_TOKEN) - Row Level Security (RLS) on all tables
- Service role key bypasses RLS (single-tenant design)
See Security Hardening for production setup.
Next Steps
- Hybrid Search - Deep dive into RRF
- Chunking Strategy - How documents are split
- Embeddings - Vector representations