Skip to main content

Local-first, provider-agnostic error/fix memory with a semantic search TUI.

Project description

errnest

Local-first, provider-agnostic error/fix memory for the command line.

Capture the errors you hit and how you fixed them. errnest surfaces the past fix the next time a failure looks the same — matched semantically via embeddings, with an offline text-match fallback when no AI backend is reachable. Browse everything in an interactive terminal dashboard.

tests PyPI Python License: MIT


Contents

Why errnest

Every developer re-solves the same handful of errors over and over — port already in use, a ModuleNotFoundError after switching branches, a Docker permission error. errnest is a small, local database of those errors and their fixes, plus a fast way to ask "have I seen this before?" — from a shell one-liner, a TUI, or your own tooling.

  • Local-first. SQLite on disk, no server, no account, no telemetry.
  • Provider-agnostic AI. Ollama by default (fully offline); swap in OpenAI, an OpenAI-compatible endpoint, Anthropic, or Gemini via one config key. The rest of the codebase only ever calls embed() / generate().
  • Degrades gracefully. No AI backend reachable? Search falls back to text matching instead of failing.
  • Redacts before it stores. Secrets and volatile tokens (paths, hex, emails) are stripped/normalized before anything hits disk.
  • A real dashboard, not just a CLI — see below.

Install

pip install errnest                 # core (local Ollama backend)
pip install errnest[openai]         # + OpenAI / OpenAI-compatible
pip install errnest[anthropic]      # + Anthropic (generation)
pip install errnest[gemini]         # + Google Gemini
pip install errnest[all-providers]  # everything

Requires Python 3.9+. No provider is required to install or run errnest — with nothing configured it talks to a local Ollama daemon, and even without Ollama running, capture/search/dashboard all still work (offline text matching instead of semantic search).

Quickstart

some-failing-command 2>&1 | errnest capture -c "some-failing-command"
errnest resolve 1 "bumped the timeout in config.yaml"
errnest search "connection refused on startup"
errnest doctor       # check provider + models + credentials
errnest dashboard    # browse everything interactively

The dashboard

errnest dashboard opens an interactive TUI (built with Textual) over your error store — search, filter by status or tag, resolve/dismiss/copy fixes, see semantically-similar past errors, and spot recurring patterns via clustering.

errnest dashboard

Panes: a filterable, searchable error list on the left; a detail view on the right with metadata, error output, applied fix, an AI explanation (once resolved), and the top 3 semantically similar past errors. A Patterns tab clusters your error history (k-means over embeddings) once you've captured 20+ errors, so you can spot what's actually costing you the most time.

Keybindings:

Key Action
j / k or / Navigate the error list
r Mark selected error resolved
d Dismiss selected error (won't-fix)
c Copy the fix text to your clipboard
s Focus search
/ Focus filter chips
p or 14 Switch tabs (All / Unresolved / Resolved / Patterns)
q or Ctrl-C Quit

Search is semantic (embeddings + cosine similarity) when an embed backend is reachable, and degrades to a live substring filter when it isn't — with no error shown, just a quieter dashboard.

AI backends

The rest of errnest only calls embed() / generate() — it never references a provider directly. The active provider comes from [ai] provider in ~/.errnest/config.toml:

[ai]
provider = "ollama"        # ollama | openai | openai-compatible | anthropic | gemini
embed_fallback = "ollama"  # used when the provider can't embed (e.g. anthropic)

[ai.ollama]
host = "http://localhost:11434"
embed_model = "nomic-embed-text"
gen_model = "llama3"

[ai.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
gen_model = "claude-haiku-4-5"

Provider SDKs are imported lazily; a provider that's unreachable or missing its SDK degrades to a clear AIUnavailableError, and every caller in errnest (search, the dashboard, doctor) handles that by falling back rather than crashing.

Switch providers without hand-editing TOML:

errnest config set ai.provider anthropic
errnest config show     # effective config, secrets masked

See USAGE.md for the full config reference, every environment variable, and per-provider setup steps.

CLI reference

Command Description
errnest capture -c "<cmd>" Capture a failing command + error output (stdin) as unresolved
errnest resolve <id> "<fix>" Record the fix and mark an error resolved
errnest dismiss <id> Mark an error won't-fix
errnest search "<query>" Show the most similar past errors + fixes
errnest show <id> Full detail for one error
errnest dashboard Open the interactive TUI
errnest doctor Check provider/model reachability and credentials
errnest config show Print effective config (secrets masked)
errnest config set <key> <value> Set a config value, e.g. ai.provider anthropic

Embedding in other tools

from errnest import ErnestClient

client = ErnestClient()

# Never raises — returns None if there's no confident, resolved match.
fix = client.surface(stderr_text)

# Browse recent errors, optionally scoped to a project directory.
recent = client.search("build failed", cwd="/path/to/project", top_k=3)

Wrap it behind a try/except ImportError in your own tool to make errnest an optional dependency — never import it at module top level, and treat every call as safe-to-fail (it already is, on errnest's side).

Configuration

Environment variables:

Variable Purpose Default
ERRNEST_CONFIG Path to the config file ~/.errnest/config.toml
ERRNEST_DB Path to the SQLite error store ~/.errnest/errors.db
ERRNEST_SIM_THRESHOLD Cosine-similarity cutoff for auto-surfacing 0.7
OLLAMA_HOST Ollama daemon URL http://localhost:11434

Full config file reference, per-provider setup, and troubleshooting: USAGE.md.

How it works

  • Storage: SQLite (~/.errnest/errors.db), one row per captured error, with an optional embedding vector attached at capture time.
  • Redaction: API keys, tokens, emails, and provider-specific credential patterns are stripped before storage; paths/hex/numbers are normalized so near-identical errors from different runs still match.
  • Search: cosine similarity over embeddings when an embed backend is reachable; Jaccard token overlap over normalized text otherwise.
  • Patterns: a small pure-Python k-means (no numpy) over stored embeddings, computed once per dashboard session.

See CHANGELOG.md for release history.

Contributing

Issues and PRs welcome. To run the test suite locally:

pip install -e ".[dev,all-providers]"
pytest
ruff check .

Provider tests mock the SDK/HTTP layer — no real API calls or a running Ollama instance are needed to run the suite.

License

MIT

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

errnest-0.1.0.tar.gz (227.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

errnest-0.1.0-py3-none-any.whl (34.4 kB view details)

Uploaded Python 3

File details

Details for the file errnest-0.1.0.tar.gz.

File metadata

  • Download URL: errnest-0.1.0.tar.gz
  • Upload date:
  • Size: 227.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for errnest-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6b5c14706290fccc0b5d5ae48b509212f0ca2b30df9083296b34490c052acc80
MD5 21f1725b25d1933e4005c41ff8f8a082
BLAKE2b-256 ee4c854d6cd99df7ce9756c256f3d686cce10507c2562cb00379c8418d569256

See more details on using hashes here.

File details

Details for the file errnest-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: errnest-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 34.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for errnest-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e5677e5f9362d0b75f8f30ed861ed6a898bd05b8ced83916d215c436db33dbe6
MD5 15c88156f1d75c50bffc3024d0e4ccc5
BLAKE2b-256 c0fb2f9bf1000ec434d83ba5f2287181df47fd32bf4fe6ed57e05952f1a09a92

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page