Run it locally
Choose a deployment before running a command. The two options use different images, ports, databases, and feature sets.
| Open source server | Customer-local bundle | |
|---|---|---|
| Source | PioneerSquareLabs/metergraph, Apache-2.0 |
A signed release bundle from Metergraph |
| Start it with | docker compose up |
./bin/start |
| Serves on | http://localhost:8787 |
http://127.0.0.1:8080 |
| Database | postgres:16 |
postgres:17 |
| You get | The performance dashboard | Dashboard, alerts, and optimization analysis |
| Content | Stripped at ingest, always | Captured unless you turn it off |
| Account needed | None | A registry credential from Metergraph |
If you are still choosing between running it yourself and the hosted service, read Choosing a deployment first.
The open source server
Section titled “The open source server”The Apache-2.0 server needs no account, key minting, or outbound network access. It serves the React dashboard and FastAPI API from one process, backed by Postgres 16.
It records and prices traffic. It does not run alerts or optimization analysis, and it never stores content: the ingest handler projects rows through a column allowlist, so prompts and completions cannot reach the database whatever the SDK is configured to send.
-
Start it
Section titled “Start it”git clone https://github.com/PioneerSquareLabs/metergraphcd metergraphMG_TOKENS=dev-token docker compose upThe compose file already defaults
MG_TOKENStodev-token, so a baredocker compose upworks too. Set the variable when you want a token of your own:MG_TOKENS=$(openssl rand -hex 16) docker compose up -dTokens are whatever you say they are.
MG_TOKENStakes a comma-separated list, so you can give each producer its own and rotate them independently. -
Point your app at it
Section titled “Point your app at it”export METERGRAPH_INGEST_URL=http://localhost:8787export METERGRAPH_APP_TOKEN=dev-tokenMoving between a self-hosted server and the hosted service later is
METERGRAPH_INGEST_URLin either direction, and nothing else. See Install the SDK. -
Open the dashboard
Section titled “Open the dashboard”http://localhost:8787, and enter the same token. The server runs its migrations on startup, so there is no separate schema step. -
Optional: seed some traffic
Section titled “Optional: seed some traffic”python -m pip install 'metergraph>=0.4,<1'MG_TOKEN=dev-token python scripts/seed_demo.pyThe demo wraps local OpenAI-, Anthropic- and Google-shaped clients with the published SDK, so it exercises the real session exchange and batched ingest without a provider key and without spending anything. Seeded calls land in the
demoenvironment, which you can deselect in the dashboard.
Configuring the open source server
Section titled “Configuring the open source server”Each of these is read from the environment by the server process.
| Variable | Default | What it does |
|---|---|---|
DATABASE_URL |
postgresql://metergraph:metergraph@localhost:5432/metergraph |
Postgres DSN. The compose file points it at the postgres service. |
MG_TOKENS |
empty, which rejects every request | Comma-separated static bearer tokens |
MG_PRICES_PATH |
the bundled prices.yaml |
Mount a newer price catalog without rebuilding |
MG_REGION |
global |
Preferred price region, falling back to * then global |
MG_MAX_BODY_BYTES |
8388608 |
Ingest body cap |
MG_MAX_ROWS |
5000 |
Rows per ingest request |
MG_SESSION_TTL_SECONDS |
300, clamped to 60 through 3600 |
Ingest session lifetime |
MG_DASHBOARD_DIST |
/app/static in the image |
Where the built dashboard lives |
Authentication is a static bearer token, and the dashboard keeps its token in browser local storage. Run the server inside a network boundary you trust, and treat dashboard access as trusted-network access.
The customer-local bundle
Section titled “The customer-local bundle”The full product on one machine: dashboard, alerts, and optimization analysis, with traces that never leave the machine. This is a signed release you download from the releases page, not a repository you clone. Each release has its own page there with the download, verification and start commands for that version. The files are public: no credential is needed to download them, only to pull the images. Eight services come up together.
| Service | Role |
|---|---|
postgres |
Your data, on the pgdata volume |
localstack |
The S3 and SQS APIs the application calls, kept local |
clickhouse |
The analytics store: a copy of call metadata, no prompt or response content, rebuilt from postgres if lost |
bootstrap |
One shot: migrates the schema, creates the admin, exits |
api |
Dashboard and HTTP API on http://127.0.0.1:8080 |
worker |
Ingestion and scheduled work |
detector-worker |
Detector scans on a separate queue and worker process |
local_runner |
Runs analyses. The only service given a provider key |
Before you start
Section titled “Before you start”- Docker with Compose, on macOS or Linux. On Windows, run the bundle inside WSL with Docker’s WSL integration on.
cosign.bin/startverifies the release with it and refuses to run without it.- A pull-only registry credential for the private images, which comes with your invitation.
Automatic workload classification is enabled by default once a workspace has 10 usable traces, so a model provider key is needed for classification as well as manually started analyses. Sign-in, ingestion, the dashboard, the readiness check and demo ingestion all work without one.
Bring it up
Section titled “Bring it up”Verify the bundle before extracting it. Follow
Verifying a release: bin/start ships
inside the archive and cannot verify itself.
-
Sign in to the image registry
Section titled “Sign in to the image registry”echo "$METERGRAPH_PULL_TOKEN" | docker login ghcr.io \-u "$METERGRAPH_PULL_USER" --password-stdin -
Create your settings file
Section titled “Create your settings file”cp .env.example .envThree values in
.envmust be set before the first boot.local/.env METERGRAPH_LOCAL_ADMIN_EMAIL=admin@example.comMETERGRAPH_LOCAL_ADMIN_PASSWORD=<choose a strong password>METERGRAPH_DB_PASSWORD=<choose a strong password>The Settings page hides the local setup card automatically because this bundle runs with the local deployment profile. No additional setting is needed.
Compose needs two more variables,
METERGRAPH_APP_IMAGEandMETERGRAPH_RUNNER_IMAGE, and neither is yours to set.bin/startresolves both from the signed release manifest into a generated.images.env, and passes that file to Compose last so a stray value in.envcannot win. A third generated file,.runtime.env, holdsMETERGRAPH_RUNTIME_DB_PASSWORD: the least-privilege database login the API, workers and detector worker use. It is machine-generated on first boot and reset by every migration, so it is never your input either. -
./bin/start
It first runs
./bin/doctor, a preflight that checks Docker, Compose,cosign,curl, Python, free disk space, port 8080, the required.envsettings, and which provider keys are set. It prints names only, never values, and stops before Compose starts if a check fails.It then verifies the manifest and both image digests with
cosign, resolves those digests, checks that the registry serves both images, runs Compose, and waits until every service is healthy andbootstraphas exited zero. Then it prints a JSON readiness report, and on the first boot of a new database it sends one demo trace through the real ingestion API under environmentlocal-demo.If
bootstrapfails, the API, workers and runner never start, andbin/startexits non-zero naming the log to read. On success it printsMetergraph is readywith the dashboard URL and the SSH tunnel command. -
Sign in
Section titled “Sign in”Open
http://localhost:8080/and use the admin email and password from.env.
Send your own traces
Section titled “Send your own traces”Create an ingest key under Keys in the dashboard, then point an application at the machine:
export METERGRAPH_INGEST_URL=http://localhost:8080export METERGRAPH_APP_TOKEN=mg_...To load traffic you already record elsewhere, the same two variables drive Importing existing traffic.
Running an analysis
Section titled “Running an analysis”An analysis makes two kinds of model call, and they are configured separately.
Only local_runner ever receives a key.
Its own calls, which classify workloads, build the evaluations and judge
the results, go out on the channel you set in .env:
METERGRAPH_ANALYSIS_CONTROL_CHANNEL |
Key it reads |
|---|---|
vercel-ai-gateway (default) |
AI_GATEWAY_API_KEY |
anthropic-api |
ANTHROPIC_API_KEY |
openai-api |
OPENAI_API_KEY |
Until that channel’s key is set, an analysis request is refused up front with a message naming it. No gateway account is required: set the channel to whichever provider you already have.
The candidate calls, which try your workload on other models, use every key
you have set. A gateway key compares the widest field, FIREWORKS_API_KEY adds
the models Fireworks publishes, and a direct provider key compares that
provider’s own models. GOOGLE_API_KEY routes no candidate on its own and is
read only by search-enabled workloads.
Automatic weekly analysis is off by default and runs separately from automatic
workload classification. Turn it on once a manual analysis has succeeded, with
METERGRAPH_AUTOMATIC_ANALYSIS_ENABLED=true in .env and another
./bin/start.
Automatic workload classification is enabled by default in the customer-local
bundle. The worker checks hourly and starts a classification-only run after
the workspace reaches 10 distinct usable traces, then waits until 24 hours
after the last successful classification before refreshing. A usable trace
contains captured, non-truncated request content and at least one non-soak
call. The classification is saved as a reusable checkpoint and does not
create an analysis report. Set METERGRAPH_AUTOMATIC_CLASSIFICATION_MIN_TRACES
in .env to a value of 10 or higher to tune the threshold, or set
METERGRAPH_AUTOMATIC_CLASSIFICATION_ENABLED=false to pause automatic
classification. Apply .env changes with ./bin/start. The configured
analysis control-channel provider key is required for classification calls.
Day to day
Section titled “Day to day”./bin/status prints the readiness report on demand. ./bin/verify runs it and
then sends a demo trace. Both are content-free and work with no provider key.
Use stop and start between sessions rather than down. Your database
survives down, but the raw ingested payloads held in local object storage do
not.
docker compose --env-file .env --env-file .runtime.env --env-file .images.env \ -f docker-compose.yml stopBackups, upgrades, workspace and key management, and the tenant purge are on Operations.