Metrics Reference
The API serves Prometheus metrics at GET /api/v1/admin/metrics in text exposition format 0.0.4. This page lists every family it can emit. For scraping, authentication and Helm setup, see Self-Hosted: Operator metrics.
Rules every label follows
Section titled “Rules every label follows”- Closed vocabularies only. Every label value comes from a fixed list shown on this page. A value outside the list is recorded as
other. - No names and no ids by default. Labels never carry persona names, template, suite or policy slugs, step names, titles, emails, or user, ticket, meeting, session, project or org ids.
- No dollar metrics. Agent spend is reported in tokens only.
- Bounded cardinality. Each family is capped at 10,000 series per process. Past the cap, samples are dropped and counted in
sessionfs_metrics_series_dropped_total. With the default settings every family’s worst case is far below the cap.
Per-tenant labels
Section titled “Per-tenant labels”Set SFS_METRICS_TENANT_LABELS=true (Helm: api.metrics.tenantLabels: true) to add org_id and project_id labels to the families marked tenant below. The value is always an id, never a name. A sample with no org or project (for example a run in a personal project, which has no org) leaves that label out.
It is off by default, and the hosted service leaves it off: series then add up across every tenant. Turn it on only on a self-hosted install where you want per-team dashboards. Series then grow with the number of orgs and projects, still capped at 10,000 per family.
Aggregating across replicas
Section titled “Aggregating across replicas”Counters and histograms are per process. Sum them across replicas with sum() or sum by (...).
Families marked DB-derived are computed from the database when the endpoint is scraped and cached for 30 seconds. Every replica reports the same cluster-wide value, so take max() or max by (...) instead of summing. sessionfs_sweep_lag_seconds is set by whichever replica ran the sweep last, so take max() across replicas too.
Requests, sync and security
Section titled “Requests, sync and security”| Metric | Type | Labels and values |
|---|---|---|
http_request_duration_seconds |
histogram | method: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, other. route: the matched route template (for example /api/v1/sessions/{session_id}/sync), or unmatched for every 404 and 405. status_class: 2xx, 3xx, 4xx, 5xx. For a streaming response this is the time to first headers. |
sessionfs_push_total |
counter | outcome: ok, conflict, rejected_quota, rejected_dlp, error. size_bucket: <1MB, 1-10MB, 10-50MB, 50-100MB, >100MB. |
sessionfs_sync_pull_total |
counter | none. Successful session downloads. |
sessionfs_handoff_create_total |
counter | none. Handoffs created. |
sessionfs_handoff_claim_total |
counter | none. Handoffs claimed. |
sessionfs_dlp_findings_total |
counter | severity: critical, high, medium, low, other. action: block, redact, warn, other. |
sessionfs_auth_failures_total |
counter | reason: missing_bearer, invalid_key, revoked, inactive_key, expired, inactive_user. |
sessionfs_metrics_series_dropped_total |
counter | none. Samples dropped by the series cap. |
Database and users (DB-derived)
Section titled “Database and users (DB-derived)”| Metric | Type | Labels and values |
|---|---|---|
sessionfs_active_users |
gauge | window: 1h, 1d, 7d. Distinct users with a sync in the window. Take max(). |
sessionfs_sessions |
gauge | none. Non-deleted sessions. Take max(). |
sessionfs_db_pool_size |
gauge | none. This process’s pool size. Absent without a live pool (SQLite). Sum across replicas. |
sessionfs_db_pool_checked_out |
gauge | none. Connections checked out in this process. |
sessionfs_db_pool_overflow |
gauge | none. Overflow connections in this process. |
Scheduled sweeps
Section titled “Scheduled sweeps”Sweep labels: org-digest, ticket-notifications, kb-compile, jira-sync, confluence-publish, helper-retention, meeting-retention, contact-retention, eval-outputs, reminders-due, attention-hides, idempotency-keys, github-webhook-deliveries (both its /sweep and /purge paths), skills-verify, skills-catalogs-regenerate, skills-rescan, marketplace-freshness, marketplace-publishers-recheck.
| Metric | Type | Labels and values |
|---|---|---|
sessionfs_sweep_runs_total |
counter | sweep. result: ok (2xx), rejected (the sweep refused its request, for example a retention override sent with a service key), error (5xx or crash). Only calls that passed authorization count. |
sessionfs_sweep_duration_seconds |
histogram | sweep. Wall-clock time of an authorized run. Buckets from 0.1 s to 30 min. |
sessionfs_sweep_lag_seconds |
gauge | sweep. How long the oldest due item had been waiting when the sweep last started; 0 when nothing was due. Reported for reminders-due (oldest unsent due reminder), jira-sync (oldest due outbox row) and ticket-notifications (oldest undelivered notification). Take max(). |
sessionfs_sweep_denied_total |
counter | sweep. reason: unauthenticated (no or unknown key), rate_limited, auth_rejected (revoked, expired or otherwise refused key, or SSO enforcement), not_admin (a user key that isn’t a platform admin), insufficient_scope (a service key without platform_sweeps:run), owner_not_admin and minter_not_admin (the key’s owner or minter is no longer an active platform admin), minter_missing, other. Alert on any increase: a scheduler using a stopped key shows up here, not only in the logs. |
Integrations
Section titled “Integrations”| Metric | Type | Labels and values |
|---|---|---|
sessionfs_jira_sync_total |
counter, tenant (org_id) |
direction: outbound, inbound. result for outbound, one per delivery attempt from the outbox: done, skipped (sync turned off, link gone, superseded), failed (will retry), exhausted (gave up after five attempts). result for inbound, one per verified webhook event: applied, ignored (unsupported event, unknown issue, stale link, plan without Jira), duplicate. other is reserved. |
sessionfs_jira_sync_lag_seconds |
histogram, tenant (org_id) |
direction. outbound: time from the change being queued to Jira accepting it. inbound: time from Jira’s event timestamp to SessionFS applying it (skipped when the timestamp is missing, in the future or older than 30 days). |
sessionfs_confluence_publish_total |
counter, tenant | result: published, in_progress (another publish holds the page), drifted (the page was edited in Confluence), conflict (title clash, page missing, superseded), too_large, timeout, rejected (other 4xx), error. Counts manual and swept publishes. |
sessionfs_webhook_ingest_total |
counter | source: github (GitHub App), gitlab (merge request webhooks), jira, delivery_github and delivery_gitlab (org delivery webhooks), plus one source used only by the hosted service’s billing, which a self-hosted server never reports. result: ok (any 2xx or 3xx, including deliveries the server ignores), unauthorized (401/403, for example a bad signature), not_found, too_large, rejected (other 4xx), unavailable (503, for example no webhook secret configured), error. Never carries an org id, even with tenant labels on. |
Agents and review
Section titled “Agents and review”| Metric | Type | Labels and values |
|---|---|---|
sessionfs_agent_tokens_total |
counter, tenant | token_kind: input, output, cache_read, cache_write. model_family: anthropic, openai, google, openrouter, deepseek, kimi, xai, mistral, zai, qwen, minimax, groq, together, fireworks, other. The family is the run’s provider when it is one of these, else it is inferred from the model name; the model text itself is never a label. Incremented by the tokens each usage report, completion, worker finish and review round adds. |
sessionfs_agent_runs_total |
counter, tenant | status: passed, failed, errored, cancelled. role: implementer, ui-implementer, reviewer, design-reviewer, security-reviewer, release, grader, none (no role recorded), other. One per run reaching a terminal status. |
sessionfs_approval_requests |
gauge, DB-derived, tenant | status: pending, approved, rejected, expired, superseded. Take max(). |
sessionfs_approval_decision_seconds |
histogram, tenant | decision: approved, rejected. Time from the request being raised to the decision that settled it. Buckets from 1 minute to 14 days. |
sessionfs_review_loop_items |
gauge, DB-derived, tenant (project_id) |
status: pending, active, waiting, done, failed, needs_human (parked for a person by a budget or round cap). Counts work-queue items whose ticket belongs to a review loop. Take max(). |
Limits
Section titled “Limits”| Metric | Type | Labels and values |
|---|---|---|
sessionfs_org_concurrency_rejected_total |
counter, tenant (org_id) |
route_class: extraction (meeting and chat extraction), helper (session helper turns), compile (knowledge compile, rebuild and group compile), export (CSV exports), other. One per request refused with 429 org_concurrency_limit. A refusal in a personal project carries no org id. See Tenancy and Isolation. |
Meetings and chat
Section titled “Meetings and chat”| Metric | Type | Labels and values |
|---|---|---|
sessionfs_extraction_server_seconds |
histogram | kind: meeting, chat, other. result: done, failed, other. Time an extraction spent in the server: its wall time minus the time spent waiting on the model provider. Recorded for every extraction that finished, successfully or not. Buckets from 10 ms to 10 s. Used by the extraction SLO. |
Example queries
Section titled “Example queries”# Sweeps that failed or were refused in the last hoursum by (sweep, result) (increase(sessionfs_sweep_runs_total{result!="ok"}[1h]))sum by (sweep, reason) (increase(sessionfs_sweep_denied_total[1h]))
# Oldest due reminder, in minutesmax by (sweep) (sessionfs_sweep_lag_seconds) / 60
# Jira outbound p95 laghistogram_quantile(0.95, sum by (le) (rate(sessionfs_jira_sync_lag_seconds_bucket{direction="outbound"}[15m])))
# Agent tokens per hour by model familysum by (model_family) (increase(sessionfs_agent_tokens_total[1h]))
# Review-loop items waiting on a personmax(sessionfs_review_loop_items{status="needs_human"})A ready-made Grafana dashboard with panels for every family ships in the repository at docs/observability/sessionfs-ops.json. The objectives built on these metrics, with their queries and alert rules, are on Service Level Objectives.