Your agent has amnesia. Noshy fixes that. Persistent memory for AI agents — LLM extraction, hybrid search, zero deps.
SaferSkills independently audited Noshy (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.

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 │
└────────────────────┘~/.noshy/config.toml with env var overrides, no code changes neededNOSHY_LOG_FILE or run in a container to get ~/.noshy/noshy.log (5MB x 3 rotation)contradicts edges so future recalls warn about themHermes 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:
# 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 mcpOr install from source:
curl -fsSL https://raw.githubusercontent.com/noshkoto/Noshy/main/install.sh | sh# 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 statsAdd 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"]
}
}
}| 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 |
# 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'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:
localStorage?page=1&limit=25 for large databasesWhen 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.
hermes_skill.py ships with the package and exposes memory operations as native Hermes Agent tool functions, for workflows that call Python directly instead of going through MCP. It holds one shared store and reads NOSHY_DB for the database path.
The module also ships as a Hermes Agent skill module. Drop it into your skills directory and the five functions below become native agent tools, with no MCP round trip and no server process to keep alive.
| Function | What it does |
|---|---|
noshy_remember | Store a memory with keywords, importance, and project |
noshy_recall | Hybrid search returning a numbered result list |
noshy_learn | Store permanent knowledge as a memoir |
noshy_summary | Overview for session start: database counts plus the 20 most recent memories that still carry weight |
noshy_link | Resolve two queries to memories and connect them with a graph edge. Memoir hits are filtered from both endpoints and self-links are rejected with a message instead of raising sqlite3.IntegrityError |
import hermes_skill as noshy
noshy.noshy_remember("auth-fix", "Staging egress needs a SOCKS5 proxy",
keywords=["proxy"], importance="high", project="api")
noshy.noshy_link("proxy", "deploy", relation="depends_on")
print(noshy.noshy_summary(project="api"))noshy_link connects memories only. Memoir matches are filtered out of both endpoints, because graph edges carry foreign keys into the memories table. Self-links (both queries resolving to the same memory) are rejected with a clear message instead of raising. Valid relations are related, extends, depends_on, contradicts, and caused_by.
The module also runs as a CLI for quick lookups:
python3 hermes_skill.py recall "deploy config" --project apiNoshy 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.
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 memoriesUseful 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 whosenames look like secrets (password, token, api_key, ...) are auto-redacted
skip_if=lambda r: r is None — don't store certain return valuesttl_seconds=... — auto-expire after N secondsFor long-running sessions, noshy.extractor.stream_extract(chunks) yields memories incrementally as transcript chunks arrive.
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# Install Python 3.10+ if needed
brew install [email protected]
# Install Noshy
curl -fsSL https://raw.githubusercontent.com/noshkoto/Noshy/main/install.sh | sh
# Optional: local embeddings
pip3 install fastembedsudo apt install python3 # Debian/Ubuntu
sudo dnf install python3 # Fedora
curl -fsSL https://raw.githubusercontent.com/noshkoto/Noshy/main/install.sh | sh# 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# 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 extensionThe image runs as a non-root user, exposes a /health endpoint, and uses /data as a persistent volume.
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.0Clients 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.
Noshy supports two configuration methods. Environment variables always take precedence over the 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| 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_HOST | 127.0.0.1 | Bind address for the HTTP server. Overridden by --host |
NOSHY_HTTP_PORT | 8720 | Port for the HTTP server. Overridden by --port |
NOSHY_HTTP_TOKEN | _unset_ | If set, every HTTP route except /health and / requires an Authorization: Bearer header |
NOSHY_LOG_FILE | _unset_ | If set (or stderr is not a tty), rotating logs go to ~/.noshy/noshy.log (5MB x 3) |
Noshy auto-migrates the database schema on startup (v1 through v4). No manual steps required. New columns are added transparently; existing data is preserved.
┌─────────────────────────────────────────┐
│ 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 memories from an existing ICM database
python3 server.py import ~/.config/icm/memories.db
# Verify
python3 server.py statsThe schema is compatible — memories, memoirs, concepts, and metadata all transfer. Graph edges and feedback are preserved when available.
| 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 |
| Contradiction detection | None | LLM-powered conflict scan with persistent contradicts edges |
| Extraction queue | Synchronous only | Async queue with background drain |
| Logs | stdout only | Rotating file logs (5MB x 3) |
| Dashboard auth | None | Token prompt modal, localStorage persistence |
@noshy.remember)importance="auto")extractor.stream_extract)list_projects / delete_project)find_clusters / consolidate_clusters)NOSHY_HTTP_TOKEN)pytest tests/)pip install noshy)noshy_stream_extract)~/.noshy/config.toml)NOSHY_LOG_FILE)noshy_find_contradictions + contradicts edges on recall)noshy_queue_extraction / noshy_process_queue)hermes_skill.py, no MCP round trip)Apache 2.0 — same as ICM. Built as a drop-in improvement.
"Your agent shouldn't forget what you fixed last week."
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.