npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

opencode-elf

v0.5.3

Published

Emergent Learning Framework (ELF) plugin for OpenCode - Learn from past successes and failures with hybrid global/project storage

Readme

OpenCode ELF Plugin

Emergent Learning Framework (ELF) for OpenCode - Learn from past successes and failures to continuously improve your AI coding assistant.

Overview

  • Golden Rules: Constitutional principles that guide all actions
  • Heuristics: Pattern-based suggestions triggered by keywords/regex
  • Learnings: Automatic recording of tool execution failures and successes
  • Context Injection: Relevant past experiences are injected into each conversation
  • Hybrid Storage: Support for both global and project-scoped memories
  • Hybrid Search: Combined vector (semantic) + FTS5 (keyword) search for best results
  • Privacy Controls: Use <private> tags to exclude sensitive data from storage
  • Automatic Cleanup: Configurable expiration for unused rules and old learnings
  • Local-First: Uses local SQLite storage and local embeddings (no API calls)

Key Features

Hybrid Storage

ELF supports both global and project-scoped memories:

  • Global memories: Shared across all projects (stored in ~/.opencode/elf/memory.db)
  • Project memories: Specific to each project (stored in <project>/.opencode/elf/memory.db)
  • Project detection via .git or .opencode directories
  • Project memories are prioritized in context injection
  • Add project memories to .gitignore for privacy, or commit for team sharing

Example usage:

"Add a global rule: Always validate user inputs"
"Add a project rule: This API requires JWT authentication"

Context injection shows both, with project memories tagged:

Golden Rules:
- Always validate user inputs
- This API requires JWT authentication [project]

Performance Optimizations

  • Lazy Loading: Non-blocking plugin initialization - OpenCode starts instantly
  • Parallel Database Queries: Global + project databases queried simultaneously (30-50% faster)
  • Embedding Cache: LRU cache with 5-minute TTL reduces embedding generation by 60-70% on repeated queries
  • Efficient Context Retrieval: Optimized vector similarity search with intelligent caching

Local-First Architecture

  • Uses local SQLite storage (no cloud dependencies)
  • Local embeddings with @xenova/transformers (no API calls)
  • All data stays on your machine
  • Works offline after initial model download (~90MB)
  • Automatic cleanup prevents database from growing indefinitely

Hybrid Search (Vector + FTS)

ELF now supports hybrid search combining semantic vector search with SQLite FTS5 full-text search:

  • Vector Search: Great for concepts ("how do I fix a database lock?")
  • FTS Search: Superior for specifics ("error code 503", "function processData")
  • Hybrid: Combines both approaches for best results

Results include a matchType indicator:

  • semantic - Found via vector similarity
  • keyword - Found via FTS keyword match
  • hybrid - Found by both (boosted score)

Example usage via the elf tool:

"Search my learnings for error code ENOENT"
"Find learnings about authentication failures"

Privacy Controls

Protect sensitive data using <private> tags:

The API key is <private>sk-abc123xyz</private>

How it works:

  • Content wrapped in <private>...</private> tags is never stored
  • If the entire content contains privacy tags, the learning is skipped
  • Partial private content is replaced with [REDACTED]
  • Works for both content and context in learnings

Installation

Add to your OpenCode config:

// opencode.jsonc
{
  "plugin": ["opencode-elf@latest"]
}

Using @latest ensures you always get the newest version automatically when OpenCode starts.

Restart OpenCode. The plugin will automatically load.

Architecture

┌──────────────────────────────────────────────────────┐
│              OpenCode ELF Plugin                     │
├──────────────────────────────────────────────────────┤
│                                                      │
│  Initialization: LAZY LOADING                        │
│  ┌────────────────────────────────────────────────┐  │
│  │ Background: DB init + Model load + Seeding     │  │
│  │ Returns hooks immediately (non-blocking)       │  │
│  │ First interaction waits for init completion    │  │
│  └────────────────────────────────────────────────┘  │
│                                                      │
│  Hooks:                                              │
│  ┌─────────────────┐      ┌────────────────────┐     │
│  │  chat.params    │─────▶│ Context Injection  │     │
│  │  (pre-LLM)      │      │ - Golden Rules     │     │
│  │                 │      │ - Past Learnings   │     │
│  │                 │      │ - Heuristics       │     │
│  └─────────────────┘      └────────────────────┘     │
│                                                      │
│  ┌─────────────────┐      ┌────────────────────┐     │
│  │  event          │─────▶│ Learning Loop      │     │
│  │  (post-tool)    │      │ - Record failures  │     │
│  │                 │      │ - Track patterns   │     │
│  └─────────────────┘      └────────────────────┘     │
│                                                      │
│  Storage:                                            │
│  ┌──────────────────────────────────────────────┐    │
│  │  libsql (SQLite)                             │    │
│  │  ~/.opencode/elf/memory.db                   │    │
│  └──────────────────────────────────────────────┘    │
│                                                      │
│  Embeddings:                                         │
│  ┌──────────────────────────────────────────────┐    │
│  │  @xenova/transformers                        │    │
│  │  Model: Xenova/all-MiniLM-L6-v2              │    │
│  └──────────────────────────────────────────────┘    │
│                                                      │
└──────────────────────────────────────────────────────┘

How It Works

Context Injection (Before each message)

When you send a message to OpenCode, ELF:

  1. Generates an embedding for your message
  2. Searches for relevant Golden Rules and past Learnings
  3. Injects this context into the system prompt

Example injection:

[ELF MEMORY]

Golden Rules:
- Always validate user inputs before processing
- Use TypeScript strict mode for type safety
- This project requires JWT authentication [project]

Relevant Past Experiences:
✗ [85%] Tool 'bash' failed: command not found - npm
✗ [78%] API authentication failed without JWT token [project]

Applicable Heuristics:
- When working with npm, always check if node_modules exists

Learning Loop (After each tool execution)

When a tool executes, ELF:

  1. Monitors the result (stdout, stderr, exit codes)
  2. Records failures automatically to project database
  3. Stores them with embeddings for future retrieval

Agent Tool (Programmatic Access)

The plugin provides an elf tool that agents can invoke to manage memory:

Available modes:

  • list-rules - List all golden rules (optional scope: "global" | "project")
  • list-heuristics - List all heuristics (optional scope)
  • list-learnings - View recent learnings (optional limit and scope)
  • add-rule - Add new golden rule (auto-generates embeddings, optional scope)
  • add-heuristic - Add new heuristic pattern (optional scope)
  • metrics - View performance metrics
  • search - Hybrid search across all learnings (requires query, optional limit)

Examples:

"Add a global rule: Always use async/await"
"Add a project rule: This API requires authentication tokens"
"Show me project-specific golden rules"
"List all learnings from this project"
"Search learnings for error code ENOENT"

Quick Start

1. Installation & First Run

After installing the plugin, restart OpenCode. The plugin uses lazy loading for fast startup:

What happens:

  • OpenCode starts immediately (plugin loads in background)
  • Database initialization happens asynchronously
  • Embedding model loads in background (~90MB download on first run)
  • Default data seeding occurs if needed (first run only)

You'll see output like:

ELF: Initializing in background...
ELF: Ready (took 2847ms)

First interaction timing:

  • Your first message will wait for initialization to complete (1-3 seconds)
  • Subsequent messages are instant (no waiting)
  • This moves the "loading time" from startup to first use

The plugin is ready to use! No manual setup required.

2. Verify Installation (Optional)

If you're developing locally, you can run the simulation test to verify everything works:

npm run test:simulate

Expected output:

🤖 Starting ELF Simulation...

1️⃣  Seeding Golden Rule...
ELF: Loading embedding model...
ELF: Model loaded.

2️⃣  Simulating Chat Request...
✅ SUCCESS: Context injected Golden Rule into system prompt.

3️⃣  Simulating Tool Failure...
✅ Tool failure event processed.

4️⃣  Verifying Learning Retrieval...
✅ SUCCESS: Retrieved the learned failure from memory.

🎉 Simulation Complete.

3. Start Using OpenCode

The plugin now works automatically! Golden rules and learnings will be injected into conversations as context.

Managing Data

The plugin automatically seeds default data on first run. You can view and manage this data in three ways:

1. Natural Conversation (Recommended)

Simply ask OpenCode to manage your ELF memory in natural language:

"Add a golden rule: Always use async/await instead of callbacks"
"Add a project-specific rule: This API requires JWT authentication"
"Show me my current golden rules"
"Show me project-specific learnings"
"Add a heuristic for npm errors"
"What have I learned recently?"

OpenCode will automatically invoke the elf tool to:

  • Add new golden rules (with automatic embedding generation)
  • Add new heuristics
  • List rules, heuristics, and learnings
  • View performance metrics

2. Optional: Slash Commands

If you prefer slash commands for quick inspection, you can add them to your OpenCode config:

// opencode.jsonc or ~/.config/opencode/opencode.jsonc
{
  "plugin": ["opencode-elf@latest"],
  "command": {
    "elf": {
      "template": "Use the elf tool. Arguments: $ARGUMENTS",
      "description": "ELF memory system. Commands: rules list, heuristics list, learnings list, search, metrics, rules add, heuristics add"
    }
  }
}

Then you can use:

/elf
/elf rules list
/elf search "error code 503"
/elf metrics

3. Using CLI Tools (Advanced)

For local development or advanced management, use the npm scripts (requires plugin directory access):

Golden Rules

Golden Rules are constitutional principles that should always guide the AI's behavior.

# Add a new rule
npm run rules:add "Always validate inputs before processing"

# List all rules
npm run rules:list

# Re-seed default rules (if you deleted them)
npm run rules:seed

Heuristics

Heuristics are pattern-based suggestions triggered by regex matching.

# Add a new heuristic
npm run heuristics:add "npm install" "Check package.json exists first"

# List all heuristics
npm run heuristics:list

# Re-seed default heuristics (if you deleted them)
npm run heuristics:seed

Learnings

View recorded successes and failures:

# View all learnings
npm run learnings:view

# View only failures
npm run learnings:view failure

# View only successes
npm run learnings:view success

Performance Metrics

Track ELF's performance and usage:

npm run metrics:view

This shows:

  • Average latency for context injection
  • Total context injections
  • Failures learned
  • Recent activity

Cleanup & Maintenance

ELF includes automatic cleanup to prevent the database from growing indefinitely:

Automatic Cleanup (Default: Enabled)

  • Runs once per day during normal operation
  • Deletes golden rules with 0 hits after 90 days
  • Deletes learnings older than 60 days
  • Deletes heuristics older than 180 days

Manual Cleanup:

# Preview what would be deleted
npm run cleanup:preview

# Delete expired data
npm run cleanup:clean

Configuration: Edit src/config.ts to customize expiration settings:

export const RULE_EXPIRATION_DAYS = 90;        // Delete unused rules
export const RULE_MIN_HITS_TO_KEEP = 1;        // Rules with < 1 hits
export const LEARNING_EXPIRATION_DAYS = 60;    // Delete old learnings
export const HEURISTIC_EXPIRATION_DAYS = 180;  // Delete old heuristics
export const AUTO_CLEANUP_ENABLED = true;      // Enable/disable auto-cleanup

After editing config, rebuild with npm run build.

Configuration

The plugin can be configured by modifying src/config.ts and rebuilding with npm run build.

Query & Performance Settings

// Query limits
export const MAX_GOLDEN_RULES = 5;             // Max rules to inject per message
export const MAX_RELEVANT_LEARNINGS = 10;      // Max learnings to inject
export const SIMILARITY_THRESHOLD = 0.7;       // Min similarity for relevance

// Embedding model
export const EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";

// Hybrid storage
export const ENABLE_HYBRID_STORAGE = true;     // Enable project-scoped memories

Expiration Settings

export const RULE_EXPIRATION_DAYS = 90;        // Delete unused rules after 90 days
export const RULE_MIN_HITS_TO_KEEP = 1;        // Rules with 0 hits are candidates
export const LEARNING_EXPIRATION_DAYS = 60;    // Delete learnings after 60 days
export const HEURISTIC_EXPIRATION_DAYS = 180;  // Delete heuristics after 180 days
export const AUTO_CLEANUP_ENABLED = true;      // Enable automatic cleanup

Database Locations

Global Storage (cross-project):

  • macOS/Linux: ~/.opencode/elf/memory.db
  • Windows: C:\Users\<username>\.opencode\elf\memory.db

Project Storage (project-specific):

  • <project-root>/.opencode/elf/memory.db
  • Automatically detected by finding .git or .opencode directories

To query the database directly:

sqlite3 ~/.opencode/elf/memory.db "SELECT * FROM golden_rules"

To reset all data:

rm -rf ~/.opencode/elf/

Database Schema

The plugin uses SQLite with the following tables:

golden_rules

  • id (TEXT PK)
  • content (TEXT)
  • embedding (TEXT - JSON array)
  • created_at (INTEGER - timestamp)
  • hit_count (INTEGER - usage tracking)

learnings

  • id (TEXT PK)
  • content (TEXT)
  • category ('success' | 'failure')
  • embedding (TEXT - JSON array)
  • created_at (INTEGER)
  • context_hash (TEXT - for deduplication)

learnings_fts (FTS5 Virtual Table)

  • Full-text search index on learnings
  • Synced automatically via triggers
  • Enables fast keyword-based search

heuristics

  • id (TEXT PK)
  • pattern (TEXT - regex)
  • suggestion (TEXT)
  • created_at (INTEGER)

Project Structure

opencode-elf/
├── package.json              # Dependencies & scripts
├── tsconfig.json             # TypeScript config
├── README.md                 # This file
├── LICENSE                   # MIT license
│
├── src/
│   ├── index.ts              # Plugin entry (hooks)
│   ├── config.ts             # Configuration
│   │
│   ├── types/
│   │   └── elf.ts            # TypeScript types
│   │
│   ├── db/
│   │   └── client.ts         # Database client & schema
│   │
│   └── services/
│       ├── embeddings.ts     # Vector embeddings
│       ├── metrics.ts        # Performance tracking
│       ├── query.ts          # Context builder
│       └── cleanup.ts        # Automatic data cleanup
│
├── scripts/
│   ├── manage-rules.js       # CLI: add/list/delete rules
│   ├── manage-heuristics.js  # CLI: add/list/delete heuristics
│   ├── view-learnings.js     # CLI: view learnings
│   ├── view-metrics.js       # CLI: view metrics
│   ├── cleanup-expired.js    # CLI: cleanup expired data
│   ├── seed-rules.js         # Seed default rules
│   └── seed-heuristics.js    # Seed default heuristics
│
└── tests/
    ├── simulate.ts           # End-to-end simulation
    ├── test-hybrid.ts        # Hybrid storage tests
    └── benchmark.ts          # Performance benchmarks

Development

Building

# Install dependencies
npm install

# Build for production
npm run build

# Watch mode for development
npm run dev

Testing

# Run end-to-end simulation
npm run test:simulate

# Test hybrid storage functionality
npm run test:hybrid

# Run performance benchmarks
npm run test:benchmark

Local Development Installation

For local development without publishing to npm:

# Clone and build
git clone https://github.com/mark-hingston/opencode-elf.git
cd opencode-elf
npm install
npm run build

# Add to your opencode.jsonc using local path
{
  "plugin": ["file:///absolute/path/to/opencode-elf"]
}

Troubleshooting

Plugin Not Loading

  • Check OpenCode logs for errors
  • Verify plugin is in your opencode.jsonc config
  • Ensure dist/ folder exists (run npm run build)
  • Check for TypeScript compilation errors

Embedding Model Download

First run will download the model (~90MB). This takes 1-2 minutes. Subsequent runs are instant.

Performance Issues

Expected performance (lazy loading + optimizations enabled):

| Operation | First Run | Subsequent Runs | With Cache | |-----------|-----------|-----------------|------------| | Plugin startup | Returns immediately | Instant | - | | First message | 1-3s (waits for init) | ~200-500ms | ~100-200ms | | Context query | ~200-500ms | ~200-500ms | ~100-200ms | | Add golden rule | ~50-100ms | ~50-100ms | - | | Record learning | ~100-200ms | ~100-200ms | - |

Performance Optimizations:

  • Parallel Database Queries: Global + project databases queried simultaneously (30-50% faster)
  • Embedding Cache: LRU cache with 5-min TTL (60-70% faster on repeated prompts)
  • Lazy Loading: Non-blocking startup (OpenCode ready instantly)

Note: With lazy loading, OpenCode starts immediately. Initialization happens in the background, so only your first interaction waits for the model to load.

If performance is slower than expected, check:

  • Model is loaded (check logs for "ELF: Ready")
  • Database isn't locked
  • Sufficient disk space for embeddings cache (~90MB)
  • First message timing is expected (includes initialization)

Run performance benchmark:

npm run test:benchmark

Roadmap

  • [x] Core learning loop
  • [x] Golden rules
  • [x] Heuristics
  • [x] CLI management tools
  • [x] Performance metrics
  • [x] Simulation testing
  • [x] Hybrid storage (global + project-scoped memories)
  • [x] Performance optimizations (parallel queries + embedding cache)
  • [x] Hybrid search (vector + FTS5 full-text search)
  • [x] Privacy controls (<private> tag filtering)
  • [ ] Success detection (currently only failures are auto-recorded)
  • [ ] Experiment tracking (hypothesis testing)
  • [ ] Decision records (ADRs)
  • [ ] Vector index optimization (avoid scanning all learnings)
  • [ ] Export/import memory database
  • [ ] Analytics dashboard
  • [ ] Web UI for management

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes
  4. Run tests: npm run test:simulate
  5. Build: npm run build
  6. Commit your changes: git commit -m 'Add my feature'
  7. Push to the branch: git push origin feature/my-feature
  8. Submit a pull request

Code Style

  • Use TypeScript strict mode
  • Follow existing code patterns
  • Add JSDoc comments for public APIs
  • Keep functions small and focused

License

MIT