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
baseUrlconfig; the evaluation API is identical to cloud.
Architecture
Vengtoo Cloud Your Infrastructure
+-------------------------+ +---------------------------+
| Vengtoo Cloud | bundle | Vengtoo Agent |
| GET /v1/policies/ | (tar.gz) | |
| bundle | ─────────► | - in-memory evaluation |
+-------------------------+ every | - disk-cached bundle |
30s | - localhost:8181 |
+-------------+-------------+
│
POST /access/v1/evaluation
│
+-------------v-------------+
| Your service |
+---------------------------+
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. The following features are only enforced when evaluation goes through the cloud endpoint (api.vengtoo.com/access/v1/evaluation) — they have no effect when calling the local agent:
| Feature | Cloud endpoint | Local 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=azx_... \
-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:
--config <path>— explicit path passed as a CLI flag./vengtoo-agent.yaml— current working directory$HOME/.vengtoo/agent.yaml— home directory fallback
Environment variables override whichever YAML file was loaded.
| Env var | YAML key | Default | Purpose |
|---|---|---|---|
VENGTOO_API_KEY | api_key | — (required) | Bearer token sent to the cloud policy bundle endpoint. |
VENGTOO_CLOUD_URL | cloud_url | https://api.vengtoo.com | Cloud base URL. Override for staging or self-hosted. |
VENGTOO_TENANT_ID | tenant_id | auto-resolved | Usually inferred from the bundle. Set explicitly for multi-tenant bundles. |
VENGTOO_LISTEN_ADDR | listen_addr | 0.0.0.0:8181 | HTTP listen address. |
VENGTOO_POLL_INTERVAL | poll_interval | 30s | Go time.Duration. Bundle re-pull frequency. |
VENGTOO_CACHE_DIR | cache_dir | ~/.vengtoo/bundles | Where bundle.json is persisted. |
VENGTOO_LOG_LEVEL | log_level | info | Log level. |
VENGTOO_DECISION_LOG | decision_log | false | Set to true to emit a JSON log line per decision. |
VENGTOO_AGENT_NAME | agent_name | hostname | Identifies this agent instance in the dashboard. Defaults to os.Hostname(). Set explicitly when running multiple agents in the same tenant. |
VENGTOO_AUDIT_FORWARDING | audit_forwarding | true | Forwards decisions to cloud for the Decision Log. Set to false to disable. |
VENGTOO_CLIENT_SECRET | client_secret | — (optional) | When set, requires Authorization: Bearer <secret> on /access/v1/evaluation. /healthz and /readyz stay open. |
VENGTOO_AGENT_REGION | agent_region | — | Display label for the region this agent runs in. Shown in the dashboard. |
VENGTOO_AGENT_DOMAIN | agent_domain | — | Display label for the domain or environment (e.g. prod, staging). Shown in the dashboard. |
VENGTOO_HEARTBEAT_INTERVAL | heartbeat_interval | 30s | How often the agent sends a liveness ping to cloud. |
VENGTOO_AUDIT_ENDPOINT | audit_endpoint | derived from cloud_url | Override the endpoint where decision events are forwarded. Defaults to <cloud_url>/v1/agent-logs/ingest. |
VENGTOO_AUDIT_BATCH_SIZE | audit_batch_size | 100 | Number of decision events to buffer before flushing to cloud. |
VENGTOO_AUDIT_BATCH_INTERVAL | audit_batch_interval | 5s | Maximum time to wait before flushing a partial batch. |
VENGTOO_AUDIT_BUFFER_SIZE | audit_buffer_size | 10000 | In-memory buffer capacity for decision events. Events are dropped if the buffer fills. |
VENGTOO_AUDIT_RETRY_ATTEMPTS | audit_retry_attempts | 5 | Number of retry attempts for failed audit log flushes. |
VENGTOO_TRUSTED_KEYS_PATH | trusted_keys_path | ~/.vengtoo/trusted_keys.json | Path 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: "azx_..."
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:
- Go
- Node.js
- Python
client := vengtoo.NewClient("", vengtoo.WithBaseURL("http://localhost:8181"))
const vengtoo = new Vengtoo({ baseUrl: 'http://localhost:8181' })
client = Vengtoo(base_url="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
| Endpoint | Purpose |
|---|---|
GET /healthz | Diagnostic JSON: bundle revision, last sync time, degraded flag, consecutive failures, sync age. Returns 200 while the process is up, even when stale. |
GET /readyz | 200 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.
| Metric | Type | Labels | Meaning |
|---|---|---|---|
vengtoo_agent_up | gauge | — | 1 while the process is alive. |
vengtoo_agent_decisions_total | counter | allowed, access_path | One per /access/v1/evaluation call. |
vengtoo_agent_decision_duration_seconds | histogram | allowed | Eval latency. Buckets tuned for sub-ms. |
vengtoo_agent_bundle_last_sync_timestamp_seconds | gauge | — | Unix ts of last successful sync. |
vengtoo_agent_bundle_sync_failures_total | counter | — | Monotonic count of failed bundle polls. |
vengtoo_agent_bundle_cache_hit | counter | source (cache / sync) | How the agent became ready at startup. |
vengtoo_agent_degraded | gauge | — | 1 when serving stale data because cloud sync is failing. |
vengtoo_agent_consecutive_sync_failures | gauge | — | Current sync failure streak. Resets on success. |
Recommended alerts:
vengtoo_agent_up == 0— process is down.vengtoo_agent_degraded == 1for 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"'
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:
- Load from disk cache — if
bundle.jsonexists inVENGTOO_CACHE_DIR, the agent starts serving decisions immediately./readyzgoes 200 before any network call. - 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_secondsgrowing.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
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
| Symptom | Likely cause | Check |
|---|---|---|
/readyz is 503 after a minute | Initial sync failed and no cache on disk | Is VENGTOO_CACHE_DIR mounted? Can the agent reach VENGTOO_CLOUD_URL? |
[FATAL] Failed to load config: API key is required | VENGTOO_API_KEY unset | Check env vars / mounted config. |
vengtoo_agent_degraded == 1 sustained | Cloud unreachable | Verify 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 request | Bundle parses but evaluation fails on this input shape | Set VENGTOO_DECISION_LOG=true and capture the failing input. |