Self-hostable, local-first AgentOps tool that monitors production health and explains what it finds.
Project description
Tendwell
Self-hosted, local-first AgentOps for production health. Tendwell is an agent that watches your production signals and operational knowledge, reasons over them with a local LLM, and explains what it finds in plain language - then, only when you allow it, proposes remediations that a human approves and a tamper-evident audit log records.
It is built for the teams that cannot send production data to someone else's cloud: security-conscious and regulated environments. By default nothing leaves your infrastructure - not the metrics, not the runbooks, not the model.
- Local-first by default. No egress out of the box, including the LLM and embeddings. Point a backend off-host and Tendwell warns you, loudly, at startup.
- The LLM never executes. It can only propose. Deterministic validation and a human approval gate sit between any proposal and any change. Every step is an append-only, hash-chained audit event that cannot be silenced.
- Bring your own everything. Any OpenAI-compatible model (Ollama, vLLM, llama.cpp, LocalAI, LiteLLM), pluggable data sources, and - for actions - your own executor. The open core ships no real executor, so it cannot mutate anything until you wire one in.
Free and Apache-2.0. Not a SaaS. Not tied to any cloud, vendor, or monitoring stack.
See it work in under a minute
The instant demo runs against a synthetic production scenario with a stub model - no model download, no external services, no egress:
git clone https://github.com/bmoldo/tendwell
cd tendwell
docker compose up
You get a real health report immediately. The SLO evaluation and the cited runbooks are real; only the narrative is a stub until you add a model:
[CRITICAL] Production health
2 SLO(s) breached.
SLOs:
- availability [breached]: error_rate=0.057, healthy below 0.01
- latency [breached]: latency_p99=0.92, healthy below 0.5
Citations:
- error-rate-runbook.md
- latency-postmortem.md
For genuine model-driven narrative, add the Ollama profile - this pulls a small model once (a few hundred MB to ~1 GB, the honest one-time cost):
docker compose --profile model up
Then point it at your own stack: edit a config to use the Prometheus source and your local model. See the quickstart.
How it works
A deployment is one YAML file plus injected secrets; the code carries zero environment-specific values. Four layers sit behind stable interfaces, so you can swap any of them without touching the core:
- Data sources - where live signal comes from. Prometheus, Loki, and a
generic HTTP/JSON adapter today, normalized into one result shape. A failing
source degrades an SLO to
unknown; it never crashes the run. - LLM backend - any OpenAI-compatible endpoint via a configurable
base_url. Small models that are weak at native tool calls fall back to a prompt-based ReAct loop with strict parsing. - Context store - runbooks and postmortems embedded locally and retrieved by relevance. Citations come only from retrieved chunks, so the model cannot invent a source.
- Output / action surface - how findings are served and, only when you explicitly enable it, how gated actions are taken.
The agent is deliberately hybrid: a deterministic pre-fetch evaluates every SLO without the LLM, so even a weak model that fails every tool call still produces a correct status. The model adds interpretation and correlation on top.
The security model is the product
For a regulated buyer this is the part that matters. Mutating production runs through four separated stages, with a human and deterministic checks between the model and any change:
- Propose - the LLM emits a structured proposal. It records intent and executes nothing.
- Validate - deterministic checks (allowlist, argument schema, scope, rate limit, circuit breaker, kill switch) run before a human is ever paged.
- Approve - a human approves out-of-band, with identity and time captured. The model has no tool, endpoint, or path to approve.
- Execute - a separate, non-LLM executor acts per target, with write-scoped credentials held only for that run. Partial failure is first-class.
Read-only is the default and the open core ships no real executor: with no action surface configured, the agent is structurally unable to change anything. Audit logging is append-only, hash-chained, and cannot be disabled. See the security model.
Documentation
- Quickstart - zero to a working Tendwell.
- Configuration reference - every field and what is locked by design.
- Security model - the full version of the above.
- Bring your own LLM - any OpenAI-compatible runtime, plus the compatibility matrix.
- Add a data source - implement the
DataSourceinterface. - Register an executor - wire a real executor with the safety contract.
- Contributing.
- Deploy: a Helm chart and a Terraform module.
Development
uv sync --dev
uv run ruff check . && uv run ruff format --check .
uv run mypy tendwell
uv run pytest
License
Apache 2.0. See LICENSE. The free core stays genuinely capable; it is
never crippled to sell an upgrade.
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 tendwell-0.0.1.tar.gz.
File metadata
- Download URL: tendwell-0.0.1.tar.gz
- Upload date:
- Size: 323.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a79cd0ecc71937ccacd7402c1c787333772b0eb1d252fa898ab06809dc1fd5d
|
|
| MD5 |
9295f1afeaaa95d484e71b54398e511f
|
|
| BLAKE2b-256 |
f3c53e348e1625be20f573f1d4fab49e74cee07b5828779629167476a6462e34
|
File details
Details for the file tendwell-0.0.1-py3-none-any.whl.
File metadata
- Download URL: tendwell-0.0.1-py3-none-any.whl
- Upload date:
- Size: 76.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8561205fe73b208137139651d6f7837200bc39f25ba6b6c25c14366c40c6e735
|
|
| MD5 |
c525dfac50e19bacd881fc32abd6cecb
|
|
| BLAKE2b-256 |
3120604eb13578a7b757bb2be498bbeec8fc24d4e693384dbc82a2dea950cc09
|