Metadata-Version: 2.5
Name: loadcoach
Version: 1.1.6
Summary: Turns FreeWeight's measurements (or declared capabilities) into routed, queued, validated inference execution with a fully explainable decision for every job.
Project-URL: Homepage, https://github.com/JPKell/LoadCoach
Project-URL: Documentation, https://github.com/JPKell/LoadCoach/tree/main/docs
Project-URL: Changelog, https://github.com/JPKell/LoadCoach/blob/main/CHANGELOG.md
Author: Local AI Suite contributors
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: alembic<2,>=1.13
Requires-Dist: baseaicore<0.5,>=0.4.2
Requires-Dist: fastapi<1,>=0.115
Requires-Dist: httpx<1,>=0.27
Requires-Dist: jinja2<4,>=3.1
Requires-Dist: mirrorwall<0.3,>=0.2.2
Requires-Dist: modelrack<0.8,>=0.7
Requires-Dist: pydantic<3,>=2.9
Requires-Dist: setspec<0.7,>=0.6
Requires-Dist: sqlalchemy<3,>=2.0.30
Requires-Dist: sweatmeter<0.5,>=0.4
Requires-Dist: typer<1,>=0.12
Requires-Dist: uvicorn[standard]<1,>=0.30
Requires-Dist: weightsdb<0.3,>=0.2
Provides-Extra: dev
Requires-Dist: import-linter<3,>=2.0; extra == 'dev'
Requires-Dist: mypy<2,>=1.11; extra == 'dev'
Requires-Dist: pytest-cov<6,>=5; extra == 'dev'
Requires-Dist: pytest-randomly<4,>=3; extra == 'dev'
Requires-Dist: pytest<10,>=9.0.3; extra == 'dev'
Requires-Dist: respx<1,>=0.21; extra == 'dev'
Requires-Dist: ruff<1,>=0.6; extra == 'dev'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]<4,>=3.2; extra == 'postgres'
Description-Content-Type: text/markdown

# LoadCoach

Turns FreeWeight's measurements (or declared capabilities) into routed, queued, validated inference
execution with a fully explainable decision for every job.

**Status:** `1.1.6` in the repository (tagged `v1.1.5`; `pip index versions loadcoach` says what PyPI serves). Every phase of the
[development plan](docs/apps/loadcoach/development-plan.md) through 11 is built: the registry and
task profiles; evidence-weighted routing with a readable explanation for every decision;
synchronous and streaming generation with validation and corrective retries; a durable priority
queue with leases, ageing, cancellation, recovery and a circuit breaker; FreeWeight evidence
import, now binding an adapter-bearing subject rather than only the bare base; more than one
provider, with adapter subjects that route and pin like any other candidate (LA2/LA3); a complete
operator UI (dashboard, jobs, live queue, models, reliability, system, settings); and the hardening
a LAN bind needs — scopes checked at the route and in the service, per-token rate limits,
per-source queue caps, CSRF, Host validation, body limits, content retention.

Every runtime dependency resolves from PyPI (`weightsdb>=0.2,<0.3`, `mirrorwall>=0.2.2,<0.3`);
`pip install loadcoach` resolves entirely from the index, `requirements/ci.lock` is hash-pinned
against it, and every CI job installs from that lock.

Part of the **Local AI Suite**.

## Install

```bash
pip install loadcoach
loadcoach serve                # web UI + API on http://127.0.0.1:8766, zero configuration
loadcoach doctor               # every documented failure mode, ✓ / ! / ✗, with what to do
```

No provider, no GPU, no FreeWeight is required to start; each absence is a documented degraded
state. Ollama on `127.0.0.1:11434` is the default provider.

## What it does

* **Routes explainably.** Every decision is persisted in full — candidates, per-capability scores
  with their source and age, the four adjustment factors with their inputs, every rejection with
  its numbers — and `/jobs/<id>` answers *why this model?* before it shows a table.
* **Learns from production.** Attempt outcomes and caller feedback become bounded per-model
  reliability statistics that deprioritize a failing model, exclude it through a circuit breaker
  with a re-probe, and flag a regression against the model's own history.
* **Queues durably.** Priority classes, ageing with a proven starvation bound, leases, cancellation
  within a chunk, VRAM-aware admission, residency management, and recovery after a kill that loses
  and duplicates nothing.
* **Exposes safely.** Loopback and open by default; on a LAN, tokens with cumulative scopes checked
  twice, Host validation before authentication, CSRF on forms, rate limits with `Retry-After`,
  and a `doctor` that names what is wrong.

## Compatibility

Declared version ranges from `pyproject.toml` — kept from drifting by
`tests/unit/test_readme_compatibility.py`, which parses the file and fails if this table disagrees:

| Package | Range |
|---|---|
| `baseaicore` | `>=0.4.2,<0.5` |
| `setspec` | `>=0.6,<0.7` |
| `modelrack` | `>=0.7,<0.8` |
| `sweatmeter` | `>=0.4,<0.5` |
| `weightsdb` | `>=0.2,<0.3` |
| `mirrorwall` | `>=0.2.2,<0.3` |

## Documentation

| Read this | For |
|---|---|
| [docs/quickstart.md](docs/quickstart.md) | The first request, reading a decision, feedback |
| [docs/configuration.md](docs/configuration.md) | Every key, generated from the settings model |
| [docs/routing.md](docs/routing.md) | How a model is chosen and how to change the answer |
| [docs/operations.md](docs/operations.md) | Health, queue controls, retention, backups, what to watch |
| [docs/troubleshooting.md](docs/troubleshooting.md) | Every error code and what to do |
| [docs/upgrading.md](docs/upgrading.md) | Migrations, behaviour changes, the downgrade path |
| [docs/security.md](docs/security.md) | The LAN-exposure path end to end |
| [docs/openapi.json](docs/openapi.json) | The API, as a committed OpenAPI snapshot |
| [docs/apps/loadcoach/](docs/apps/loadcoach/) | The specification, routing, queue and API documents (mirrored from the suite) |

## Development

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pre-commit install
ruff format --check . && ruff check . && mypy src tests && lint-imports
pytest -m "not live and not performance"
pytest -m performance            # every spec §15 budget, measured
pytest tests/security            # Security Standards §14, item by item
```

Licensed under the Apache License 2.0.
