Open-source observability for AI coding tools. Track usage, cost, latency, plan/seat utilization, and configuration health across Codex, Claude Code, Cursor, Continue, local models, and more.
Site: usejunction.dev · Guides: Plan usage & waste · Team AI coding insights · llms.txt
UseJunction is currently maintained by a single independent developer. The project is open for evaluation, feedback, and self-hosted use today, with a fuller community contribution setup coming soon.
UseJunction separates verified usage (vendor-reported charges, e.g. Cursor usage events) from estimated usage (local scans and pricing models). The combinations below have been tested on real machines and confirmed to surface verified usage correctly in the admin UI.
| Tool | Platform | Verified usage |
|---|---|---|
| Cursor | macOS | ✓ |
| Codex | macOS | ✓ |
| Cursor | Windows | ✓ |
Other tools and platforms are supported by the agent collector; this table will grow as additional stacks are validated end-to-end.
Run the entire stack in Docker — admin on :3001 (host; configurable via ADMIN_HOST_PORT), Langfuse on :3000, LiteLLM on :4000.
cp .env.example .env
# Optional: add provider keys to test real LiteLLM completions
# OPENAI_API_KEY=sk-...
# ANTHROPIC_API_KEY=sk-ant-...
# Without keys, full-stack E2E still passes by verifying the ingest API directly.
cd infra
docker compose build admin
docker compose up -d
docker compose ps # wait until all services are healthyIf port 3001 is taken:
ADMIN_HOST_PORT=3020 docker compose up -d
ADMIN_URL=http://localhost:3020 ./run-e2e.shLangfuse project keys (one-time, for traces):
- Open http://localhost:3000 → create account → create project
- Copy Public Key and Secret Key into root
.env - Restart LiteLLM:
cd infra && docker compose restart litellm
The admin container runs prisma db push and seeds seed-org plus a demo enrollment token on first start.
Verify end-to-end:
chmod +x scripts/full-stack-e2e.sh
./scripts/full-stack-e2e.sh
# or from infra/
./run-e2e.shManual gateway request (use a user id from Developers):
curl http://localhost:4000/v1/chat/completions \
-H "Authorization: Bearer sk-usejunction-master" \
-H "Content-Type: application/json" \
-H "x-usejunction-user: <userId>" \
-H "x-usejunction-tool: codex" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"ping"}]}'| Service | URL |
|---|---|
| Admin UI | http://localhost:3001 (admin@example.com / admin) |
| Langfuse | http://localhost:3000 |
| LiteLLM | http://localhost:4000 |
| Postgres (host) | localhost:5433 |
cp .env.example .env
cd infra
docker compose up -d postgres langfuse-db litellm-db langfuse litellm
# Wait for DBs, then start admin locally:
cd ..
pnpm install
pnpm db:push
pnpm db:seed
pnpm devAdmin UI: http://localhost:3001
Generate a developer-bound enrollment token after signing in and joining the organization:
curl -X POST http://localhost:3001/api/me/enrollment-token \
-H "Cookie: uj_session=..." | jqFrom a repo checkout (builds the Go agent locally — preferred for development):
chmod +x install.sh
./install.sh --token <token> --url http://localhost:3001
# enrolls, enables Claude OTEL, sends first report, and starts the daemonOne-liner (downloads a prebuilt binary from the control plane, or builds from source if the repo is on disk):
# optional for pnpm/dev without Docker: publish binaries into apps/admin/public
./scripts/build-agent-releases.sh 0.2.0
curl -fsSL http://localhost:3001/install.sh | sh -s -- --token <token> --url http://localhost:3001Windows 10/11 PowerShell (x64 or ARM64, no administrator shell required):
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "& ([scriptblock]::Create((Invoke-RestMethod -UseBasicParsing 'http://localhost:3001/install.ps1'))) -Token '<token>' -Url 'http://localhost:3001'"Teammate connect (from Team → Share connect command):
curl -fsSL http://localhost:3001/install.sh | sh -s -- --connect <token> --url http://localhost:3001
# opens browser to authenticate with the invited email, then enrollsThe onboarding and invite screens provide a separate Windows PowerShell command. Windows installs run through a per-user Scheduled Task at logon and collect native Windows coding-tool data; WSL stores are not scanned.
Or build manually:
cd agent && go build -o usejunction .
./usejunction enroll --token <token> --url http://localhost:3001
./usejunction doctor
./usejunction reportAfter the agent is enrolled once, rebuild and reinstall into ~/.usejunction whenever agent/ changes:
# one-shot rebuild + swap + daemon restart
pnpm agent:reinstall
# or: ./scripts/dev-agent-reinstall.sh
# watch agent sources and reinstall on change
pnpm dev:agent
# or: ./scripts/dev-agent-watch.shRequires an existing ~/.usejunction/config.json (from ./install.sh --token …). This path stamps a 0.0.0-dev.<sha>.<unix> version, swaps the local binary/app bundle, and restarts launchd/systemd. It does not publish a control-plane release or enroll a new device.
For faster change detection, install fswatch (brew install fswatch). Without it, the watcher polls every ~750ms.
Coding tools → LiteLLM Proxy → Providers
↓
Langfuse (traces)
↓
UseJunction callback → Admin API → Postgres
↑
Go agent (heartbeat, tool detection, local log scans)
↑
Provider Admin APIs + Claude Code OTLP/HTTP JSON
Analytical reads are centralized through UsageDaily, the SQL query engine, and a PostgreSQL result cache. See Central Analytics Engine, Usage Accounting Contract, and Subscription Cycle Utilization.
Signals collection is documented in docs/signals-collection.md. It covers the optional activity-flow layer that collects AI-adjacent app/domain sessions from the enrolled desktop agent.
| Command | Description |
|---|---|
usejunction enroll --token <t> |
Enroll device (runs setup by default) |
usejunction setup |
Enable Claude OTEL and send initial report |
usejunction doctor |
Detect installed tools |
usejunction status |
Show enrollment state |
usejunction cost --tool all |
Local usage scan (JSONL / sqlite / extension task JSON) |
usejunction update --check |
Check the active release without installing |
usejunction update |
Download, verify, and install an available update |
usejunction update --rollback |
Restore the retained previous binary |
usejunction update --force |
Reinstall a version locally blocked after rollback |
usejunction uninstall |
Remove agent |
Existing 0.1.0 installations need one final updater bootstrap after the first release is promoted:
curl -fsSL <control-plane>/install.sh | sh -s -- --upgrade --url <control-plane>Hosted production (Vercel, env vars, migrations, crons) is documented in Production deployment.
Agent release operations, triggers, rollout behavior, and fleet coverage are documented in Controlled Agent Releases.
When you are changing the release system itself, this is the fastest local loop:
cd agent && go test ./...
pnpm test
./scripts/build-agent-releases.sh 0.2.0Then exercise the rollout path against a local or staging control plane:
git tag agent-v0.2.0
git push origin agent-v0.2.0The protected promotion workflow and the control-plane endpoints are described in docs/agent-releases.md.
infra/ Docker Compose (Postgres, LiteLLM, Langfuse)
apps/admin/ Next.js admin UI + control plane API
packages/db/ Prisma schema + client
agent/ Go local agent CLI
install.sh One-line enroll installer
scripts/ Full-stack E2E
Privacy first. Observability second. Local scans read usage signals from tool-local storage (JSONL sessions, sqlite DBs, extension task JSON). There is no keystroke surveillance, browser capture, or network interception.
Signals can add optional work context (including allowlisted clipped summaries when enabled). That detail can be turned off. It does not collect screenshots, raw chat transcripts, clipboard text, or full URLs, and the employee ledger shows exactly what was uploaded.
UseJunction Community License — based on Apache 2.0 with additional terms:
- Use as-is commercially — run the unmodified software (frontend, backend, or self-hosted) in a commercial context.
- Derivatives require a license — developing or distributing a modified fork for commercial use requires a separate license. Contact hello@usejunction.dev.