Veefore docs

Observability

Every metric Veefore exports, the traces, the log shape, and the six alerts worth having.

Three signals, all on by default except tracing.

ini
METRICS_ENABLED=true
OTEL_ENABLED=true
OTEL_SERVICE_NAME=veefore
LOG_LEVEL=info

#Metrics

Prometheus format at /metrics on both planes.

#Enforcement

Metric Type Labels
veefore_gateway_requests_total counter organization environment protocol mode decision outcome
veefore_gateway_request_duration_ms histogram protocol mode outcome
veefore_policy_decisions_total counter environment decision policy
veefore_policy_evaluation_duration_ms histogram environment decision
veefore_blocked_requests_total counter organization environment reason

veefore_gateway_requests_total carries both mode and decision, which is what lets you see divergence in OBSERVE as a time series rather than by reading logs.

#Identity

Metric Type Labels
veefore_authentication_duration_ms histogram kind result
veefore_authentication_failures_total counter kind reason
veefore_agent_tokens_issued_total counter kind

veefore_authentication_failures_total by reason is the one to watch. A spike in nonce_replayed or timestamp_out_of_window is not a user error at scale — it is either a broken client or someone replaying captured traffic.

#Approvals, credentials, tools

Metric Type Labels
veefore_approval_decision_duration_seconds histogram organization decision
veefore_credential_leases_total counter provider type
veefore_credential_broker_errors_total counter provider operation
veefore_tool_failures_total counter tool kind reason

veefore_approval_decision_duration_seconds is your approval SLA, measured rather than asserted. If the p95 is longer than your rule TTLs, your approvals are expiring systematically.

#Audit and jobs

Metric Type Labels
veefore_audit_events_total counter event_type severity
veefore_audit_pipeline_errors_total counter —
veefore_job_queue_depth gauge queue
veefore_job_runs_total counter queue result

#Infrastructure

Metric Type Labels
veefore_http_requests_total counter method route status
veefore_http_request_duration_ms histogram method route
veefore_db_query_duration_ms histogram operation
veefore_db_errors_total counter operation

`organization` as a label is a cardinality decision

Fine for tens or hundreds of tenants. At thousands it will hurt your Prometheus. Drop the label with a relabel rule if you operate at that scale, and get per-tenant breakdown from the audit trail instead.

#The six alerts worth having

yaml
groups:
  - name: veefore
    rules:
      # Enforcement cannot evaluate. Protected actions are being refused.
      - alert: VeeforeDependencyUnavailable
        expr: |
          sum(rate(veefore_gateway_requests_total{outcome="FAILED"}[5m]))
            / sum(rate(veefore_gateway_requests_total[5m])) > 0.05
        for: 5m
        labels: { severity: critical }
        annotations:
          summary: Over 5% of protected actions are failing. Check /health/ready.

      # The audit trail is the thing you cannot reconstruct.
      - alert: VeeforeAuditPipelineErrors
        expr: increase(veefore_audit_pipeline_errors_total[10m]) > 0
        for: 0m
        labels: { severity: critical }
        annotations:
          summary: Audit writes are failing. Evidence is being lost right now.

      # A stalled queue breaks nothing visibly, which is why it needs an alert.
      - alert: VeeforeJobQueueStalled
        expr: veefore_job_queue_depth > 100
        for: 15m
        labels: { severity: warning }
        annotations:
          summary: "Queue {{ $labels.queue }} is backing up. Is a worker running?"

      # Either a broken client or replayed traffic.
      - alert: VeeforeAuthFailureSpike
        expr: sum(rate(veefore_authentication_failures_total[5m])) > 1
        for: 10m
        labels: { severity: warning }
        annotations:
          summary: Sustained agent authentication failures.

      # Approvals are expiring because nobody is working the queue.
      - alert: VeeforeApprovalsNotBeingWorked
        expr: |
          histogram_quantile(0.95,
            rate(veefore_approval_decision_duration_seconds_bucket[1h])) > 900
        for: 30m
        labels: { severity: warning }
        annotations:
          summary: p95 approval time exceeds the default 900s TTL.

      # The gateway is on the latency path for every protected action.
      - alert: VeeforeGatewayLatency
        expr: |
          histogram_quantile(0.99,
            rate(veefore_gateway_request_duration_ms_bucket[5m])) > 500
        for: 10m
        labels: { severity: warning }
        annotations:
          summary: Gateway p99 decision latency above 500ms.

Do not alert on blocked requests

veefore_blocked_requests_total rising means enforcement is working. Paging on it teaches the on-call to see refusals as incidents, and the natural response to an alert you do not want is to make the rule looser.

Alert on changes in the rate if you want a signal, or review it on a schedule. A refusal is not an outage.

What is worth watching but probably not paging on: refusal rate dropping to zero. That can mean your agents fixed their behaviour, or that enforcement stopped being applied.

#Traces

OpenTelemetry, exported through the standard OTEL_EXPORTER_* environment variables.

A protected action produces one span per pipeline stage, named for the stage: REQUEST, AUTHENTICATION, IDENTITY, LIFECYCLE, CAPABILITY, DELEGATION, POLICY, RISK, APPROVAL, CREDENTIAL, EXECUTION, RESULT.

That decomposition is the fastest way to answer "why was that slow": the stage with the time in it is the stage with the problem. Usually it is EXECUTION, which means your downstream, not Veefore.

Trace context propagates to the downstream on real egress, so a single trace spans the agent's request, the Veefore decision and your service's handling.

#Logs

Structured JSON through pino. Every line carries requestId and traceId.

json
{
  "level": "info",
  "time": 1759492684123,
  "requestId": "req_01JAV7YQ4T2K9M3E8H6R5N1XZ0",
  "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
  "event": "gateway.action_decided",
  "agentId": "agt_01JAV…",
  "tool": "refund_customer",
  "decision": "REQUIRE_APPROVAL",
  "mode": "ENFORCE",
  "latencyMs": 38,
  "msg": "Protected action requires approval"
}

Redaction happens on the way in

Credential material, private keys, session tokens and parameters listed in a tool's sensitive_parameters are redacted before the line is constructed.

There is no code path where a secret is written to a log and later filtered, which means log shipping, retention and backups cannot leak what was never written.

Index on requestId and traceId. Given a request_id from an error response you then have every log line, the action record and the audit event in one query.

`debug` in production is expensive and sticky

debug logs request and response shapes. Redaction still applies, but the volume costs money and a log retained for 90 days is a much larger surface than one retained for 7. Raise it for an investigation; lower it afterwards.

#What Veefore gives you that metrics cannot

Metrics tell you a decision happened. The action record tells you why:

bash
veefore logs --decision BLOCK --limit 50
curl -s $CP/v1/actions/act_01ABC -H "Authorization: Bearer $KEY"

Policy and version, the deciding rule, the per-condition trace, the resolved authority, the delegation chain, the risk signals with their explanations, the approval and who decided it, the credential lease by reference, the downstream status.

Do not try to reproduce that in a metric. Alert on rates; investigate in the action record.

#Product analytics

Veefore tracks adoption without collecting agent content: time to first agent, time to first protected action, OBSERVE→SIMULATE and SIMULATE→ENFORCE conversion, policies created.

Those are the numbers that tell you whether the thing is being adopted or just installed — an organization with fifty agents still in OBSERVE has not adopted anything.

Identity, authority, policy and enforcement for autonomous AI agents.