5.1 Release Notes
Patch Releases
All patch release notes for 5.1.x are available on the releases page.
AI Models Integration
Harper 5.1 introduces a built-in models layer that provides a unified interface for AI model backends. This enables embedding generation and text generation from directly within Harper applications, without managing external API connections per-application.
The models layer is exposed via scope.models in application code:
// Generate embeddings
const vector = await scope.models.embed('text to embed', { model: 'my-embedding-model' });
// Generate text
const response = await scope.models.generate([{ role: 'user', content: 'Hello' }], { model: 'my-chat-model' });
// Streaming generation
for await (const chunk of scope.models.generateStream(messages, { model: 'my-chat-model' })) {
// ...
}
Supported backends are Anthropic, AWS Bedrock, OpenAI, and Ollama, configured under the models key in harper-config.yaml:
models:
anthropic:
apiKey: your-api-key
openai:
apiKey: your-api-key
baseUrl: https://api.openai.com/v1 # optional override
ollama:
baseUrl: http://localhost:11434
bedrock:
region: us-east-1
@embed Schema Directive
The @embed directive automates vector embedding at the schema level, eliminating the need for application code to compute and store embeddings on every write. Add it to any Float array field with a source pointing to the text field to embed:
type Document @table {
id: ID @primaryKey
content: String
embedding: [Float] @embed(source: "content", model: "my-embedding-model") @indexed(type: "HNSW")
}
On every write, Harper automatically calls the specified model to compute the embedding from source and stores it on the record. The @indexed(type: "HNSW") index is attached automatically when not explicitly specified.
Agent Loop
scope.models.generate now supports toolMode: 'auto', which runs an agentic loop — the model can invoke tools and Harper will automatically dispatch them until the model produces a final non-tool response. This makes it straightforward to build tool-using agents directly in Harper application code.
MCP Server
Harper 5.1 includes a built-in Model Context Protocol server, allowing LLM clients such as Claude Desktop, Cursor, and Zed to connect directly to a Harper instance and interact with its data and operations.
The MCP server exposes two profiles:
- Operations profile — wraps Harper's operations catalog as tools, with a curated default allow-list of read-only operations
- Application profile — auto-generates tools from a Harper application's Resource verb methods
The harper mcp CLI command provides a stdio bridge for use with MCP clients:
# Generate a config block for Claude Desktop
harper mcp print-config --client claude-desktop
# Run diagnostics against a running instance
harper mcp doctor
MCP is enabled by adding an mcp block to harper-config.yaml. See the MCP reference documentation for full configuration options, authentication, and tool customization.
Application Routing & Middleware
Harper 5.1 adds a named middleware ordering and URL routing system for application components, giving fine-grained control over how request handlers are composed.
urlPath routing
A component's HTTP handler can now declare a urlPath to scope its routes to a URL prefix. Harper strips the prefix before dispatching to the handler, so the handler's logic sees clean relative paths regardless of where it's mounted.
// This handler only receives requests under /api/v2/
export const handleHttpRequest = {
urlPath: '/api/v2',
async handleRequest(request) {
// request.url here is the path *after* /api/v2/ is stripped
},
};
before/after ordering
Components declare their execution order relative to other named middleware using before or after. The primary use case is ordering relative to Harper's built-in authentication middleware:
export const handleHttpRequest = {
name: 'my-rate-limiter',
before: 'authentication', // run this handler before authentication
async handleRequest(request) { ... },
};
export const handleAuthenticatedRequests = {
name: 'my-data-handler',
after: 'authentication', // only runs after authentication has completed
async handleRequest(request) { ... },
};
The name field makes a handler addressable so that others can reference it in their before/after declarations. Cyclic ordering is detected at startup and logged as a warning.
These options apply uniformly to HTTP handlers (handleHttpRequest), WebSocket handlers (onWebSocket), and protocol upgrade handlers (onUpgrade).
Node.js middleware adapter
request.getNodeRequestResponse() returns a { nodeRequest, nodeResponse, response } triple that bridges Harper's W3C-style Request/Response to Node.js's IncomingMessage/ServerResponse API. This makes it possible to integrate third-party Node.js middleware (Express, Koa, Passport, etc.) directly inside a Harper application handler without wrapping the entire server.
import someMiddleware from 'some-package';
export async function handleRequest(request) {
const { nodeRequest, nodeResponse, response } = request.getNodeRequestResponse();
someMiddleware(nodeRequest, nodeResponse, () => {});
return response;
}
nodeRequest mirrors the current request state (including any mutations from earlier middleware), while nodeResponse captures headers and body written by the consumer and resolves response once headers are available.
Deployment Tracking
deploy_component now records a full audit trail for every deployment in the system.hdb_deployment system table. Each deployment gets a deployment_id and tracks phases (prepare → load → replicate → restart → success), per-node outcomes, and a bounded event log capturing install output.
The response from deploy_component now includes a deployment_id:
{
"deployment_id": "a3f8c2...",
"message": "Component deployed successfully"
}
New operations provide access to deployment history:
list_deployments— query deployment history with filtersget_deployment— fetch a single deployment record; supports live SSE streaming for in-progress deploysget_deployment_payload— retrieve the stored tarball for a deploymentdelete_deployment_payload— free storage by removing the payload blob after deployment
See Deployment Operations in the Operations API reference for details.
HNSW int8 Quantization
HNSW vector indexes now support int8 quantization, reducing index storage by approximately 3× and improving search throughput approximately 5× with around 1% recall loss at recall@10:
type Document @table {
embedding: [Float] @indexed(type: "HNSW", quantization: "int8")
}
Search uses asymmetric scoring: queries use full-precision float vectors while the index graph uses int8, and results are reranked against full-precision vectors before returning. The full-precision vector is always stored on the record itself.
Per-query ef can be overridden at query time for applications that need to tune the recall/latency tradeoff dynamically.
int8 quantization is on by default for new HNSW indexes in 5.1. Existing indexes can be reindexed to take advantage of it.
Replication Improvements
Several replication reliability improvements are included in 5.1:
- Resumable bulk clone — interrupted full-table copies resume from where they left off rather than restarting from the beginning
- Client-side receive watchdog — dead WebSocket connections are now detected and recovered without waiting for a server-side timeout
- Wedge detection and recovery — stalled replication streams are detected and re-subscribed automatically
isLeaderflag onadd_node— explicitly request a full-table copy when joining a cluster, independent of the normal subscription logicreplication.pingInterval/replication.pingTimeout— configurable keepalive intervals for replication connections (values in milliseconds)- Reconnect backoff cap — reconnect retry backoff is now capped at 30 seconds; previously it could grow unbounded and leave a peer effectively unable to reconnect
- Boot replay bounded — the startup transaction-log replay is now bounded so it cannot stall indefinitely on corrupted or out-of-order entries; corrupt frames are skipped, and aged transaction logs are purged before replay begins
HTTP Caching
Harper 5.1 improves HTTP caching behavior in the CacheOfHttp resource. Responses are now cached based on RFC 9111 cacheable status codes rather than a hardcoded list. The allowStaleWhileRevalidate option enables serving stale cached content while refreshing in the background, reducing perceived latency for read-heavy workloads. The sourcedFrom configuration field identifies the upstream source for a cache table and drives the eviction and revalidation logic.
LOCAL_ONLY Writes
A new LOCAL_ONLY metadata flag allows writes that are persisted locally but never replicated to cluster peers:
await table.put({ id: 'node-local-key', value: 42 }, { metadata: { LOCAL_ONLY: true } });
This is useful for node-local state — per-node counters, cache metadata, or analytics that don't belong in the replicated dataset.
Configuration
HARPER_CONFIG environment variable
HARPER_CONFIG is now the recommended way to specify the configuration file location:
HARPER_CONFIG=/etc/harper/harper-config.yaml harper
Previously only HARPERDB_SETTINGS and CLI flags were available for this purpose.
RocksDB memory configuration
storage.rocks.blockCacheSize explicitly sets the RocksDB block cache size. When not set, Harper auto-sizes it based on available memory. The WriteBufferManager is now on by default at 1/3 of the block cache, which improves memory pressure handling under write-heavy workloads.
migrateOnStart
Setting storage.migrateOnStart: true automatically migrates LMDB databases to RocksDB on the next startup. This provides a path to migrate existing LMDB-backed instances without manual tooling, at the cost of a longer first startup time.
v4 to v5 Upgrade Improvements
Several reliability fixes landed for in-place v4→v5 upgrades:
- The node
hostnamefield no longer defaults tolocalhostduring an in-place upgrade. Previously, all nodes in a cluster would end up withhostname: localhostafter a v4→v5 upgrade, causing silent split-brain where nodes couldn't locate each other correctly. - The
__dbis__structure dictionary is now correctly persisted to RocksDB during the LMDB→RocksDB migration. Without this, cold restarts after migration would fail to decode records. - Blob file references, expiry metadata (
expiresAt), and residency flags are preserved during migration rather than being dropped.
These fixes make the in-place upgrade path substantially more reliable for clustered deployments. See the migration guide for the recommended upgrade procedure.
Please see the migration guide for suggestions on how to migrate from v4 to v5.