{"_id":"@dn-inc/openclaw-seahorse","_rev":"4-16c4b6d5c51bdbaf28917c4715842bb9","name":"@dn-inc/openclaw-seahorse","dist-tags":{"latest":"0.2.2"},"versions":{"0.1.0":{"name":"@dn-inc/openclaw-seahorse","version":"0.1.0","license":"MIT","_id":"@dn-inc/openclaw-seahorse@0.1.0","maintainers":[{"name":"dnotitia","email":"support@dnotitia.com"}],"dist":{"shasum":"e6873d55cc9b7bdad7bdbdbc3a73a6c3af47b478","tarball":"https://registry.npmjs.org/@dn-inc/openclaw-seahorse/-/openclaw-seahorse-0.1.0.tgz","fileCount":12,"integrity":"sha512-0QxNs9k2vDw8mKoGYdjKyOCV2Kr52n4g/j0PYga597L1IUOm7jRXjNpsLUQsQdzSrjaLIpPJz02hZvXrOSRZdQ==","signatures":[{"sig":"MEYCIQCAEKRMjMCJViqLT/Tpta6MUqfc6WfHlGNanbgHZRhecwIhAMhixbsvFIucCxq2LTDVSxJxvLTwasGXvZn4XDLKDeFa","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":61510},"main":"./index.ts","type":"module","engines":{"node":">=20"},"gitHead":"ee9c56dfb756af00d8faa2bbfdd76140c9cffcb4","scripts":{"test":"vitest run"},"_npmUser":{"name":"dnotitia","email":"support@dnotitia.com"},"openclaw":{"extensions":["./index.ts"]},"_npmVersion":"11.6.1","description":"Seahorse memory plugin for OpenClaw","directories":{},"_nodeVersion":"24.11.0","dependencies":{"ky":"^1.7.0","@sinclair/typebox":"^0.34.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.9.3","@types/node":"^20.0.0"},"peerDependencies":{"openclaw":">=2026.1.26"},"_npmOperationalInternal":{"tmp":"tmp/openclaw-seahorse_0.1.0_1771564575560_0.32366937054600653","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@dn-inc/openclaw-seahorse","version":"0.2.0","license":"MIT","_id":"@dn-inc/openclaw-seahorse@0.2.0","maintainers":[{"name":"dnotitia","email":"support@dnotitia.com"}],"dist":{"shasum":"58abbe579ffaa4366b7b51306c93581b2dd3f3f9","tarball":"https://registry.npmjs.org/@dn-inc/openclaw-seahorse/-/openclaw-seahorse-0.2.0.tgz","fileCount":12,"integrity":"sha512-RBxdmP96Oluot6Ip+YlHO9C6/2Y3hfqLIAHnvXNvqccbQ6Ad0yQD8zHLnSxh1nMksCMsMS+H7RYyoaqRgupaGg==","signatures":[{"sig":"MEYCIQCCQ5QQypAFINUmedUjEBi/eAtLFU53nXDi25BLXTQzbwIhAIbfzAkJ7tKm02pNdFpKmymnRiy9dMJNuyh3zLhJCrFv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":67617},"main":"./index.ts","type":"module","engines":{"node":">=20"},"gitHead":"9ba479713ca6dc71e9d51ea28da8d26fb49d735c","scripts":{"test":"vitest run"},"_npmUser":{"name":"dnotitia","email":"support@dnotitia.com"},"openclaw":{"extensions":["./index.ts"]},"_npmVersion":"11.6.1","description":"Seahorse memory plugin for OpenClaw","directories":{},"_nodeVersion":"24.11.0","dependencies":{"ky":"^1.7.0","@sinclair/typebox":"^0.34.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.9.3","@types/node":"^20.0.0"},"peerDependencies":{"openclaw":">=2026.1.26"},"_npmOperationalInternal":{"tmp":"tmp/openclaw-seahorse_0.2.0_1772082999435_0.2620587710886053","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@dn-inc/openclaw-seahorse","version":"0.2.1","license":"MIT","_id":"@dn-inc/openclaw-seahorse@0.2.1","maintainers":[{"name":"dnotitia","email":"support@dnotitia.com"}],"dist":{"shasum":"05c1c9ec35083068f38f569f46246de9fa6b22c3","tarball":"https://registry.npmjs.org/@dn-inc/openclaw-seahorse/-/openclaw-seahorse-0.2.1.tgz","fileCount":12,"integrity":"sha512-DujE3/Ucmkfxe+tmqw9jhIAOy/xkIispHKL1mlUosdpCBcWXK7x3TAT4iWbde8DhegVKvPuUTzQTnVm8omNtDg==","signatures":[{"sig":"MEYCIQCVaGD+CQV6P1YoUw/WEEb6MbVAjOLbrvsZNky1szdTWwIhANFMqUlEmU2vZOZoFB5eRSbbHxITcM2h3pIbNhbtP8nr","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":68651},"main":"./index.ts","type":"module","engines":{"node":">=20"},"gitHead":"209208e2fab21ca3ee51ac787ed9e01bd5f1e482","scripts":{"test":"vitest run"},"_npmUser":{"name":"dnotitia","email":"support@dnotitia.com"},"openclaw":{"extensions":["./index.ts"]},"_npmVersion":"11.6.1","description":"Seahorse memory plugin for OpenClaw","directories":{},"_nodeVersion":"24.11.0","dependencies":{"ky":"^1.7.0","@sinclair/typebox":"^0.34.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.9.3","@types/node":"^20.0.0"},"peerDependencies":{"openclaw":">=2026.1.26"},"_npmOperationalInternal":{"tmp":"tmp/openclaw-seahorse_0.2.1_1772087853791_0.8525213932780944","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@dn-inc/openclaw-seahorse","type":"module","version":"0.2.2","description":"Seahorse memory plugin for OpenClaw","license":"MIT","main":"./index.ts","publishConfig":{"access":"public"},"dependencies":{"@sinclair/typebox":"^0.34.0","ky":"^1.7.0"},"peerDependencies":{"openclaw":">=2026.1.26"},"engines":{"node":">=20"},"openclaw":{"extensions":["./index.ts"]},"scripts":{"test":"vitest run"},"devDependencies":{"@types/node":"^20.0.0","typescript":"^5.9.3","vitest":"^3.0.0"},"gitHead":"8a4a36350ed63b801e084c942c2da01c0b99b8c8","_id":"@dn-inc/openclaw-seahorse@0.2.2","_nodeVersion":"24.11.0","_npmVersion":"11.6.1","dist":{"integrity":"sha512-7TPEBvnmrq+ijZ9cVH5wkX2QTDWOZu9oVa5di3LtINdAB52Ukqoz/eAS8BYIlYuh3ln6V5DunB8Zl4nL3W8ScQ==","shasum":"83ac2e8ea01376022d815c8f76e599a66cfdca0a","tarball":"https://registry.npmjs.org/@dn-inc/openclaw-seahorse/-/openclaw-seahorse-0.2.2.tgz","fileCount":12,"unpackedSize":71217,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD6aR583TmCXSLlPZKs5zTttrXas3zhKyk9wETkjh/rGgIhAPbhHGcxIRPNmKBiHQw+mitx+9gSyWcJOY3dilwvleWj"}]},"_npmUser":{"name":"dnotitia","email":"support@dnotitia.com"},"directories":{},"maintainers":[{"name":"dnotitia","email":"support@dnotitia.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/openclaw-seahorse_0.2.2_1772098009414_0.7860341964587694"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-20T05:16:15.384Z","modified":"2026-02-26T09:26:49.737Z","0.1.0":"2026-02-20T05:16:15.681Z","0.2.0":"2026-02-26T05:16:39.572Z","0.2.1":"2026-02-26T06:37:33.933Z","0.2.2":"2026-02-26T09:26:49.576Z"},"license":"MIT","description":"Seahorse memory plugin for OpenClaw","maintainers":[{"name":"dnotitia","email":"support@dnotitia.com"}],"readme":"# Seahorse Memory Plugin for OpenClaw\n\nDrop-in replacement for OpenClaw's built-in memory search, powered by [Seahorse](https://seahorse.dnotitia.ai).\n\n- Uploads local memory files (`MEMORY.md`, `memory/**/*.md`) to Seahorse Storage\n- Syncs the entire workspace for full semantic search (`syncWorkspace: true`)\n- Routes `memory_search` to Seahorse's vector search API\n- Keeps `memory_get` reading from local files (same as native)\n\n## Why Seahorse?\n\nOpenClaw's built-in memory only indexes markdown notes the agent explicitly writes (`MEMORY.md` and `memory/**/*.md`). But agents produce far more than markdown — JSON data, YAML configs, PDF reports, images, spreadsheets, and other artifacts accumulate in the workspace over time, invisible to memory search.\n\nWith `syncWorkspace: true`, Seahorse indexes every supported file in the workspace automatically. The agent can semantically search across all of its own output — not just what it remembered to write down. Documents, data files, images, and markup (37 supported extensions) all become searchable through the same `memory_search` tool, with no API or workflow changes.\n\n## Requirements\n\n- Node.js 20+\n- OpenClaw >= 2026.1.26\n- Seahorse account (Storage + Table tenants)\n\n## Quick Start\n\n1. Install the plugin:\n\n```bash\nopenclaw plugins install @dn-inc/openclaw-seahorse\n```\n\n2. Get your Storage URL, Table URL, and API key from the [Seahorse console](https://seahorse.dnotitia.ai), then add to `plugins.entries` in `openclaw.json`:\n\n```jsonc\n\"openclaw-seahorse\": {\n  \"config\": {\n    \"storageUrl\": \"https://<your-storage-id>.api.seahorse.dnotitia.ai\",\n    \"tableUrl\": \"https://<your-table-id>.api.seahorse.dnotitia.ai\",\n    \"apiKey\": \"your-key-here\",\n    // Optional: search your entire workspace, not just memory files\n    \"syncWorkspace\": true\n  }\n}\n```\n\nThe `apiKey` field supports `${ENV_VAR}` syntax (e.g., `\"${SEAHORSE_API_KEY}\"`), or you can omit it entirely and set the `SEAHORSE_API_KEY` environment variable.\n\nThat's it. The plugin auto-syncs your files on startup and watches for changes in real time.\n\n## File Sync\n\nThe plugin runs a background service (`seahorse-sync`) that keeps Seahorse Storage in sync:\n\n- **Initial sync**: scans files on startup, uploads only changed files\n- **Live watch**: detects file create/modify/delete via `fs.watch` (1.5s debounce)\n- **Dedup**: mtime-based state tracking prevents redundant uploads\n- **Delete sync**: local file deletion triggers Seahorse Storage deletion\n\nBy default, only memory files (`MEMORY.md` + `memory/**/*.md`) are synced. Set `syncWorkspace: true` to sync the entire workspace — all supported files become searchable via `memory_search` without any tool or API changes.\n\nSupported file extensions (workspace sync):\n\n| Category | Extensions |\n|----------|-----------|\n| Documents | `.doc`, `.docx`, `.hwp`, `.hwpx`, `.odg`, `.odp`, `.odt`, `.pdf`, `.ppt`, `.pptx`, `.rtf` |\n| Data | `.csv`, `.json`, `.ods`, `.toml`, `.tsv`, `.xls`, `.xlsx`, `.yaml`, `.yml` |\n| Images | `.bmp`, `.gif`, `.jpeg`, `.jpg`, `.png`, `.tif`, `.tiff`, `.webp` |\n| Text / Markup | `.epub`, `.htm`, `.html`, `.markdown`, `.md`, `.text`, `.txt`, `.xhtml`, `.xml` |\n\nWhen workspace sync is enabled, dotfiles/dotdirs (`.*`) are always excluded. Add further patterns via `syncBlacklist`:\n\n```json\n{\n  \"storageUrl\": \"...\", \"tableUrl\": \"...\", \"apiKey\": \"...\",\n  \"syncWorkspace\": true,\n  \"syncBlacklist\": [\"node_modules/\", \"dist/\", \"*.log\", \"*.tmp\"]\n}\n```\n\nSupported blacklist patterns:\n\n| Pattern | Example | Matches |\n|---------|---------|---------|\n| `\"dir/\"` | `\"node_modules/\"` | Directory with that exact name |\n| `\"*.ext\"` | `\"*.tmp\"` | Any segment ending with `.tmp` |\n| `\"prefix*\"` | `\".*\"` | Any segment starting with `.` (built-in) |\n| `\"name\"` | `\"Thumbs.db\"` | Exact filename in any directory |\n\n## Storage Layout\n\nAll synced files are stored under the `openclaw/` prefix in Seahorse Storage (e.g., `MEMORY.md` → `openclaw/MEMORY.md`). This isolates plugin data from other data in the same Seahorse tenant. Search results are mapped back to workspace-relative paths automatically.\n\n## Tools\n\n### `memory_search`\n\nSemantic vector search over synced files via Seahorse.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `query` | string | Yes | Search query |\n| `maxResults` | number | No | Max results (default: `topK` config) |\n| `minScore` | number | No | Min relevance score 0-1 (default: `minScore` config) |\n\n### `memory_get`\n\nRead a local file by path.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `path` | string | Yes | Relative path (e.g., `MEMORY.md`, `memory/notes.md`) |\n| `from` | number | No | Start line (1-based) |\n| `lines` | number | No | Number of lines to read |\n\nBy default, allowed paths are `MEMORY.md` and files under `memory/` only. With `syncWorkspace: true`, any workspace file is accessible (except blacklisted paths).\n\n## Config Reference\n\n### Layer 0: Connection (required)\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `storageUrl` | string | Yes | Seahorse Storage tenant URL |\n| `tableUrl` | string | Yes | Seahorse Table tenant URL |\n| `apiKey` | string | No | API key. Auto-reads from `SEAHORSE_API_KEY` env var if omitted. Supports `${ENV_VAR}` syntax. |\n\n### Layer 1: Search & Sync Behavior (optional)\n\nThese override the OpenClaw-compatible defaults.\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `topK` | number | `6` | Number of results to return |\n| `minScore` | number | `0.35` | Minimum relevance score (0-1) |\n| `searchMode` | string | `\"hybrid\"` | `\"dense\"`, `\"sparse\"`, or `\"hybrid\"` |\n| `syncWorkspace` | boolean | `false` | Sync entire workspace (not just memory files) |\n| `syncBlacklist` | string[] | `[]` | Additional blacklist patterns for workspace sync (see [File Sync](#file-sync)) |\n\nExample — return more results with a lower score threshold:\n\n```json\n{\n  \"storageUrl\": \"...\", \"tableUrl\": \"...\", \"apiKey\": \"...\",\n  \"topK\": 20,\n  \"minScore\": 0.2\n}\n```\n\n### Layer 2: Seahorse Tuning (optional, advanced)\n\nFine-grained control over Seahorse search parameters. Omitted values use Seahorse server defaults.\n\n#### `dense` — Dense Vector Search\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `dense.column` | string | `\"dense_vector\"` | Dense vector column name |\n| `dense.efSearch` | number | *(server)* | HNSW ef_search parameter |\n\n#### `sparse` — Sparse (BM25) Search\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `sparse.column` | string | `\"sparse_vector\"` | Sparse vector column name |\n| `sparse.b` | number | *(server: 0.75)* | BM25 document length normalization (0-1) |\n| `sparse.k` | number | *(server: 1.2)* | BM25 term frequency saturation |\n\n#### `fusion` — Hybrid Fusion\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `fusion.type` | string | `\"rrf\"` | Fusion algorithm |\n| `fusion.alpha` | number | `0.7` | Dense weight (0-1). Sparse weight = 1 - alpha |\n| `fusion.k` | number | *(server: 60)* | RRF k parameter |\n\n#### `projection`\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `projection` | string | `\"id, text, metadata, distance, score\"` | SQL projection for returned fields |\n\nExample — dense-only search with custom ef_search:\n\n```json\n{\n  \"storageUrl\": \"...\", \"tableUrl\": \"...\", \"apiKey\": \"...\",\n  \"searchMode\": \"dense\",\n  \"dense\": { \"efSearch\": 200 }\n}\n```\n\nExample — hybrid with equal dense/sparse weighting (Seahorse native behavior):\n\n```json\n{\n  \"storageUrl\": \"...\", \"tableUrl\": \"...\", \"apiKey\": \"...\",\n  \"fusion\": { \"alpha\": 0.5 }\n}\n```\n\n## Defaults Comparison: OpenClaw vs Seahorse\n\nThe plugin ships with OpenClaw-compatible defaults. The table below shows where these differ from Seahorse server defaults, so you can tune toward Seahorse-native behavior when desired.\n\n| Parameter | Plugin Default | OpenClaw Native | Seahorse Server | Notes |\n|-----------|---------------|-----------------|-----------------|-------|\n| Search mode | `hybrid` | hybrid | *(must specify)* | OpenClaw uses hybrid by default |\n| Top K | `6` | 6 | *(must specify)* | OpenClaw returns 6 results |\n| Min score | `0.35` | 0.35 | *(no server filter)* | Client-side filtering |\n| Fusion alpha | `0.7` | vector 70% | `0.5` | **Key difference.** OpenClaw weights dense at 70%. Seahorse defaults to 50/50. Set `fusion.alpha: 0.5` for Seahorse-native. |\n| Fusion k | *(server)* | N/A | `60` | Omitted; server default used |\n| BM25 b | *(server)* | N/A | `0.75` | Omitted; server default used |\n| BM25 k | *(server)* | N/A | `1.2` | Omitted; server default used |\n| ef_search | *(server)* | N/A | *(server decides)* | Omitted; server default used |\n| Dense column | `dense_vector` | N/A | N/A | Must match your Seahorse table schema |\n| Sparse column | `sparse_vector` | N/A | N/A | Must match your Seahorse table schema |\n| Projection | `\"id, text, metadata, distance, score\"` | N/A | *(must specify)* | Requests both `distance` (dense) and `score` (hybrid) for proper normalization |\n\n> **Hybrid (RRF) Score Normalization**: In hybrid mode, Seahorse returns raw RRF scores (~0.01-0.03). The plugin normalizes these to a 0-1 scale by dividing by the theoretical maximum (`numRankers / (k + 1)`), making them compatible with the `minScore` threshold. With default k=60 and 2 rankers, a raw score of 0.016 becomes ~0.49 after normalization.\n","readmeFilename":"README.md"}