Skip to main content

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:

  1. Propose - the LLM emits a structured proposal. It records intent and executes nothing.
  2. Validate - deterministic checks (allowlist, argument schema, scope, rate limit, circuit breaker, kill switch) run before a human is ever paged.
  3. Approve - a human approves out-of-band, with identity and time captured. The model has no tool, endpoint, or path to approve.
  4. 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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tendwell-0.0.1.tar.gz (323.7 kB view details)

Uploaded Source

Built Distribution

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

tendwell-0.0.1-py3-none-any.whl (76.5 kB view details)

Uploaded Python 3

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

Hashes for tendwell-0.0.1.tar.gz
Algorithm Hash digest
SHA256 9a79cd0ecc71937ccacd7402c1c787333772b0eb1d252fa898ab06809dc1fd5d
MD5 9295f1afeaaa95d484e71b54398e511f
BLAKE2b-256 f3c53e348e1625be20f573f1d4fab49e74cee07b5828779629167476a6462e34

See more details on using hashes here.

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

Hashes for tendwell-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8561205fe73b208137139651d6f7837200bc39f25ba6b6c25c14366c40c6e735
MD5 c525dfac50e19bacd881fc32abd6cecb
BLAKE2b-256 3120604eb13578a7b757bb2be498bbeec8fc24d4e693384dbc82a2dea950cc09

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