© 2026 EPAGOGE LLC. All rights reserved.
EPAGOGE ANS is a deterministic agent-governance substrate. Its founding invariant is AI off the
reliability path: deterministic, testable controls decide; models only advise, and every
advisory is sealed and logged, never gating. It governs both ends of an autonomous agent's activity
on one hybrid post-quantum (Ed25519 + ML-DSA-65) sealed chain — an inbound network perimeter that
screens what reaches an agent, and an outbound gateway (intent-lineage gate + egress wall +
capability-earning) that governs what an agent does. npm start opens a live trust console over it.
It also carries the original causal network-behavioral layer this repository began as: security derived from physical causality rather than mathematical hardness — detecting credential-theft, lateral-movement, and exfiltration by behavioral-signature mismatch rather than signature matching. Both layers put deterministic controls on the reliability path and seal every decision.
This is a working prototype (originally built for an SBIR Phase I submission). Honest metrics and limits are stated throughout, and in full in SECURITY_ARCHITECTURE.md.
📐 SECURITY_ARCHITECTURE.md — the hard background. Every security control in this codebase, what it defends against, how it actually works, and where it is honestly limited: the intent-lineage gate, the hybrid post-quantum sealed chain, the outbound egress wall (IFC), the inbound perimeter + semantic + trajectory-drift layers, IntentCapability tokens, cross-surface corroboration, the Overwatch deny-floor, and the canary oracle. Read that for the machinery; this README is the face.
A fresh clone runs with one command — Node bootstraps the Python runtime for you (creates a
virtualenv, installs deps, launches the console, opens your browser). No manual pip/venv steps.
git clone https://github.com/EPAGOGE/agentic-network-security.git
cd agentic-network-security
npm startThen open http://localhost:8079 (the launcher opens it for you). That's it — you're in.
Requirements: Python 3.11+ and Node 18+ on your PATH. First run takes a minute or two to install dependencies; later runs launch instantly. Everything else is optional and degrades gracefully — no API keys, no Ollama, and no post-quantum library are needed to start (the console tells you honestly what's active).
| Command | What it does |
|---|---|
npm start |
Launch the console in simulation mode (the default demo — baseline + attack cycles) |
npm run live |
Launch in live mode (empty start; real events arrive via POST /api/ingest) |
npm test |
Run the test suite (installs test deps on first use) |
npm run demo |
Run the end-to-end governed session in the terminal (no browser) |
npm run setup |
Install dependencies only, without launching |
Optional feature extras (power users): pip install -e '.[full]' inside .venv adds the world tab,
Overwatch-AI (Claude), the local Hermes lane, post-quantum signing, and S3 ingestion. The core
console needs none of them.
cwca/ # Python package — the architecture (import name kept as `cwca`)
│
│ # ── Agent-governance substrate (the console) ──
├── gateway/ # Outbound gateway — intent-lineage gate, egress wall (IFC),
│ # capability-earning, overwatch deny-floor, canary oracle
├── intent/ # Intent lineage — anchored vs orphan, earned trust envelope, decay
├── network/ # Inbound perimeter + semantic screen + trajectory-drift monitor
├── connections/ # Cross-surface corroboration (account-takeover freeze)
├── provenance/ # Genealogy + keystore (sealed provenance)
├── attestation.py # Hybrid Ed25519 + ML-DSA-65 tamper-evident sealed chain
│
│ # ── Causal network-behavioral layer ──
├── model/ # Event, AbsenceRecord, BehavioralProfile, Histogram
├── storage/ # StorageBackend + SQLite implementation
├── gossip/ # Gossip protocol, signing, transport, ObservationStore
├── dashboard/ # FastAPI + HTML live trust console
├── rules.py # Causal predecessor dependency rules
├── absence.py # Absence set generation
├── scoring.py # Four-dimension confidence scoring
├── anomaly.py # Anomaly detection
├── node.py # Per-node event processing pipeline
├── election.py # Supernode election (diversity + pulse + stranger)
├── rotation.py # Truncated-exponential tenure timing
├── handoff.py # Encrypted fragmented supernode handoff (X25519/ChaCha20)
├── cluster_state.py # Per-cluster seat lifecycle + election orchestration
├── summary.py # SupernodeSummary production
├── tower.py # Tower-layer compromise detection, adversarial cross-check
├── baseline.py # UserProfileLibrary + baseline traffic generator
├── attack.py # Network + AttackSimulator + three-act demo
├── validation.py # End-to-end validator producing the Section 9 report
└── __main__.py # CLI: `python -m cwca validate`
tests/ # 1,289 tests across every module (more with the optional world extra)
deploy/ # Dockerfile, docker-compose, Terraform for AWS Fargate
scripts/launch.mjs # Zero-dependency Node bootstrap/launcher behind `npm start`
SECURITY_ARCHITECTURE.md # The full control-by-control security machinery + honest limits
VALIDATION_REPORT.txt # Latest honest-metrics output
npm start above is the recommended path. To drive the Python package directly:
python -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
python -m pytest # run the tests
python -m cwca validate --baseline-hours 72 # full end-to-end validation (writes a report)
python -m cwca dashboard --mode simulation --port 8079 # the live consoleThe dashboard binds to 127.0.0.1 (loopback) by default. The mutating API has no auth, so only
pass --host 0.0.0.0 behind a trusted proxy you control — never expose it directly.
See VALIDATION_REPORT.txt for the full output.
Summary (72-hour simulated baseline, ~13,700 steady-state interactions):
| Act | Target | Outcome | Mechanism |
|---|---|---|---|
| 1 | <10s, <0.4 conf | 7s, 0.398 ✓ | confidence threshold (bootstrap zone) |
| 2 | <30s, <0.4 conf | 2s ✓ (anomaly fired) | relationship_novelty — user's session reaches a never-accessed target |
| 3 | <60s, <0.4 conf | 2s ✓ (anomaly fired) | directional_anomaly — per-target payload in the extreme tail for a known counterparty |
False-positive rate: 0 anomalies across 13,794 baseline interactions — meets the Section 9 target (<1 per 10,000).
Overall: All three acts meet their criteria. Each detects via its intended
primitive, not via residual state from a prior act. The directional_anomaly
and relationship_novelty detectors became the Act 2 and Act 3 mechanisms
after the cross-phase audit surfaced that the earlier "0s detection" readings
were bootstrap-zone carryover through a sleep-only cooldown. See the
honest-metrics notes below for what each mechanism does and doesn't cover.
Observations worth flagging for grant reviewers:
-
Act 1's detection signal is the attacker's bootstrap-zone low confidence, not credential-identity linkage. The spec's Act 1 narrative implies the legitimate user's profile alerts when their credential is used from an unusual source. The prototype doesn't carry credentials on events — that's a Phase II architectural addition. The current signal (bootstrap-zone confidence on a fresh attacker source) hits the time budget and the <0.4 confidence threshold, but is architecturally narrower than what the full spec envisions.
-
Act 2 detects via
relationship_novelty, not credential-aware profile linkage. The attack is scripted withsource=legitimate_userto represent the stolen-credential session. The user's mature profile (≥20 interactions across ≥3 distinct counterparties, both gates set incwca/constants.py) is used to judge whether the access target has any prior history. A never-before-seen target raises the anomaly. Full credential-aware detection (profiles keyed by credential, actor-source novelty) remains Phase II; what exists today is the graph-novelty piece. -
Act 3 detects via
directional_anomaly— per-target payload outlier. The per-target distribution histogram (seeBehavioralProfile.outbound_payload_per_target) lets the detector ask "has this source ever sent this much to THIS counterparty?" independently of the global per-event-typepayload_deviationcheck. Exfiltration through a known-good intermediary (defaultdrain_target="svc-docs") fires directional_anomaly; exfiltration to an unknown destination would firerelationship_noveltyinstead — both paths are covered. True inbound-vs-outbound traffic-direction detection (flagging a reversal in which side initiates) requires Node to also process events from the target perspective; that's Phase II. -
Temporal detection requires a matured activity model (≥24 simulated hours of observation). During the learning period, the temporal dimension returns 1.0 for any hour — the architecture refuses to flag "novel hour" as anomalous until it has had a chance to observe the user's full cycle. This eliminates first-day FPs cleanly. For deployments shorter than 24h, temporal-based detection is unavailable by design (the system doesn't yet know what normal looks like for temporal patterns).
deploy/ contains a production-ready Dockerfile and Terraform for single-
service AWS Fargate deployment. See deploy/README.md
for the build/push/apply runbook. Multi-service decomposition
(separate node/supernode/tower Fargate services) requires a TCP
Transport implementation and is a Phase II refactor — the Phase H
Terraform is structured so expansion is additive.
| Phase | Scope | Status |
|---|---|---|
| A | Core data model + SQLite storage | done |
| B | Single-node behavior + scoring | done |
| C | Gossip protocol + ObservationStore | done |
| D | Supernode election, rotation, handoff | done |
| E | Tower layer + adversarial cross-check | done |
| F | Attack simulator + baseline | done (all three acts detect via intended primitives) |
| G | Dashboard (FastAPI + WebSocket) | done |
| H | AWS Fargate deployment artifacts | artifacts authored; never applied — no live deploy run or verified on AWS |
| I | Validation runner + honest report | done |
The following are architecturally accommodated (clean interfaces exist) but not implemented in the prototype:
- Credential-identity linkage (Event carries
credential_id; profile keyed by credential; actor-source novelty detection). - Real TCP
TransportreplacingInProcessTransportfor true multi-service deployment. - Zone-based containment (routing compromised entities into quarantine zones based on tower alerts).
- Interrogator investigators (Layer 3) — dormant probes activated by tower escalations.
- RDS PostgreSQL + ElastiCache Redis for persistent state at production scale (prototype uses in-memory SQLite).
- Recording learned
ExpectedEventRuleinstances automatically from observed traffic regularity.
These items were audit-flagged gaps and are now implemented:
- TTL-based gossip dedup (
cwca/gossip/engine.py:_TTLCacheSet). Replaces the earlier LRU-only cache with a 300-second TTL window per spec Section 4. Time function is injectable so tests can pin a fake clock. Size bound (dedup_cache_size, default 10,000) remains as a memory guard during bursts. - Absence corroboration escalation (
cwca/gossip/store.py).record_observationandrecord_absencenow share a single escalation path, so a missed heartbeat corroborated by 3+ / 6+ independent observers fires the local / cluster callbacks identically to any other anomaly. Synthetic anomaly tag (absence:<event_type>) keeps them from colliding with same-bucket observation corroboration. - Tower orchestrator with pairwise cross-check and quorum flag
(
cwca/tower.py:TowerOrchestrator). Drives the Layer 4 pipeline end-to-end in one cycle: summary production → bus publication → per-tower detection → pairwiseadversarial_cross_check→ cross-cluster spread detection →insufficient_quorumalert when a cluster under-reports. - Edge nodes and cross-cluster spread (
cwca/tower.py:ClusterTopology,EdgeNodeMembership). Adjacency is derived from registered edge nodes;Tower.detect_cross_cluster_spreadflags counterparties with cluster-level escalations in two or more adjacent clusters, surfacing attacks that bridge cluster boundaries via edge-node gossip. - Periodic tower execution via
TowerScheduler(cwca/tower.py).TowerOrchestrator.run_cycleis now driven on anasynciotimer matching theGossipEngine.gossip_looppattern. The dashboard backend spawns it during FastAPI'slifespanand tears it down on shutdown.on_cyclecallbacks let consumers react to each producedOrchestratorCyclewithout reaching into scheduler state. - Full engine wired into the dashboard (
cwca/dashboard/backend.py).SimulationSessionnow stands up a 5-seatClusterState, threeTowerinstances on aTowerBus, aClusterTopology, theTowerOrchestrator, and theTowerScheduleralongside the existing Layer-1 Node. Every processed event replicates into each non-muted supernode'sObservationStore, so tower cycles see real cluster divergence. New endpoints:/api/cluster,/api/tower,/api/mute/{sn},/api/unmute/{sn}. WebSocket stream emitstower_cycleframes on every orchestrator pass. - Auto-cycling attack scenarios (
AutoAttackScheduler). Drives the three-act sequence on a configurable pair of intervals (act_pause_sbetween acts,cycle_pause_sbetween cycles) and resets attacker profile state at cycle boundaries so each new cycle starts from a clean bootstrap./api/auto_attack,/api/auto_attack/start,/api/auto_attack/stop. WebSocket stream emitsauto_attackframes on act transitions. Dashboard AUTO button toggles live. - Hygiene pass:
LOW_CONFIDENCE_HISTORY_GATEnamed incwca/constants.py(removed the magic 0.5 inanomaly.py). Truncated-exponential KS test intests/test_rotation.pyvalidates 1000 draws match the spec's distribution (Section 9 line 882). Deterministic tied-score election test intests/test_election.pypins node_id tie-break behavior. Handoff fragment-loss visibility inHandoffReassembler.pending_handoffs()andpurge_stale(ttl_s), with WARNING logs on timed-out partial state and on fragment-0-missing reassembly — no more silent state accumulation. role_reversaldetector (cwca/anomaly.py,cwca/model/profile.py:inbound_*fields). The Node pipeline now updates both source and target profiles per event, so a target accumulates inbound history. When an entity that has historically been a receiver from peer X (≥ROLE_REVERSAL_MIN_INBOUND, ≤ROLE_REVERSAL_MAX_OUTBOUND) suddenly appears as source sending to X,role_reversalfires. Distinct fromdirectional_anomaly— payload size is irrelevant; the signal is who initiates.