How the code is laid out
Fifteen packages, and the whole point of the layout is that the two which decide anything depend on nothing.
packages/
core/ domain types, constants, store + advisor ports, zero dependencies
policy-engine/ deterministic evaluation + risk classification, zero dependencies
local-gate/ in-process argument matching, so payloads never leave the machine
memory/ team decisions as machine-checkable constraints
risk/ behavioral, trust, verification, taint and dependency advisors
content-shield/ offline secret + PII scanning, and the security baseline
code-graph/ file-level import graph and blast radius
runtime/ the gateway, HTTP server with RBAC, local stores, reporting
postgres/ Postgres adapters for the storage ports
redis/ Redis adapters for locks and session taint
sdk/ TypeScript client
mcp-firewall/ transparent MCP proxy
intelligence/ optional BYOK layer: drafts and explains, never decides
cli/ the memnox command, editor hooks, and the MCP server
trust-bench/ the public governance benchmark
sdks/
python/, go/ thin dependency-free clients
examples/
policies/ ready-to-use policy filesThe dependency direction is strict
core depends on nothing. policy-engine depends only on core. Everything
else composes those.
Never import from another package's internals, only from its index.ts.
That is what keeps the two zero-dependency packages honest. The moment
policy-engine reaches into runtime, the claim that policy evaluation is pure
stops being checkable by reading one directory.
Where each decision stage lives
ActionGateway.authorize() in packages/runtime/src/action-gateway.ts runs the
same five steps for every request. The gateway owns the pipeline; identity and
approvals are collaborators it composes.
ActionGateway ──▶ AgentRegistry identity, credentials, rotation
└─▶ ApprovalService raise, consent, quorum, break-glass
└─▶ evaluateConsent() pure, in coreStage
Identity
Policy
Advisors
Approval
Audit
Two routes short-circuit that pipeline deliberately:
POST /v1/evaluate-riskruns steps 1, 3 and stops. It reports what the verdict would be without auditing anything or creating an approval, asking is not attempting.POST /v1/contextruns the same steps and renders them as a briefing throughActionGateway.brief→buildActionBriefing(incore) plussecurityRequirementsFor(incontent-shield). Both halves are lookups.
Extending the gateway
New escalation logic is an ActionAdvisor. @memnox/memory and
@memnox/risk are the worked examples.
Three rules an advisor must satisfy, and a reviewer will check all three:
- It may only tighten a decision, never loosen one.
- It must be deterministic, same input, same escalation.
- Its failure must mean "no escalation", never a crash, never a blanket block.
The one exception to rule 3 is the taint advisor, which is fail-closed: an unreadable taint store means the session is treated as tainted. If you think your advisor needs the same exception, that is a conversation before it is a patch.
Ports and adapters
Storage sits behind small interfaces in core: IdentityStore, AuditLog,
ApprovalStore, LockService. The local adapters are plain JSON and JSONL
files; @memnox/postgres and @memnox/redis implement the same ports.
That is why "no account required" is true rather than marketing, the zero-infrastructure path is the same code path, not a demo mode. A new backend means implementing a port, not touching the gateway.
The pieces that make the guarantees checkable
Guarantee
Verdicts are reproducible
A rule change can be tested first
Payloads never leave the machine
A model cannot decide
Model-derived graph edges cannot decide
A briefing is reproducible
Reading order for a newcomer
packages/core
The vocabulary. Types, constants, ports, and
evaluateConsent. Nothing here does IO, so it reads quickly.packages/policy-engine
Matching, precedence and risk classification. Zero dependencies, so it is the easiest place to prove to yourself that evaluation is pure.
packages/runtime/src/action-gateway.ts
The five stages, in one file, in order.
One advisor
@memnox/memoryis the smallest. It shows the whole advisor contract in a few hundred lines.

