Self-hosting
One compose file, one machine
trimset runs next to your apps, on your own server. No account, no outside service, and nothing leaves the machine unless you send it.
Start it
Two secrets in a .env file, then compose. The server and the worker set up the database themselves on first start.
git clone https://github.com/trimset/trimset
cd trimset
echo "TRIMSET_DB_PASSWORD=$(openssl rand -hex 16)" > .env
echo "TRIMSET_SECRET=$(openssl rand -hex 32)" >> .env
docker compose up -d
# a project and its first key, shown once
docker compose exec server trimset-server create-project acme
docker compose exec server trimset-server create-key acme --scope proxy
What it starts, and what it needs
proxy and server · :8800
The proxy is the front door: it forwards model calls unchanged and passes everything else to the API behind it. Health on /health, readiness on /ready, JSON logs.
worker
The jobs that run in the background: joining late outcomes, default labels, fits and compiles, and later drift checks.
Postgres 18
The only store. No Redis, no queue, no second database. Decisions live in monthly partitions.
You bring
Docker with Compose. Aimed at a 2 vCPU, 4 GB machine, with Postgres on the same box.
Upstreams are set only on the server, never through the API, so a key holder can't point trimset somewhere else. A model key you set here only ever goes to its own URL.
TRIMSET_UPSTREAM_OLLAYA_URL=http://host.docker.internal:11435
TRIMSET_UPSTREAM_JEV_URL=https://api.typesafe.ai
TRIMSET_UPSTREAM_JEV_KEY=… # optional, https only
Privacy
- Raw state is never stored. trimset keeps a keyed hash of it, unique to each project, so the same input can be recognised but not read.
- Tag keys can be limited to a per-project allow-list, so personal data can't slip in through tags.
- Keys are stored as hashes and shown once. A key in a URL is redacted from every log line.
- Keeping raw state for reviewers is a per-project switch, off by default. Coming soon.
Data retention
- Each project sets how long it keeps decisions. The default is 400 days.
- Decisions are stored by month, so an expired month goes as a whole, with its outcomes. Coming soon.
- Deleting everything for one external reference, for a data-subject request. Coming soon.
- Fits keep probabilities and labels, never decision ids or state. Policies keep only thresholds and the numbers behind them.