@shodocan/opencode-hindsight
v1.0.3
Published
OpenCode plugin that gives coding agents persistent memory using Hindsight
Downloads
173
Maintainers
Readme
@shodocan/opencode-hindsight
Shodocan OpenCode Hindsight plugin — Agent-aware persistent memory for OpenCode AI coding assistants.
This package is the Shodocan distribution of the OpenCode Hindsight plugin, published as
@shodocan/opencode-hindsighton npm. It is not the vanilla Vectorize Hindsight plugin. The Hindsight server remains a separate backend that you deploy independently; this plugin is the OpenCode integration layer that connects agents to Hindsight memory.
Your agent remembers what you tell it — across sessions, across projects.
Shodocan Changes
Compared to the vanilla opencode-hindsight plugin, this distribution adds:
- Agent-aware project bank routing — subagents and the main agent use separate project banks via
agentProjectBanks(exact name and*glob patterns), so review agents and build agents keep their memories isolated. - Runtime bank aliases —
runtimeProjectBanksdefines allowlisted per-tool-call bank aliases (bankAlias) so an agent can query other projects' banks in a single call without reconfiguration. - Trusted tool-context routing — project bank precedence chain (
HINDSIGHT_PROJECT_BANK_ID→HINDSIGHT_BANK_ID→runtimeProjectBanksalias →agentProjectBanksmatch →projectBank→ generated bank) ensures predictable routing for every tool call. - Compaction memory routing — when OpenCode context hits the compaction threshold, project memories are injected into the summary context and the session summary is saved as a memory, preserving context across compaction events.
- Privacy-safe logging — content wrapped in
<private>tags is never stored in Hindsight memory; structured logging keeps plugin operations visible without leaking user data. - Offline / Chinese deployment notes — the Quick Start section documents Huawei SWR mirror pull commands for
ghcr.io-blocked regions and local model mounting for air-gapped deployments.
Quick Start
1. Deploy Hindsight Server
Hindsight is the semantic memory backend required by this plugin. You need to deploy it first.
Using Docker Compose (recommended):
This project includes a ready-to-use Docker Compose configuration in the deploy/ directory that's pre-configured for DeepSeek integration.
# Navigate to the deploy directory
cd deploy/
# Create .env file with your DeepSeek API key
echo "HINDSIGHT_API_LLM_API_KEY=your-deepseek-api-key-here" > .env
# Start Hindsight server
docker compose up -dConfiguration Notes:
- The Docker Compose setup uses DeepSeek's reasoning model (
deepseek-reasoner) by default - You need a valid DeepSeek API key from DeepSeek Platform
- The configuration includes persistent volume mounting at
~/.hindsight-docker - Server runs on port 8888 (web interface) and 9999 (additional service)
Using Docker (simple):
# Pull the latest Hindsight image
docker pull ghcr.io/vectorize-io/hindsight:latest
# Run Hindsight server on port 8888 with persistent storage
docker run -d \
--name hindsight \
-p 8888:8888 \
-v hindsight_data:/data \
ghcr.io/vectorize-io/hindsight:latestFor Chinese users: If you cannot access
ghcr.io, use the Huawei SWR mirror:docker pull swr.cn-north-4.myhuaweicloud.com/cn/hindsight:latest docker run -d \ --name hindsight \ -p 8888:8888 \ -v hindsight_data:/data \ swr.cn-north-4.myhuaweicloud.com/cn/hindsight:latest
Offline / No-network access:
When running in an environment without internet access, Hindsight will fail to download embedding and reranker models from HuggingFace. To use pre-downloaded local models:
# docker-compose.yml additions
environment:
HINDSIGHT_API_EMBEDDINGS_PROVIDER: local
HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL: /home/hindsight/models/bge-m3
HINDSIGHT_API_RERANKER_PROVIDER: local
HINDSIGHT_API_RERANKER_LOCAL_MODEL: /home/hindsight/models/bge-reranker-v2-m3
volumes:
- /path/to/your/models/bge-m3:/home/hindsight/models/bge-m3
- /path/to/your/models/bge-reranker-v2-m3:/home/hindsight/models/bge-reranker-v2-m3Models can be pre-downloaded from ModelScope or HuggingFace on a machine with internet, then mounted into the container. The default models are BAAI/bge-small-en-v1.5 (embeddings, 384-dim) and cross-encoder/ms-marco-MiniLM-L-6-v2 (reranker).
Note: If changing the embedding model after the database is initialized, you must clear existing data first: stop the container, run
rm -rf ~/.hindsight-docker, then restart.
Alternative deployment methods:
- Binary release: Download pre-built binaries from Hindsight releases
- From source: Clone and build from Hindsight repository
Verify deployment:
curl http://localhost:8888/health
# Expected response: {"status":"healthy","database":"connected"}2. Install the Plugin
From npm (recommended)
npm install -g @shodocan/opencode-hindsightThen register the plugin in your OpenCode configuration:
{
"plugin": ["@shodocan/opencode-hindsight"]
}Save the file to ~/.config/opencode/opencode.json.
From source (local / file:// development)
Clone the repository and build locally:
git clone https://github.com/Shodocan/opencode-hindsight.git
cd opencode-hindsight
bun install
bun run build
# Link the plugin to OpenCode configuration using a file:// path
echo '{"plugin": ["file://'$(pwd)'"]}' > ~/.config/opencode/opencode.jsonThis will:
- Clone the plugin source code
- Install all required dependencies
- Build the plugin locally
- Register the plugin in your OpenCode configuration using a local file:// path
- Create the
/hindsight-initcommand for codebase indexing
Note: Restart OpenCode for the changes to take effect.
3. Configure Connection
If your Hindsight server is not running on localhost:8888, configure the connection:
Using environment variable:
export HINDSIGHT_BASE_URL="http://localhost:8888"Using configuration file:
Create ~/.config/opencode/hindsight.jsonc:
{
"baseUrl": "http://localhost:8888"
}4. Restart and Verify
Restart your OpenCode session and verify the plugin is loaded:
opencode -c # Should show 'hindsight' in the available toolsTest the plugin:
After restarting OpenCode, ask the agent to save a test memory, or use the in-session hindsight tool if your OpenCode UI exposes tool calls directly. The hindsight tool is an OpenCode agent tool, not the opencode-hindsight terminal binary.
Installation
Note: For a complete step-by-step guide including Hindsight server deployment, see the Quick Start section above.
From npm (Recommended)
Install the package and register it in your OpenCode configuration:
npm install -g @shodocan/opencode-hindsightAdd the plugin entry to ~/.config/opencode/opencode.json:
{
"plugin": ["@shodocan/opencode-hindsight"]
}Hindsight runs locally on port 8888 by default. If you need to connect to a different server, set the base URL:
export HINDSIGHT_BASE_URL="http://localhost:8888"Or let your agent do it — paste this into OpenCode:
Install @shodocan/opencode-hindsight by following https://raw.githubusercontent.com/Shodocan/opencode-hindsight/main/README.mdLocal Source / File:// Development
When developing or testing the plugin locally, use a file path in your OpenCode configuration:
{
"plugin": ["file:///path/to/opencode-hindsight"]
}Replace /path/to/opencode-hindsight with the absolute path to the plugin directory. The plugin source repository is https://github.com/Shodocan/opencode-hindsight.
For LLM Agents
If you're an LLM agent helping set up @shodocan/opencode-hindsight, follow these steps:
Step 1: Install from npm or clone from source
npm install (recommended):
npm install -g @shodocan/opencode-hindsightOr clone and build:
git clone https://github.com/Shodocan/opencode-hindsight.git
cd opencode-hindsight
bun install
bun run buildStep 2: Register in OpenCode configuration
For npm install:
{
"plugin": ["@shodocan/opencode-hindsight"]
}For local source:
{
"plugin": ["file:///path/to/opencode-hindsight"]
}Replace /path/to/opencode-hindsight with the absolute path of the cloned directory.
Save to ~/.config/opencode/opencode.json.
Note: OpenCode uses .json format for opencode.json. The plugin path can be a local file path if developing locally.
Step 3: Configure Hindsight server
Hindsight runs locally on port 8888 by default. If you need to connect to a different server, set the base URL:
export HINDSIGHT_BASE_URL="http://localhost:8888"Or create ~/.config/opencode/hindsight.jsonc:
{
"baseUrl": "http://localhost:8888" // Optional, defaults to localhost:8888
}Both .jsonc and .json formats are supported for Hindsight configuration, but OpenCode configuration uses .json format only.
Step 4: Verify setup
Tell the user to restart OpenCode and run:
opencode -cThey should see hindsight in the tools list. If not, check:
- Is Hindsight server running? (default: http://localhost:8888)
- Is the plugin in
opencode.json? - Check logs:
tail ~/.opencode-hindsight.log
Step 5: Initialize codebase memory (optional)
Run /hindsight-init to have the agent explore and memorize the codebase.
Features
Context Injection
Context injection happens automatically when the user sends the first message of a new session — not when OpenCode starts up. The mechanism works as follows:
- Detection: The
chat.messagehook checks whether the current session ID has been seen before via an in-memoryinjectedSessionsSet - First message only: If the session ID is not in the Set, it's added immediately (preventing double-injection on subsequent messages in the same session)
- Three parallel API calls are made using the user's message as the search query:
getProfile(banks.user, userMessage)— retrieves cross-project user profile facts via semantic searchsearchMemories(userMessage, banks.user)— retrieves relevant user-scoped memories via semantic searchlistMemories(banks.project, maxProjectMemories)— lists the latest N project memories (no relevance filtering, all have[100%]similarity)
- Format & Inject: Results are formatted into the
[HINDSIGHT]context block and prepended as a syntheticPartto the message parts — invisible to the user, visible only to the AI model
Timing summary:
| Event | When | |---|---| | OpenCode starts | No injection | | User sends first message | Hook fires → injection happens → message processed | | User sends second message | Hook fires but session already marked → skip injection |
Example of what the agent sees:
[HINDSIGHT]
User Profile:
- Prefers concise responses
- Expert in TypeScript
Project Knowledge:
- [100%] Uses Bun, not Node.js
- [100%] Build: bun run build
Relevant Memories:
- [82%] Build fails if .env.local missingThe agent uses this context automatically — no manual prompting needed.
Keyword Detection
Say "remember", "save this", "don't forget" etc. and the agent auto-saves to memory.
You: "Remember that this project uses bun"
Agent: [saves to project memory]Add custom triggers via keywordPatterns config.
Codebase Indexing
Run /hindsight-init to explore and memorize your codebase structure, patterns, and conventions.
Preemptive Compaction
When context hits 80% capacity:
- Triggers OpenCode's summarization
- Injects project memories into summary context
- Saves session summary as a memory
This preserves conversation context across compaction events.
Privacy
Secret content is <private>sk-abc123</private>Content in <private> tags is never stored.
Tool Usage
The hindsight tool is available to the agent:
| Mode | Args | Description |
| --------- | ---------------------------- | ----------------- |
| add | content, type?, scope? | Store memory (asynchronous) |
| search | query, scope? | Search memories |
| profile | query? | View user profile |
| list | scope?, limit? | List memories |
| forget | memoryId, scope? | Delete memory |
Scopes: user (cross-project), project (default)
Types: project-config, architecture, error-solution, preference, learned-pattern, conversation
Important Notes:
addoperation is asynchronous by default to prevent timeouts during memory processing- Metadata values must be strings — non-string values are automatically converted
- Response includes
operationIdfor tracking asynchronous operations - Memory processing may take 30-60 seconds for complex content extraction
Example Usage
// Store a project-specific configuration
hindsight({
mode: "add",
content: "This project uses Bun for package management and TypeScript for type safety",
type: "project-config",
scope: "project"
})
// Search for relevant memories
hindsight({
mode: "search",
query: "package manager",
scope: "project",
limit: 5
})
// View user profile (cross-project preferences)
hindsight({
mode: "profile"
})Memory Scoping
| Scope | Tag | Persists |
| ------- | -------------------------------------- | ------------ |
| User | hindsight_user_{sha256(git email)} | All projects |
| Project | hindsight_project_{sha256(directory)} | This project |
Configuration
Create ~/.config/opencode/hindsight.jsonc or ~/.config/opencode/hindsight.json:
{
// Hindsight server URL (default: http://localhost:8888)
"baseUrl": "http://localhost:8888",
// Min similarity for memory retrieval (0-1, default: 0.6)
"similarityThreshold": 0.6,
// Max memories injected per request (default: 5)
"maxMemories": 5,
// Max project memories listed (default: 10)
"maxProjectMemories": 10,
// Max profile facts injected (default: 5)
"maxProfileItems": 5,
// Include user profile in context (default: true)
"injectProfile": true,
// Prefix for bank names when userBank/projectBank not set (default: "opencode")
"bankPrefix": "opencode",
// Optional: Set exact user bank (overrides auto-generated bank)
"userBank": "my-custom-user-bank",
// Optional: Set exact project bank (overrides auto-generated bank)
"projectBank": "my-project-bank",
// Optional: Route specific agents/subagents to project banks by exact name or glob
"agentProjectBanks": {
"review-*": "proj-review",
"tdd": "proj-tdd"
},
// Optional: Allowlisted per-tool-call project bank aliases
"runtimeProjectBanks": {
"other-repo": "proj-other-repo",
"review": "proj-review"
},
// Max tokens for recall operations (default: 4096)
"maxTokens": 4096,
// Budget for recall operations: 'low', 'mid', or 'high' (default: 'mid')
"budget": "mid",
// Extra keyword patterns for memory detection (regex)
"keywordPatterns": ["log\\s+this", "write\\s+down"],
// Context usage ratio that triggers compaction (0-1, default: 0.8)
"compactionThreshold": 0.8
}All fields optional.
Environment Variables
The following environment variables take precedence over configuration file settings:
HINDSIGHT_BASE_URL: Hindsight server URL (e.g.,http://localhost:8888)- Priority: Highest — overrides config file and defaults
- Use case: Different servers for development/production, docker containers
Configuration loading order (highest to lowest priority):
- Environment variables
- Configuration file (
hindsight.jsoncorhindsight.json) - Default values
Project bank precedence (highest to lowest):
HINDSIGHT_PROJECT_BANK_IDHINDSIGHT_BANK_ID- allowlisted
bankAliasfromruntimeProjectBanks - matching
agentProjectBanksexact/glob entry projectBank- generated
p_<project>_<hash>bank
Configuration Notes:
- File format: Both
.jsonc(with comments) and.jsonformats are supported - Memory operations are asynchronous by default to prevent timeouts (30-60 seconds processing time)
- Metadata values must be strings — non-string values are automatically converted:
- Numbers and booleans: converted to string representation
- Objects and arrays: converted to JSON strings
- Null/undefined: converted to empty string
- Bank names are auto-generated using SHA-256 hashes if not explicitly specified
Bank Selection
By default, banks are auto-generated using bankPrefix plus a SHA-256 hash:
- User bank:
{prefix}_user_{sha256(git_email)}- Uses git user.email if available, otherwise falls back to system username
- Project bank:
{prefix}_project_{sha256(project_directory)}- Uses the absolute path of the current working directory
You can override this by specifying exact bank names:
{
// Use a specific bank for user memories (cross-project)
"userBank": "my-team-workspace",
// Use a specific bank for project memories (project-specific)
"projectBank": "my-awesome-project",
}This is useful when you want to:
- Share memories across team members (same
userBank) - Sync memories between different machines for the same project
- Organize memories using your own naming scheme
- Integrate with existing Hindsight banks from other tools
Bank Names from Environment Variables
Bank fields can reference environment variables when the entire configured value is a variable reference. Supported forms are $VAR and ${VAR}, where variable names use shell-style identifiers matching [A-Za-z_][A-Za-z0-9_]*:
{
"userBank": "$OPENCODE_USER_BANK",
"projectBank": "$OPENCODE_PROJECT_BANK",
"agentProjectBanks": {
"review-*": "$OPENCODE_REVIEW_BANK"
},
"runtimeProjectBanks": {
"reviews": "${OPENCODE_REVIEW_BANK}"
}
}Rules:
- Only full-value references are expanded; unsupported or partial env-reference syntax remains literal.
"proj-$OPENCODE_REVIEW_BANK"remains literal. - Missing or empty environment variables are treated as unset.
- For
agentProjectBanksandruntimeProjectBanks, entries with missing or empty env refs are dropped. - Expansion happens when the plugin loads configuration, so restart OpenCode after changing these variables.
Agent-Aware Project Bank Routing
Subagents can use different project banks without changing OpenCode core. Configure agentProjectBanks with exact names or * glob patterns:
{
"projectBank": "proj-default",
"agentProjectBanks": {
"review-*": "proj-review",
"agent-a": "proj-agent-a",
"agent-b": "proj-agent-b"
}
}With this configuration:
- the main/default agent uses
proj-default agent-ausesproj-agent-aagent-busesproj-agent-breview-security-skeptic,review-bug-hunter, and otherreview-*agents useproj-review
Exact agent matches take precedence over glob patterns. If no agent mapping matches, the plugin falls back to projectBank or the generated project bank.
Runtime Project Bank Aliases
For one-off tool calls, configure allowlisted aliases with runtimeProjectBanks:
{
"runtimeProjectBanks": {
"other-repo": "proj-other-repo"
}
}Then call:
hindsight(mode: "search", query: "auth flow", bankAlias: "other-repo")bankAlias applies only to that tool call. Unknown aliases return an error. The tool does not accept arbitrary bank IDs from the model.
API Compatibility
This plugin uses the official @vectorize-io/hindsight-client (v0.6.2) and is compatible with Hindsight API v1. Key compatibility notes:
- Asynchronous operations: Memory addition uses
async: trueby default to prevent timeouts - Metadata handling: All metadata values are converted to strings to match API requirements
- Response format: Responses include
operationId(notid) for tracking asynchronous operations - Timeout handling: Operations timeout after 120 seconds to accommodate Hindsight's processing time
Usage with Oh My OpenCode
If you're using Oh My OpenCode, disable its built-in auto-compact hook to let hindsight handle context compaction:
Add to ~/.config/opencode/oh-my-opencode.json:
{
"disabled_hooks": ["anthropic-context-window-limit-recovery"]
}Development
# Clone and setup
git clone https://github.com/Shodocan/opencode-hindsight.git
cd opencode-hindsight
# Install dependencies
bun install
# Build the plugin
bun run build
# Type checking
bun run typecheck
# Test with local configuration (file:// path)
echo '{"plugin": ["file://'$(pwd)'"]}' > ~/.config/opencode/opencode.jsonTroubleshooting
Common Issues
Timeout errors when adding memories
- Cause: Hindsight server processing takes 30-60 seconds for memory extraction
- Solution: Plugin uses asynchronous operations (
async: true) by default - Verification: Check if response includes
operationIdinstead ofid
hindsighttool not available- Cause: Plugin not loaded or configuration incorrect
- Solution:
- Verify plugin is in
~/.config/opencode/opencode.json - Restart OpenCode after configuration changes
- Check Hindsight server is running:
curl http://localhost:8888/health
- Verify plugin is in
Metadata not saving correctly
- Cause: Hindsight API requires all metadata values to be strings
- Solution: Plugin automatically converts non-string values:
- Numbers/booleans → string representation
- Objects/arrays → JSON strings
- Null/undefined → empty strings
Empty results from
listcommand- Cause: The
listDocumentsAPI may not return all memories - Workaround: Use
searchwith specific queries instead - Note: This is a limitation of the current Hindsight API implementation
- Cause: The
Memory not appearing in searches
- Cause: Asynchronous processing may still be in progress
- Solution: Wait 1-2 minutes for memory consolidation
- Verification: Check Hindsight server logs for processing status
Logs
# Plugin logs
tail -f ~/.opencode-hindsight.log
# Hindsight server logs (if running locally)
# Check your Hindsight server documentation for log locationLicense
MIT
