Architecture
A hook process, a deterministic engine, and two ways of reading the catalog. Everything runs on your machine; there is no Zence service.
The path
What happens on a tool call
Claude Code session in ~/clients/northstar-analytics/
│
├─ SessionStart ──────► resolve boundary ──► inject context + session title
├─ UserPromptSubmit ──► classify intent (never decides on prose alone)
├─ PreToolUse ────────► normalize ─ extract ─ resolve ─ evaluate ─ decide
│ matchers: mcp__.*datahub.*__.* | Bash | Write|Edit|NotebookEdit
│ │
│ ├─ LiveProvider ──► DataHub GMS (SDK, cached)
│ └─ decision ─────► local audit
├─ PostToolUse ───────► record outcome against the decision
└─ Stop / SessionEnd ─► finalize ──► DataHub document (idempotent upsert)Choices
Three decisions that shaped everything else
The MCP server is the interception surface; the SDK is the enforcement path
Claude reads the catalog through the DataHub MCP server, so that is where a cross-client lookup first becomes visible — and what the PreToolUse matcher keys on. Zence’s own evidence lookups go through the Python SDK instead, because a hook cannot borrow the agent’s MCP connection, and enforcement needs typed aspects rather than text shaped for a model to read.
Policy is data, not code
A rule is a set of field/predicate pairs ANDed together. There is no expression language and no eval, so a policy file cannot execute anything. Field paths are an allowlist: a typo is rejected at load time rather than silently evaluating to null — which, for a not_in predicate, would quietly invert the rule.
Fixtures are recorded, never written
The same interface serves a live DataHub and a recorded snapshot, and they are never silently interchanged: every piece of evidence carries which produced it, and that value reaches the decision and the audit record. A fixture is created only by capturing real responses.
Repository
Where things live
packages/zence-core/ policy engine, providers, extraction, hooks
packages/zence-cli/ the zence command
bin/zence-hook POSIX shim — bootstraps a venv, fails safe
hooks/hooks.json hook wiring
.claude-plugin/ plugin + marketplace manifests
demo/catalog/ the synthetic two-client catalog
examples/clients/ two workspaces with opposite boundaries
examples/artifacts/ real decisions, rendered on this site