Persistent memory for AI agents — MCP-native, works with any LLM
Project description
Noshy — Persistent Memory for AI Agents
ICM-compatible. MCP-native. Works with any LLM.
Noshy gives your AI agent real memory — not note-taking, not context stuffing, not a vector database you have to manage. Store facts, search across sessions, build knowledge graphs. It's what ICM wanted to be, re-built to work everywhere.
Noshy
┌───────────┼───────────┐
│ MEMORIES │ MEMOIRS
│ (time-bound) │ (permanent)
│ │
│ ┌───┐ ┌───┐ ┌───┐ │ ┌───┐
│ │bug│ │fix│ │pref│ │ │doc│
│ └───┘ └───┘ └───┘ │ └───┘
│ │ │ │ │
│ └───┬───┘ │ │
│ ┌─────┴─────┐ │ │
│ │ GRAPH │ │ │
│ │ relations │ │ │
│ └───────────┘ │ │
└──────────────────┴─────┘
│
┌─────────┴──────────┐
│ HYBRID SEARCH │
│ keyword+semantic │
│ +graph │
└────────────────────┘
Why Noshy
- LLM-powered extraction — not regex. Uses any OpenAI-compatible API to extract structured facts from transcripts
- Hybrid search — keyword + semantic + graph recall in one query
- ICM compatible — import your existing ICM databases, uses the same schema
- MCP native — works with Claude Code, Hermes, Codex, Copilot, and any MCP client
- Any embedding provider — OpenAI, fastembed (local, free), or Hermes API server
- Zero dependencies — core runs on Python stdlib. fastembed and OpenAI are optional
- Single binary feel — one Python file does everything
- TOML config —
~/.noshy/config.tomlwith env var overrides, no code changes needed - Graceful shutdown — SIGTERM/SIGINT handlers WAL-checkpoint the database and close connections cleanly
- Retry with backoff — LLM extraction retries on 429/5xx with exponential backoff (3 attempts)
- Input validation — empty topics, summaries, and titles are rejected before hitting the database
- Session hooks — automatic memory extraction at session end, no manual calls required
- Numpy-vectorized cosine — cluster detection and semantic search are ~50x faster with numpy (optional, pure-Python fallback included)
- Rotating request logs — set
NOSHY_LOG_FILEor run in a container to get~/.noshy/noshy.log(5MB x 3 rotation)
Hermes vs Noshy
Hermes has built-in memory that persists across sessions, but it's small and limited to keyword matching. Noshy replaces that with a proper database that understands what you meant, not just what words you used.
What Noshy adds that Hermes doesn't have by default:
- Semantic search — finds memories by meaning, not just keyword matching. Ask about "that proxy issue" and it finds the entry about SOCKS5 configuration even if the word "proxy" isn't in it.
- Unbounded storage — Hermes caps memory at ~3,500 chars. Noshy stores unlimited entries in SQLite.
- Richer memory types — memories (facts/decisions), memoirs (permanent knowledge), and concepts (related ideas linked together). Hermes just has flat text entries.
- Graph relationships — links related memories so recalling one pulls up connected ones.
- Session context injection — automatically surfaces what you were working on, recent decisions, and active projects when a session starts.
- Decision timeline — chronological log of what was decided and why, so you can trace back.
- Pattern detection — notices when the same solution keeps coming up and suggests turning it into a skill.
- Weight decay — older, less-referenced memories fade in relevance automatically instead of cluttering results.
Quick Start
# Install from PyPI (recommended)
pip install noshy
# Start the HTTP server + dashboard
noshy serve
# → http://127.0.0.1:8720/
# Or run as an MCP stdio server
noshy mcp
Or install from source:
curl -fsSL https://raw.githubusercontent.com/noshkoto/Noshy/main/install.sh | sh
Usage
CLI
# Store a memory (optional --ttl, --importance auto, --project)
python3 server.py store "deploy-config" "Deploy uses Cloudflare Pages with GitHub Actions"
# Recall (add --json for machine output)
python3 server.py recall "deployment config"
# List projects with counts and last activity
python3 server.py projects
# Delete: by id, by topic, or wipe an entire project
python3 server.py delete --id 01J...
python3 server.py delete --topic "old-bug" --scope onboarding
python3 server.py delete --project staging --yes
# Maintenance
python3 server.py purge # delete expired
python3 server.py consolidate-clusters # merge near-duplicates
python3 server.py find-contradictions # detect + link conflicting memory pairs
python3 server.py sweep # purge + decay + consolidate + drain queue
# Async extraction queue (hand off long transcripts without blocking on the LLM)
python3 server.py queue --file session.txt --session-id sess-2026-06-18
python3 server.py process-queue --limit 10
# Import from ICM
python3 server.py import /path/to/icm/memories.db
# Stats
python3 server.py stats
MCP Server (Claude Code, Hermes, Codex, Copilot)
Add to your MCP client config:
Claude Code (~/.claude/mcp_servers.json):
{
"mcpServers": {
"noshy": {
"command": "python3",
"args": ["/path/to/noshy/server.py", "mcp"],
"env": {
"NOSHY_EMBED_PROVIDER": "openai",
"OPENAI_API_KEY": "sk-..."
}
}
}
}
Hermes (config.yaml):
mcp_servers:
noshy:
command: "python3"
args: ["/path/to/noshy/server.py", "mcp"]
env:
NOSHY_EMBED_PROVIDER: "openai"
OPENAI_API_KEY: "sk-..."
Codex CLI (~/.codex/mcp.json):
{
"mcpServers": {
"noshy": {
"command": "python3",
"args": ["/path/to/noshy/server.py", "mcp"]
}
}
}
MCP Tools
| Tool | What it does |
|---|---|
noshy_store_memory |
Remember a fact, decision, or preference (optional ttl_seconds to auto-expire) |
noshy_store_memoir |
Store permanent knowledge (docs, reference) |
noshy_recall |
Search memories (keyword, semantic, hybrid) — also surfaces matching memoirs |
noshy_extract_session |
LLM-powered extraction from conversation transcripts |
noshy_stream_extract |
Incremental extraction for very long transcripts (chunked + overlap) |
noshy_session_context |
Generate context for a new session — critical memories, recent decisions, active work. Call at session start |
noshy_decision_timeline |
Chronological timeline of decisions, fixes, and resolutions. Answer "what did we decide about X?" |
noshy_detect_patterns |
Find repeated solutions across sessions — candidates for creating reusable skills |
noshy_consolidate |
Merge related memories on a topic |
noshy_delete |
Remove a memory by id, or all memories under a topic |
noshy_feedback |
Rate a memory +1/-1 to influence how long it survives |
noshy_list_projects |
List every project with per-project counts and last activity |
noshy_delete_project |
Wipe all memories and memoirs for a project (irreversible) |
noshy_predict_importance |
LLM-classify a candidate fact without storing it |
noshy_find_clusters |
Preview clusters of semantically near-duplicate memories |
noshy_consolidate_clusters |
Auto-merge those clusters in one pass |
noshy_find_contradictions |
Detect (and link) pairs of memories that assert conflicting facts |
noshy_queue_extraction |
Hand off a transcript for later LLM extraction without blocking |
noshy_process_queue |
Drain queued extractions through the LLM |
noshy_get_stats |
Database overview |
HTTP API
# Store
curl -X POST http://127.0.0.1:8720/tools/call \
-H 'Content-Type: application/json' \
-d '{"name":"noshy_store_memory","arguments":{"topic":"my-topic","summary":"What to remember"}}'
# Recall
curl -X POST http://127.0.0.1:8720/tools/call \
-H 'Content-Type: application/json' \
-d '{"name":"noshy_recall","arguments":{"query":"search keywords"}}'
# Stats
curl http://127.0.0.1:8720/stats
# Recent memories (JSON)
curl 'http://127.0.0.1:8720/memories?limit=25'
Web Dashboard
The HTTP server also serves a zero-dependency web dashboard. Start the server and open the root URL in a browser:
python3 server.py http
# then visit http://127.0.0.1:8720/
Dashboard features:
- Hyrule color palette — Rupee emerald, Navi fairy blue, Sunset amber accents on a twilight dark background
- Animated gradient orbs — floating radial gradients with CSS grid background art
- Project picker — custom dropdown with gradient-tinted selection, animated chevron, count pills, click-outside/Esc to close
- Hybrid search — keyword + semantic + graph in one query box; memoirs included
- Cluster view — surface groups of near-duplicate memories and merge them in one click
- Inline delete — hover a card, click the trash icon to remove it (with custom confirm dialog)
- Dark / light theme — auto-detected, manually toggleable, persisted to
localStorage - Animated stat counters — live database stats with skeleton loaders on first paint
- Toast notifications — feedback on store/delete/consolidate actions
- Pagination —
?page=1&limit=25for large databases
When NOSHY_HTTP_TOKEN is set, the dashboard shows a token prompt modal on
first load. The token persists in localStorage across reloads. A "Forget"
button clears it. API routes enforce auth; / and /health stay public.
Session Hooks
Noshy can automatically extract memories when a session ends. Drop the hook into your Hermes workflow or call it from any MCP client:
from hooks import on_session_end
result = on_session_end(transcript, project="my-project", max_memories=8)
# → {"extracted": 5, "ids": [...], "concepts": ["deploy", "ci"]}
The hook skips transcripts shorter than 100 characters and returns structured results with extracted memory IDs and discovered concepts.
Python API
For scripts and apps, Noshy ships a small Python API with decorators that make any function self-remembering:
import noshy
@noshy.remember(topic="deploy", importance="high")
def deploy(env):
return f"deployed to {env}"
deploy("prod") # auto-stores: deploy -> 'deployed to prod'
# Scope memories to a project (and inherit tags) for a block of code
with noshy.session(project="checkout-bugfix", tags=["sprint-23"]):
do_work() # every @remember inside picks up the project
noshy.recall("deploy") # hybrid search returns matching memories
Useful keyword arguments on @noshy.remember:
importance="auto"— let the LLM classify each memory (critical/high/medium/low)on_error=True(default) — exceptions are stored as high-importance memoriescapture_args=True— include arg names in the summary; arguments whose names look like secrets (password,token,api_key, ...) are auto-redactedskip_if=lambda r: r is None— don't store certain return valuesttl_seconds=...— auto-expire after N seconds
For long-running sessions, noshy.extractor.stream_extract(chunks) yields
memories incrementally as transcript chunks arrive.
Embedding Providers
Noshy auto-detects the best available embedding provider. Set NOSHY_EMBED_PROVIDER to override:
| Provider | Env Var | API Key | Quality |
|---|---|---|---|
| OpenAI | NOSHY_EMBED_PROVIDER=openai |
OPENAI_API_KEY |
Best |
| fastembed | NOSHY_EMBED_PROVIDER=fastembed |
None (local) | Good |
| Hermes API | auto-detected | API_SERVER_KEY |
Varies |
| None | No embedding | None | Keyword only |
# With OpenAI
export OPENAI_API_KEY="sk-..."
python3 server.py http
# With free local embeddings
pip install fastembed
python3 server.py http
# Keyword-only (no embeddings)
NOSHY_EMBED_PROVIDER=none python3 server.py http
Platform Setup
macOS
# Install Python 3.10+ if needed
brew install python@3.12
# Install Noshy
curl -fsSL https://raw.githubusercontent.com/noshkoto/Noshy/main/install.sh | sh
# Optional: local embeddings
pip3 install fastembed
Linux
sudo apt install python3 # Debian/Ubuntu
sudo dnf install python3 # Fedora
curl -fsSL https://raw.githubusercontent.com/noshkoto/Noshy/main/install.sh | sh
Windows
# Install Python from python.org (check "Add to PATH")
# Download Noshy
Invoke-WebRequest -Uri https://github.com/noshkoto/Noshy/archive/refs/heads/main.zip -OutFile noshy.zip
Expand-Archive noshy.zip -DestinationPath $env:USERPROFILE\.noshy
Rename-Item $env:USERPROFILE\.noshy\Noshy-main $env:USERPROFILE\.noshy\src
# Run
python $env:USERPROFILE\.noshy\src\server.py http
Docker
# Build the image from the included Dockerfile
docker build -t noshy .
# Run it (data persists in a named volume)
docker run -d --name noshy \
-p 8720:8720 \
-v noshy-data:/data \
-e OPENAI_API_KEY=sk-... \
noshy
# Or with HTTP auth enabled
docker run -d --name noshy \
-p 8720:8720 \
-v noshy-data:/data \
-e NOSHY_HTTP_TOKEN=$(openssl rand -hex 32) \
noshy
# Optional build flags
docker build --build-arg WITH_FASTEMBED=1 -t noshy . # bake local embeddings
docker build --build-arg WITH_SQLITE_VEC=0 -t noshy . # skip the vec extension
The image runs as a non-root user, exposes a /health endpoint, and uses
/data as a persistent volume.
HTTP authentication
By default the HTTP server is unauthenticated and binds to 127.0.0.1 only.
To expose it on a network or behind a proxy, set a bearer token:
export NOSHY_HTTP_TOKEN="$(openssl rand -hex 32)"
python3 server.py serve --host 0.0.0.0
Clients must then send Authorization: Bearer <token> on every request. The
/health endpoint and the dashboard HTML at / stay public so probes and
human visitors still work.
Configuration
Noshy supports two configuration methods. Environment variables always take precedence over the config file.
Config file
Create ~/.noshy/config.toml (or set NOSHY_CONFIG to a custom path):
[noshy]
db-path = "~/.noshy/memories.db"
embed-provider = "openai"
embed-model = ""
api-base = "http://127.0.0.1:8642/v1"
model = "hermes-agent"
http-host = "127.0.0.1"
http-port = 8720
Environment variables
| Env Variable | Default | Description |
|---|---|---|
NOSHY_CONFIG |
~/.noshy/config.toml |
Path to config file |
NOSHY_DB |
~/.noshy/memories.db |
Database path |
NOSHY_EMBED_PROVIDER |
auto | openai, fastembed, hermes, or none |
NOSHY_EMBED_MODEL |
provider default | Embedding model name |
NOSHY_EMBED_API_BASE |
provider default | Embedding API URL |
NOSHY_EMBED_API_KEY |
OPENAI_API_KEY |
Embedding API key |
NOSHY_API_BASE |
http://127.0.0.1:8642/v1 |
LLM API for extraction |
NOSHY_API_KEY |
API_SERVER_KEY |
LLM API key |
NOSHY_MODEL |
hermes-agent |
Model for extraction |
NOSHY_HTTP_TOKEN |
unset | If set, all HTTP routes require Authorization: Bearer *** (except /healthand/`) |
NOSHY_LOG_FILE |
unset | If set (or stderr is not a tty), rotating logs go to ~/.noshy/noshy.log (5MB x 3) |
Database migrations
Noshy auto-migrates the database schema on startup (v1 through v4). No manual steps required. New columns are added transparently; existing data is preserved.
Architecture
┌─────────────────────────────────────────┐
│ Noshy MCP Server │
│ ┌──────────┐ ┌────────┐ ┌───────────┐ │
│ │Extractor │ │ Store │ │ Embedder │ │
│ │(LLM API) │ │(SQLite)│ │(OpenAI/ │ │
│ │ + retry │ │ +migrate│ │ fastembed) │ │
│ │ │ │ factory│ │ +numpy cos│ │
│ └──────────┘ └────────┘ └───────────┘ │
│ │ │ │ │
│ └──────────┼───────────┘ │
│ │ │
│ ┌───────────┴────────┐ │
│ │ Hybrid Search │ │
│ │ keyword semantic │ │
│ │ + graph │ │
│ └────────────────────┘ │
│ │ │
│ ┌────────┴───────┐ │
│ │ MCP / HTTP │ │
│ │ (stdio+API) │ │
│ └────────────────┘ │
│ │ │
│ ┌────────┴───────┐ │
│ │ Session Hooks │ │
│ │ (auto-extract)│ │
│ └────────────────┘ │
└─────────────────────────────────────────┘
Import from ICM
# Import memories from an existing ICM database
python3 server.py import ~/.config/icm/memories.db
# Verify
python3 server.py stats
The schema is compatible — memories, memoirs, concepts, and metadata all transfer. Graph edges and feedback are preserved when available.
Comparison
| ICM | Noshy | |
|---|---|---|
| Extraction | Rule-based regex | LLM-powered (any provider) |
| Search | Keyword + vector | Keyword + semantic + graph |
| Embeddings | fastembed only | OpenAI, fastembed, Hermes, none |
| Relationships | Memoir categories only | Full graph with weighted edges |
| Consolidation | Manual | LLM-assisted auto-merge |
| Deployment | Rust binary (compile) | Python stdlib (zero-deps core) |
| MCP | Yes | Yes |
| API | MCP only | MCP + HTTP + Python import |
| ICM import | N/A | Built-in |
| Config | Env vars only | TOML file + env var overrides |
| Lifecycle | Manual process management | Graceful shutdown, auto-migration, retry |
| Cosine similarity | Pure Python | Numpy-vectorized (~50x faster), pure-Python fallback |
| Logs | stdout only | Rotating file logs (5MB x 3) |
| Dashboard auth | None | Token prompt modal, localStorage persistence |
Roadmap
- Web dashboard
- Semantic search over memoirs (auto-embedded on store)
- Automatic, importance-aware memory decay
- Consolidation that prunes merged duplicates
- Python decorator for automatic function memory (
@noshy.remember) - Memory importance prediction (
importance="auto") - Streaming extraction (
extractor.stream_extract) - Project isolation (
list_projects/delete_project) - Graph-based memory consolidation (
find_clusters/consolidate_clusters) - HTTP bearer-token auth (
NOSHY_HTTP_TOKEN) - Real Dockerfile (multi-stage, non-root, healthcheck)
- Integration test suite (
pytest tests/) - PyPI release (
pip install noshy) - Streaming extraction MCP tool (
noshy_stream_extract) - Dashboard polish (project picker, cluster view, inline delete, theme toggle)
- TOML config file (
~/.noshy/config.toml) - Schema auto-migration (v1-v4)
- Graceful shutdown (SIGTERM/SIGINT + WAL checkpoint)
- LLM extraction retry with exponential backoff
- Session context, decision timeline, and pattern detection MCP tools
- Session-end auto-extraction hooks
- Glassmorphism dashboard redesign
- Hyrule color palette (emerald, fairy blue, sunset amber)
- Numpy-vectorized cosine similarity (~50x faster)
- Dashboard extracted to dashboard.html (server.py 1832 -> 1012 lines)
- Dashboard auth UI (token prompt modal, localStorage, Forget button)
- Rotating HTTP request logs (
NOSHY_LOG_FILE) - Input validation and silent-except cleanup
- Per-user database isolation (multi-tenant — one DB per token)
License
Apache 2.0 — same as ICM. Built as a drop-in improvement.
"Your agent shouldn't forget what you fixed last week."
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file noshy-0.4.0.tar.gz.
File metadata
- Download URL: noshy-0.4.0.tar.gz
- Upload date:
- Size: 90.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff0f388a7c00eb4b80df20dcbf23dec2aab17bb81d7dc6f27990160c7641b502
|
|
| MD5 |
080875bc676c96d15c967c603655f4dc
|
|
| BLAKE2b-256 |
124f8f1611e4965ec7e9b43e5f9502d975f22143e80be0a845c4715ffbfed73b
|
Provenance
The following attestation bundles were made for noshy-0.4.0.tar.gz:
Publisher:
release.yml on Noshkoto/Noshy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
noshy-0.4.0.tar.gz -
Subject digest:
ff0f388a7c00eb4b80df20dcbf23dec2aab17bb81d7dc6f27990160c7641b502 - Sigstore transparency entry: 1859650824
- Sigstore integration time:
-
Permalink:
Noshkoto/Noshy@b90f49cdf1219f8624e6ea44078aaaee8c124142 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/Noshkoto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b90f49cdf1219f8624e6ea44078aaaee8c124142 -
Trigger Event:
push
-
Statement type:
File details
Details for the file noshy-0.4.0-py3-none-any.whl.
File metadata
- Download URL: noshy-0.4.0-py3-none-any.whl
- Upload date:
- Size: 74.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1f2a626815b1cd33ba04579447f6dedc72d40adfd0d8080c6f4a4227332462e
|
|
| MD5 |
7f663410cea1801bb1b6706a0f2d162c
|
|
| BLAKE2b-256 |
1361d22ecca52e9c9e36dc044ef2a4d39e2e2037dbbfcf658132fcd83c0ac64f
|
Provenance
The following attestation bundles were made for noshy-0.4.0-py3-none-any.whl:
Publisher:
release.yml on Noshkoto/Noshy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
noshy-0.4.0-py3-none-any.whl -
Subject digest:
c1f2a626815b1cd33ba04579447f6dedc72d40adfd0d8080c6f4a4227332462e - Sigstore transparency entry: 1859650840
- Sigstore integration time:
-
Permalink:
Noshkoto/Noshy@b90f49cdf1219f8624e6ea44078aaaee8c124142 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/Noshkoto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b90f49cdf1219f8624e6ea44078aaaee8c124142 -
Trigger Event:
push
-
Statement type: