Skip to main content

Vengtoo Agent

The Vengtoo Agent runs on your infrastructure. It pulls your tenant's policy bundle from Vengtoo cloud on a configurable interval (default: 30 seconds), evaluates it in-memory, and answers POST /access/v1/evaluation requests locally.

Why run the agent

  • Low latency: decisions are evaluated in-memory locally, with no network round-trip to the cloud.
  • Data stays local: decision inputs never leave your network.
  • Graceful degradation: if the cloud is unreachable, the agent keeps serving from the last cached bundle.
  • No code changes: point any SDK at the agent with a single baseUrl config; the evaluation API is identical to cloud.

Architecture

On restart, the agent loads the cached bundle from disk and starts serving immediately, without waiting for the next cloud sync.

Feature scope

The agent always contacts Vengtoo Cloud to pull its policy bundle: that connection is how policies stay current. What changes when you route evaluation calls to the agent (localhost:8181) instead of the cloud endpoint is which features are enforced at decision time.

RBAC, ABAC, direct grants, and policy modifiers are baked into the bundle and evaluated fully in-memory on the agent.

Some features are enforced only on the cloud endpoint

The features marked below have no effect when calling the local agent: they are enforced only when evaluation goes through the cloud endpoint (pdp.vengtoo.com/access/v1/evaluation). Route any decision that depends on delegation, human-in-the-loop approval, rate limiting, or JIT subject creation to the cloud endpoint.

FeatureCloud endpointLocal agent endpoint
RBAC / ABAC / direct grants
Policy modifiers (time window, IP allowlist)
Agent-to-agent delegation✗ Delegation records are live DB state
Human-in-the-loop approval✗ Approval state changes on human action
Rate limiting✗ Per-subject counters require shared state
JIT subject creation✗ Writes to the entity DB

The agent still forwards decision events to the cloud audit log when reachable (VENGTOO_AUDIT_FORWARDING=true, the default). Set it to false to suppress forwarding entirely.

If you need delegation chains or human-in-the-loop approval enforced on the local evaluation path (for example, in an air-gapped deployment), contact us about Enterprise private-PDP options.

Install

Binary

Download the latest release from GitHub Releases for your platform (linux/amd64, linux/arm64, darwin/arm64).

Go install

go install github.com/vengtoo/agent/cmd/agent@latest

Docker

Image: vengtoo/agent on Docker Hub.

docker pull vengtoo/agent:latest
docker run -d \
--name vengtoo-agent \
-e VENGTOO_API_KEY=vgt_... \
-p 8181:8181 \
-v vengtoo-cache:/var/lib/vengtoo/bundles \
-e VENGTOO_CACHE_DIR=/var/lib/vengtoo/bundles \
vengtoo/agent:latest

Docker Compose

services:
vengtoo-agent:
image: vengtoo/agent:latest
environment:
VENGTOO_API_KEY: ${VENGTOO_API_KEY}
VENGTOO_CACHE_DIR: /var/lib/vengtoo/bundles
volumes:
- vengtoo-cache:/var/lib/vengtoo/bundles
ports:
- "8181:8181"

volumes:
vengtoo-cache:

Mount a persistent volume at VENGTOO_CACHE_DIR so the agent can warm-start across container replacements.

Configuration

The agent resolves configuration in this order:

  1. --config <path>: explicit path passed as a CLI flag
  2. ./vengtoo-agent.yaml: current working directory
  3. $HOME/.vengtoo/agent.yaml: home directory fallback

Environment variables override whichever YAML file was loaded.

Env varYAML keyDefaultPurpose
VENGTOO_API_KEYapi_key— (required)Bearer token sent to the cloud policy bundle endpoint.
VENGTOO_CLOUD_URLcloud_urlhttps://api.vengtoo.comCloud base URL. Override for staging or self-hosted.
VENGTOO_TENANT_IDtenant_idauto-resolvedUsually inferred from the bundle. Set explicitly for multi-tenant bundles.
VENGTOO_LISTEN_ADDRlisten_addr0.0.0.0:8181HTTP listen address.
VENGTOO_POLL_INTERVALpoll_interval30sGo time.Duration. Bundle re-pull frequency.
VENGTOO_CACHE_DIRcache_dir~/.vengtoo/bundlesWhere bundle.json is persisted.
VENGTOO_LOG_LEVELlog_levelinfoLog level.
VENGTOO_DECISION_LOGdecision_logfalseSet to true to emit a JSON log line per decision.
VENGTOO_AGENT_NAMEagent_namehostnameIdentifies this agent instance in the dashboard. Defaults to os.Hostname(). Set explicitly when running multiple agents in the same tenant.
VENGTOO_AUDIT_FORWARDINGaudit_forwardingtrueForwards decisions to cloud for the Decision Log. Set to false to disable.
VENGTOO_CLIENT_SECRETclient_secret— (optional)When set, requires Authorization: Bearer <secret> on /access/v1/evaluation. /healthz and /readyz stay open.
VENGTOO_AGENT_REGIONagent_regionDisplay label for the region this agent runs in. Shown in the dashboard.
VENGTOO_AGENT_DOMAINagent_domainDisplay label for the domain or environment (e.g. prod, staging). Shown in the dashboard.
VENGTOO_HEARTBEAT_INTERVALheartbeat_interval30sHow often the agent sends a liveness ping to cloud.
VENGTOO_AUDIT_ENDPOINTaudit_endpointderived from cloud_urlOverride the endpoint where decision events are forwarded. Defaults to <cloud_url>/v1/agent-logs/ingest.
VENGTOO_AUDIT_BATCH_SIZEaudit_batch_size100Number of decision events to buffer before flushing to cloud.
VENGTOO_AUDIT_BATCH_INTERVALaudit_batch_interval5sMaximum time to wait before flushing a partial batch.
VENGTOO_AUDIT_BUFFER_SIZEaudit_buffer_size10000In-memory buffer capacity for decision events. Events are dropped if the buffer fills.
VENGTOO_AUDIT_RETRY_ATTEMPTSaudit_retry_attempts5Number of retry attempts for failed audit log flushes.
VENGTOO_TRUSTED_KEYS_PATHtrusted_keys_path~/.vengtoo/trusted_keys.jsonPath to a pinned public keys file for bundle signature verification in air-gapped environments.

All variables are prefixed VENGTOO_.

Example vengtoo-agent.yaml:

api_key: "vgt_..."
cloud_url: "https://api.vengtoo.com"
listen_addr: "0.0.0.0:8181"
poll_interval: "30s"
cache_dir: "/var/lib/vengtoo/bundles"
decision_log: true

Using with SDKs

Point any SDK at the agent:

client := vengtoo.NewClient("", vengtoo.WithBaseURL("http://localhost:8181"))

No API key is needed on calls to the agent: the agent authenticates with cloud on your behalf to fetch bundles.

Health endpoints

EndpointPurpose
GET /healthzDiagnostic JSON: bundle revision, last sync time, degraded flag, consecutive failures, sync age. Returns 200 while the process is up, even when stale.
GET /readyz200 once a bundle has loaded (from cache or cloud). 503 during the cold-start window. Use this as your orchestrator readiness probe.

Example /healthz body:

{
"status": "ok",
"bundle_revision": "a3f8c2d1",
"last_sync": "2026-04-19T14:02:41Z",
"degraded": false,
"consecutive_failures": 0,
"sync_age_seconds": 12.4
}

Metrics

GET /metrics exposes Prometheus-format metrics.

MetricTypeLabelsMeaning
vengtoo_agent_upgauge1 while the process is alive.
vengtoo_agent_decisions_totalcounterallowed, access_pathOne per /access/v1/evaluation call.
vengtoo_agent_decision_duration_secondshistogramallowedEval latency. Buckets tuned for sub-ms.
vengtoo_agent_bundle_last_sync_timestamp_secondsgaugeUnix ts of last successful sync.
vengtoo_agent_bundle_sync_failures_totalcounterMonotonic count of failed bundle polls.
vengtoo_agent_bundle_cache_hitcountersource (cache / sync)How the agent became ready at startup.
vengtoo_agent_degradedgauge1 when serving stale data because cloud sync is failing.
vengtoo_agent_consecutive_sync_failuresgaugeCurrent sync failure streak. Resets on success.

Recommended alerts:

  • vengtoo_agent_up == 0: process is down.
  • vengtoo_agent_degraded == 1 for more than 5 minutes: sustained cloud unreachability.
  • time() - vengtoo_agent_bundle_last_sync_timestamp_seconds > 600: no successful sync in 10 minutes.

Decision logs

Set VENGTOO_DECISION_LOG=true to emit one JSON line to stdout per /access/v1/evaluation call:

{
"time": "2026-04-19T14:03:11.482Z",
"level": "INFO",
"msg": "decision",
"subject_id": "a5f77b72-d139-46e7-b3f2-09dfe049bedc",
"resource_id": "14d9ce16-dea0-4de4-b528-ef5949ef9614",
"action": "view",
"decision": true,
"reason": "Access granted via role",
"access_path": "role",
"policy_id": "550e8400-e29b-41d4-a716-446655440000",
"ms": 0.42
}

Tail them live:

docker logs -f vengtoo-agent | grep '"msg":"decision"'
Decision logs can contain PII

Volume can be high under load, and subject/resource attributes may contain PII: leave this off in production by default. Pipe through Datadog, Loki, CloudWatch, or any structured-log collector as needed.

Graceful degradation

On every startup, the agent does two things in order:

  1. Load from disk cache: if bundle.json exists in VENGTOO_CACHE_DIR, the agent starts serving decisions immediately. /readyz goes 200 before any network call.
  2. Sync with cloud: pulls a fresh bundle and replaces the in-memory engine on revision bump.

If the cloud is unreachable, the agent continues serving from the cached bundle. The following signal the degraded state:

  • /healthz"degraded": true, consecutive_failures > 0, sync_age_seconds growing.
  • vengtoo_agent_degraded == 1.
  • Log line at every fifth failure: [ERROR] Bundle sync failing for N consecutive attempts, serving from cache (last successful sync: <age>).

When sync recovers, the agent logs Bundle sync recovered after N consecutive failures, cache refreshed.

If the cloud has never been reached and there is no cached bundle on disk, /readyz stays 503 until the first successful sync.

Trust model

The agent trusts anything that can reach it by default

By default the agent trusts anything that can reach :8181: deploy it inside a Docker network, Kubernetes NetworkPolicy, or VPC with the same isolation guarantees you apply to any internal service.

For stricter isolation, set VENGTOO_CLIENT_SECRET. When set, the agent requires Authorization: Bearer <secret> on every /access/v1/evaluation call and rejects requests without it. Health and readiness probes (/healthz, /readyz) remain open so orchestrators can probe without the secret.

Troubleshooting

SymptomLikely causeCheck
/readyz is 503 after a minuteInitial sync failed and no cache on diskIs VENGTOO_CACHE_DIR mounted? Can the agent reach VENGTOO_CLOUD_URL?
[FATAL] Failed to load config: API key is requiredVENGTOO_API_KEY unsetCheck env vars / mounted config.
vengtoo_agent_degraded == 1 sustainedCloud unreachableVerify outbound connectivity. Logs print last successful sync age at every fifth failure.
Every user sees "permission denied"Wrong tenant bundle, or bundle is stale/healthz → compare bundle_revision with cloud.
[ERROR] Evaluation failed per requestBundle parses but evaluation fails on this input shapeSet VENGTOO_DECISION_LOG=true and capture the failing input.