Stops your coding agent repeating the same mistake.
Project description
never-again
A failure memory for coding agents. When an agent hits an error, it can check whether that same failure was already solved — in this repo, by an earlier session — instead of debugging it again from scratch. Once solved, the fix is written down so the next session gets it for free.
It runs locally on top of a SQLite file. No server to stand up, no API keys, no data leaving your machine. pip install, point your agent at it, done.
What it does
never-again exposes three tools to an MCP-compatible agent (Claude Code, Cursor, Gemini CLI, or anything that speaks MCP):
query_failures(text, limit)— search past failures similar to an error or task. Each result includes the fix that worked and a shortWHEN / CHECK / BECAUSEprevention rule. If nothing genuinely matches, it returns an empty list rather than a confident wrong answer.log_failure(error, solution, context, scope)— record a solved failure. Secrets, tokens, emails, and usernames are stripped before anything is written.verify_resolution(failure_id)— confirm a fix worked, which nudges it higher in future results.
The intended loop is simple:
error ──▶ query_failures ──▶ apply known fix ──▶ verify_resolution
│ │
└────────── no match ───────────┘
│
solve it yourself ──▶ log_failure
What it doesn't do
- It isn't a shared public knowledge base. By default everything stays in a local SQLite file scoped to you. Team sharing is opt-in (see below).
- It doesn't fix anything itself. It surfaces a prior fix and a rule; your agent decides whether the situation actually matches and applies it.
- It won't always have an answer. A memory that always responds would send agents chasing fixes for problems they don't have, so it abstains when the match is weak. Empty results are the expected case early on, and on a brand-new repo.
When it helps (and when it doesn't)
Being honest about this up front, because it sets the right expectations:
It pays off when
- You work in a mature repo with a history of recurring, stack-specific failures (migrations, async pitfalls, build/packaging quirks, Docker networking). These fail in repeatable ways, which is exactly what a memory catches.
- The same class of error shows up across sessions or across agents — the durable edge here is cross-session memory, the part a model's context window doesn't cover.
- A team hits the same problems and wants the first person's fix to save the next person's afternoon (team tier).
It won't do much when
- You're on a brand-new or greenfield project — there's little history to seed from, so early queries return empty. That's correct behavior, but it means the value arrives later, as failures accumulate.
- The bugs are one-off and novel rather than recurring — there's nothing to remember.
The payoff is a non-event: an error you didn't have to debug a second time. That makes it easy to under-notice when it's working. Give it a few weeks of real use before judging it.
Install
pip install never-again
If you want the never-again command available globally — recommended, and
required if you use the session-start hook (see Agent skill) —
install it as a tool instead, so it lands on your PATH:
uv tool install never-again # or: pipx install never-again
Register it with your agent. For Claude Code, add to your MCP config:
{
"mcpServers": {
"never-again": { "command": "never-again-mcp" }
}
}
That's the whole setup. It stores failures in ~/.never-again/failures.db.
On first run inside a git repo, it seeds your memory from the repo's own history — mining fix-shaped commits from git log so the first few queries can already match something real. This reads git log only; nothing leaves your machine. (If GITHUB_TOKEN is set and the repo has a GitHub remote, it also pulls error text from closed issues.)
CLI
The same operations are available from a terminal:
never-again search "asyncpg cannot determine parameter type"
never-again log # interactive prompt
never-again verify <id>
never-again health # show config and whether Ollama is reachable
Optional upgrades
Everything below is off by default. Configuration is read from environment variables. There are two ways to set them:
In your MCP client's config (recommended). This is where MCP server settings belong — the client passes them straight to the server, regardless of which project your agent is working in:
{
"mcpServers": {
"never-again": {
"command": "never-again-mcp",
"env": { "NEVER_AGAIN_EMBEDDER": "local" }
}
}
}
With a .env file. Copy .env.example to .env and edit
it. This is handy for the CLI and local development. Note that the MCP server is
launched by your agent's client, not from your project folder, so a bare .env
sitting in a project directory will not be picked up by the server. To use a
file with the MCP server, point at it with an absolute path:
{ "env": { "NEVER_AGAIN_ENV_FILE": "/home/you/.never-again/.env" } }
Either way, real environment variables always take precedence over the file.
The base install matches errors by keyword (SQLite FTS5). That catches errors phrased similarly to a past one. To also match errors that mean the same thing but are worded differently, turn on semantic search:
pip install "never-again[local]"
NEVER_AGAIN_EMBEDDER=local
local runs an embedding model in-process via fastembed — still no server, nothing leaves the machine. If you already run Ollama, ollama uses it for embeddings instead.
| Variable | Default | Purpose |
|---|---|---|
NEVER_AGAIN_EMBEDDER |
fts |
local(in-process semantic search) orollama |
NEVER_AGAIN_COSINE_FLOOR |
0.45 |
min similarity to count as a match (semantic path) |
NEVER_AGAIN_TEAM |
local |
your team slug, when sharing |
NEVER_AGAIN_URL |
unset | a team server URL; when set, tools talk to it instead of local SQLite |
OLLAMA_EMBED_MODEL |
nomic-embed-text |
any Ollama embedding model |
Team sharing
To share failures across a team, run the included server (FastAPI + Postgres with pgvector) and point clients at it with NEVER_AGAIN_URL. The deployment files are in deploy/ — see deploy/docker-compose.yml.
How it works
Each error is fingerprinted — paths, numbers, hex, and UUIDs are normalized away — so the same error logged twice is deduplicated rather than stored twice. Search blends keyword ranking (FTS) with optional semantic ranking using Reciprocal Rank Fusion, then drops anything below a relevance floor so weak matches are filtered out instead of returned. Each entry carries a WHEN / CHECK / BECAUSE prevention rule, written by the agent that logged the failure (or formatted from the recorded fix when none is supplied, such as from the CLI).
Tiers at a glance
| Tier | Install | What you get |
|---|---|---|
| Base | pip install never-again |
SQLite + keyword search, zero dependencies |
| Local semantic | pip install "never-again[local]" |
in-process embeddings via fastembed |
| Ollama | pip install "never-again[ollama]" |
semantic embeddings via a running Ollama |
| Team | seedeploy/ |
shared Postgres + pgvector across a team |
Development
pip install -e ".[local]"
pip install pytest pytest-asyncio fastapi httpx mcp
pytest
The test suite is fully mocked — no network, no real embedding models, no external services.
Contributing
Contributions are welcome — see CONTRIBUTING.md for dev setup and the design principles to keep in mind, and ARCHITECTURE.md for how the pieces fit together and why. The most-wanted improvements are better cold-start seeding and an eval harness; both are described there.
Release notes live in CHANGELOG.md.
License
Project details
Release history Release notifications | RSS feed
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 never_again-0.1.0.tar.gz.
File metadata
- Download URL: never_again-0.1.0.tar.gz
- Upload date:
- Size: 39.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f10b7428902a647632dd8f790c4c37fa60af40f70418985bac6c4e4708534e0e
|
|
| MD5 |
a1c4b7fe11c6a4da85fd7995e2e7acea
|
|
| BLAKE2b-256 |
87c08751458d3465380e0aebbba0641f6292b304806835dd4ea7ee8851f1297b
|
Provenance
The following attestation bundles were made for never_again-0.1.0.tar.gz:
Publisher:
publish.yml on nicoalbo0/never-again
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
never_again-0.1.0.tar.gz -
Subject digest:
f10b7428902a647632dd8f790c4c37fa60af40f70418985bac6c4e4708534e0e - Sigstore transparency entry: 1966688281
- Sigstore integration time:
-
Permalink:
nicoalbo0/never-again@225790713fdff44de2218b44d1631b75718961d5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nicoalbo0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@225790713fdff44de2218b44d1631b75718961d5 -
Trigger Event:
release
-
Statement type:
File details
Details for the file never_again-0.1.0-py3-none-any.whl.
File metadata
- Download URL: never_again-0.1.0-py3-none-any.whl
- Upload date:
- Size: 38.6 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 |
84e1128bd15cdefaa10f6019966ce015ee0eeecf982ba30eef1c1e2ea33c95bd
|
|
| MD5 |
dae6a8c75f10cb3796aaec054f67e527
|
|
| BLAKE2b-256 |
0bacf13bae68902199541f994819cce9478e8c682b2ff6d4d2f86fa1549b2126
|
Provenance
The following attestation bundles were made for never_again-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on nicoalbo0/never-again
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
never_again-0.1.0-py3-none-any.whl -
Subject digest:
84e1128bd15cdefaa10f6019966ce015ee0eeecf982ba30eef1c1e2ea33c95bd - Sigstore transparency entry: 1966688471
- Sigstore integration time:
-
Permalink:
nicoalbo0/never-again@225790713fdff44de2218b44d1631b75718961d5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nicoalbo0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@225790713fdff44de2218b44d1631b75718961d5 -
Trigger Event:
release
-
Statement type: