Knowledge Graph
Zentinelle maintains a SQLite-backed knowledge graph of its codebase — 1300+ nodes covering models, views, evaluators, URLs, pages, and their relationships.
Open Interactive Graph →
Rebuild locally:
python3 scripts/codemap.py build # index codebase → codemap.sqlite
python3 scripts/codemap.py query X # search nodes
python3 scripts/codemap.py show X # show node + connections
python3 scripts/codemap.py stats # overview
python3 scripts/codemap.py export # export JSON for viz
Node types
| Type |
Count |
What |
model |
95 |
Django models (AgentEndpoint, Policy, Event, InteractionLog, ...) |
view |
44 |
REST API views and GraphQL views |
evaluator |
47 |
Policy evaluators (rate_limit, tool_permission, ...) |
class |
555 |
Python classes |
graphql_type |
118 |
GraphQL ObjectTypes and InputTypes |
enum |
53 |
TextChoices enums (AgentType, PolicyType, ...) |
url |
33 |
REST API URL patterns |
page |
18 |
Next.js frontend pages |
nginx_route |
5 |
Nginx location blocks |
file |
205 |
Python source files |
function |
185 |
Top-level functions |
Edge types
| Type |
Count |
Meaning |
contains |
1094 |
File contains class/function |
inherits |
640 |
Class extends another |
imports |
542 |
File imports from another |
routes_to |
33 |
URL pattern routes to a view |
evaluates |
22 |
PolicyEngine dispatches to evaluator |
Data flows
Hook flow (Claude Code / Gemini CLI)
Agent tool call
│
▼
PreToolUse hook (pre_tool.py)
│ reads: stdin (tool_name, tool_input)
│ calls: POST /api/zentinelle/v1/evaluate
│ sends: {agent_id, action: "tool_call", context: {tool, tool_input}}
│
▼
EvaluateView (api/views/evaluate.py)
│ auth: X-Zentinelle-Key → ZentinelleAPIKeyAuthentication
│ calls: PolicyEngine.evaluate()
│ creates: Event (audit) + InteractionLog (monitoring)
│ returns: {allowed, reason, policies_evaluated}
│
▼
PolicyEngine (services/policy_engine.py)
│ loads: get_effective_policies() with scope inheritance
│ cache: versioned keys in Redis (invalidated on policy CRUD)
│ runs: each evaluator in services/evaluators/
│ returns: EvaluationResult
│
▼
PreToolUse hook
│ exit 0 = allow, exit 2 = block (writes JSON to stdout)
│
▼
Agent executes tool (or shows block reason)
│
▼
PostToolUse hook (post_tool.py)
│ reads: stdin (tool_name, tool_input, tool_response)
│ calls: POST /api/zentinelle/v1/events
│ fire-and-forget (background thread, always exit 0)
Proxy flow (Codex / any agent)
Agent LLM call
│ e.g. POST http://127.0.0.1:8742/responses
│
▼
Local SDK proxy (zentinelle_agent/proxy.py)
│ injects: X-Zentinelle-Key header
│ forwards to: http://zentinelle:8080/proxy/openai/responses
│
▼
nginx (/proxy/ location)
│ proxy_pass to backend:8000
│
▼
ProxyView (proxy/views.py)
│ auth: X-Zentinelle-Key → StandaloneTenantResolver
│ extracts: model, input_tokens from request body
│ calls: PolicyEngine.evaluate(action="llm:invoke")
│ creates: InteractionLog
│ if blocked: returns 403 {error: "policy_denied"}
│
▼
httpx forward to upstream provider
│ strips: X-Zentinelle-Key, reverse-proxy headers
│ sets: Host header to provider hostname
│ streams: SSE responses back to agent
│
▼
Agent receives LLM response
Policy evaluation
PolicyEngine.evaluate(endpoint, action, user_id, context)
│
├── get_effective_policies(endpoint, user_id)
│ scope inheritance: Org → SubOrg → Deployment → Endpoint → User
│ cache: versioned key "policies:v{N}:{tenant}:{endpoint}:{user}"
│ merge: higher priority wins, later scope overrides
│
├── for each policy:
│ evaluator = _get_evaluator(policy.policy_type)
│ result = evaluator.evaluate(policy, action, user_id, context)
│ if enforcement == "enforce" and result.failed → BLOCK
│ if enforcement == "audit" and result.failed → LOG (don't block)
│
└── return EvaluationResult(allowed, reason, policies_evaluated, warnings)
Event processing
Event created (by evaluate, events endpoint, or heartbeat)
│
▼
process_event_batch.apply_async([event_ids], category)
│ routed to Celery queue by category (telemetry/audit/alert)
│
▼
Celery worker processes event
│ updates: Event.status → PROCESSED
│ optionally: writes to ClickHouse for analytics
Entry points
| URL |
View |
Service |
Model |
POST /api/zentinelle/v1/register |
RegisterView |
-- |
AgentEndpoint |
POST /api/zentinelle/v1/evaluate |
EvaluateView |
PolicyEngine |
Event, InteractionLog |
POST /api/zentinelle/v1/events |
EventsView |
-- |
Event |
POST /api/zentinelle/v1/heartbeat |
HeartbeatView |
-- |
AgentEndpoint, Event |
POST /api/zentinelle/v1/interaction |
LogInteractionView |
-- |
InteractionLog |
POST /proxy/<provider>/<path> |
ProxyView |
PolicyEngine |
InteractionLog |
POST /gql/zentinelle/ |
GraphQLView |
-- |
all models |
Key files
| File |
What it does |
backend/zentinelle/services/policy_engine.py |
Core policy evaluation with scope inheritance and caching |
backend/zentinelle/services/evaluators/*.py |
22 individual policy evaluators |
backend/zentinelle/proxy/views.py |
LLM proxy with policy enforcement |
backend/zentinelle/api/views/evaluate.py |
Policy evaluation REST endpoint |
backend/zentinelle/api/auth.py |
API key authentication |
backend/zentinelle/auth/resolver.py |
TenantResolver interface |
backend/zentinelle/models/endpoint.py |
AgentEndpoint model (agent types, keys, health) |
backend/zentinelle/models/policy.py |
Policy model (types, scopes, config) |
backend/zentinelle/models/event.py |
Event model (telemetry, audit, alert) |
backend/zentinelle/models/compliance.py |
InteractionLog, ContentScan, ComplianceAlert |
backend/config/urls.py |
URL routing (api/, gql/, proxy/, admin/) |
docker/nginx.conf |
Reverse proxy routing |
zentinelle-sdk.git/plugins/agent/ |
SDK: hooks, proxy, CLI |
scripts/codemap.py |
Knowledge graph builder + query CLI |
Model relationships
AgentEndpoint
├── has many: Event
├── has many: InteractionLog
├── has many: Policy (via scope_endpoint)
└── belongs to: AgentGroup (optional)
Policy
├── scope_type: organization | sub_organization | deployment | endpoint | user
├── policy_type: rate_limit | tool_permission | model_restriction | ... (22 types)
└── enforcement: enforce | audit | disabled
Event
├── belongs to: AgentEndpoint
├── category: telemetry | audit | alert
└── status: pending | processing | processed | failed
InteractionLog
├── belongs to: AgentEndpoint
├── interaction_type: chat | function_call | code_gen | ...
└── has one: ContentScan (optional, for compliance scanning)