● Free and open source, forever

See what happens
between your systems.

Your logs tell you a request was slow. They do not tell you that it started when a third party began rate-limiting you, that it has run for two hours, or that it affects one of the six places you call them from.

Self-host it in one command Read the source

Groq started refusing. OpenAI picked up the load. One of those is an incident; the other is Tuesday.

Three steps, then it watches itself

No agent to run, no collector to operate, no sampling to tune. One file in your application and a key.

1

Point it at your instance

Two environment variables. Leave the key unset and the client is inert, so tests and local runs send nothing.

ICC_URL=https://integrations.your-domain
ICC_API_KEY=iop_…
2

Name the calls you care about

Wrap an outbound call and give the edge a name. The first event creates it, so there is nothing to model up front.

await observability.track("bruno-to-groq", () =>
  groq.chat.completions.create(params))
3

Watch it fill in

Every call one request caused is correlated into a trace. Health is re-derived on a timer, so a status change is noticed while nobody is looking, and incidents open and close on their own.

What it gets right

01

A refusal is not an outage

A 429 is recorded as rejected, not failed. The dependency is working and telling you to slow down. Counting that as downtime makes a noisy client look like a broken service, and teaches everyone to ignore the dashboard.

02

A fallback is two integrations

When your primary sheds load and your backup absorbs it, that is the system working. Report each leg separately and you can see it. Merge them and it looks like an outage in something that never broke.

03

It cannot hurt the thing it watches

Recording costs an array push. Sending happens on a timer. Every path swallows its own errors, the queue is bounded, and a batch that can never succeed is dropped rather than retried forever.

04

Six call sites, six numbers

Calling one provider from six places is six integrations, not one. A failure in recipe tagging should not drag down the health of payments just because they share a vendor.

Open source, and staying that way

Good tools should not be rationed by budget. Everything here is free and open source, and no capability is held back behind a paid tier. There is no Enterprise edition, no seat limit, no feature that quietly stops working past some threshold.

This is not a growth tactic. Too many promising projects start open and slowly close: first a feature flag, then an edition, then a licence change, and the thing you built your work on is no longer the thing you adopted. That pattern is the reason this is licensed under the AGPL rather than a permissive licence. Run it, change it, share it. If you run a modified version as a service for other people, publish your changes too.

Self-hosting is the first-class path, not the degraded one. There is no hosted tier that gets the good version. If a hosted option ever exists, it will exist because running servers is a chore some people would rather pay to avoid, and it will run this same code.

Run it yourself

Three images and a Postgres. Nothing is built on your server, and nothing phones home. A small VPS is plenty.

curl -O https://raw.githubusercontent.com/\
FredrikHillbert/nexus/master/\
docker-compose.production.yml

# three settings, then:
docker compose -f docker-compose.production.yml up -d

What you need

A host with Docker, a domain pointed at it, and about 1 GB of RAM. Identity, migrations and partitioning all set themselves up on first boot.

Deploying with Coolify takes the same file: point it at the repository, give the web service your domain, set three variables.

Full instructions