Guidance for coding agents working in this repository.
This repository is a self-hosted Docker Compose dashboard for OpenCode usage:
OpenCode → Node collector/control service → PostgreSQL → Rill/DuckDB → dashboard
The supported product is the collector, PostgreSQL store, controls page, and Rill dashboard. Do not add separate reporting surfaces or file-based caches.
src/server.js— control HTTP server and process lifecyclesrc/collector.js— refresh scheduling, pagination, database and Rill orchestrationsrc/opencode.js— OpenCode page/runtime discovery and API fetchersrc/usage.js— fingerprinting, normalization, overlap, and sanitizationsrc/db.js— PostgreSQL access and parameterized upsertspostgres/init.sql— initial database schema embedded byDockerfile.postgresrill/— Rill data/AI connectors, model, metrics view, and Explore dashboardrill/connectors/openai.yaml— OpenAI-compatible Rill AI connector using environment references onlycompose.yaml— service topology and loopback-only published portsDockerfile.rill— pinned architecture-aware Rill binary and checksums.env.example— safe configuration template.env— real secrets; never commit or print
Never commit or print secrets. OPENCODE_AUTH is an auth cookie and OPENAI_API_KEY is an AI-provider credential; both must be treated as live credentials.
The ignored .env file contains live local secrets and must never be read aloud, printed, or committed. Keep AI credentials in .env/deployment secrets and reference them from connector YAML; never embed them in tracked files.
Additional requirements:
- Keep Coolify's Use Docker Build Secrets option disabled. Secrets are runtime-only; Coolify's Dockerfile rewriting is incompatible with this multi-service build.
- Keep
postgres/init.sqlembedded throughDockerfile.postgres; do not restore a relative runtime file bind mount for the initialization script. - Keep PostgreSQL internal to Compose.
- Keep direct host bindings for controls and Rill on
127.0.0.1; remote access must pass through an authenticated proxy such as Coolify plus Cloudflare Access. - Do not expose key IDs, auth cookies, DSNs, raw OpenCode payloads, or stack traces in the controls page/API.
- Keep errors sanitized through
sanitizeError. - Rill Developer has no production authentication boundary; never document direct public exposure as safe.
Preserve the five-sequential-request overlap logic for incremental updates. The fingerprint intentionally includes:
- request ID
- workspace ID
- timestamp
- model/provider
- input/output/reasoning token counts
- cache-read, 5-minute cache-write, and 1-hour cache-write counts
- raw cost
- key ID/session ID
- plan
Page size is 50. Page snapshots remain disabled. If no overlap is found, fetch to the final short page and use idempotent PostgreSQL upserts.
PostgreSQL is the durable source of truth. A new database performs a clean refetch from OpenCode.
Manual and automatic refreshes must share one pipeline. Guard runs with both the in-process flag and PostgreSQL advisory lock. A PostgreSQL success must not be rolled back merely because Rill is down; retain state and permit a Rill-only retry.
- Keep one request-grain metrics view named
opencode_usage, displayed as OpenCode Usage. - Keep Rill AI on the tracked
openaiconnector, with API key, compatible base URL, and model supplied through runtime environment variables. - Do not mix quota snapshots into this metrics view.
- PostgreSQL timestamps are UTC; Rill controls display timezone.
- The collector triggers model refreshes. Do not add a competing Rill cron.
- Rill release archives must be pinned and checksum-verified for both AMD64 and ARM64.
- Keep Rill in
--previewmode for its dashboard-only interface; Cloudflare Access provides the authentication boundary for remote deployment.
Keep dependencies minimal. The collector uses Node.js built-ins plus pg. Do not add a web framework for the small local controls page without a demonstrated need.
Run before finishing code changes:
npm test
docker compose config --quiet
docker compose build
docker compose up -d
docker compose psWhen credentials and network access are available, also verify:
- an empty volume performs a full refetch;
- the Rill dashboard loads at
http://localhost:9009; - PostgreSQL and dashboard totals agree;
- a no-change refresh normally fetches one API page;
- refresh/toggle state persists across restarts;
- invalid auth or Rill downtime retains existing data;
- published ports resolve only to
127.0.0.1.
Never run docker compose down -v without explicit user approval because it permanently deletes the database and Rill volumes.