Add shodh-memory skill for persistent context across sessions
This commit is contained in:
105
skills/shodh-memory/SKILL.md
Normal file
105
skills/shodh-memory/SKILL.md
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
name: shodh-memory
|
||||
description: Persistent cognitive memory for AI agents. Use when user wants to remember context across conversations, recall past decisions, or store learnings.
|
||||
---
|
||||
|
||||
# Shodh Memory
|
||||
|
||||
Persistent memory for AI agents - memories persist across sessions and can be recalled semantically.
|
||||
|
||||
## Overview
|
||||
|
||||
Shodh Memory provides:
|
||||
- **Persistent Context** - Memories survive across Claude Code sessions
|
||||
- **Semantic Search** - Find memories by meaning, not just keywords
|
||||
- **Auto-Learning** - Frequently accessed memories become easier to find (Hebbian learning)
|
||||
- **Automatic Decay** - Irrelevant memories fade over time
|
||||
- **Knowledge Graph** - Related memories surface together
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
First run → Downloads server (~15MB) + embedding model (~23MB)
|
||||
Server runs locally at http://localhost:3030
|
||||
No cloud, no API keys needed (auto-generated)
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Args | Description |
|
||||
|---------|------|-------------|
|
||||
| `remember` | `<content>` | Store a memory |
|
||||
| `recall` | `<query>` | Search memories by meaning |
|
||||
| `proactive` | `<context>` | Get relevant memories for current context |
|
||||
| `stats` | | Get memory counts and health |
|
||||
| `forget` | `<memory_id>` | Delete a specific memory |
|
||||
| `context` | | Get summary of recent memories |
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `--type` | Context | Memory type: Decision, Learning, Error, Discovery, Pattern, Context, Task, Observation |
|
||||
| `--tags` | | Comma-separated tags for organization |
|
||||
| `--limit` | 5 | Number of results to return |
|
||||
|
||||
## Memory Types
|
||||
|
||||
| Type | When to Use |
|
||||
|------|-------------|
|
||||
| Decision | User choices, architectural decisions |
|
||||
| Learning | New knowledge gained |
|
||||
| Error | Bugs found and fixes |
|
||||
| Discovery | Insights, aha moments |
|
||||
| Pattern | Recurring behaviors |
|
||||
| Context | Background information |
|
||||
| Task | Work in progress |
|
||||
| Observation | General notes |
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Store a decision
|
||||
python3 scripts/shodh_memory.py remember "User prefers PostgreSQL over MongoDB" --type Decision --tags "database,architecture"
|
||||
|
||||
# Store a learning
|
||||
python3 scripts/shodh_memory.py remember "The API requires OAuth2 with PKCE flow" --type Learning --tags "auth,api"
|
||||
|
||||
# Recall memories
|
||||
python3 scripts/shodh_memory.py recall "user preferences" --limit 5
|
||||
|
||||
# Proactive context (call at session start)
|
||||
python3 shodh_memory.py proactive "building authentication system"
|
||||
|
||||
# Check memory stats
|
||||
python3 scripts/shodh_memory.py stats
|
||||
|
||||
# Forget a memory
|
||||
python3 scripts/shodh_memory.py forget abc123
|
||||
```
|
||||
|
||||
## Auto-Start
|
||||
|
||||
The install script creates a macOS LaunchAgent that auto-starts the server on login/restart.
|
||||
|
||||
To manually start/stop:
|
||||
```bash
|
||||
launchctl load ~/Library/LaunchAgents/com.shodh.memory.plist
|
||||
launchctl unload ~/Library/LaunchAgents/com.shodh.memory.plist
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
The skill calls REST API at `http://localhost:3030/api/*`:
|
||||
- `POST /api/remember` - Store memory
|
||||
- `POST /api/recall` - Semantic search
|
||||
- `POST /api/relevant` - Proactive context
|
||||
- `GET /api/memories` - List memories
|
||||
- `DELETE /api/memory/{id}` - Delete memory
|
||||
|
||||
## Notes
|
||||
|
||||
- Server runs on port 3030 by default
|
||||
- First run downloads models (~38MB total), works offline after
|
||||
- All data stored locally in `~/.shodh/` or default location
|
||||
- Memory types affect importance and decay rate
|
||||
9
skills/shodh-memory/scripts/.env.example
Normal file
9
skills/shodh-memory/scripts/.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
# Shodh Memory - Persistent cognitive memory for AI agents
|
||||
# Auto-generated on install - no manual setup needed
|
||||
# Server runs at http://localhost:3030
|
||||
# Default dev key: sk-shodh-dev-default
|
||||
|
||||
SHODH_API_KEY=sk-shodh-dev-default
|
||||
SHODH_HOST=http://localhost
|
||||
SHODH_PORT=3030
|
||||
SHODH_USER_ID=default
|
||||
206
skills/shodh-memory/scripts/cli.py
Executable file
206
skills/shodh-memory/scripts/cli.py
Executable file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def load_env():
|
||||
env_paths = [
|
||||
Path(__file__).parent / ".env",
|
||||
Path.home() / ".config/opencode/.env",
|
||||
]
|
||||
|
||||
for env_path in env_paths:
|
||||
if env_path.exists():
|
||||
for line in env_path.read_text().splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
k, v = line.split("=", 1)
|
||||
os.environ.setdefault(k.strip(), v.strip().strip("\"'"))
|
||||
|
||||
load_env()
|
||||
|
||||
try:
|
||||
from shodh_memory import MemorySystem
|
||||
memory = MemorySystem()
|
||||
except Exception as e:
|
||||
print(f"Error: Failed to import shodh_memory: {e}", file=sys.stderr)
|
||||
print("Install with: pip install shodh-memory", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_remember(content, memory_type="Context", tags=None, user_id=None):
|
||||
try:
|
||||
tag_list = [t.strip() for t in tags.split(",")] if tags else None
|
||||
result = memory.remember(content, memory_type=memory_type, tags=tag_list)
|
||||
print(f"Result: memory stored [{result}]")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_recall(query, limit=5, user_id=None):
|
||||
try:
|
||||
results = memory.recall(query, limit=limit)
|
||||
|
||||
if not results:
|
||||
print("No memories found")
|
||||
return
|
||||
|
||||
for i, mem in enumerate(results, 1):
|
||||
content = mem.get("content", "") if isinstance(mem, dict) else str(mem)[:100]
|
||||
print(f"\n{i}. {content[:100]}{'...' if len(str(content)) > 100 else ''}")
|
||||
|
||||
print(f"\nResult: {len(results)} memories found")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_proactive(context, limit=5, user_id=None):
|
||||
try:
|
||||
results = memory.proactive_context(context, limit=limit)
|
||||
|
||||
if not results:
|
||||
print("No relevant memories found")
|
||||
return
|
||||
|
||||
print("Relevant memories:")
|
||||
for i, mem in enumerate(results, 1):
|
||||
content = mem.get("content", "") if isinstance(mem, dict) else str(mem)
|
||||
print(f"\n{i}. {content[:150]}{'...' if len(str(content)) > 150 else ''}")
|
||||
|
||||
print(f"\nResult: {len(results)} relevant memories")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_stats(user_id=None):
|
||||
try:
|
||||
stats = memory.get_stats()
|
||||
|
||||
print("Memory Statistics:")
|
||||
if isinstance(stats, dict):
|
||||
for key, value in stats.items():
|
||||
print(f" {key}: {value}")
|
||||
else:
|
||||
print(f" {stats}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_forget(memory_id):
|
||||
try:
|
||||
memory.forget(memory_id)
|
||||
print(f"Result: memory deleted [{memory_id}]")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_context(limit=10, user_id=None):
|
||||
try:
|
||||
summary = memory.context_summary(limit=limit)
|
||||
|
||||
print("Context Summary:")
|
||||
if isinstance(summary, dict):
|
||||
for key, value in summary.items():
|
||||
print(f" {key}: {value}")
|
||||
else:
|
||||
print(f" {summary}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_list(user_id=None, limit=20):
|
||||
try:
|
||||
results = memory.list_memories(limit=limit)
|
||||
|
||||
if not results:
|
||||
print("No memories stored")
|
||||
return
|
||||
|
||||
print(f"Stored memories ({len(results)}):")
|
||||
for i, mem in enumerate(results, 1):
|
||||
if isinstance(mem, dict):
|
||||
content = mem.get("content", "")[:60]
|
||||
mem_id = mem.get("id", "")
|
||||
else:
|
||||
content = str(mem)[:60]
|
||||
mem_id = "unknown"
|
||||
print(f"{i}. {content}... [{mem_id}]")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Shodh Memory - Persistent cognitive memory for AI agents"
|
||||
)
|
||||
subparsers = parser.add_subparsers(dest="command", help="Commands")
|
||||
|
||||
remember_parser = subparsers.add_parser("remember", help="Store a memory")
|
||||
remember_parser.add_argument("content", help="Memory content")
|
||||
remember_parser.add_argument("--type", "-t", default="Context",
|
||||
help="Memory type (Decision, Learning, Error, etc.)")
|
||||
remember_parser.add_argument("--tags", help="Comma-separated tags")
|
||||
remember_parser.add_argument("--user", help="User ID")
|
||||
|
||||
recall_parser = subparsers.add_parser("recall", help="Search memories by meaning")
|
||||
recall_parser.add_argument("query", help="Search query")
|
||||
recall_parser.add_argument("--limit", "-l", type=int, default=5, help="Number of results")
|
||||
recall_parser.add_argument("--user", help="User ID")
|
||||
|
||||
proactive_parser = subparsers.add_parser("proactive", help="Get relevant memories for context")
|
||||
proactive_parser.add_argument("context", help="Current context")
|
||||
proactive_parser.add_argument("--limit", "-l", type=int, default=5, help="Number of results")
|
||||
proactive_parser.add_argument("--user", help="User ID")
|
||||
|
||||
stats_parser = subparsers.add_parser("stats", help="Get memory statistics")
|
||||
stats_parser.add_argument("--user", help="User ID")
|
||||
|
||||
forget_parser = subparsers.add_parser("forget", help="Delete a memory")
|
||||
forget_parser.add_argument("memory_id", help="Memory ID to delete")
|
||||
|
||||
context_parser = subparsers.add_parser("context", help="Get context summary")
|
||||
context_parser.add_argument("--limit", "-l", type=int, default=10, help="Number of results")
|
||||
context_parser.add_argument("--user", help="User ID")
|
||||
|
||||
list_parser = subparsers.add_parser("list", help="List all memories")
|
||||
list_parser.add_argument("--limit", "-l", type=int, default=20, help="Number of results")
|
||||
list_parser.add_argument("--user", help="User ID")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
if args.command == "remember":
|
||||
cmd_remember(args.content, args.type, args.tags, args.user)
|
||||
elif args.command == "recall":
|
||||
cmd_recall(args.query, args.limit, args.user)
|
||||
elif args.command == "proactive":
|
||||
cmd_proactive(args.context, args.limit, args.user)
|
||||
elif args.command == "stats":
|
||||
cmd_stats(args.user)
|
||||
elif args.command == "forget":
|
||||
cmd_forget(args.memory_id)
|
||||
elif args.command == "context":
|
||||
cmd_context(args.limit, args.user)
|
||||
elif args.command == "list":
|
||||
cmd_list(args.user, args.limit)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
76
skills/shodh-memory/scripts/install.sh
Executable file
76
skills/shodh-memory/scripts/install.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Shodh Memory Install Script
|
||||
# Installs npm package and sets up auto-start on macOS
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
INFO='\033[0;34m'
|
||||
SUCCESS='\033[0;32m'
|
||||
WARNING='\033[1;33m'
|
||||
ERROR='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_info() { echo -e "${INFO}[INFO]${NC} $1"; }
|
||||
print_success() { echo -e "${SUCCESS}[OK]${NC} $1"; }
|
||||
print_warning() { echo -e "${WARNING}[WARN]${NC} $1"; }
|
||||
print_error() { echo -e "${ERROR}[ERR]${NC} $1"; }
|
||||
|
||||
check_dependencies() {
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
print_error "python3 is required"
|
||||
exit 1
|
||||
fi
|
||||
print_success "Dependencies checked"
|
||||
}
|
||||
|
||||
install_npm() {
|
||||
print_info "Installing shodh-memory Python SDK..."
|
||||
|
||||
if pip3 install shodh-memory; then
|
||||
print_success "shodh-memory installed"
|
||||
else
|
||||
print_error "Failed to install shodh-memory"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
generate_api_key() {
|
||||
print_info "No API key needed - using local storage"
|
||||
}
|
||||
|
||||
create_launchagent() {
|
||||
print_info "No auto-start needed - SDK runs on-demand"
|
||||
}
|
||||
|
||||
start_server() {
|
||||
print_info "Ready to use!"
|
||||
}
|
||||
|
||||
show_status() {
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
print_success "Shodh Memory Installation Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " python3 $SCRIPT_DIR/cli.py remember \"text\" --type Decision"
|
||||
echo " python3 $SCRIPT_DIR/cli.py recall \"query\""
|
||||
echo " python3 $SCRIPT_DIR/cli.py stats"
|
||||
echo ""
|
||||
}
|
||||
|
||||
main() {
|
||||
echo "Shodh Memory Installer"
|
||||
echo "======================"
|
||||
echo ""
|
||||
|
||||
check_dependencies
|
||||
install_npm
|
||||
show_status
|
||||
}
|
||||
|
||||
main "$@"
|
||||
2
skills/shodh-memory/scripts/requirements.txt
Normal file
2
skills/shodh-memory/scripts/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
shodh-memory>=0.1.81
|
||||
requests>=2.31.0
|
||||
Reference in New Issue
Block a user