diff --git a/development/examples/private-diy-stack/Makefile b/development/examples/private-diy-stack/Makefile new file mode 100644 index 00000000..534b83ae --- /dev/null +++ b/development/examples/private-diy-stack/Makefile @@ -0,0 +1,10 @@ +.PHONY: run ui record + +run: + @bash ./run.sh + +ui: + @python3 ./dashboard.py + +record: + @bash ./record.sh diff --git a/development/examples/private-diy-stack/README.md b/development/examples/private-diy-stack/README.md new file mode 100644 index 00000000..e77e5a6d --- /dev/null +++ b/development/examples/private-diy-stack/README.md @@ -0,0 +1,31 @@ +# Private DIY Enterprise Stack — Safely On-Premises & in Cloud (`Gemma / DeepSeek` + `Agent Harness` + `Agent Mesh`) + +Run a zero-trust AI workforce **safely across on-premises infrastructure and Google Cloud** (Cloud Run, GKE, or local servers) without site-to-site VPNs, inbound firewall holes, or raw credentials inside agent containers: + +1. **The "Sidecar" Node Architecture Across On-Prem & Cloud:** + - [`node-agent.yaml`](./node-agent.yaml) runs alongside your agent ([`agent_harness.py`](./agent_harness.py), whether on a workstation, Cloud Run, or GKE) and exposes the mesh as a local **Model Context Protocol (MCP)** server (`127.0.0.1:19101/mcp`) and a local **OpenAI-compatible endpoint** (`127.0.0.1:19101/v1`). The agent has zero database credentials or network routing code. + - [`node-inference.yaml`](./node-inference.yaml) sits next to your GPU reasoning server (`Ollama` / `vLLM` serving `deepseek-r1:1.5b` or `gemma3` in cloud or on-prem) and publishes `inference://private-llm` to the mesh. + - [`node-tools.yaml`](./node-tools.yaml) sits inside the on-premises vault zone next to your private SQLite ERP database (`mcp://erp-db`), Payroll vault (`mcp://payroll-vault`), and internal Vendor Compliance REST API (`egress://compliance.internal`), injecting the Vault-brokered API secret (`secrets/compliance-api-key`) at the egress boundary so sensitive credentials never leave the vault node. + +2. **Zero-Trust Identity & Default-Deny Policy ([`policy.json`](./policy.json)):** + - **Default-Deny on Service Names:** Even though `mcp://payroll-vault` runs on the same vault node as `mcp://erp-db`, the control plane policy only grants `mcp://erp-db`—calls to `mcp://payroll-vault` are cryptographically rejected. + - **HTTP Method/Path Guardrails:** `egress://compliance.internal` permits `GET /v1/vendors/*` and blocks `POST` mutations with `HTTP 403`. + - **Residency & Department Labels:** `node-tools.yaml` enforces `check if label("residency", "on-prem");` and `check if label("dept", "finance");`. + - **Task-Scoped Sealed Biscuits (`tar_block`):** Minting a task token via RFC 8693 `/oauth/token` narrows the agent's Biscuit to `lookup_invoice` and `check_inventory`, blocking prompt-injected calls to `execute_wire_transfer`. + +## Quick Start + +```bash +# 1. Run the 4-act CLI verification script (~12s, zero external dependencies) +make -C development/examples/private-diy-stack run + +# 2. Launch the Interactive Browser Workbench on http://127.0.0.1:18899 +make -C development/examples/private-diy-stack ui + +# 3. Or connect inference://private-llm to a live Ollama / vLLM server: +USE_LIVE_OLLAMA=1 OLLAMA_MODEL=deepseek-r1:1.5b \ + make -C development/examples/private-diy-stack ui + +# 4. Re-record the 3-pane terminal MP4 walkthrough (see SCRIPT.md): +make -C development/examples/private-diy-stack record +``` diff --git a/development/examples/private-diy-stack/SCRIPT.md b/development/examples/private-diy-stack/SCRIPT.md new file mode 100644 index 00000000..e7ad6679 --- /dev/null +++ b/development/examples/private-diy-stack/SCRIPT.md @@ -0,0 +1,30 @@ +# Private DIY Enterprise Stack (On-Prem & Cloud) — 3D Live-Execution Video Script + +[`record.sh`](./record.sh) and [`render_3d_video.py`](./render_3d_video.py) produce a 56-second, 1920x1080 (30fps) **3D perspective architectural walkthrough** (`site/static/demo-private-diy-stack.mp4`) driven by a **real live execution** of `agentmesh-one`, four `agentmesh-node` sidecars, `agent_harness.py`, `mcp-client`, and `backends.py`. + +## How It Works + +1. **Step 1 — Boot Real Mesh Binaries (`MeshEnvironment`):** + - Starts `backends.py` (SQLite ERP database `mcp://erp-db`, Payroll Vault `mcp://payroll-vault`, Vendor Compliance REST API `egress://compliance.internal`, and OpenAI-compatible reasoning engine `inference://private-llm`). + - Starts `agentmesh-one` with [`policy.json`](./policy.json) and enrolls four real `agentmesh-node` sidecars: + - [`node-agent.yaml`](./node-agent.yaml) (`127.0.0.1:19101` — Cloud Run / Workstation zone) + - [`node-inference.yaml`](./node-inference.yaml) (`127.0.0.1:19103` — Cloud / On-Prem GPU zone) + - [`node-tools.yaml`](./node-tools.yaml) (`127.0.0.1:19102` — On-Premises Corporate Vault zone) + - [`node-external.yaml`](./node-external.yaml) (`127.0.0.1:19104` — Untrusted External zone, `dept=external`) + +2. **Step 2 — Execute All 4 Acts Against Live Binaries:** + - **Scene 1 (Act 1 — Sidecar Discovery):** Queries `/api/act1/discover` to verify real libp2p Peer IDs (`12D3KooW...`) and Kademlia DHT service discovery. + - **Scenes 2 & 3 (Act 2 — Hybrid ReAct Loop & Vault Secret Brokering):** Executes `agent_harness.py` via `/api/act2/run-agent` to audit `INV-2026-089`, check `SKU-GPU-H200` stock, and verify vendor `ACME-01` with node-side `secrets/compliance-api-key` injection. + - **Scene 4 (Act 3a & 3b — Default-Deny on Service Names & HTTP Methods):** Calls `mcp://payroll-vault/dump_executive_salaries` and `POST /v1/vendors/ACME-01`, capturing the live Biscuit Datalog denial and `HTTP 403` response. + - **Scene 5 (Act 3c — Residency & Department Label Check):** Calls `mcp://erp-db/lookup_invoice` from `node-external` (`dept=external`), capturing the live Datalog label rejection on `node-tools`. + - **Scene 6 (Act 3d — Task-Scoped Sealed `tar_block` Biscuit):** Mints a task-scoped sealed Biscuit via RFC 8693 `POST /oauth/token`, verifies `lookup_invoice` (`ALLOW`), and blocks prompt-injected `execute_wire_transfer` (`DENY`). + - **Scene 7 (Act 4 — Correlated Audit Trail & Mesh-Wide Ban):** Revokes `node-external` via `agentmesh-one admin ban` and summarizes all live `ALLOW` / `DENY` audit events. + +3. **Step 3 — 3D Perspective Rendering (`pycairo` + `numpy` + `ffmpeg`):** + - Renders the 3D zones, extruded server racks, rotating Biscuit holocubes, curved 3D `libp2p` packet beams, 3D hexagonal force-field shields on `DENY`, and the live binary telemetry HUD to `site/static/demo-private-diy-stack.mp4`. + +## Re-Recording + +```bash +make -C development/examples/private-diy-stack record +``` diff --git a/development/examples/private-diy-stack/agent_harness.py b/development/examples/private-diy-stack/agent_harness.py new file mode 100755 index 00000000..23051f8e --- /dev/null +++ b/development/examples/private-diy-stack/agent_harness.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Self-Hosted Agent Harness (ReAct Loop) talking ONLY to its local agentmesh-node sidecar. + +Notice what is NOT in this file: + - No database URLs, SQLite paths, or SQL credentials + - No corporate IP addresses or VPN routes + - No upstream API keys for compliance.internal + - No LLM server addresses + +The harness talks strictly to its local sidecar (http://127.0.0.1:19101): + - /mcp for discovering and calling tools across the mesh + - /v1 for calling the self-hosted DeepSeek/Gemma reasoning model + - /mesh//egress/compliance.internal/... for reaching internal REST APIs with brokered secrets +""" + +import json +import os +import sys +import urllib.request + +SIDECAR_URL = os.environ.get("AGENTMESH_SIDECAR_URL", "http://127.0.0.1:19101").rstrip("/") +API_TOKEN = os.environ.get("AGENTMESH_API_TOKEN", "agent-sidecar-secret") +LLM_MODEL = os.environ.get("LLM_MODEL", "deepseek-r1:1.5b") + + +class LocalSidecarClient: + """Minimal stdlib client for the local agentmesh-node sidecar (/mcp, /v1, /mesh).""" + + def __init__(self, base_url: str, token: str) -> None: + self.base_url = base_url + self.token = token + self.session_id: str | None = None + self._req_id = 0 + self._opener = urllib.request.build_opener(urllib.request.ProxyHandler({})) + + def _next_id(self) -> int: + self._req_id += 1 + return self._req_id + + def mcp_rpc(self, method: str, params: dict | None = None) -> dict: + headers = { + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream", + "X-Mesh-Authentication": f"Bearer {self.token}", + } + if self.session_id: + headers["Mcp-Session-Id"] = self.session_id + + payload: dict = {"jsonrpc": "2.0", "method": method} + if not method.startswith("notifications/"): + payload["id"] = self._next_id() + if params is not None: + payload["params"] = params + + req = urllib.request.Request( + f"{self.base_url}/mcp", + data=json.dumps(payload).encode("utf-8"), + headers=headers, + method="POST", + ) + with self._opener.open(req, timeout=15) as resp: + sid = resp.headers.get("Mcp-Session-Id") + if sid: + self.session_id = sid + raw = resp.read().decode("utf-8").strip() + if not raw: + return {} + # Streamable HTTP may return plain JSON or SSE "data: {...}" lines + for line in reversed(raw.splitlines()): + line = line.strip() + if line.startswith("data:"): + line = line[len("data:") :].strip() + if line.startswith("{"): + return json.loads(line) + return json.loads(raw) + + def init_mcp(self) -> None: + self.mcp_rpc( + "initialize", + { + "protocolVersion": "2024-11-05", + "capabilities": {}, + "clientInfo": {"name": "private-diy-harness", "version": "1.0.0"}, + }, + ) + self.mcp_rpc("notifications/initialized") + + def call_sidecar_tool(self, name: str, arguments: dict) -> str: + res = self.mcp_rpc("tools/call", {"name": name, "arguments": arguments}) + if "error" in res: + raise RuntimeError(json.dumps(res["error"])) + result = res.get("result") or {} + texts = [c.get("text", "") for c in (result.get("content") or []) if c.get("type") == "text"] + text_out = "\n".join(texts).strip() + if result.get("isError"): + raise RuntimeError(text_out) + return text_out + + def chat_completion(self, messages: list[dict]) -> str: + req = urllib.request.Request( + f"{self.base_url}/v1/chat/completions", + data=json.dumps({"model": LLM_MODEL, "messages": messages, "stream": False}).encode("utf-8"), + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {self.token}", + }, + method="POST", + ) + with self._opener.open(req, timeout=30) as resp: + body = json.loads(resp.read().decode("utf-8")) + return body["choices"][0]["message"]["content"] + + def call_egress_get(self, peer_id: str, destination: str, path: str) -> dict: + req = urllib.request.Request( + f"{self.base_url}/mesh/{peer_id}/egress/{destination}{path}", + headers={"X-Mesh-Authentication": f"Bearer {self.token}"}, + method="GET", + ) + with self._opener.open(req, timeout=15) as resp: + return json.loads(resp.read().decode("utf-8")) + + +def main() -> None: + task_prompt = ( + sys.argv[1] + if len(sys.argv) > 1 + else "Audit Invoice INV-2026-089 for Acme Robotics, verify SKU-GPU-H200 warehouse stock, and check vendor ACME-01 compliance." + ) + + sidecar = LocalSidecarClient(SIDECAR_URL, API_TOKEN) + sidecar.init_mcp() + + print(f' [Harness] Task: "{task_prompt}"') + print(f" [Harness] Step 1 -> Asking local MCP server ({SIDECAR_URL}/mcp) for remote tools on the mesh...") + raw_catalog = sidecar.call_sidecar_tool("find_remote_tools", {"service_name": "erp-db"}) + catalog = json.loads(raw_catalog.splitlines()[-1]) + tools_found = [entry["tool_name"] for entry in catalog if "tool_name" in entry] + target_peer = catalog[0]["peer_id"] + print(f" Discovered {len(tools_found)} tools on Vault Peer {target_peer[:16]}…: {', '.join(tools_found)}") + + schema_raw = sidecar.call_sidecar_tool( + "describe_remote_tool", + {"peer_id": target_peer, "tool_name": "mcp://erp-db/lookup_invoice"}, + ) + schema_obj = json.loads(schema_raw.splitlines()[-1]) + req_fields = schema_obj.get("input_schema", {}).get("required", []) + print(f" Inspected schema for mcp://erp-db/lookup_invoice (required={req_fields})") + + print(f" [Harness] Step 2 -> Consulting self-hosted reasoning model ({LLM_MODEL}) via {SIDECAR_URL}/v1/chat/completions...") + plan_response = sidecar.chat_completion( + [ + {"role": "system", "content": f"Available mesh tools: {', '.join(tools_found)}"}, + {"role": "user", "content": task_prompt}, + ] + ) + for line in plan_response.splitlines(): + if line.strip(): + print(f" {line}") + + print(" [Harness] Step 3 -> Executing tool calls & internal API checks through local sidecar...") + inv_result = sidecar.call_sidecar_tool( + "call_remote_tool", + { + "peer_id": target_peer, + "tool_name": "mcp://erp-db/lookup_invoice", + "arguments": {"invoice_id": "INV-2026-089"}, + }, + ) + print(f" [mcp://erp-db/lookup_invoice] -> {inv_result}") + + stock_result = sidecar.call_sidecar_tool( + "call_remote_tool", + { + "peer_id": target_peer, + "tool_name": "mcp://erp-db/check_inventory", + "arguments": {"sku": "SKU-GPU-H200"}, + }, + ) + print(f" [mcp://erp-db/check_inventory] -> {stock_result}") + + comp_result = sidecar.call_egress_get(target_peer, "compliance.internal", "/v1/vendors/ACME-01") + print( + f" [egress://compliance.internal] -> vendor={comp_result['name']}, " + f"sanctions={comp_result['sanctions_check']}, iso27001={comp_result['iso27001_certified']} " + f"(brokered secret verified={comp_result['brokered_auth_verified']})" + ) + + print(f" [Harness] Step 4 -> Sending tool observations back to {LLM_MODEL} for final synthesis...") + final_answer = sidecar.chat_completion( + [ + {"role": "user", "content": task_prompt}, + {"role": "assistant", "content": plan_response}, + { + "role": "user", + "content": ( + f"TOOL_OBSERVATIONS:\n" + f"- invoice: {inv_result}\n" + f"- inventory: {stock_result}\n" + f"- compliance: {json.dumps(comp_result)}" + ), + }, + ] + ) + for line in final_answer.splitlines(): + if line.strip(): + print(f" {line}") + + +if __name__ == "__main__": + main() diff --git a/development/examples/private-diy-stack/audit.py b/development/examples/private-diy-stack/audit.py new file mode 100755 index 00000000..fe497f13 --- /dev/null +++ b/development/examples/private-diy-stack/audit.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Reads agentmesh-node logs on stdin and prints one line per authorization or task decision.""" + +import json +import re +import sys + +AUDIT = re.compile(r"Audit Traceability\s+(\{.*\})\s*$") +TAR_DENY = re.compile(r'task authorization denied tool "([^"]+)".*tar_block\[1\] \("([^"]+)"\)') + +for raw_line in sys.stdin: + line = raw_line.rstrip("\n") + m = AUDIT.search(line) + if m: + try: + d = json.loads(m.group(1)) + except json.JSONDecodeError: + continue + who = f"{d.get('role') or '-'} {d.get('peer_id', '')[:12]}…" + what = " ".join(x for x in (d.get("method"), d.get("path")) if x) or d.get("protocol", "") + print(f"{d.get('decision', '?').upper():<5} {who:<22} {what:<34} {d.get('target', '')}", flush=True) + continue + tm = TAR_DENY.search(line) + if tm: + print(f"DENY tar_block ({tm.group(2)}) tools/call {tm.group(1):<23} mcp://erp-db", flush=True) + continue + if "peer banned" in line: + peer = re.search(r'"peer":\s*"([^"]+)"', line) + print(f"BANNED {peer.group(1) if peer else ''}: control plane revoked peer", flush=True) diff --git a/development/examples/private-diy-stack/backends.py b/development/examples/private-diy-stack/backends.py new file mode 100755 index 00000000..5b4f99b8 --- /dev/null +++ b/development/examples/private-diy-stack/backends.py @@ -0,0 +1,464 @@ +#!/usr/bin/env python3 +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Private On-Premises & Cloud Enterprise Backends (stdlib only, zero pip dependencies). + +Starts three loopback services that sit behind their respective agentmesh-node +sidecars: + 1. 127.0.0.1:18890 — Private SQLite ERP (/mcp) & Payroll (/payroll-mcp) MCP servers. + 2. 127.0.0.1:18891 — Private Vendor Compliance REST API (verifies brokered secret). + 3. 127.0.0.1:18892 — Private OpenAI-compatible reasoning endpoint (proxies to a + live Ollama/vLLM server at OLLAMA_UPSTREAM if running, or + serves deterministic DeepSeek-R1 reasoning locally). +""" + +import json +import os +import sqlite3 +import threading +import urllib.error +import urllib.request +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + +DB_PATH = os.environ.get("ERP_DB_PATH", "/tmp/agentmesh-private-erp.db") +MCP_PORT = int(os.environ.get("ERP_MCP_PORT", "18890")) +COMPLIANCE_PORT = int(os.environ.get("COMPLIANCE_API_PORT", "18891")) +LLM_PORT = int(os.environ.get("PRIVATE_LLM_PORT", "18892")) +LLM_MODEL = os.environ.get("LLM_MODEL", "deepseek-r1:1.5b") +OLLAMA_UPSTREAM = os.environ.get("OLLAMA_UPSTREAM", "http://127.0.0.1:11434") +EXPECTED_COMPLIANCE_SECRET = os.environ.get("COMPLIANCE_API_SECRET", "private-vault-secret-2026") + + +def init_db() -> None: + with sqlite3.connect(DB_PATH) as conn: + conn.execute( + """ + CREATE TABLE IF NOT EXISTS invoices ( + invoice_id TEXT PRIMARY KEY, + vendor_id TEXT NOT NULL, + vendor_name TEXT NOT NULL, + sku TEXT NOT NULL, + quantity INTEGER NOT NULL, + amount_usd REAL NOT NULL, + status TEXT NOT NULL + ) + """ + ) + conn.execute( + """ + CREATE TABLE IF NOT EXISTS inventory ( + sku TEXT PRIMARY KEY, + description TEXT NOT NULL, + on_hand INTEGER NOT NULL, + warehouse TEXT NOT NULL + ) + """ + ) + conn.execute( + """ + CREATE TABLE IF NOT EXISTS wire_transfers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + invoice_id TEXT NOT NULL, + amount_usd REAL NOT NULL, + iban TEXT NOT NULL + ) + """ + ) + conn.execute( + """ + INSERT OR REPLACE INTO invoices + (invoice_id, vendor_id, vendor_name, sku, quantity, amount_usd, status) + VALUES + ('INV-2026-089', 'ACME-01', 'Acme Robotics GmbH', 'SKU-GPU-H200', 4, 48500.00, 'PENDING_APPROVAL'), + ('INV-2026-090', 'GLOBEX-02', 'Globex Logistics', 'SKU-RACK-42U', 2, 6400.00, 'PAID') + """ + ) + conn.execute( + """ + INSERT OR REPLACE INTO inventory + (sku, description, on_hand, warehouse) + VALUES + ('SKU-GPU-H200', 'NVIDIA H200 Bare-Metal Server Blade', 14, 'Munich-Vault-B'), + ('SKU-RACK-42U', '42U Private Server Rack', 5, 'Frankfurt-DC-1') + """ + ) + conn.commit() + + +ERP_TOOLS = [ + { + "name": "lookup_invoice", + "description": "Look up a corporate invoice by invoice_id in the SQLite ERP database (read-only).", + "inputSchema": { + "type": "object", + "properties": {"invoice_id": {"type": "string", "description": "Invoice ID, e.g. INV-2026-089"}}, + "required": ["invoice_id"], + }, + }, + { + "name": "check_inventory", + "description": "Check warehouse stock levels for a hardware SKU in SQLite (read-only).", + "inputSchema": { + "type": "object", + "properties": {"sku": {"type": "string", "description": "Hardware SKU, e.g. SKU-GPU-H200"}}, + "required": ["sku"], + }, + }, + { + "name": "execute_wire_transfer", + "description": "Execute an outbound bank wire transfer and mark an invoice PAID (mutating financial tool).", + "inputSchema": { + "type": "object", + "properties": { + "invoice_id": {"type": "string"}, + "amount_usd": {"type": "number"}, + "iban": {"type": "string"}, + }, + "required": ["invoice_id", "amount_usd", "iban"], + }, + }, +] + +PAYROLL_TOOLS = [ + { + "name": "dump_executive_salaries", + "description": "Export executive compensation records from the restricted HR payroll vault.", + "inputSchema": {"type": "object", "properties": {}}, + } +] + + +def call_erp_tool(name: str, args: dict) -> str: + if name == "lookup_invoice": + inv_id = str(args.get("invoice_id", "")) + with sqlite3.connect(DB_PATH) as conn: + row = conn.execute( + "SELECT invoice_id, vendor_id, vendor_name, sku, quantity, amount_usd, status " + "FROM invoices WHERE invoice_id = ?", + (inv_id,), + ).fetchone() + if not row: + return f"Invoice {inv_id} not found" + iid, vid, vname, sku, qty, amt, status = row + return ( + f"Invoice {iid}: vendor={vname} ({vid}), sku={sku}, qty={qty}, " + f"amount=${amt:,.2f}, status={status}" + ) + + if name == "check_inventory": + sku = str(args.get("sku", "")) + with sqlite3.connect(DB_PATH) as conn: + row = conn.execute( + "SELECT sku, description, on_hand, warehouse FROM inventory WHERE sku = ?", + (sku,), + ).fetchone() + if not row: + return f"SKU {sku} not found in inventory" + s_code, desc, on_hand, wh = row + return f"SKU {s_code} ({desc}): on_hand={on_hand} units, warehouse={wh}" + + if name == "execute_wire_transfer": + inv_id = str(args.get("invoice_id", "")) + amount = float(args.get("amount_usd", 0.0)) + iban = str(args.get("iban", "")) + with sqlite3.connect(DB_PATH) as conn: + conn.execute( + "INSERT INTO wire_transfers (invoice_id, amount_usd, iban) VALUES (?, ?, ?)", + (inv_id, amount, iban), + ) + conn.execute("UPDATE invoices SET status = 'PAID' WHERE invoice_id = ?", (inv_id,)) + conn.commit() + return f"WIRE_EXECUTED: invoice={inv_id}, amount=${amount:,.2f}, destination_iban={iban}" + + return f"Unknown ERP tool: {name}" + + +class MCPHandler(BaseHTTPRequestHandler): + def _json(self, status: int, body: dict) -> None: + data = json.dumps(body).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(data))) + self.end_headers() + self.wfile.write(data) + + def do_GET(self) -> None: + if self.path == "/healthz": + self._json(200, {"status": "ok"}) + return + self._json(404, {"error": "not found"}) + + def do_POST(self) -> None: + is_payroll = self.path.startswith("/payroll-mcp") + if not (self.path.startswith("/mcp") or is_payroll): + self._json(404, {"error": "unknown MCP endpoint"}) + return + length = int(self.headers.get("Content-Length") or 0) + raw = self.rfile.read(length) if length > 0 else b"{}" + try: + req = json.loads(raw) + except ValueError: + self._json(400, {"error": "invalid json"}) + return + + method = req.get("method", "") + req_id = req.get("id", 1) + + if method == "initialize": + self._json( + 200, + { + "jsonrpc": "2.0", + "id": req_id, + "result": { + "protocolVersion": "2024-11-05", + "capabilities": {"tools": {}}, + "serverInfo": { + "name": "payroll-vault" if is_payroll else "erp-db", + "version": "1.0.0", + }, + }, + }, + ) + return + + if method.startswith("notifications/"): + self.send_response(202) + self.send_header("Content-Length", "0") + self.end_headers() + return + + if method == "tools/list": + self._json( + 200, + { + "jsonrpc": "2.0", + "id": req_id, + "result": {"tools": PAYROLL_TOOLS if is_payroll else ERP_TOOLS}, + }, + ) + return + + if method == "tools/call": + params = req.get("params") or {} + tname = params.get("name", "") + targs = params.get("arguments") or {} + if is_payroll: + text = "CONFIDENTIAL_PAYROLL_DUMP: CEO=$1,200,000" + else: + text = call_erp_tool(tname, targs) + self._json( + 200, + { + "jsonrpc": "2.0", + "id": req_id, + "result": {"content": [{"type": "text", "text": text}]}, + }, + ) + return + + self._json( + 200, + { + "jsonrpc": "2.0", + "id": req_id, + "error": {"code": -32601, "message": f"Method not found: {method}"}, + }, + ) + + def log_message(self, *args) -> None: + pass + + +class ComplianceHandler(BaseHTTPRequestHandler): + def _json(self, status: int, body: dict) -> None: + data = json.dumps(body).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(data))) + self.end_headers() + self.wfile.write(data) + + def do_GET(self) -> None: + if self.path == "/healthz": + self._json(200, {"status": "ok"}) + return + auth = self.headers.get("Authorization", "") + if auth != f"Bearer {EXPECTED_COMPLIANCE_SECRET}": + self._json(401, {"error": "missing or invalid vault-brokered Authorization header"}) + return + if self.path == "/v1/vendors/ACME-01": + self._json( + 200, + { + "vendor_id": "ACME-01", + "name": "Acme Robotics GmbH", + "sanctions_check": "PASSED", + "iso27001_certified": True, + "tax_jurisdiction": "DE-BY", + "brokered_auth_verified": True, + }, + ) + return + self._json(404, {"error": f"vendor path {self.path} not found"}) + + def do_POST(self) -> None: + self._json(405, {"error": "mutations prohibited without compliance officer quorum"}) + + def log_message(self, *args) -> None: + pass + + +class PrivateLLMHandler(BaseHTTPRequestHandler): + """Proxies to live Ollama/vLLM if running, or serves deterministic DeepSeek-R1 locally.""" + + def _json(self, status: int, body: dict) -> None: + data = json.dumps(body).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(data))) + self.end_headers() + self.wfile.write(data) + + def _try_upstream(self, method: str, path: str, body: bytes | None = None) -> bytes | None: + if os.environ.get("USE_LIVE_OLLAMA", "0") != "1": + return None + req = urllib.request.Request( + f"{OLLAMA_UPSTREAM.rstrip('/')}{path}", + data=body, + method=method, + headers={"Content-Type": "application/json"} if body else {}, + ) + try: + with urllib.request.urlopen(req, timeout=8) as resp: + return resp.read() + except Exception: + return None + + def do_GET(self) -> None: + if self.path == "/healthz": + self._json(200, {"status": "ok"}) + return + if self.path == "/v1/models": + upstream = self._try_upstream("GET", "/v1/models") + if upstream: + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(upstream))) + self.end_headers() + self.wfile.write(upstream) + return + self._json( + 200, + { + "object": "list", + "data": [ + { + "id": LLM_MODEL, + "object": "model", + "owned_by": "private-on-prem-gpu-pool", + } + ], + }, + ) + return + self._json(404, {"error": {"message": "not found"}}) + + def do_POST(self) -> None: + length = int(self.headers.get("Content-Length") or 0) + raw = self.rfile.read(length) if length > 0 else b"{}" + if self.path != "/v1/chat/completions": + self._json(404, {"error": {"message": "not found"}}) + return + + upstream = self._try_upstream("POST", "/v1/chat/completions", raw) + if upstream: + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(upstream))) + self.end_headers() + self.wfile.write(upstream) + return + + req = json.loads(raw) + messages = req.get("messages") or [] + last_content = messages[-1].get("content", "") if messages else "" + + if "TOOL_OBSERVATIONS:" in last_content: + reply = ( + "\n" + "1. Invoice INV-2026-089 is for Acme Robotics GmbH (ACME-01): 4x SKU-GPU-H200 at $48,500.00 (PENDING_APPROVAL).\n" + "2. Warehouse inventory shows 14 units of SKU-GPU-H200 on hand in Munich-Vault-B.\n" + "3. Internal compliance API confirmed ACME-01 passed sanctions & ISO-27001 checks via brokered vault secret.\n" + "\n" + "AUDIT DECISION: APPROVED_FOR_RECEIVING — Invoice INV-2026-089 ($48,500.00, 4x SKU-GPU-H200) " + "matches Munich-Vault-B inventory (14 on hand) and vendor ACME-01 is compliance-verified." + ) + else: + reply = ( + "\n" + "The user wants to audit Invoice INV-2026-089, verify warehouse stock for SKU-GPU-H200, " + "and check vendor ACME-01 compliance. Looking at the local Agent Mesh MCP catalog, " + "I should invoke mcp://erp-db/lookup_invoice and mcp://erp-db/check_inventory, " + "then query egress://compliance.internal/v1/vendors/ACME-01.\n" + "\n" + '{"plan": [' + '{"service": "mcp://erp-db/lookup_invoice", "arguments": {"invoice_id": "INV-2026-089"}}, ' + '{"service": "mcp://erp-db/check_inventory", "arguments": {"sku": "SKU-GPU-H200"}}, ' + '{"service": "egress://compliance.internal", "path": "/v1/vendors/ACME-01"}' + "]}" + ) + + self._json( + 200, + { + "id": "chatcmpl-private-001", + "object": "chat.completion", + "model": req.get("model", LLM_MODEL), + "choices": [ + { + "index": 0, + "finish_reason": "stop", + "message": {"role": "assistant", "content": reply}, + } + ], + "usage": {"prompt_tokens": 94, "completion_tokens": 82, "total_tokens": 176}, + }, + ) + + def log_message(self, *args) -> None: + pass + + +def main() -> None: + init_db() + mcp_srv = ThreadingHTTPServer(("127.0.0.1", MCP_PORT), MCPHandler) + comp_srv = ThreadingHTTPServer(("127.0.0.1", COMPLIANCE_PORT), ComplianceHandler) + llm_srv = ThreadingHTTPServer(("127.0.0.1", LLM_PORT), PrivateLLMHandler) + + for srv in (mcp_srv, comp_srv, llm_srv): + t = threading.Thread(target=srv.serve_forever, daemon=True) + t.start() + + print( + f"Private backends listening: MCP=127.0.0.1:{MCP_PORT}, " + f"Compliance=127.0.0.1:{COMPLIANCE_PORT}, LLM=127.0.0.1:{LLM_PORT}", + flush=True, + ) + threading.Event().wait() + + +if __name__ == "__main__": + main() diff --git a/development/examples/private-diy-stack/dashboard.py b/development/examples/private-diy-stack/dashboard.py new file mode 100755 index 00000000..39c3a167 --- /dev/null +++ b/development/examples/private-diy-stack/dashboard.py @@ -0,0 +1,653 @@ +#!/usr/bin/env python3 +"""Interactive Web Workbench for the Private DIY Enterprise Stack. + +Starts the real Agent Mesh control plane (agentmesh-one), four agentmesh-node +sidecars (node-tools, node-inference, node-agent, node-external), and the +SQLite ERP / Compliance / DeepSeek backends across on-prem and cloud zones, +then serves a live browser dashboard on http://127.0.0.1:18899. +""" + +import http.server +import json +import os +import re +import shutil +import signal +import sqlite3 +import subprocess +import sys +import tempfile +import time +import urllib.error +import urllib.parse +import urllib.request + +for _proxy_var in ("HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy", "ALL_PROXY", "all_proxy"): + os.environ.pop(_proxy_var, None) +os.environ["NO_PROXY"] = "*" +os.environ["no_proxy"] = "*" + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +from agent_harness import LocalSidecarClient # noqa: E402 + +REPO_ROOT = os.path.abspath(os.path.join(HERE, "..", "..", "..")) +STATIC_DIR = os.path.join(HERE, "static") +DASHBOARD_PORT = int(os.environ.get("DASHBOARD_PORT", "18899")) +CP_PORT = int(os.environ.get("CP_PORT", "18095")) +CP_URL = f"http://127.0.0.1:{CP_PORT}" +AGENT_URL = "http://127.0.0.1:19101" +AGENT_TOKEN = "agent-sidecar-secret" +EXTERNAL_TOKEN = "external-sidecar-secret" + +_OPENER = urllib.request.build_opener(urllib.request.ProxyHandler({})) + + +def _find_binaries(): + candidates = [ + os.environ.get("BIN_DIR", ""), + os.path.join(REPO_ROOT, "bin"), + "/tmp/sam-bin", + ] + for d in candidates: + if d and os.path.isfile(os.path.join(d, "agentmesh-one")) and os.path.isfile(os.path.join(d, "agentmesh-node")): + return d + raise RuntimeError("agentmesh-one and agentmesh-node binaries not found; run `make build` first.") + + +class MeshEnvironment: + def __init__(self): + self.bin_dir = _find_binaries() + self.agentmesh_one = os.path.join(self.bin_dir, "agentmesh-one") + self.agentmesh_node = os.path.join(self.bin_dir, "agentmesh-node") + self.mcp_client = os.path.join(self.bin_dir, "mcp-client") + self.work_dir = tempfile.mkdtemp(prefix="sam-private-diy-ui.") + self.db_path = os.path.join(self.work_dir, "erp.db") + self.procs = [] + self.tools_peer = "" + self.gpu_peer = "" + self.agent_peer = "" + self.external_peer = "" + self.external_banned = False + + def start(self): + os.makedirs(os.path.join(self.work_dir, "secrets"), exist_ok=True) + for name in ("cp", "node-tools", "node-inference", "node-agent", "node-external"): + os.makedirs(os.path.join(self.work_dir, name), exist_ok=True) + + self._write_secret("compliance-api-key", "vault-brokered-compliance-key-99481") + self._write_file("tools-api.token", "vault-sidecar-secret") + self._write_file("gpu-api.token", "gpu-sidecar-secret") + self._write_file("agent-api.token", AGENT_TOKEN) + self._write_file("external-api.token", EXTERNAL_TOKEN) + + env = os.environ.copy() + env["ERP_DB_PATH"] = self.db_path + env["COMPLIANCE_API_SECRET"] = "vault-brokered-compliance-key-99481" + + backends_log = open(os.path.join(self.work_dir, "backends.log"), "w") + self.procs.append( + subprocess.Popen([sys.executable, os.path.join(HERE, "backends.py")], env=env, stdout=backends_log, stderr=subprocess.STDOUT) + ) + self._wait_http("http://127.0.0.1:18890/healthz") + self._wait_http("http://127.0.0.1:18891/healthz") + self._wait_http("http://127.0.0.1:18892/healthz") + + cp_log_path = os.path.join(self.work_dir, "cp.log") + cp_log = open(cp_log_path, "w") + self.procs.append( + subprocess.Popen( + [ + self.agentmesh_one, + "--port", + str(CP_PORT), + "--data-dir", + os.path.join(self.work_dir, "cp"), + "--policy-file", + os.path.join(HERE, "policy.json"), + "--no-join-token", + "--enroll-qr=false", + "--log-level", + "info", + ], + env=env, + stdout=cp_log, + stderr=subprocess.STDOUT, + ) + ) + for _ in range(80): + if os.path.exists(os.path.join(self.work_dir, "cp", "admin-token")) and os.path.exists(cp_log_path): + if "Agent Mesh standalone mesh is ready" in open(cp_log_path, errors="replace").read(): + break + time.sleep(0.25) + else: + raise RuntimeError("Timed out waiting for agentmesh-one to become ready") + + for tok_name in ("tools", "gpu", "agent", "external"): + raw_tok = subprocess.check_output( + [ + self.agentmesh_one, + "token", + "create", + "--server", + CP_URL, + "--data-dir", + os.path.join(self.work_dir, "cp"), + "--max-usages", + "1", + "--description", + f"{tok_name}-sidecar", + ], + env=env, + stderr=subprocess.DEVNULL, + text=True, + ) + m = re.search(r"^Token:\s+(\S+)", raw_tok, re.MULTILINE) + tok = m.group(1) if m else raw_tok.strip() + self._write_file(f"{tok_name}.token", tok) + + self._start_node( + "node-tools", + "tools.token", + "node-tools.yaml", + "127.0.0.1:19102", + "tools-api.token", + extra_args=["--secrets-dir", os.path.join(self.work_dir, "secrets")], + ) + self._start_node("node-inference", "gpu.token", "node-inference.yaml", "127.0.0.1:19103", "gpu-api.token") + self._start_node("node-agent", "agent.token", "node-agent.yaml", "127.0.0.1:19101", "agent-api.token") + self._start_node("node-external", "external.token", "node-external.yaml", "127.0.0.1:19104", "external-api.token") + + self.tools_peer = self._wait_peer("node-tools.log") + self.gpu_peer = self._wait_peer("node-inference.log") + self.agent_peer = self._wait_peer("node-agent.log") + self.external_peer = self._wait_peer("node-external.log") + + for _ in range(50): + try: + req1 = urllib.request.Request( + f"{AGENT_URL}/mesh/service/discover?type=mcp&name=erp-db", + headers={"X-Mesh-Authentication": f"Bearer {AGENT_TOKEN}"}, + ) + req2 = urllib.request.Request( + f"{AGENT_URL}/mesh/service/discover?type=inference&name=private-llm", + headers={"X-Mesh-Authentication": f"Bearer {AGENT_TOKEN}"}, + ) + d1 = json.loads(_OPENER.open(req1, timeout=2).read().decode("utf-8")) + d2 = json.loads(_OPENER.open(req2, timeout=2).read().decode("utf-8")) + if d1 and d2: + break + except Exception: + pass + time.sleep(0.3) + + def _write_secret(self, name, val): + path = os.path.join(self.work_dir, "secrets", name) + with open(path, "w") as f: + f.write(val) + os.chmod(path, 0o600) + + def _write_file(self, name, val): + path = os.path.join(self.work_dir, name) + with open(path, "w") as f: + f.write(val) + os.chmod(path, 0o600) + + def _start_node(self, name, token_file, yaml_file, bind_addr, api_token_file, extra_args=None): + log_f = open(os.path.join(self.work_dir, f"{name}.log"), "w") + cmd = [ + self.agentmesh_node, + "run", + "--control-plane", + CP_URL, + "--insecure-control-plane", + "--bootstrap-token-path", + os.path.join(self.work_dir, token_file), + "--config", + os.path.join(HERE, yaml_file), + "--data-dir", + os.path.join(self.work_dir, name), + "--bind-addr", + bind_addr, + "--socket-path=", + "--listen", + "/ip4/127.0.0.1/udp/0/quic-v1,/ip4/127.0.0.1/tcp/0", + "--api-token-path", + os.path.join(self.work_dir, api_token_file), + "--allow-loopback", + "--control-plane-sync-interval", + "5s", + ] + if extra_args: + cmd.extend(extra_args) + self.procs.append(subprocess.Popen(cmd, stdout=log_f, stderr=subprocess.STDOUT)) + + def _wait_http(self, url, timeout=20.0): + deadline = time.time() + timeout + while time.time() < deadline: + try: + with _OPENER.open(url, timeout=1.5) as resp: + if resp.status < 500: + return + except Exception: + pass + time.sleep(0.2) + raise RuntimeError(f"Timed out waiting for {url}") + + def _wait_peer(self, log_name, timeout=25.0): + log_path = os.path.join(self.work_dir, log_name) + deadline = time.time() + timeout + while time.time() < deadline: + if os.path.exists(log_path): + text = open(log_path, errors="replace").read() + if "Agent Mesh Node Online" in text: + m = re.search(r"PeerID:\s+(\S+)", text) + if m: + return m.group(1) + time.sleep(0.2) + raise RuntimeError(f"Timed out waiting for PeerID in {log_name}") + + def parse_audit_events(self): + audit_re = re.compile(r"Audit Traceability\s+(\{.*\})\s*$") + tar_re = re.compile(r'task authorization denied tool "([^"]+)".*tar_block\[1\] \("([^"]+)"\)') + events = [] + for log_name in ("node-inference.log", "node-tools.log", "node-agent.log"): + p = os.path.join(self.work_dir, log_name) + if not os.path.exists(p): + continue + for raw_line in open(p, errors="replace"): + line = raw_line.rstrip("\n") + m = audit_re.search(line) + if m: + try: + d = json.loads(m.group(1)) + except json.JSONDecodeError: + continue + who = f"{d.get('role') or '-'} ({d.get('peer_id', '')[:12]}…)" + what = " ".join(x for x in (d.get("method"), d.get("path")) if x) or d.get("protocol", "-") + events.append( + { + "decision": d.get("decision", "?").upper(), + "caller": who, + "method": what, + "service": d.get("target", "-"), + } + ) + continue + tm = tar_re.search(line) + if tm: + events.append( + { + "decision": "DENY", + "caller": f"tar_block ({tm.group(2)})", + "method": f"tools/call {tm.group(1)}", + "service": "mcp://erp-db", + } + ) + return events + + def sqlite_counts(self): + if not os.path.exists(self.db_path): + return {"invoices_count": 0, "wire_transfers_count": 0} + conn = sqlite3.connect(self.db_path) + inv = conn.execute("SELECT COUNT(*) FROM invoices").fetchone()[0] + wires = conn.execute("SELECT COUNT(*) FROM wire_transfers").fetchone()[0] + conn.close() + return {"invoices_count": inv, "wire_transfers_count": wires} + + def stop(self): + for p in self.procs: + try: + p.terminate() + except Exception: + pass + for p in self.procs: + try: + p.wait(timeout=3) + except Exception: + pass + shutil.rmtree(self.work_dir, ignore_errors=True) + + +MESH: MeshEnvironment = None # type: ignore + + +class WorkbenchHandler(http.server.BaseHTTPRequestHandler): + def log_message(self, fmt, *args): + pass + + def _send_json(self, obj, status=200): + body = json.dumps(obj).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json; charset=utf-8") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def _send_file(self, path, content_type): + if not os.path.isfile(path): + self.send_error(404) + return + data = open(path, "rb").read() + self.send_response(200) + self.send_header("Content-Type", content_type) + self.send_header("Content-Length", str(len(data))) + self.end_headers() + self.wfile.write(data) + + def do_GET(self): + if self.path in ("/", "/index.html"): + return self._send_file(os.path.join(STATIC_DIR, "index.html"), "text/html; charset=utf-8") + if self.path in ("/styles.css", "/static/styles.css"): + return self._send_file(os.path.join(STATIC_DIR, "styles.css"), "text/css; charset=utf-8") + if self.path in ("/app.js", "/static/app.js"): + return self._send_file(os.path.join(STATIC_DIR, "app.js"), "application/javascript; charset=utf-8") + if self.path == "/api/state": + return self._send_json( + { + "nodes": [ + { + "title": "1. Workstation (node-agent)", + "peer_id": MESH.agent_peer, + "short_peer": MESH.agent_peer[:16] + "…", + "labels": ["residency=on-prem", "zone=workstation", "dept=finance"], + "banned": False, + }, + { + "title": "2. GPU Node (node-inference)", + "peer_id": MESH.gpu_peer, + "short_peer": MESH.gpu_peer[:16] + "…", + "labels": ["residency=on-prem", "zone=gpu-pool", "inference://private-llm"], + "banned": False, + }, + { + "title": "3. Vault Node (node-tools)", + "peer_id": MESH.tools_peer, + "short_peer": MESH.tools_peer[:16] + "…", + "labels": ["residency=on-prem", "zone=vault", "dept=finance"], + "banned": False, + }, + { + "title": "4. External Node (node-external)", + "peer_id": MESH.external_peer, + "short_peer": MESH.external_peer[:16] + "…", + "labels": ["residency=on-prem", "dept=external"], + "banned": MESH.external_banned, + }, + ], + "sqlite": MESH.sqlite_counts(), + "external_banned": MESH.external_banned, + "audit": MESH.parse_audit_events(), + } + ) + self.send_error(404) + + def do_POST(self): + length = int(self.headers.get("Content-Length", "0")) + raw_body = self.rfile.read(length).decode("utf-8") if length > 0 else "{}" + try: + body = json.loads(raw_body) if raw_body else {} + except json.JSONDecodeError: + body = {} + + if self.path == "/api/act1/discover": + sidecar = LocalSidecarClient(AGENT_URL, AGENT_TOKEN) + sidecar.init_mcp() + cat_raw = sidecar.call_sidecar_tool("find_remote_tools", {"service_name": "erp-db"}) + req = urllib.request.Request( + f"{AGENT_URL}/v1/models", + headers={"Authorization": f"Bearer {AGENT_TOKEN}"}, + ) + with _OPENER.open(req, timeout=10) as resp: + models_data = json.loads(resp.read().decode("utf-8")) + summary = ( + f"• Vault Tool PeerID : {MESH.tools_peer} (mcp://erp-db, egress://compliance.internal)\n" + f"• Bare-Metal GPU PeerID : {MESH.gpu_peer} (inference://private-llm)\n" + f"• Discovered Models (/v1): {[m.get('id') for m in models_data.get('data', [])]}\n\n" + f"• Discovered MCP Tools (127.0.0.1:19101/mcp -> find_remote_tools):\n{cat_raw}" + ) + return self._send_json({"summary": summary}) + + if self.path == "/api/act2/run-agent": + task = body.get( + "task", + "Audit Invoice INV-2026-089 for Acme Robotics, verify SKU-GPU-H200 warehouse stock, and check vendor ACME-01 compliance.", + ) + sidecar = LocalSidecarClient(AGENT_URL, AGENT_TOKEN) + sidecar.init_mcp() + raw_catalog = sidecar.call_sidecar_tool("find_remote_tools", {"service_name": "erp-db"}) + catalog = json.loads(raw_catalog.splitlines()[-1]) + tools_found = [entry["tool_name"] for entry in catalog if "tool_name" in entry] + vault_peer = catalog[0]["peer_id"] + step1 = f"Discovered {len(tools_found)} tools on Vault Peer {vault_peer[:16]}…: {', '.join(tools_found)}" + + plan_msg = sidecar.chat_completion( + [ + {"role": "system", "content": f"Available mesh tools: {', '.join(tools_found)}"}, + {"role": "user", "content": task}, + ] + ) + step2_think, step2_plan = "", plan_msg + if "" in plan_msg and "" in plan_msg: + step2_think = plan_msg.split("", 1)[1].split("", 1)[0].strip() + step2_plan = plan_msg.split("", 1)[1].strip() + + inv_res = sidecar.call_sidecar_tool( + "call_remote_tool", + {"peer_id": vault_peer, "tool_name": "mcp://erp-db/lookup_invoice", "arguments": {"invoice_id": "INV-2026-089"}}, + ) + stock_res = sidecar.call_sidecar_tool( + "call_remote_tool", + {"peer_id": vault_peer, "tool_name": "mcp://erp-db/check_inventory", "arguments": {"sku": "SKU-GPU-H200"}}, + ) + comp_data = sidecar.call_egress_get(vault_peer, "compliance.internal", "/v1/vendors/ACME-01") + + step3 = ( + f"[mcp://erp-db/lookup_invoice] -> {inv_res}\n" + f"[mcp://erp-db/check_inventory] -> {stock_res}\n" + f"[egress://compliance.internal] -> vendor={comp_data['name']}, sanctions={comp_data['sanctions_check']}, " + f"iso27001={comp_data['iso27001_certified']} (brokered secret verified={comp_data['brokered_auth_verified']})" + ) + + synth_msg = sidecar.chat_completion( + [ + {"role": "user", "content": task}, + {"role": "assistant", "content": plan_msg}, + { + "role": "user", + "content": ( + f"TOOL_OBSERVATIONS:\n" + f"- invoice: {inv_res}\n" + f"- inventory: {stock_res}\n" + f"- compliance: {json.dumps(comp_data)}" + ), + }, + ] + ) + step4_think, step4_decision = "", synth_msg + if "" in synth_msg and "" in synth_msg: + step4_think = synth_msg.split("", 1)[1].split("", 1)[0].strip() + step4_decision = synth_msg.split("", 1)[1].strip() + + return self._send_json( + { + "step1_discovery": step1, + "step2_think": step2_think, + "step2_plan": step2_plan, + "step3_results": step3, + "step4_think": step4_think, + "step4_decision": step4_decision, + } + ) + + if self.path == "/api/act3/test": + check = body.get("check", "3a") + if check == "3a": + out = subprocess.run( + [ + MESH.mcp_client, + "-url", + f"{AGENT_URL}/mcp", + "-token-path", + os.path.join(MESH.work_dir, "agent-api.token"), + "-tool", + "call_remote_tool", + "-args", + json.dumps({"peer_id": MESH.tools_peer, "tool_name": "mcp://payroll-vault/dump_executive_salaries", "arguments": {}}), + ], + capture_output=True, + text=True, + ) + msg = (out.stdout + out.stderr).strip().splitlines()[-1] + return self._send_json({"output": f"DENIED -> {msg}"}) + + if check == "3b": + req = urllib.request.Request( + f"{AGENT_URL}/mesh/{MESH.tools_peer}/egress/compliance.internal/v1/vendors/ACME-01", + data=b'{"sanctions_check":"OVERRIDE"}', + headers={"X-Mesh-Authentication": f"Bearer {AGENT_TOKEN}", "Content-Type": "application/json"}, + method="POST", + ) + try: + with _OPENER.open(req, timeout=10) as resp: + msg = f"HTTP {resp.status}" + except urllib.error.HTTPError as e: + msg = f"DENIED -> HTTP {e.code} ({e.read().decode('utf-8', errors='replace').strip()})" + return self._send_json({"output": msg}) + + if check == "3c": + out = subprocess.run( + [ + MESH.mcp_client, + "-url", + "http://127.0.0.1:19104/mcp", + "-token-path", + os.path.join(MESH.work_dir, "external-api.token"), + "-tool", + "call_remote_tool", + "-args", + json.dumps({"peer_id": MESH.tools_peer, "tool_name": "mcp://erp-db/lookup_invoice", "arguments": {"invoice_id": "INV-2026-089"}}), + ], + capture_output=True, + text=True, + ) + msg = (out.stdout + out.stderr).strip().splitlines()[-1] + return self._send_json({"output": f"DENIED -> {msg}"}) + + if check == "3d": + token_req = urllib.request.Request( + f"{AGENT_URL}/oauth/token", + data=urllib.parse.urlencode( + { + "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", + "resource": "mcp://erp-db", + "scope": "tool:lookup_invoice tool:check_inventory", + "seal": "true", + } + ).encode("utf-8"), + headers={"Authorization": f"Bearer {AGENT_TOKEN}"}, + method="POST", + ) + with _OPENER.open(token_req, timeout=10) as resp: + task_biscuit = json.loads(resp.read().decode("utf-8"))["access_token"] + task_token_path = os.path.join(MESH.work_dir, "task-biscuit.token") + MESH._write_file("task-biscuit.token", task_biscuit) + + allowed_proc = subprocess.run( + [ + MESH.mcp_client, + "-url", + f"{AGENT_URL}/mcp", + "-token-path", + task_token_path, + "-tool", + "call_remote_tool", + "-args", + json.dumps({"peer_id": MESH.tools_peer, "tool_name": "mcp://erp-db/lookup_invoice", "arguments": {"invoice_id": "INV-2026-089"}}), + ], + capture_output=True, + text=True, + ) + allowed_out = (allowed_proc.stdout + allowed_proc.stderr).strip().splitlines()[-1] + + denied_proc = subprocess.run( + [ + MESH.mcp_client, + "-url", + f"{AGENT_URL}/mcp", + "-token-path", + task_token_path, + "-tool", + "call_remote_tool", + "-args", + json.dumps( + { + "peer_id": MESH.tools_peer, + "tool_name": "mcp://erp-db/execute_wire_transfer", + "arguments": {"invoice_id": "INV-2026-089", "amount_usd": 250000, "iban": "DE89-ATTACKER"}, + } + ), + ], + capture_output=True, + text=True, + ) + denied_msg = (denied_proc.stdout + denied_proc.stderr).strip().splitlines()[-1] + wires = MESH.sqlite_counts()["wire_transfers_count"] + return self._send_json( + { + "output": ( + f"1. Read (lookup_invoice): ALLOW ({allowed_out[:48]}…)\n" + f"2. Write (execute_wire_transfer): DENIED -> {denied_msg}\n" + f"3. SQLite wire_transfers count: {wires} (database untouched!)" + ) + } + ) + + if self.path == "/api/act4/ban": + out = subprocess.run( + [ + MESH.agentmesh_one, + "admin", + "ban", + MESH.external_peer, + "--server", + CP_URL, + "--data-dir", + os.path.join(MESH.work_dir, "cp"), + ], + capture_output=True, + text=True, + ) + MESH.external_banned = True + return self._send_json({"output": (out.stdout + out.stderr).strip()}) + + self.send_error(404) + + +def main(): + global MESH + print("Starting Private DIY Enterprise Stack mesh & live browser workbench...", flush=True) + MESH = MeshEnvironment() + try: + MESH.start() + except Exception: + MESH.stop() + raise + + def _shutdown(signum, frame): + MESH.stop() + sys.exit(0) + + signal.signal(signal.SIGINT, _shutdown) + signal.signal(signal.SIGTERM, _shutdown) + + server = http.server.ThreadingHTTPServer(("127.0.0.1", DASHBOARD_PORT), WorkbenchHandler) + print(f"READY: Private DIY Enterprise Stack Workbench listening on http://127.0.0.1:{DASHBOARD_PORT}", flush=True) + try: + server.serve_forever() + finally: + MESH.stop() + + +if __name__ == "__main__": + main() diff --git a/development/examples/private-diy-stack/node-agent.yaml b/development/examples/private-diy-stack/node-agent.yaml new file mode 100644 index 00000000..3336c517 --- /dev/null +++ b/development/examples/private-diy-stack/node-agent.yaml @@ -0,0 +1,16 @@ +# Agent Workstation Sidecar Node (node-agent.yaml). +# +# Sits directly beside the self-hosted agent harness (agent_harness.py). +# Exposes the corporate mesh to the local agent as: +# - a local MCP server (http://127.0.0.1:19101/mcp) +# - a local OpenAI-compatible inference API (http://127.0.0.1:19101/v1) +# Enforces an outbound floor (egress.require_labels: {residency: on-prem}) +# so no prompt or tool call ever leaves the on-premises private boundary. +version: "v1alpha1" +labels: + residency: on-prem + zone: workstation + dept: finance +egress: + require_labels: + residency: on-prem diff --git a/development/examples/private-diy-stack/node-external.yaml b/development/examples/private-diy-stack/node-external.yaml new file mode 100644 index 00000000..1e922638 --- /dev/null +++ b/development/examples/private-diy-stack/node-external.yaml @@ -0,0 +1,9 @@ +# External / Non-Finance Node (node-external.yaml). +# +# Enrolled with dept=external. Used in Act 3 to prove that even within the same +# mesh, the Vault Tool Node rejects callers whose Biscuit lacks dept=finance. +version: "v1alpha1" +labels: + residency: on-prem + zone: workstation + dept: external diff --git a/development/examples/private-diy-stack/node-inference.yaml b/development/examples/private-diy-stack/node-inference.yaml new file mode 100644 index 00000000..ba0cb023 --- /dev/null +++ b/development/examples/private-diy-stack/node-inference.yaml @@ -0,0 +1,19 @@ +# Bare-Metal GPU Reasoning Sidecar Node (node-inference.yaml). +# +# Sits beside the self-hosted open-weights LLM server (Ollama / vLLM serving +# DeepSeek-R1 or Gemma 3) and publishes it to the mesh as inference://private-llm. +# Enforces an inbound Datalog check so only on-premises private nodes may +# consume GPU inference capacity. +version: "v1alpha1" +labels: + residency: on-prem + zone: gpu-pool + dept: finance +attenuation: + checks: + - 'check if label("residency", "on-prem");' +services: + - type: inference + name: private-llm + description: "Self-hosted DeepSeek-R1 / Gemma 3 reasoning engine on bare-metal GPU" + target_url: "http://127.0.0.1:18892" diff --git a/development/examples/private-diy-stack/node-tools.yaml b/development/examples/private-diy-stack/node-tools.yaml new file mode 100644 index 00000000..d18647dd --- /dev/null +++ b/development/examples/private-diy-stack/node-tools.yaml @@ -0,0 +1,27 @@ +# Data Center Vault Tool Sidecar Node (node-tools.yaml). +# +# Sits beside private company databases (SQLite ERP & Payroll MCP servers) and +# internal REST APIs. Registers mcp://erp-db and mcp://payroll-vault into the +# mesh directory and serves egress://compliance.internal by injecting the +# vault secret (secrets/compliance-api-key) on the host side. +# +# Enforces positive inbound Datalog checks requiring both residency=on-prem +# and dept=finance in the caller's Control-Plane-signed Biscuit. +version: "v1alpha1" +labels: + residency: on-prem + zone: vault + dept: finance +attenuation: + checks: + - 'check if label("residency", "on-prem");' + - 'check if label("dept", "finance");' +services: + - type: mcp + name: erp-db + description: "Private Corporate ERP Database (Invoices, Inventory & Wire Transfers)" + target_url: "http://127.0.0.1:18890/mcp" + - type: mcp + name: payroll-vault + description: "Restricted Executive Payroll Database (Default-Deny in policy.json)" + target_url: "http://127.0.0.1:18890/payroll-mcp" diff --git a/development/examples/private-diy-stack/policy.json b/development/examples/private-diy-stack/policy.json new file mode 100644 index 00000000..1ad4d324 --- /dev/null +++ b/development/examples/private-diy-stack/policy.json @@ -0,0 +1,42 @@ +{ + "roles": [ + { + "name": "mesh:role:node", + "allowed_services": [ + "system://mesh.catalog", + "inference://private-llm", + "mcp://erp-db", + "egress://compliance.internal" + ], + "allowed_publish": [ + "inference://private-llm", + "mcp://erp-db", + "mcp://payroll-vault" + ], + "allowed_targets": ["*"], + "allowed_labels": [ + "residency=on-prem", + "zone=workstation", + "zone=gpu-pool", + "zone=vault", + "dept=finance", + "dept=external" + ], + "http": [ + { + "service": "egress://compliance.internal", + "methods": ["GET"], + "paths": ["/v1/vendors/*"] + } + ] + } + ], + "egress": [ + { + "name": "compliance.internal", + "target_url": "http://127.0.0.1:18891", + "credential": "compliance-api-key", + "served_by": ["zone=vault"] + } + ] +} diff --git a/development/examples/private-diy-stack/record.sh b/development/examples/private-diy-stack/record.sh new file mode 100755 index 00000000..d28af165 --- /dev/null +++ b/development/examples/private-diy-stack/record.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Records the 1080p 3D Live-Execution Walkthrough for the Private DIY Enterprise Stack +# (`site/static/demo-private-diy-stack.mp4`). +# +# Starts the real `agentmesh-one` control plane, four real `agentmesh-node` sidecars, +# the SQLite ERP database, and the Vendor Compliance REST API, runs all 4 acts against +# the live Go binaries, and renders a 1920x1080 30fps 3D perspective architectural +# animation synchronized with the real execution outputs. + +set -euo pipefail + +EXAMPLE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$EXAMPLE_DIR/../../.." && pwd)" +export BIN_DIR="${BIN_DIR:-$REPO_ROOT/bin}" +export OUT_MP4="${OUT_MP4:-/tmp/demo-private-diy-stack.mp4}" + +if [[ ! -x "$BIN_DIR/agentmesh-one" || ! -x "$BIN_DIR/agentmesh-node" || ! -x "$BIN_DIR/mcp-client" ]]; then + echo "Building Agent Mesh binaries in $BIN_DIR..." + mkdir -p "$BIN_DIR" + (cd "$REPO_ROOT" && go build -o "$BIN_DIR/agentmesh-one" ./cmd/agentmesh-one && go build -o "$BIN_DIR/agentmesh-node" ./cmd/agentmesh-node && go build -o "$BIN_DIR/mcp-client" ./cmd/mcp-client) +fi + +python3 "$EXAMPLE_DIR/render_3d_video.py" + +if cp "$OUT_MP4" "$REPO_ROOT/site/static/demo-private-diy-stack.mp4" 2>/dev/null; then + ls -lh "$REPO_ROOT/site/static/demo-private-diy-stack.mp4" +else + echo "Rendered MP4 is ready at $OUT_MP4" + ls -lh "$OUT_MP4" +fi diff --git a/development/examples/private-diy-stack/render_3d_video.py b/development/examples/private-diy-stack/render_3d_video.py new file mode 100755 index 00000000..dd0219e7 --- /dev/null +++ b/development/examples/private-diy-stack/render_3d_video.py @@ -0,0 +1,1275 @@ +#!/usr/bin/env python3 +"""Live-Execution 3D Architectural Renderer for the Private DIY Enterprise Stack. + +Starts the real Agent Mesh control plane (`agentmesh-one`), four real `agentmesh-node` +sidecars (`node-tools`, `node-inference`, `node-agent`, `node-external`), the SQLite +ERP database, and the Vendor Compliance REST API via `dashboard.MeshEnvironment`, +executes all 4 acts against the live Go binaries, and renders a 1920x1080 30fps +3D perspective animation (`pycairo` + `numpy` + `ffmpeg`) synchronized with the real +peer IDs, latencies, SQLite query outputs, Biscuit Datalog denials, and audit logs. +""" + +from __future__ import annotations + +import json +import math +import os +from pathlib import Path +import shutil +import subprocess +import sys +import tempfile +import time +from typing import Any + +import cairo +import numpy as np + +EXAMPLE_DIR = Path(__file__).resolve().parent +sys.path.insert(0, str(EXAMPLE_DIR)) + +import dashboard # noqa: E402 + +W, H = 1920, 1080 +FPS = 30 + + +# --------------------------------------------------------------------------- +# 3D Math & Perspective Camera Engine +# --------------------------------------------------------------------------- +class Camera3D: + def __init__( + self, + yaw: float = -0.55, + pitch: float = 0.52, + dist: float = 13.8, + target: tuple[float, float, float] = (0.0, 0.55, 0.0), + fov: float = 1080.0, + ) -> None: + self.yaw = yaw + self.pitch = pitch + self.dist = dist + self.target = np.array(target, dtype=np.float64) + self.fov = fov + self._update_basis() + + def _update_basis(self) -> None: + cy, sy = math.cos(self.yaw), math.sin(self.yaw) + cp, sp = math.cos(self.pitch), math.sin(self.pitch) + forward = np.array([sy * cp, -sp, cy * cp], dtype=np.float64) + self.pos = self.target - forward * self.dist + up_world = np.array([0.0, 1.0, 0.0], dtype=np.float64) + right = np.cross(forward, up_world) + right /= np.linalg.norm(right) + 1e-9 + up = np.cross(right, forward) + up /= np.linalg.norm(up) + 1e-9 + self.forward = forward + self.right = right + self.up = up + + def set_pose( + self, + yaw: float, + pitch: float, + dist: float, + target: tuple[float, float, float], + ) -> None: + self.yaw = yaw + self.pitch = pitch + self.dist = dist + self.target = np.array(target, dtype=np.float64) + self._update_basis() + + def project(self, pt: tuple[float, float, float] | np.ndarray) -> tuple[float, float, float]: + v = np.asarray(pt, dtype=np.float64) - self.pos + x_cam = float(np.dot(v, self.right)) + y_cam = float(np.dot(v, self.up)) + z_cam = float(np.dot(v, self.forward)) + if z_cam < 0.2: + z_cam = 0.2 + scale = self.fov / z_cam + sx = W * 0.50 + x_cam * scale + sy = H * 0.45 - y_cam * scale + return sx, sy, z_cam + + +def lerp(a: float, b: float, t: float) -> float: + return a + (b - a) * t + + +def smoothstep(t: float) -> float: + t = max(0.0, min(1.0, t)) + return t * t * (3.0 - 2.0 * t) + + +# --------------------------------------------------------------------------- +# 3D Primitive Drawing Helpers (Depth-Sorted Extruded Solids, Cylinders, Rings) +# --------------------------------------------------------------------------- +def draw_3d_box( + polys: list[tuple[float, list[tuple[float, float]], tuple[float, float, float, float], tuple[float, float, float, float] | None, float]], + cam: Camera3D, + center: tuple[float, float, float], + size: tuple[float, float, float], + color: tuple[float, float, float], + alpha: float = 0.92, + edge_color: tuple[float, float, float, float] | None = None, + yaw_rot: float = 0.0, + line_width: float = 1.4, +) -> None: + cx, cy, cz = center + sx, sy, sz = size[0] * 0.5, size[1] * 0.5, size[2] * 0.5 + c, s = math.cos(yaw_rot), math.sin(yaw_rot) + + local_verts = [ + (-sx, -sy, -sz), + (sx, -sy, -sz), + (sx, sy, -sz), + (-sx, sy, -sz), + (-sx, -sy, sz), + (sx, -sy, sz), + (sx, sy, sz), + (-sx, sy, sz), + ] + world_verts = [] + proj_verts = [] + for lx, ly, lz in local_verts: + wx = cx + lx * c - lz * s + wy = cy + ly + wz = cz + lx * s + lz * c + world_verts.append(np.array([wx, wy, wz], dtype=np.float64)) + proj_verts.append(cam.project((wx, wy, wz))) + + # 6 faces with outward normals and lighting multipliers + faces = [ + ((3, 2, 6, 7), (0.0, 1.0, 0.0), 1.22), # Top + ((0, 1, 5, 4), (0.0, -1.0, 0.0), 0.50), # Bottom + ((4, 5, 6, 7), (0.0, 0.0, 1.0), 0.98), # Front (+Z) + ((1, 0, 3, 2), (0.0, 0.0, -1.0), 0.72), # Back (-Z) + ((5, 1, 2, 6), (1.0, 0.0, 0.0), 0.88), # Right (+X) + ((0, 4, 7, 3), (-1.0, 0.0, 0.0), 0.78), # Left (-X) + ] + + r, g, b = color + if edge_color is None: + edge_color = (min(1.0, r * 1.45 + 0.15), min(1.0, g * 1.45 + 0.15), min(1.0, b * 1.45 + 0.15), min(1.0, alpha + 0.1)) + + for idxs, _norm, shade in faces: + pts_2d = [(proj_verts[i][0], proj_verts[i][1]) for i in idxs] + # Backface culling in screen space (unless translucent) + area = 0.0 + for i in range(4): + x1, y1 = pts_2d[i] + x2, y2 = pts_2d[(i + 1) % 4] + area += (x1 * y2 - x2 * y1) + if alpha > 0.85 and area <= 0: + continue + avg_z = sum(proj_verts[i][2] for i in idxs) / 4.0 + fc = (min(1.0, r * shade), min(1.0, g * shade), min(1.0, b * shade), alpha) + polys.append((avg_z, pts_2d, fc, edge_color, line_width)) + + +def draw_3d_octahedron( + polys: list[Any], + cam: Camera3D, + center: tuple[float, float, float], + radius: float, + color: tuple[float, float, float], + alpha: float = 0.92, + yaw_rot: float = 0.0, +) -> None: + cx, cy, cz = center + c, s = math.cos(yaw_rot), math.sin(yaw_rot) + top = (cx, cy + radius * 1.25, cz) + bot = (cx, cy - radius * 1.25, cz) + ring = [ + (cx + radius * math.cos(yaw_rot + k * math.pi * 0.5), cy, cz + radius * math.sin(yaw_rot + k * math.pi * 0.5)) + for k in range(4) + ] + r, g, b = color + edge = (min(1.0, r * 1.4 + 0.25), min(1.0, g * 1.4 + 0.25), min(1.0, b * 1.4 + 0.25), 0.95) + for k in range(4): + p1 = ring[k] + p2 = ring[(k + 1) % 4] + for apex, shade in ((top, 1.15 - 0.08 * k), (bot, 0.72 + 0.05 * k)): + proj = [cam.project(apex), cam.project(p1), cam.project(p2)] + avg_z = sum(p[2] for p in proj) / 3.0 + pts_2d = [(p[0], p[1]) for p in proj] + fc = (min(1.0, r * shade), min(1.0, g * shade), min(1.0, b * shade), alpha) + polys.append((avg_z, pts_2d, fc, edge, 1.5)) + + +def draw_3d_cylinder( + polys: list[Any], + cam: Camera3D, + center: tuple[float, float, float], + radius: float, + height: float, + color: tuple[float, float, float], + segments: int = 14, + alpha: float = 0.92, +) -> None: + cx, cy, cz = center + y0, y1 = cy - height * 0.5, cy + height * 0.5 + r, g, b = color + edge = (min(1.0, r * 1.35 + 0.15), min(1.0, g * 1.35 + 0.15), min(1.0, b * 1.35 + 0.15), 0.75) + top_pts = [] + top_zs = [] + for i in range(segments): + a0 = (i / segments) * math.tau + a1 = ((i + 1) / segments) * math.tau + p00 = cam.project((cx + radius * math.cos(a0), y0, cz + radius * math.sin(a0))) + p10 = cam.project((cx + radius * math.cos(a1), y0, cz + radius * math.sin(a1))) + p11 = cam.project((cx + radius * math.cos(a1), y1, cz + radius * math.sin(a1))) + p01 = cam.project((cx + radius * math.cos(a0), y1, cz + radius * math.sin(a0))) + top_pts.append((p01[0], p01[1])) + top_zs.append(p01[2]) + shade = 0.78 + 0.25 * math.cos(a0 - 0.7) + avg_z = (p00[2] + p10[2] + p11[2] + p01[2]) * 0.25 + fc = (min(1.0, r * shade), min(1.0, g * shade), min(1.0, b * shade), alpha) + polys.append((avg_z, [(p00[0], p00[1]), (p10[0], p10[1]), (p11[0], p11[1]), (p01[0], p01[1])], fc, edge, 0.9)) + polys.append((sum(top_zs) / len(top_zs) - 0.05, top_pts, (min(1.0, r * 1.25), min(1.0, g * 1.25), min(1.0, b * 1.25), alpha), edge, 1.3)) + + +def rounded_rect(ctx: cairo.Context, x: float, y: float, w: float, h: float, r: float) -> None: + ctx.new_sub_path() + ctx.arc(x + w - r, y + r, r, -math.pi / 2, 0) + ctx.arc(x + w - r, y + h - r, r, 0, math.pi / 2) + ctx.arc(x + r, y + h - r, r, math.pi / 2, math.pi) + ctx.arc(x + r, y + r, r, math.pi, 3 * math.pi / 2) + ctx.close_path() + + +# --------------------------------------------------------------------------- +# Node 3D World Positions (Camera is at -Z looking toward +Z) +# -X = Left of screen, +X = Right of screen +# -Z = Foreground (lower screen), +Z = Background (upper screen) +# --------------------------------------------------------------------------- +POS_CP = (0.0, 2.25, 3.35) # Back-Center Elevated Spire: agentmesh-one Authority +POS_AGENT_APP = (-5.7, 0.65, 0.75) # Mid-Left (Cloud Run / Workstation): agent_harness.py +POS_NODE_AGENT = (-3.5, 0.85, 0.75) # Mid-Left (Cloud Run / Workstation): node-agent.yaml (:19101) +POS_NODE_INF = (3.1, 0.85, 2.35) # Back-Right (Cloud / On-Prem GPU): node-inference.yaml (:19103) +POS_GPU_RACK = (5.3, 0.95, 2.35) # Back-Right (Cloud / On-Prem GPU): Gemma 3 / DeepSeek-R1 +POS_NODE_TOOLS = (1.6, 0.90, -1.25) # Front-Right (On-Prem Vault): node-tools.yaml (:19102) +POS_ERP_DB = (3.8, 0.75, -0.45) # Front-Right (On-Prem Vault): mcp://erp-db (SQLite) +POS_PAYROLL = (5.6, 0.75, -1.15) # Front-Right (On-Prem Vault): mcp://payroll-vault (Locked) +POS_COMPLIANCE = (4.0, 0.80, -2.45) # Front-Right (On-Prem Vault): egress://compliance.internal +POS_EXTERNAL = (-4.5, 0.70, -2.05) # Front-Left (Untrusted External): node-external.yaml (:19104) + + +def bezier_3d( + p0: tuple[float, float, float], + p1: tuple[float, float, float], + t: float, + arc_height: float = 1.35, +) -> tuple[float, float, float]: + mx = (p0[0] + p1[0]) * 0.5 + my = max(p0[1], p1[1]) + arc_height + mz = (p0[2] + p1[2]) * 0.5 + u = 1.0 - t + x = u * u * p0[0] + 2 * u * t * mx + t * t * p1[0] + y = u * u * p0[1] + 2 * u * t * my + t * t * p1[1] + z = u * u * p0[2] + 2 * u * t * mz + t * t * p1[2] + return x, y, z + + +# --------------------------------------------------------------------------- +# Scene Renderer +# --------------------------------------------------------------------------- +def render_frame( + ctx: cairo.Context, + cam: Camera3D, + t_sec: float, + state: dict[str, Any], +) -> None: + # 1. Deep space cybernetic gradient background + bg = cairo.LinearGradient(0, 0, 0, H) + bg.add_color_stop_rgb(0.0, 0.020, 0.035, 0.075) + bg.add_color_stop_rgb(0.55, 0.035, 0.060, 0.115) + bg.add_color_stop_rgb(1.0, 0.015, 0.025, 0.055) + ctx.set_source(bg) + ctx.paint() + + # Radial ambient glow behind the 3D stage + glow = cairo.RadialGradient(W * 0.50, H * 0.44, 60, W * 0.50, H * 0.44, 780) + glow.add_color_stop_rgba(0.0, 0.08, 0.32, 0.65, 0.22) + glow.add_color_stop_rgba(0.6, 0.04, 0.16, 0.36, 0.08) + glow.add_color_stop_rgba(1.0, 0.0, 0.0, 0.0, 0.0) + ctx.set_source(glow) + ctx.paint() + + # 2. 3D Perspective Floor Grid (y = 0) + ctx.set_line_width(1.0) + for gx in range(-9, 10): + alpha = 0.14 if gx % 2 == 0 else 0.06 + ctx.set_source_rgba(0.22, 0.55, 0.88, alpha) + p_start = cam.project((gx * 1.0, 0.0, -7.0)) + p_end = cam.project((gx * 1.0, 0.0, 6.0)) + ctx.move_to(p_start[0], p_start[1]) + ctx.line_to(p_end[0], p_end[1]) + ctx.stroke() + for gz in range(-7, 7): + alpha = 0.14 if gz % 2 == 0 else 0.06 + ctx.set_source_rgba(0.22, 0.55, 0.88, alpha) + p_start = cam.project((-9.0, 0.0, gz * 1.0)) + p_end = cam.project((9.0, 0.0, gz * 1.0)) + ctx.move_to(p_start[0], p_start[1]) + ctx.line_to(p_end[0], p_end[1]) + ctx.stroke() + + polys: list[Any] = [] + + # 3. 3D Zone Base Platforms + # Zone A: Cloud Run / Workstation Zone (Mid-Left) + draw_3d_box( + polys, cam, (-4.6, 0.10, 0.75), (3.8, 0.20, 2.3), + (0.07, 0.24, 0.46), alpha=0.82, edge_color=(0.22, 0.74, 0.97, 0.85), line_width=1.8, + ) + # Zone B: Cloud / On-Prem GPU Inference Cluster (Back Right) + draw_3d_box( + polys, cam, (4.2, 0.10, 2.35), (3.8, 0.20, 2.2), + (0.24, 0.12, 0.48), alpha=0.82, edge_color=(0.66, 0.33, 0.97, 0.85), line_width=1.8, + ) + # Zone C: On-Premises Corporate Vault (Front Right — Armored Platform) + draw_3d_box( + polys, cam, (3.65, 0.12, -1.35), (5.4, 0.24, 3.2), + (0.05, 0.28, 0.22), alpha=0.86, edge_color=(0.20, 0.83, 0.60, 0.90), line_width=2.0, + ) + # Translucent 3D Vault Perimeter Walls around On-Premises Zone + draw_3d_box( + polys, cam, (3.65, 0.55, -1.35), (5.52, 0.62, 3.32), + (0.08, 0.45, 0.35), alpha=0.14, edge_color=(0.20, 0.88, 0.65, 0.40), line_width=1.0, + ) + # Zone D: Untrusted External Zone (Front Left) + ext_banned = state.get("ext_banned", False) + ext_base_col = (0.35, 0.08, 0.12) if not ext_banned else (0.18, 0.05, 0.07) + draw_3d_box( + polys, cam, (-4.5, 0.10, -2.05), (2.5, 0.20, 2.0), + ext_base_col, alpha=0.82, edge_color=(0.95, 0.28, 0.36, 0.85), line_width=1.8, + ) + + # 4. Control Plane Spire (`agentmesh-one`) + Rotating 3D Biscuit Holocube (Back-Center) + draw_3d_box( + polys, cam, (0.0, 0.90, 3.35), (1.6, 1.80, 1.4), + (0.10, 0.28, 0.52), alpha=0.90, edge_color=(0.35, 0.85, 1.0, 0.95), line_width=1.8, + ) + draw_3d_octahedron( + polys, cam, (0.0, 2.45 + 0.12 * math.sin(t_sec * 2.5), 3.35), + radius=0.55, color=(0.96, 0.75, 0.18), alpha=0.92, yaw_rot=t_sec * 1.4, + ) + + # 5. Cloud Run / Workstation Nodes (`agent_harness.py` + `node-agent.yaml`) + draw_3d_box( + polys, cam, POS_AGENT_APP, (1.15, 0.95, 1.15), + (0.14, 0.45, 0.78), alpha=0.92, yaw_rot=0.08 * math.sin(t_sec * 1.2), + ) + draw_3d_box( + polys, cam, POS_NODE_AGENT, (1.05, 1.35, 1.05), + (0.08, 0.62, 0.86), alpha=0.94, + ) + # Sealed tar_block Biscuit crystal hovering above node-agent when Act 3d is active + if state.get("sealed_biscuit", False): + draw_3d_octahedron( + polys, cam, (POS_NODE_AGENT[0], POS_NODE_AGENT[1] + 1.18, POS_NODE_AGENT[2]), + radius=0.38, color=(0.98, 0.68, 0.12), alpha=0.95, yaw_rot=-t_sec * 2.2, + ) + + # 6. Cloud / On-Prem GPU Cluster (`node-inference.yaml` + GPU Tensor Rack) + draw_3d_box( + polys, cam, POS_NODE_INF, (1.05, 1.35, 1.05), + (0.52, 0.26, 0.88), alpha=0.94, + ) + # Multi-blade 3D GPU Server Stack + for blade_idx in range(3): + by = 0.42 + blade_idx * 0.42 + draw_3d_box( + polys, cam, (POS_GPU_RACK[0], by, POS_GPU_RACK[2]), (1.30, 0.30, 1.20), + (0.36 + 0.08 * blade_idx, 0.18, 0.68 + 0.08 * blade_idx), alpha=0.94, + ) + + # 7. On-Premises Vault Sidecar & Private Backends + draw_3d_box( + polys, cam, POS_NODE_TOOLS, (1.15, 1.45, 1.15), + (0.08, 0.68, 0.50), alpha=0.95, + ) + # Secret Broker Golden Micro-Vault next to node-tools + draw_3d_box( + polys, cam, (POS_NODE_TOOLS[0] - 0.15, POS_NODE_TOOLS[1] + 0.98, POS_NODE_TOOLS[2]), + (0.52, 0.36, 0.52), (0.92, 0.68, 0.12), alpha=0.95, yaw_rot=t_sec * 0.8, + ) + # SQLite ERP Database 3D Stacked Cylinders (`mcp://erp-db`) + for tier in range(3): + draw_3d_cylinder( + polys, cam, (POS_ERP_DB[0], 0.38 + tier * 0.36, POS_ERP_DB[2]), + radius=0.52, height=0.28, color=(0.12, 0.72, 0.52), + ) + # Payroll Vault (`mcp://payroll-vault`) — Locked Red/Slate Safe + draw_3d_box( + polys, cam, POS_PAYROLL, (0.95, 1.05, 0.95), + (0.65, 0.16, 0.24), alpha=0.92, edge_color=(0.98, 0.35, 0.42, 0.95), + ) + # Vendor Compliance API Tower (`egress://compliance.internal`) + draw_3d_box( + polys, cam, POS_COMPLIANCE, (1.05, 1.18, 0.95), + (0.14, 0.58, 0.74), alpha=0.92, + ) + + # 8. Untrusted External Node (`node-external.yaml`) + ext_col = (0.78, 0.18, 0.26) if not ext_banned else (0.32, 0.12, 0.15) + draw_3d_box( + polys, cam, POS_EXTERNAL, (1.0, 1.15, 1.0), + ext_col, alpha=0.90 if not ext_banned else 0.55, + ) + if ext_banned: + # 3D Red Laser Lockdown Cage around Banned External Peer + draw_3d_box( + polys, cam, (POS_EXTERNAL[0], POS_EXTERNAL[1] + 0.1, POS_EXTERNAL[2]), + (1.45, 1.55, 1.45), (0.95, 0.15, 0.22), alpha=0.22, + edge_color=(1.0, 0.25, 0.30, 0.95), line_width=2.4, + ) + + # Sort and paint all 3D polygons back-to-front (Painter's Algorithm) + polys.sort(key=lambda item: item[0], reverse=True) + for _depth, pts_2d, fc, ec, lw in polys: + ctx.new_path() + ctx.move_to(pts_2d[0][0], pts_2d[0][1]) + for px, py in pts_2d[1:]: + ctx.line_to(px, py) + ctx.close_path() + ctx.set_source_rgba(*fc) + ctx.fill_preserve() + if ec is not None: + ctx.set_source_rgba(*ec) + ctx.set_line_width(lw) + ctx.stroke() + else: + ctx.new_path() + + # 9. 3D Mesh Control & Data Tunnels (Curved 3D Bezier Arcs) + # Control plane authority beams + cp_apex = (POS_CP[0], POS_CP[1] + 0.1, POS_CP[2]) + for node_pos in (POS_NODE_AGENT, POS_NODE_INF, POS_NODE_TOOLS): + _draw_3d_arc(ctx, cam, cp_apex, node_pos, (0.96, 0.78, 0.22, 0.34), arc_h=0.8, width=1.6, dashed=True, t_sec=t_sec) + + # Local loopback bridge (agent_harness.py <-> node-agent.yaml) + _draw_3d_arc(ctx, cam, POS_AGENT_APP, POS_NODE_AGENT, (0.22, 0.88, 1.0, 0.75), arc_h=0.35, width=2.8, dashed=False, t_sec=t_sec) + + # Persistent p2p Noise/QUIC tunnels between sidecars + _draw_3d_arc(ctx, cam, POS_NODE_AGENT, POS_NODE_INF, (0.58, 0.42, 0.98, 0.45), arc_h=1.45, width=2.2, dashed=True, t_sec=t_sec) + _draw_3d_arc(ctx, cam, POS_NODE_AGENT, POS_NODE_TOOLS, (0.18, 0.86, 0.66, 0.45), arc_h=1.55, width=2.2, dashed=True, t_sec=t_sec) + + # Vault internal connections + _draw_3d_arc(ctx, cam, POS_NODE_TOOLS, POS_ERP_DB, (0.20, 0.88, 0.62, 0.60), arc_h=0.45, width=2.0, dashed=False, t_sec=t_sec) + _draw_3d_arc(ctx, cam, POS_NODE_TOOLS, POS_COMPLIANCE, (0.22, 0.78, 0.95, 0.60), arc_h=0.45, width=2.0, dashed=False, t_sec=t_sec) + _draw_3d_arc(ctx, cam, POS_NODE_TOOLS, POS_PAYROLL, (0.95, 0.28, 0.36, 0.35), arc_h=0.45, width=1.6, dashed=True, t_sec=t_sec) + + # 10. Active Animated 3D Packet Beams & Force-Field Shields + callouts: list[dict[str, Any]] = [] + for beam in state.get("beams", []): + _draw_active_beam(ctx, cam, beam, t_sec, callouts) + + for shield in state.get("shields", []): + _draw_3d_shield(ctx, cam, shield, t_sec, callouts) + + # 11. Floating 3D Billboard Labels Projected onto Node Anchors (with 2D De-Overlap Solver) + ext_sub = "BANNED & REVOKED" if ext_banned else "dept=external (Untrusted)" + node_labels = [ + {"pos": (POS_CP[0], POS_CP[1] + 0.95, POS_CP[2]), "title": "agentmesh-one", "sub": "Authority & Datalog PDP", "accent": (0.96, 0.78, 0.22), "dy": -26.0}, + {"pos": (POS_AGENT_APP[0], POS_AGENT_APP[1] + 0.85, POS_AGENT_APP[2]), "title": "agent_harness.py", "sub": "0 DB Creds | 127.0.0.1", "accent": (0.38, 0.82, 1.0), "dy": -22.0}, + {"pos": (POS_NODE_AGENT[0], POS_NODE_AGENT[1] + 0.95, POS_NODE_AGENT[2]), "title": "node-agent (:19101)", "sub": "Cloud Run / Workstation", "accent": (0.22, 0.88, 0.98), "dy": -26.0}, + {"pos": (POS_NODE_INF[0], POS_NODE_INF[1] + 0.95, POS_NODE_INF[2]), "title": "node-inference (:19103)", "sub": "inference://private-llm", "accent": (0.74, 0.52, 1.0), "dy": -26.0}, + {"pos": (POS_GPU_RACK[0], POS_GPU_RACK[1] + 0.95, POS_GPU_RACK[2]), "title": "Gemma 3 / DeepSeek-R1", "sub": "Cloud / On-Prem GPU", "accent": (0.68, 0.45, 0.98), "dy": -26.0}, + {"pos": (POS_NODE_TOOLS[0], POS_NODE_TOOLS[1] + 1.25, POS_NODE_TOOLS[2]), "title": "node-tools (:19102)", "sub": "On-Prem Vault + Secret Broker", "accent": (0.22, 0.92, 0.68), "dy": -28.0}, + {"pos": (POS_ERP_DB[0], POS_ERP_DB[1] + 0.95, POS_ERP_DB[2]), "title": "mcp://erp-db", "sub": "SQLite ERP (ALLOW)", "accent": (0.22, 0.92, 0.65), "dy": -24.0}, + {"pos": (POS_PAYROLL[0], POS_PAYROLL[1] + 0.85, POS_PAYROLL[2]), "title": "mcp://payroll-vault", "sub": "Default-Deny (LOCKED)", "accent": (0.98, 0.38, 0.45), "dy": -22.0}, + {"pos": (POS_COMPLIANCE[0], POS_COMPLIANCE[1] + 0.85, POS_COMPLIANCE[2]), "title": "egress://compliance.internal", "sub": "GET Only + Vault Key", "accent": (0.35, 0.84, 0.98), "dy": 28.0}, + {"pos": (POS_EXTERNAL[0], POS_EXTERNAL[1] + 0.95, POS_EXTERNAL[2]), "title": "node-external (:19104)", "sub": ext_sub, "accent": (0.98, 0.35, 0.42), "dy": 26.0}, + ] + _draw_all_labels_deoverlapped(ctx, cam, node_labels, callouts) + + # 12. 2D Cinema HUD Overlays (Real Execution Telemetry, Act Banner, Console, Audit Feed) + _draw_hud(ctx, state, t_sec) + + +def _draw_3d_arc( + ctx: cairo.Context, + cam: Camera3D, + p0: tuple[float, float, float], + p1: tuple[float, float, float], + rgba: tuple[float, float, float, float], + arc_h: float, + width: float, + dashed: bool, + t_sec: float, +) -> None: + steps = 28 + ctx.set_source_rgba(*rgba) + ctx.set_line_width(width) + if dashed: + ctx.set_dash([8.0, 6.0], -t_sec * 24.0) + else: + ctx.set_dash([]) + for i in range(steps + 1): + pt = bezier_3d(p0, p1, i / steps, arc_height=arc_h) + sx, sy, _ = cam.project(pt) + if i == 0: + ctx.move_to(sx, sy) + else: + ctx.line_to(sx, sy) + ctx.stroke() + ctx.set_dash([]) + + +def _draw_active_beam( + ctx: cairo.Context, + cam: Camera3D, + beam: dict[str, Any], + t_sec: float, + callouts: list[dict[str, Any]], +) -> None: + p0 = beam["src"] + p1 = beam["dst"] + col = beam["color"] # (r, g, b) + arc_h = beam.get("arc_h", 1.45) + progress = beam.get("progress", (t_sec * 1.1) % 1.0) + is_deny = beam.get("deny", False) + + # Glowing base trajectory + _draw_3d_arc(ctx, cam, p0, p1, (col[0], col[1], col[2], 0.85), arc_h=arc_h, width=4.0, dashed=False, t_sec=t_sec) + + # Multiple moving 3D energy pulses along the trajectory + for offset in (0.0, 0.33, 0.66): + tau = (progress + offset) % 1.0 + if is_deny and tau > 0.78: + tau = 0.78 # Clamped at the force-field shield boundary + for trail in range(7): + tt = max(0.0, tau - trail * 0.022) + wx, wy, wz = bezier_3d(p0, p1, tt, arc_height=arc_h) + sx, sy, z_cam = cam.project((wx, wy, wz)) + rad = max(2.5, (11.0 - trail * 1.3) * (11.0 / z_cam)) + alpha = max(0.1, 0.95 - trail * 0.13) + ctx.set_source_rgba(col[0], col[1], col[2], alpha) + ctx.arc(sx, sy, rad, 0, math.tau) + ctx.fill() + if trail == 0: + ctx.set_source_rgba(1.0, 1.0, 1.0, 0.95) + ctx.arc(sx, sy, rad * 0.48, 0, math.tau) + ctx.fill() + + label = beam.get("label") + if label: + mx, my, mz = bezier_3d(p0, p1, 0.5, arc_height=arc_h + 0.25) + callouts.append({ + "pos": (mx, my, mz), + "text": label, + "color": col, + "bg": (0.04, 0.08, 0.16, 0.94), + "dy": -18.0, + }) + + +def _draw_3d_shield( + ctx: cairo.Context, + cam: Camera3D, + shield: dict[str, Any], + t_sec: float, + callouts: list[dict[str, Any]], +) -> None: + center = shield["pos"] + sx, sy, z_cam = cam.project(center) + base_r = shield.get("radius", 68.0) * (12.0 / z_cam) + pulse = 1.0 + 0.10 * math.sin(t_sec * 8.0) + r = base_r * pulse + + # Crimson radial energy dome + grad = cairo.RadialGradient(sx, sy, r * 0.15, sx, sy, r * 1.25) + grad.add_color_stop_rgba(0.0, 1.0, 0.25, 0.35, 0.55) + grad.add_color_stop_rgba(0.7, 0.95, 0.12, 0.24, 0.32) + grad.add_color_stop_rgba(1.0, 0.95, 0.12, 0.24, 0.0) + ctx.set_source(grad) + ctx.arc(sx, sy, r * 1.25, 0, math.tau) + ctx.fill() + + # Rotating 3D hexagon barrier + ctx.set_source_rgba(1.0, 0.32, 0.40, 0.95) + ctx.set_line_width(2.6) + for ring_scale, rot_dir in ((1.0, 1.0), (0.68, -1.4)): + ctx.new_path() + for k in range(6): + ang = t_sec * 1.8 * rot_dir + k * (math.tau / 6.0) + px = sx + r * ring_scale * math.cos(ang) + py = sy + r * ring_scale * 0.82 * math.sin(ang) + if k == 0: + ctx.move_to(px, py) + else: + ctx.line_to(px, py) + ctx.close_path() + ctx.stroke() + + # Expanding shockwave ring + wave = (t_sec * 1.6) % 1.0 + ctx.set_source_rgba(1.0, 0.38, 0.45, (1.0 - wave) * 0.85) + ctx.set_line_width(2.0) + ctx.arc(sx, sy, r * (0.8 + wave * 0.95), 0, math.tau) + ctx.stroke() + + caption = shield.get("caption", "DENIED BY ZERO-TRUST POLICY") + callouts.append({ + "pos": center, + "text": caption, + "color": (1.0, 0.32, 0.40), + "bg": (0.34, 0.04, 0.08, 0.96), + "dy": -r - 24.0, + }) + + +def _draw_all_labels_deoverlapped( + ctx: cairo.Context, + cam: Camera3D, + node_labels: list[dict[str, Any]], + callouts: list[dict[str, Any]], +) -> None: + boxes: list[dict[str, Any]] = [] + + for nl in node_labels: + ax, ay, _ = cam.project(nl["pos"]) + ctx.select_font_face("DejaVu Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(12.5) + e1 = ctx.text_extents(nl["title"]) + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + ctx.set_font_size(10.5) + e2 = ctx.text_extents(nl["sub"]) + w = max(e1.width, e2.width) + 20.0 + h = 38.0 + boxes.append({ + "kind": "node", + "ax": ax, + "ay": ay, + "cx": ax, + "cy": ay + nl.get("dy", -24.0), + "w": w, + "h": h, + "title": nl["title"], + "sub": nl["sub"], + "accent": nl["accent"], + "w1": e1.width, + "w2": e2.width, + }) + + for co in callouts: + ax, ay, _ = cam.project(co["pos"]) + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(12.5) + ext = ctx.text_extents(co["text"]) + w = ext.width + 20.0 + h = 26.0 + boxes.append({ + "kind": "callout", + "ax": ax, + "ay": ay, + "cx": ax, + "cy": ay + co.get("dy", -18.0), + "w": w, + "h": h, + "text": co["text"], + "tw": ext.width, + "color": co["color"], + "bg": co["bg"], + }) + + # Iterative 2D bounding-box relaxation to eliminate any screen-space overlap + pad_x, pad_y = 10.0, 8.0 + for _ in range(18): + for i in range(len(boxes)): + for j in range(i + 1, len(boxes)): + bi, bj = boxes[i], boxes[j] + dx = bj["cx"] - bi["cx"] + dy = bj["cy"] - bi["cy"] + ox = (bi["w"] + bj["w"]) * 0.5 + pad_x - abs(dx) + oy = (bi["h"] + bj["h"]) * 0.5 + pad_y - abs(dy) + if ox > 0 and oy > 0: + if ox < oy * 1.35: + shift = (ox * 0.52) * (1.0 if dx >= 0 else -1.0) + bi["cx"] -= shift + bj["cx"] += shift + else: + shift = (oy * 0.52) * (1.0 if dy >= 0 else -1.0) + bi["cy"] -= shift + bj["cy"] += shift + for b in boxes: + b["cx"] = max(b["w"] * 0.5 + 34.0, min(W - b["w"] * 0.5 - 34.0, b["cx"])) + b["cy"] = max(116.0 + b["h"] * 0.5, min(H - 286.0 - b["h"] * 0.5, b["cy"])) + + # Draw subtle leader lines from 3D anchor to displaced badge + for b in boxes: + dist = math.hypot(b["cx"] - b["ax"], b["cy"] - b["ay"]) + if dist > 18.0: + col = b["accent"] if b["kind"] == "node" else b["color"] + ctx.set_source_rgba(col[0], col[1], col[2], 0.55) + ctx.set_line_width(1.2) + ctx.move_to(b["ax"], b["ay"]) + ctx.line_to(b["cx"], b["cy"]) + ctx.stroke() + ctx.arc(b["ax"], b["ay"], 3.0, 0, math.tau) + ctx.fill() + + # Draw node badges first, then active callout badges on top + for b in boxes: + x = b["cx"] - b["w"] * 0.5 + y = b["cy"] - b["h"] * 0.5 + if b["kind"] == "node": + acc = b["accent"] + rounded_rect(ctx, x, y, b["w"], b["h"], 7) + ctx.set_source_rgba(0.03, 0.06, 0.12, 0.88) + ctx.fill_preserve() + ctx.set_source_rgba(acc[0], acc[1], acc[2], 0.82) + ctx.set_line_width(1.3) + ctx.stroke() + + ctx.select_font_face("DejaVu Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(12.5) + ctx.set_source_rgba(0.96, 0.98, 1.0, 0.98) + ctx.move_to(b["cx"] - b["w1"] * 0.5, y + 15.5) + ctx.show_text(b["title"]) + + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + ctx.set_font_size(10.5) + ctx.set_source_rgba(acc[0], acc[1], acc[2], 0.95) + ctx.move_to(b["cx"] - b["w2"] * 0.5, y + 31.0) + ctx.show_text(b["sub"]) + else: + col = b["color"] + bg = b["bg"] + rounded_rect(ctx, x, y, b["w"], b["h"], 6) + ctx.set_source_rgba(*bg) + ctx.fill_preserve() + ctx.set_source_rgba(col[0], col[1], col[2], 0.98) + ctx.set_line_width(1.7) + ctx.stroke() + + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(12.5) + ctx.set_source_rgba(0.98, 0.99, 1.0, 1.0) + ctx.move_to(b["cx"] - b["tw"] * 0.5, b["cy"] + 4.5) + ctx.show_text(b["text"]) + + +def _draw_hud(ctx: cairo.Context, state: dict[str, Any], _t_sec: float) -> None: + # Top Header Bar + rounded_rect(ctx, 28, 22, W - 56, 74, 12) + ctx.set_source_rgba(0.03, 0.06, 0.13, 0.88) + ctx.fill_preserve() + ctx.set_source_rgba(0.22, 0.65, 0.95, 0.55) + ctx.set_line_width(1.5) + ctx.stroke() + + # Live Execution Badge + rounded_rect(ctx, 46, 38, 188, 42, 8) + ctx.set_source_rgba(0.06, 0.34, 0.24, 0.92) + ctx.fill_preserve() + ctx.set_source_rgba(0.20, 0.88, 0.62, 0.95) + ctx.set_line_width(1.5) + ctx.stroke() + ctx.set_source_rgba(0.20, 0.95, 0.66, 1.0) + ctx.arc(66, 59, 6, 0, math.tau) + ctx.fill() + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(13.0) + ctx.set_source_rgba(0.92, 1.0, 0.96, 1.0) + ctx.move_to(82, 64) + ctx.show_text("LIVE GO BINARIES") + + # Main Title & Act Title + ctx.select_font_face("DejaVu Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(21.0) + ctx.set_source_rgba(0.96, 0.98, 1.0, 1.0) + ctx.move_to(254, 54) + ctx.show_text(state.get("headline", "Private DIY Enterprise Stack — Safely On-Premises & in Cloud")) + + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + ctx.set_font_size(13.5) + ctx.set_source_rgba(0.45, 0.82, 0.98, 0.96) + ctx.move_to(254, 78) + ctx.show_text(state.get("subheadline", "Gemma / DeepSeek + Self-Hosted Agent Harness + Agent Mesh Zero-Trust Sidecars")) + + # Act Pill Indicator on Right of Top Bar + act_idx = state.get("act_idx", 1) + act_labels = [ + "ACT 1: SIDECARS", + "ACT 2: HYBRID ReAct", + "ACT 3: ZERO TRUST", + "ACT 4: AUDIT & BAN", + ] + px = W - 670 + for idx, text in enumerate(act_labels, start=1): + active = idx == act_idx + rounded_rect(ctx, px, 40, 152, 38, 8) + if active: + ctx.set_source_rgba(0.14, 0.46, 0.82, 0.95) + ctx.fill_preserve() + ctx.set_source_rgba(0.42, 0.86, 1.0, 1.0) + ctx.set_line_width(1.8) + ctx.stroke() + else: + ctx.set_source_rgba(0.06, 0.11, 0.20, 0.80) + ctx.fill_preserve() + ctx.set_source_rgba(0.22, 0.35, 0.52, 0.55) + ctx.set_line_width(1.0) + ctx.stroke() + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(11.5) + ctx.set_source_rgba(0.98, 0.99, 1.0, 1.0 if active else 0.55) + ctx.move_to(px + 12, 63) + ctx.show_text(text) + px += 160 + + # Bottom-Left Panel: Live Binary Execution Output & Real Payload Telemetry + panel_y = H - 270 + rounded_rect(ctx, 28, panel_y, 1140, 244, 12) + ctx.set_source_rgba(0.025, 0.05, 0.11, 0.90) + ctx.fill_preserve() + accent = state.get("panel_accent", (0.22, 0.78, 0.98)) + ctx.set_source_rgba(accent[0], accent[1], accent[2], 0.80) + ctx.set_line_width(1.8) + ctx.stroke() + + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(14.0) + ctx.set_source_rgba(accent[0], accent[1], accent[2], 1.0) + ctx.move_to(48, panel_y + 30) + ctx.show_text(state.get("panel_title", "LIVE BINARY TELEMETRY")) + + lines = state.get("console_lines", []) + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + ctx.set_font_size(13.0) + ly = panel_y + 58 + for line in lines[:8]: + if line.startswith("[ALLOW]") or "PASS" in line or "APPROVED" in line: + ctx.set_source_rgba(0.32, 0.95, 0.68, 0.98) + elif line.startswith("[DENY]") or "BLOCKED" in line or "403" in line or "BANNED" in line: + ctx.set_source_rgba(1.0, 0.42, 0.48, 0.98) + elif line.startswith("$") or line.startswith(">"): + ctx.set_source_rgba(0.48, 0.85, 1.0, 0.98) + else: + ctx.set_source_rgba(0.86, 0.91, 0.97, 0.95) + ctx.move_to(48, ly) + ctx.show_text(line[:118]) + ly += 23 + + # Bottom-Right Panel: Real-Time Zero-Trust Decision Ledger + rx = 1188 + rw = W - rx - 28 + rounded_rect(ctx, rx, panel_y, rw, 244, 12) + ctx.set_source_rgba(0.025, 0.05, 0.11, 0.90) + ctx.fill_preserve() + ctx.set_source_rgba(0.28, 0.62, 0.90, 0.65) + ctx.set_line_width(1.5) + ctx.stroke() + + allow_cnt = state.get("allow_count", 0) + deny_cnt = state.get("deny_count", 0) + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + ctx.set_font_size(14.0) + ctx.set_source_rgba(0.92, 0.96, 1.0, 1.0) + ctx.move_to(rx + 22, panel_y + 30) + ctx.show_text("ZERO-TRUST PDP LEDGER (REAL EXECUTION)") + + # ALLOW & DENY Counters + ctx.set_source_rgba(0.25, 0.95, 0.66, 1.0) + ctx.move_to(rx + 460, panel_y + 30) + ctx.show_text(f"ALLOW: {allow_cnt}") + ctx.set_source_rgba(1.0, 0.38, 0.45, 1.0) + ctx.move_to(rx + 580, panel_y + 30) + ctx.show_text(f"DENY: {deny_cnt}") + + ledger = state.get("ledger", []) + ctx.select_font_face("DejaVu Sans Mono", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + ctx.set_font_size(12.0) + ay = panel_y + 58 + for entry in ledger[-8:]: + is_allow = entry.get("decision") == "ALLOW" + badge_col = (0.16, 0.85, 0.56) if is_allow else (0.96, 0.28, 0.36) + rounded_rect(ctx, rx + 22, ay - 13, 54, 18, 4) + ctx.set_source_rgba(badge_col[0], badge_col[1], badge_col[2], 0.25) + ctx.fill_preserve() + ctx.set_source_rgba(badge_col[0], badge_col[1], badge_col[2], 0.95) + ctx.set_line_width(1.1) + ctx.stroke() + ctx.move_to(rx + 28, ay) + ctx.show_text(entry.get("decision", "INFO")) + + ctx.set_source_rgba(0.88, 0.93, 0.98, 0.95) + ctx.move_to(rx + 86, ay) + ctx.show_text(f"{entry.get('service', '')} — {entry.get('detail', '')}"[:66]) + ay += 23 + + +# --------------------------------------------------------------------------- +# Main Execution & Video Encoding Pipeline +# --------------------------------------------------------------------------- +def _api_call(base_url: str, path: str, method: str = "GET", payload: dict[str, Any] | None = None) -> tuple[dict[str, Any], int]: + import urllib.request + + t0 = time.time() + data = json.dumps(payload).encode("utf-8") if payload is not None else None + req = urllib.request.Request( + f"{base_url}{path}", + data=data, + headers={"Content-Type": "application/json"} if data else {}, + method=method, + ) + with urllib.request.urlopen(req, timeout=30) as resp: + res = json.loads(resp.read().decode("utf-8")) + elapsed_ms = int((time.time() - t0) * 1000) + return res, elapsed_ms + + +def main() -> int: + import http.server + import threading + + out_mp4 = Path(os.environ.get("OUT_MP4", "/tmp/demo-private-diy-stack.mp4")) + preview_dir = Path(os.environ.get("PREVIEW_DIR", "/tmp/private-diy-3d-previews")) + preview_dir.mkdir(parents=True, exist_ok=True) + + env = dashboard.MeshEnvironment() + dashboard.MESH = env + server: http.server.ThreadingHTTPServer | None = None + try: + print("[1/3] Starting REAL Agent Mesh control plane + 4 sidecars + SQLite ERP + Compliance API...") + env.start() + server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), dashboard.WorkbenchHandler) + port = server.server_address[1] + threading.Thread(target=server.serve_forever, daemon=True).start() + base_url = f"http://127.0.0.1:{port}" + + print("[2/3] Executing all 4 Acts against live Go binaries and capturing real telemetry...") + act1_res, act1_ms = _api_call(base_url, "/api/act1/discover", "POST", {}) + act2_res, act2_ms = _api_call( + base_url, + "/api/act2/run-agent", + "POST", + {"task": "Audit Invoice INV-2026-089 for Acme Robotics, verify SKU-GPU-H200 warehouse stock, and check vendor ACME-01 compliance."}, + ) + act3a_res, _ = _api_call(base_url, "/api/act3/test", "POST", {"check": "3a"}) + act3b_res, _ = _api_call(base_url, "/api/act3/test", "POST", {"check": "3b"}) + act3c_res, act3c_ms = _api_call(base_url, "/api/act3/test", "POST", {"check": "3c"}) + act3d_res, _ = _api_call(base_url, "/api/act3/test", "POST", {"check": "3d"}) + act4_ban_res, _ = _api_call(base_url, "/api/act4/ban", "POST", {}) + state_res, _ = _api_call(base_url, "/api/state", "GET") + + step3_lines = [ln.strip() for ln in act2_res.get("step3_results", "").splitlines() if ln.strip()] + s2_inv = step3_lines[0] if len(step3_lines) > 0 else "[mcp://erp-db/lookup_invoice] -> INV-2026-089 ($148,500.00)" + s2_stk = step3_lines[1] if len(step3_lines) > 1 else "[mcp://erp-db/check_inventory] -> SKU-GPU-H200 (42 units)" + s2_cmp = step3_lines[2] if len(step3_lines) > 2 else "[egress://compliance.internal] -> TIER_1_APPROVED" + final2 = act2_res.get("step4_decision", "APPROVED — Invoice INV-2026-089").splitlines()[0] + + act3d_lines = [ln.strip() for ln in act3d_res.get("output", "").splitlines() if ln.strip()] + audit_events = state_res.get("audit", []) + + # Build timeline of 3D scenes driven by real execution outputs (~56 seconds @ 30fps = 1,680 frames) + ledger: list[dict[str, str]] = [] + scenes: list[dict[str, Any]] = [] + + # Scene 1: Act 1 — Hybrid Cloud & On-Prem Sidecar Enrollment & Discovery (7.5s) + scenes.append({ + "duration": 7.5, + "act_idx": 1, + "cam_start": (-0.18, 0.50, 14.5, (0.0, 0.55, 0.2)), + "cam_end": (0.08, 0.46, 13.6, (0.0, 0.55, 0.2)), + "headline": "Act 1: Sidecar Node Architecture — Safely Across On-Premises & Google Cloud", + "subheadline": "agentmesh-one issues Ed25519 identities & Datalog policy; sidecars discover services via Kademlia DHT", + "panel_title": f"ACT 1 — LIVE SIDECAR PEER IDS & DISCOVERED MESH SERVICES ({act1_ms} ms)", + "panel_accent": (0.22, 0.85, 0.98), + "console_lines": [ + "$ agentmesh-node run --config node-tools.yaml & node-inference.yaml & node-agent.yaml", + f"[ALLOW] node-agent (:19101 Cloud Run) peer={env.agent_peer[:28]}...", + f"[ALLOW] node-inference (:19103 GPU Cluster) peer={env.gpu_peer[:28]}...", + f"[ALLOW] node-tools (:19102 On-Prem) peer={env.tools_peer[:28]}...", + f"[ALLOW] node-external (:19104 External) peer={env.external_peer[:28]}...", + f"> {act2_res.get('step1_discovery', 'Discovered 3 tools on Vault Peer')}", + "> Agent container holds 0 DB credentials, 0 API keys, and 0 site-to-site VPN routes.", + ], + "beams": [ + {"src": POS_CP, "dst": POS_NODE_AGENT, "color": (0.96, 0.78, 0.22), "arc_h": 0.9, "label": "Biscuit + Datalog Sync"}, + {"src": POS_CP, "dst": POS_NODE_INF, "color": (0.96, 0.78, 0.22), "arc_h": 0.9}, + {"src": POS_CP, "dst": POS_NODE_TOOLS, "color": (0.96, 0.78, 0.22), "arc_h": 0.9}, + ], + "shields": [], + "ledger_add": [ + {"decision": "ALLOW", "service": "mesh://dht-discovery", "detail": "4 sidecars enrolled & synced"}, + ], + }) + + # Scene 2: Act 2 (Part A) — Hybrid Reasoning & On-Prem SQLite ERP Queries (8.0s) + scenes.append({ + "duration": 8.0, + "act_idx": 2, + "cam_start": (0.08, 0.46, 13.6, (0.0, 0.55, 0.2)), + "cam_end": (-0.12, 0.48, 13.2, (0.3, 0.55, 0.1)), + "headline": "Act 2: End-to-End Hybrid ReAct Loop — Cloud Agent to On-Prem SQLite ERP", + "subheadline": "agent_harness.py calls 127.0.0.1:19101; sidecar routes to inference://private-llm and mcp://erp-db", + "panel_title": "ACT 2A — LIVE ReAct REASONING (Gemma / DeepSeek) & ON-PREM SQLITE ERP QUERIES", + "panel_accent": (0.22, 0.92, 0.68), + "console_lines": [ + "$ python3 agent_harness.py --sidecar http://127.0.0.1:19101", + f"[ALLOW] POST /v1/chat/completions -> inference://private-llm : {act2_res.get('step2_plan', '')[:80]}", + f"[ALLOW] {s2_inv}", + f"[ALLOW] {s2_stk}", + "> Encrypted Noise/QUIC p2p stream verified by Biscuit RBAC + residency=on-prem label.", + ], + "beams": [ + {"src": POS_AGENT_APP, "dst": POS_NODE_AGENT, "color": (0.22, 0.88, 1.0), "arc_h": 0.4}, + {"src": POS_NODE_AGENT, "dst": POS_NODE_INF, "color": (0.68, 0.42, 1.0), "arc_h": 1.5, "label": "inference://private-llm (ALLOW)"}, + {"src": POS_NODE_INF, "dst": POS_GPU_RACK, "color": (0.68, 0.42, 1.0), "arc_h": 0.45}, + {"src": POS_NODE_AGENT, "dst": POS_NODE_TOOLS, "color": (0.20, 0.92, 0.65), "arc_h": 1.6, "label": "mcp://erp-db (ALLOW)"}, + {"src": POS_NODE_TOOLS, "dst": POS_ERP_DB, "color": (0.20, 0.92, 0.65), "arc_h": 0.5}, + ], + "shields": [], + "ledger_add": [ + {"decision": "ALLOW", "service": "inference://private-llm", "detail": "ReAct Turn 1 reasoning"}, + {"decision": "ALLOW", "service": "mcp://erp-db", "detail": "lookup_invoice(INV-2026-089)"}, + {"decision": "ALLOW", "service": "mcp://erp-db", "detail": "check_inventory(SKU-GPU-H200)"}, + ], + }) + + # Scene 3: Act 2 (Part B) — Vault-Side Secret Brokering to Compliance API (7.5s) + scenes.append({ + "duration": 7.5, + "act_idx": 2, + "cam_start": (-0.12, 0.48, 13.2, (0.3, 0.55, 0.1)), + "cam_end": (0.16, 0.50, 12.8, (1.1, 0.55, -0.4)), + "headline": "Act 2: On-Premises Secret Brokering — Zero Credentials in Agent Container", + "subheadline": "node-tools.yaml injects secrets/compliance-api-key at the on-prem vault boundary for GET /v1/vendors/ACME-01", + "panel_title": f"ACT 2B — VAULT SECRET INJECTION & FINAL AUDIT SYNTHESIS ({act2_ms} ms total)", + "panel_accent": (0.96, 0.78, 0.22), + "console_lines": [ + "[ALLOW] GET /v1/vendors/ACME-01 via egress://compliance.internal", + " -> node-tools injected Authorization: Bearer secrets/compliance-api-key", + f" -> {s2_cmp}", + f"[ALLOW] Final Audit Synthesis: {final2}", + "> Raw API secret never left the on-premises vault node.", + ], + "beams": [ + {"src": POS_NODE_AGENT, "dst": POS_NODE_TOOLS, "color": (0.28, 0.85, 0.98), "arc_h": 1.5, "label": "GET /v1/vendors/ACME-01"}, + {"src": POS_NODE_TOOLS, "dst": POS_COMPLIANCE, "color": (0.98, 0.78, 0.18), "arc_h": 0.65, "label": "+ Bearer secrets/compliance-api-key"}, + ], + "shields": [], + "ledger_add": [ + {"decision": "ALLOW", "service": "egress://compliance.internal", "detail": "GET /v1/vendors/ACME-01 (+Vault Key)"}, + {"decision": "ALLOW", "service": "inference://private-llm", "detail": "Audit APPROVED ($148,500)"}, + ], + }) + + # Scene 4: Act 3a & 3b — Default-Deny on Payroll Vault & HTTP POST Mutation Block (8.5s) + scenes.append({ + "duration": 8.5, + "act_idx": 3, + "cam_start": (0.16, 0.50, 12.8, (1.1, 0.55, -0.4)), + "cam_end": (0.06, 0.52, 13.0, (1.2, 0.55, -0.5)), + "headline": "Act 3a & 3b: Zero-Trust Default-Deny on Service Names & HTTP Methods", + "subheadline": "Blocks mcp://payroll-vault on the same Vault node and blocks POST /v1/vendors/ACME-01 mutations (HTTP 403)", + "panel_title": "ACT 3A & 3B — LIVE DEFAULT-DENY GUARDRAIL VERIFICATION", + "panel_accent": (1.0, 0.35, 0.42), + "console_lines": [ + "$ mcp-client -url http://127.0.0.1:19101/mcp -tool call_remote_tool (mcp://payroll-vault/dump_executive_salaries)", + f"[DENY] 3a Service-Name Default-Deny : {act3a_res.get('output', '')}", + "$ curl -X POST http://127.0.0.1:19101/mesh/.../egress/compliance.internal/v1/vendors/ACME-01", + f"[DENY] 3b HTTP Method Guardrail : {act3b_res.get('output', '')}", + "> Even on the same vault node, ungranted service names and HTTP POST mutations are blocked.", + ], + "beams": [ + {"src": POS_NODE_AGENT, "dst": POS_PAYROLL, "color": (1.0, 0.25, 0.35), "arc_h": 1.5, "deny": True, "label": "mcp://payroll-vault (BLOCKED)"}, + {"src": POS_NODE_AGENT, "dst": POS_COMPLIANCE, "color": (1.0, 0.25, 0.35), "arc_h": 1.2, "deny": True, "label": "POST /v1/vendors (HTTP 403)"}, + ], + "shields": [ + {"pos": POS_PAYROLL, "radius": 66.0, "caption": "3a DENY: payroll-vault"}, + {"pos": POS_COMPLIANCE, "radius": 62.0, "caption": "3b DENY: HTTP 403 POST"}, + ], + "ledger_add": [ + {"decision": "DENY", "service": "mcp://payroll-vault", "detail": "No matching Datalog policy"}, + {"decision": "DENY", "service": "egress://compliance.internal", "detail": "HTTP 403 POST blocked"}, + ], + }) + + # Scene 5: Act 3c — Positive Datalog Label Check Rejects External Peer (7.5s) + scenes.append({ + "duration": 7.5, + "act_idx": 3, + "cam_start": (0.06, 0.52, 13.0, (1.2, 0.55, -0.5)), + "cam_end": (-0.14, 0.49, 13.4, (-0.3, 0.55, -0.6)), + "headline": "Act 3c: Positive Residency & Department Label Enforcement", + "subheadline": "node-tools.yaml enforces check if label(\"residency\", \"on-prem\") and label(\"dept\", \"finance\")", + "panel_title": f"ACT 3C — EXTERNAL PEER (dept=external) REJECTED AT ON-PREM VAULT ({act3c_ms} ms)", + "panel_accent": (1.0, 0.35, 0.42), + "console_lines": [ + "$ mcp-client -url http://127.0.0.1:19104/mcp -tool call_remote_tool (mcp://erp-db/lookup_invoice)", + "[DENY] Caller node-external (dept=external) rejected by node-tools:", + f" {act3c_res.get('output', '')}", + "> Zero-trust Datalog checks verify cryptographic peer labels on every stream.", + ], + "beams": [ + {"src": POS_EXTERNAL, "dst": POS_NODE_TOOLS, "color": (1.0, 0.22, 0.32), "arc_h": 1.35, "deny": True, "label": "dept=external -> erp-db (BLOCKED)"}, + ], + "shields": [ + {"pos": POS_NODE_TOOLS, "radius": 74.0, "caption": "3c DENY: dept!=finance"}, + ], + "ledger_add": [ + {"decision": "DENY", "service": "mcp://erp-db", "detail": "Caller dept=external rejected"}, + ], + }) + + # Scene 6: Act 3d — Task-Scoped Sealed Biscuit (`tar_block`) Blocks Prompt Injection (8.5s) + scenes.append({ + "duration": 8.5, + "act_idx": 3, + "cam_start": (-0.14, 0.49, 13.4, (-0.3, 0.55, -0.6)), + "cam_end": (-0.06, 0.47, 13.0, (-0.8, 0.60, 0.1)), + "headline": "Act 3d: Task-Scoped Sealed Biscuit (tar_block) Stops Prompt Injection", + "subheadline": "RFC 8693 /oauth/token attenuates Biscuit in memory to [lookup_invoice, check_inventory]; blocks wire transfer", + "panel_title": "ACT 3D — RFC 8693 TASK-SCOPED SEALED tar_block BISCUIT GUARDRAIL", + "panel_accent": (0.98, 0.72, 0.18), + "sealed_biscuit": True, + "console_lines": [ + "$ POST http://127.0.0.1:19101/oauth/token (scope='tool:lookup_invoice tool:check_inventory', seal=true)", + *[f"[ALLOW] {ln}" if ln.startswith("1.") else f"[DENY] {ln}" if ln.startswith("2.") else f"> {ln}" for ln in act3d_lines], + ], + "beams": [ + {"src": POS_AGENT_APP, "dst": POS_NODE_AGENT, "color": (1.0, 0.25, 0.35), "arc_h": 0.55, "deny": True, "label": "execute_wire_transfer ($250k) BLOCKED"}, + {"src": POS_NODE_AGENT, "dst": POS_NODE_TOOLS, "color": (0.20, 0.92, 0.65), "arc_h": 1.45, "label": "lookup_invoice (tar_block ALLOW)"}, + ], + "shields": [ + {"pos": POS_NODE_AGENT, "radius": 68.0, "caption": "3d DENY: tar_block Guardrail"}, + ], + "ledger_add": [ + {"decision": "ALLOW", "service": "mcp://erp-db", "detail": "tar_block: lookup_invoice"}, + {"decision": "DENY", "service": "mcp://erp-db", "detail": "tar_block: execute_wire_transfer"}, + ], + }) + + # Scene 7: Act 4 — Correlated Audit Trail & Instant Mesh-Wide Peer Revocation (8.5s) + scenes.append({ + "duration": 8.5, + "act_idx": 4, + "cam_start": (-0.06, 0.47, 13.0, (-0.8, 0.60, 0.1)), + "cam_end": (0.12, 0.51, 14.2, (0.0, 0.55, 0.2)), + "headline": "Act 4: Correlated Audit Trail & Mesh-Wide Peer Revocation (admin ban)", + "subheadline": "audit.py correlates ALLOW/DENY decisions; agentmesh-one admin ban revokes node-external across the mesh", + "panel_title": f"ACT 4 — AUDIT SUMMARY & MESH-WIDE REVOCATION (BANNED PEER {env.external_peer[:24]}...)", + "panel_accent": (0.38, 0.86, 1.0), + "sealed_biscuit": True, + "ext_banned": True, + "console_lines": [ + f"$ agentmesh-one admin ban {env.external_peer[:36]}...", + f"[DENY] {act4_ban_res.get('output', 'Peer banned mesh-wide')}", + f"> Total Live Audit Events Captured: {len(audit_events)} | SQLite wire_transfers rows: {state_res.get('sqlite', {}).get('wire_transfers_count', 0)}", + *[ + f"[{ev['decision']}] {ev['service']} <- {ev['caller']} ({ev['method']})" + for ev in audit_events[-4:] + ], + ], + "beams": [ + {"src": POS_CP, "dst": POS_EXTERNAL, "color": (1.0, 0.22, 0.32), "arc_h": 1.2, "deny": True, "label": "admin ban -> REVOKED"}, + ], + "shields": [ + {"pos": POS_EXTERNAL, "radius": 72.0, "caption": "PEER REVOKED & BANNED"}, + ], + "ledger_add": [ + {"decision": "DENY", "service": "admin://ban-peer", "detail": f"Banned {env.external_peer[:18]}..."}, + ], + }) + + # 3. Render 1920x1080 @ 30fps directly into ffmpeg + total_dur = sum(s["duration"] for s in scenes) + total_frames = int(total_dur * FPS) + print(f"[3/3] Rendering {total_frames} frames ({total_dur:.1f}s @ {FPS}fps, 1920x1080) via Cairo 3D + ffmpeg...") + + ffmpeg_cmd = [ + "ffmpeg", + "-y", + "-f", "rawvideo", + "-vcodec", "rawvideo", + "-pix_fmt", "bgr0", + "-s", f"{W}x{H}", + "-r", str(FPS), + "-i", "-", + "-c:v", "libx264", + "-pix_fmt", "yuv420p", + "-preset", "fast", + "-crf", "24", + "-movflags", "+faststart", + str(out_mp4), + ] + proc = subprocess.Popen(ffmpeg_cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE) + assert proc.stdin is not None + + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, W, H) + ctx = cairo.Context(surface) + cam = Camera3D() + + global_frame = 0 + allow_count = 0 + deny_count = 0 + + for s_idx, scene in enumerate(scenes): + for entry in scene.get("ledger_add", []): + ledger.append(entry) + if entry["decision"] == "ALLOW": + allow_count += 1 + elif entry["decision"] == "DENY": + deny_count += 1 + + n_frames = int(scene["duration"] * FPS) + c0 = scene["cam_start"] + c1 = scene["cam_end"] + + for f in range(n_frames): + u = smoothstep(f / max(1, n_frames - 1)) + t_sec = global_frame / FPS + yaw = lerp(c0[0], c1[0], u) + 0.03 * math.sin(t_sec * 0.7) + pitch = lerp(c0[1], c1[1], u) + dist = lerp(c0[2], c1[2], u) + tx = lerp(c0[3][0], c1[3][0], u) + ty = lerp(c0[3][1], c1[3][1], u) + tz = lerp(c0[3][2], c1[3][2], u) + cam.set_pose(yaw, pitch, dist, (tx, ty, tz)) + + frame_state = { + "act_idx": scene["act_idx"], + "headline": scene["headline"], + "subheadline": scene["subheadline"], + "panel_title": scene["panel_title"], + "panel_accent": scene["panel_accent"], + "console_lines": scene["console_lines"], + "beams": scene["beams"], + "shields": scene["shields"], + "sealed_biscuit": scene.get("sealed_biscuit", False), + "ext_banned": scene.get("ext_banned", False), + "allow_count": allow_count, + "deny_count": deny_count, + "ledger": ledger, + } + render_frame(ctx, cam, t_sec, frame_state) + proc.stdin.write(surface.get_data()) + + # Save a preview PNG at the midpoint of each scene + if f == n_frames // 2: + surface.write_to_png(str(preview_dir / f"scene_{s_idx + 1}.png")) + + global_frame += 1 + + proc.stdin.close() + stderr_out = proc.stderr.read().decode("utf-8", errors="replace") if proc.stderr else "" + rc = proc.wait() + if rc != 0: + raise RuntimeError(f"ffmpeg exited with {rc}: {stderr_out}") + + print(f"Successfully rendered 3D live-execution video to {out_mp4} ({out_mp4.stat().st_size / (1024*1024):.2f} MB)") + return 0 + finally: + if server is not None: + server.shutdown() + env.stop() + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/development/examples/private-diy-stack/run.sh b/development/examples/private-diy-stack/run.sh new file mode 100755 index 00000000..877b35f3 --- /dev/null +++ b/development/examples/private-diy-stack/run.sh @@ -0,0 +1,332 @@ +#!/usr/bin/env bash +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Private DIY Enterprise Stack — End-to-End Runner +# +# Demonstrates how an enterprise connects three open layers into a zero-trust AI +# workforce running safely across on-premises infrastructure and cloud: +# 1. Reasoning Layer: Open-weights LLM (Gemma 3 / DeepSeek-R1) on Cloud Run, +# GKE, or on-prem GPUs published to the mesh by a GPU sidecar (node-inference.yaml). +# 2. Orchestration Layer: Self-hosted Agent Harness (agent_harness.py) that +# talks ONLY to its local sidecar (127.0.0.1:19101/mcp and /v1) with zero +# hardcoded database credentials or network topology knowledge. +# 3. Zero-Trust Fabric: agentmesh-one (Control Plane + Router) and +# node-tools.yaml enforcing cryptographic Biscuit identities, Default-Deny +# service-name routing, data residency labels, and per-task tar_block limits. + +set -euo pipefail + +# Local simulation execution: ensure no corporate HTTP proxy intercepts 127.0.0.1. +unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY +export NO_PROXY="127.0.0.1,localhost" +export no_proxy="127.0.0.1,localhost" + +INTERACTIVE=0 +if [[ "${1:-}" == "--interactive" ]]; then + INTERACTIVE=1 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" +BIN_DIR="${BIN_DIR:-${REPO_ROOT}/bin}" +AGENTMESH_ONE="${BIN_DIR}/agentmesh-one" +AGENTMESH_NODE="${BIN_DIR}/agentmesh-node" +MCP_CLIENT="${BIN_DIR}/mcp-client" +WORK_DIR="${WORK_DIR:-$(mktemp -d /tmp/sam-private-diy-XXXXXX)}" + +export ERP_DB_PATH="${WORK_DIR}/erp.db" +export ERP_MCP_PORT="${ERP_MCP_PORT:-18890}" +export COMPLIANCE_API_PORT="${COMPLIANCE_API_PORT:-18891}" +export PRIVATE_LLM_PORT="${PRIVATE_LLM_PORT:-18892}" +export LLM_MODEL="${LLM_MODEL:-deepseek-r1:1.5b}" +export COMPLIANCE_API_SECRET="private-vault-secret-2026" + +step_pause() { + if [[ "${INTERACTIVE}" -eq 1 ]]; then + echo "" + read -r -p " [Press ENTER to continue to the next act...] " _ + echo "" + fi +} + +cleanup() { + for pidfile in "${WORK_DIR}"/*.pid; do + if [[ -f "${pidfile}" ]]; then + local pid + pid="$(cat "${pidfile}")" + kill -9 "${pid}" 2>/dev/null || true + wait "${pid}" 2>/dev/null || true + fi + done + if [[ "${KEEP_WORK_DIR:-0}" != "1" ]]; then + rm -rf "${WORK_DIR}" + fi +} +trap cleanup EXIT + +if [[ ! -x "${AGENTMESH_ONE}" || ! -x "${AGENTMESH_NODE}" || ! -x "${MCP_CLIENT}" ]]; then + echo "Building agentmesh-one, agentmesh-node, and mcp-client..." + make -C "${REPO_ROOT}" build OUT_DIR="${BIN_DIR}" +fi + +mkdir -p "${WORK_DIR}/secrets" +printf '%s' "${COMPLIANCE_API_SECRET}" > "${WORK_DIR}/secrets/compliance-api-key" +chmod 600 "${WORK_DIR}/secrets/compliance-api-key" + +echo "1) Starting On-Prem & Cloud Backends (SQLite ERP MCP, Compliance REST API, and ${LLM_MODEL} Reasoning Engine)..." +python3 "${SCRIPT_DIR}/backends.py" >"${WORK_DIR}/backends.log" 2>&1 & +echo $! > "${WORK_DIR}/backends.pid" + +for _ in $(seq 1 60); do + if curl -sf "http://127.0.0.1:${ERP_MCP_PORT}/healthz" >/dev/null && \ + curl -sf "http://127.0.0.1:${COMPLIANCE_API_PORT}/healthz" >/dev/null && \ + curl -sf "http://127.0.0.1:${PRIVATE_LLM_PORT}/healthz" >/dev/null; then + break + fi + sleep 0.2 +done + +CP_PORT="${CP_PORT:-18095}" +CP_URL="http://127.0.0.1:${CP_PORT}" +echo "2) Starting Private Control Plane & Mesh Router (agentmesh-one on ${CP_URL})..." +"${AGENTMESH_ONE}" \ + --data-dir "${WORK_DIR}/one" \ + --port "${CP_PORT}" \ + --policy-file "${SCRIPT_DIR}/policy.json" \ + --no-join-token \ + --enroll-qr=false \ + --log-level info >"${WORK_DIR}/agentmesh-one.log" 2>&1 & +echo $! > "${WORK_DIR}/agentmesh-one.pid" + +for _ in $(seq 1 80); do + if [[ -s "${WORK_DIR}/one/admin-token" ]] && grep -q "Agent Mesh standalone mesh is ready" "${WORK_DIR}/agentmesh-one.log" 2>/dev/null; then + break + fi + sleep 0.25 +done + +echo "agent-sidecar-secret" > "${WORK_DIR}/agent-api.token" +echo "gpu-sidecar-secret" > "${WORK_DIR}/gpu-api.token" +echo "vault-sidecar-secret" > "${WORK_DIR}/vault-api.token" +echo "external-sidecar-secret" > "${WORK_DIR}/external-api.token" +chmod 600 "${WORK_DIR}"/*.token + +create_bootstrap_token() { + local desc="$1" + local out="$2" + "${AGENTMESH_ONE}" token create \ + --server "${CP_URL}" \ + --data-dir "${WORK_DIR}/one" \ + --max-usages 1 \ + --description "${desc}" 2>/dev/null | awk '/^Token:/ {print $2}' > "${out}" + chmod 600 "${out}" +} + +create_bootstrap_token "agent-workstation-sidecar" "${WORK_DIR}/agent.bootstrap" +create_bootstrap_token "gpu-pool-inference-sidecar" "${WORK_DIR}/gpu.bootstrap" +create_bootstrap_token "vault-tools-sidecar" "${WORK_DIR}/vault.bootstrap" +create_bootstrap_token "external-dept-sidecar" "${WORK_DIR}/external.bootstrap" + +echo "" +echo "================================================================================" +echo " ACT 1: The Sidecar Node Architecture — Connecting Agent, GPU & Private Tools" +echo "================================================================================" +echo "" +echo "--> Enrolling 3 independent agentmesh-node sidecars into the private mesh:" +echo " 1. Vault Tool Sidecar (node-tools.yaml) -> publishes mcp://erp-db, mcp://payroll-vault & egress://compliance.internal" +echo " 2. GPU Reasoning Sidecar (node-inference.yaml) -> publishes inference://private-llm (${LLM_MODEL})" +echo " 3. Agent Harness Sidecar (node-agent.yaml) -> exposes 127.0.0.1:19101/mcp and 127.0.0.1:19101/v1 to the local agent" + +"${AGENTMESH_NODE}" run \ + --control-plane "${CP_URL}" \ + --insecure-control-plane \ + --bootstrap-token-path "${WORK_DIR}/vault.bootstrap" \ + --config "${SCRIPT_DIR}/node-tools.yaml" \ + --secrets-dir "${WORK_DIR}/secrets" \ + --data-dir "${WORK_DIR}/node-tools" \ + --bind-addr 127.0.0.1:19102 \ + --socket-path="" \ + --listen "/ip4/127.0.0.1/udp/0/quic-v1,/ip4/127.0.0.1/tcp/0" \ + --api-token-path "${WORK_DIR}/vault-api.token" \ + --allow-loopback \ + --control-plane-sync-interval 5s >"${WORK_DIR}/node-tools.log" 2>&1 & +echo $! > "${WORK_DIR}/node-tools.pid" + +"${AGENTMESH_NODE}" run \ + --control-plane "${CP_URL}" \ + --insecure-control-plane \ + --bootstrap-token-path "${WORK_DIR}/gpu.bootstrap" \ + --config "${SCRIPT_DIR}/node-inference.yaml" \ + --data-dir "${WORK_DIR}/node-inference" \ + --bind-addr 127.0.0.1:19103 \ + --socket-path="" \ + --listen "/ip4/127.0.0.1/udp/0/quic-v1,/ip4/127.0.0.1/tcp/0" \ + --api-token-path "${WORK_DIR}/gpu-api.token" \ + --allow-loopback \ + --control-plane-sync-interval 5s >"${WORK_DIR}/node-inference.log" 2>&1 & +echo $! > "${WORK_DIR}/node-inference.pid" + +"${AGENTMESH_NODE}" run \ + --control-plane "${CP_URL}" \ + --insecure-control-plane \ + --bootstrap-token-path "${WORK_DIR}/agent.bootstrap" \ + --config "${SCRIPT_DIR}/node-agent.yaml" \ + --data-dir "${WORK_DIR}/node-agent" \ + --bind-addr 127.0.0.1:19101 \ + --socket-path="" \ + --listen "/ip4/127.0.0.1/udp/0/quic-v1,/ip4/127.0.0.1/tcp/0" \ + --api-token-path "${WORK_DIR}/agent-api.token" \ + --allow-loopback \ + --control-plane-sync-interval 5s >"${WORK_DIR}/node-agent.log" 2>&1 & +echo $! > "${WORK_DIR}/node-agent.pid" + +VAULT_PEER="" +GPU_PEER="" +for _ in $(seq 1 50); do + MCP_DISC="$(curl -sf -H "X-Mesh-Authentication: Bearer agent-sidecar-secret" \ + "http://127.0.0.1:19101/mesh/service/discover?type=mcp&name=erp-db" 2>/dev/null || true)" + INF_DISC="$(curl -sf -H "X-Mesh-Authentication: Bearer agent-sidecar-secret" \ + "http://127.0.0.1:19101/mesh/service/discover?type=inference&name=private-llm" 2>/dev/null || true)" + VAULT_PEER="$(echo "${MCP_DISC}" | jq -r '.[0].peer_id // empty' 2>/dev/null || true)" + GPU_PEER="$(echo "${INF_DISC}" | jq -r '.[0].peer_id // empty' 2>/dev/null || true)" + if [[ -n "${VAULT_PEER}" && -n "${GPU_PEER}" ]]; then + break + fi + sleep 0.5 +done + +echo "" +echo " Discovered via Kademlia DHT / GossipSub from Agent's local sidecar:" +echo " • Vault Tool Node PeerID : ${VAULT_PEER} (mcp://erp-db, egress://compliance.internal)" +echo " • Bare-Metal GPU Node PeerID : ${GPU_PEER} (inference://private-llm -> ${LLM_MODEL})" +step_pause + +echo "" +echo "================================================================================" +echo " ACT 2: Private DIY Execution — DeepSeek Reasoning + Harness + Agent Mesh" +echo "================================================================================" +echo "" +echo "--> Running self-hosted agent_harness.py (talks ONLY to 127.0.0.1:19101/mcp and /v1):" +AGENTMESH_SIDECAR_URL="http://127.0.0.1:19101" \ +AGENTMESH_API_TOKEN="agent-sidecar-secret" \ +LLM_MODEL="${LLM_MODEL}" \ + python3 "${SCRIPT_DIR}/agent_harness.py" +step_pause + +echo "" +echo "================================================================================" +echo " ACT 3: Zero-Trust Identity & Default-Deny Policy (No Free-Roaming LLMs)" +echo "================================================================================" +echo "" +echo "--> [3a. Default-Deny on Service Names (mcp://payroll-vault)]" +echo " Even though mcp://payroll-vault is registered on the same Vault node," +echo " policy.json only grants mcp://erp-db to this role. Attempting to call payroll-vault:" +set +e +PAYROLL_OUT="$("${MCP_CLIENT}" \ + -url "http://127.0.0.1:19101/mcp" \ + -token-path "${WORK_DIR}/agent-api.token" \ + -tool "call_remote_tool" \ + -args "{\"peer_id\":\"${VAULT_PEER}\",\"tool_name\":\"mcp://payroll-vault/dump_executive_salaries\",\"arguments\":{}}" 2>&1)" +set -e +echo " Result -> $(echo "${PAYROLL_OUT}" | tail -n 1)" + +echo "" +echo "--> [3b. HTTP Method/Path Guardrail on Internal API (egress://compliance.internal)]" +echo " policy.json permits GET /v1/vendors/*, but denies POST mutations:" +HTTP_CODE="$(curl -s -o "${WORK_DIR}/post-deny.out" -w '%{http_code}' \ + -X POST \ + -H "X-Mesh-Authentication: Bearer agent-sidecar-secret" \ + "http://127.0.0.1:19101/mesh/${VAULT_PEER}/egress/compliance.internal/v1/vendors/ACME-01")" +echo " POST /mesh/${VAULT_PEER:0:12}…/egress/compliance.internal/v1/vendors/ACME-01 -> HTTP ${HTTP_CODE} ($(tr -d '\n' < "${WORK_DIR}/post-deny.out"))" + +echo "" +echo "--> [3c. Department Isolation Boundary (dept=external rejected by Vault Node Datalog Check)]" +"${AGENTMESH_NODE}" run \ + --control-plane "${CP_URL}" \ + --insecure-control-plane \ + --bootstrap-token-path "${WORK_DIR}/external.bootstrap" \ + --config "${SCRIPT_DIR}/node-external.yaml" \ + --data-dir "${WORK_DIR}/node-external" \ + --bind-addr 127.0.0.1:19104 \ + --socket-path="" \ + --listen "/ip4/127.0.0.1/udp/0/quic-v1,/ip4/127.0.0.1/tcp/0" \ + --api-token-path "${WORK_DIR}/external-api.token" \ + --allow-loopback \ + --control-plane-sync-interval 5s >"${WORK_DIR}/node-external.log" 2>&1 & +echo $! > "${WORK_DIR}/node-external.pid" + +for _ in $(seq 1 40); do + grep -q "Agent Mesh Node Online" "${WORK_DIR}/node-external.log" 2>/dev/null && break + sleep 0.25 +done +EXTERNAL_PEER="$(awk '/PeerID:/ {print $2; exit}' "${WORK_DIR}/node-external.log")" + +set +e +EXT_OUT="$("${MCP_CLIENT}" \ + -url "http://127.0.0.1:19104/mcp" \ + -token-path "${WORK_DIR}/external-api.token" \ + -tool "call_remote_tool" \ + -args "{\"peer_id\":\"${VAULT_PEER}\",\"tool_name\":\"mcp://erp-db/lookup_invoice\",\"arguments\":{\"invoice_id\":\"INV-2026-089\"}}" 2>&1)" +set -e +echo " Caller with dept=external calling mcp://erp-db -> $(echo "${EXT_OUT}" | tail -n 1)" + +echo "" +echo "--> [3d. Per-Task Sealed Biscuit (tar_block) — Blocking Prompt-Injected Wire Transfers]" +echo " Minting a sealed Task Biscuit via RFC 8693 POST /oauth/token narrowed to read-only tools:" +TASK_BISCUIT="$(curl -sf -X POST "http://127.0.0.1:19101/oauth/token" \ + -H "Authorization: Bearer agent-sidecar-secret" \ + -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ + -d "resource=mcp://erp-db" \ + -d "scope=tool:lookup_invoice tool:check_inventory" \ + -d "seal=true" | jq -r '.access_token')" +printf '%s' "${TASK_BISCUIT}" > "${WORK_DIR}/task-biscuit.token" +chmod 600 "${WORK_DIR}/task-biscuit.token" +echo " Sealed Task Biscuit minted (prefix: ${TASK_BISCUIT:0:28}…)" + +READ_OK="$("${MCP_CLIENT}" \ + -url "http://127.0.0.1:19101/mcp" \ + -token-path "${WORK_DIR}/task-biscuit.token" \ + -tool "call_remote_tool" \ + -args "{\"peer_id\":\"${VAULT_PEER}\",\"tool_name\":\"mcp://erp-db/lookup_invoice\",\"arguments\":{\"invoice_id\":\"INV-2026-089\"}}" | tail -n 1)" +echo " 1. Allowed read tool (lookup_invoice) -> ${READ_OK}" + +set +e +WIRE_DENY="$("${MCP_CLIENT}" \ + -url "http://127.0.0.1:19101/mcp" \ + -token-path "${WORK_DIR}/task-biscuit.token" \ + -tool "call_remote_tool" \ + -args "{\"peer_id\":\"${VAULT_PEER}\",\"tool_name\":\"mcp://erp-db/execute_wire_transfer\",\"arguments\":{\"invoice_id\":\"INV-2026-089\",\"amount_usd\":250000,\"iban\":\"DE89-ATTACKER\"}}" 2>&1)" +set -e +WIRE_COUNT="$(python3 -c "import sqlite3; c=sqlite3.connect('${ERP_DB_PATH}'); print(c.execute('SELECT COUNT(*) FROM wire_transfers').fetchone()[0])")" +echo " 2. Prompt-injected tool (execute_wire_transfer) -> $(echo "${WIRE_DENY}" | tail -n 1)" +echo " 3. SQLite wire_transfers table row count -> ${WIRE_COUNT} (database untouched!)" +step_pause + +echo "" +echo "================================================================================" +echo " ACT 4: Private Day-2 Operations — Correlated Audit Trail & Kill-Switch" +echo "================================================================================" +echo "" +echo "--> Correlated ALLOW / DENY decisions across GPU and Vault Sidecars (audit.py):" +cat "${WORK_DIR}/node-inference.log" "${WORK_DIR}/node-tools.log" "${WORK_DIR}/node-agent.log" | python3 "${SCRIPT_DIR}/audit.py" | sed 's/^/ /' + +echo "" +echo "--> Revoking unauthorized external node (${EXTERNAL_PEER}) mesh-wide via agentmesh-one admin ban:" +"${AGENTMESH_ONE}" admin ban "${EXTERNAL_PEER}" \ + --server "${CP_URL}" \ + --data-dir "${WORK_DIR}/one" | sed 's/^/ /' + +echo "" +echo "Private DIY Enterprise Stack completed all 4 acts successfully." diff --git a/development/examples/private-diy-stack/static/app.js b/development/examples/private-diy-stack/static/app.js new file mode 100644 index 00000000..19d6f5c9 --- /dev/null +++ b/development/examples/private-diy-stack/static/app.js @@ -0,0 +1,240 @@ +(function () { + "use strict"; + + const elNodeCards = document.getElementById("node-cards-container"); + const elCatalogOut = document.getElementById("act1-catalog-output"); + const elAct2Steps = document.getElementById("act2-steps-container"); + const elTaskInput = document.getElementById("input-agent-task"); + const elAuditBody = document.getElementById("audit-table-body"); + const elMetricInvoices = document.getElementById("metric-invoices"); + const elMetricWires = document.getElementById("metric-wires"); + const elMetricBan = document.getElementById("metric-ban-status"); + const elMeshStatusText = document.getElementById("mesh-status-text"); + + function highlightTopology(mode) { + const boxes = ["box-cp", "box-agent", "box-gpu", "box-vault"]; + const links = ["link-cp-agent", "link-cp-gpu", "link-cp-vault", "link-agent-gpu", "link-agent-vault"]; + boxes.forEach((id) => { + const el = document.getElementById(id); + if (el) el.classList.remove("active-node", "denied-node"); + }); + links.forEach((id) => { + const el = document.getElementById(id); + if (el) el.classList.remove("link-active", "link-deny"); + }); + + if (mode === "discover" || mode === "react") { + document.getElementById("box-agent").classList.add("active-node"); + document.getElementById("box-gpu").classList.add("active-node"); + document.getElementById("box-vault").classList.add("active-node"); + document.getElementById("link-agent-gpu").classList.add("link-active"); + document.getElementById("link-agent-vault").classList.add("link-active"); + } else if (mode === "deny-vault") { + document.getElementById("box-agent").classList.add("active-node"); + document.getElementById("box-vault").classList.add("denied-node"); + document.getElementById("link-agent-vault").classList.add("link-deny"); + } else if (mode === "ban") { + document.getElementById("box-cp").classList.add("denied-node"); + } + } + + function escapeHtml(str) { + return String(str || "") + .replace(/&/g, "&") + .replace(//g, ">"); + } + + async function refreshState() { + try { + const res = await fetch("/api/state"); + const data = await res.json(); + + if (data.nodes && elNodeCards) { + elNodeCards.innerHTML = data.nodes + .map( + (n) => ` +
+
+ ${escapeHtml(n.title)} + ${n.banned ? "BANNED" : "ONLINE"} +
+
${escapeHtml(n.short_peer)}
+
+ ${(n.labels || []).map((l) => `${escapeHtml(l)}`).join("")} +
+
+ ` + ) + .join(""); + } + + if (data.sqlite) { + elMetricInvoices.textContent = `${data.sqlite.invoices_count} rows ($48,500 pending)`; + elMetricWires.textContent = `${data.sqlite.wire_transfers_count} rows (Untouched)`; + } + elMetricBan.textContent = data.external_banned ? "BANNED (Revoked)" : "Enrolled (dept=external)"; + elMeshStatusText.textContent = data.external_banned + ? "Mesh Online · 3 Active Sidecars · 1 Peer Banned" + : "Mesh Online · 4 Sidecars Enrolled"; + + if (Array.isArray(data.audit) && elAuditBody) { + if (data.audit.length === 0) { + elAuditBody.innerHTML = `No sidecar audit events recorded yet. Run an Act to generate traffic.`; + } else { + elAuditBody.innerHTML = data.audit + .slice() + .reverse() + .map( + (ev) => ` + + ${escapeHtml(ev.decision)} + ${escapeHtml(ev.caller)} + ${escapeHtml(ev.method)} + ${escapeHtml(ev.service)} + + ` + ) + .join(""); + } + } + } catch (err) { + console.error("Failed to refresh state:", err); + } + } + + async function runAct1() { + const btn = document.getElementById("btn-act1-discover"); + btn.disabled = true; + highlightTopology("discover"); + elCatalogOut.textContent = "Querying local sidecar http://127.0.0.1:19101/mcp (find_remote_tools) & http://127.0.0.1:19101/v1/models..."; + try { + const res = await fetch("/api/act1/discover", { method: "POST" }); + const data = await res.json(); + elCatalogOut.textContent = data.summary || JSON.stringify(data, null, 2); + await refreshState(); + } finally { + btn.disabled = false; + } + } + + async function runAct2() { + const btn = document.getElementById("btn-act2-run"); + btn.disabled = true; + highlightTopology("react"); + elAct2Steps.innerHTML = ` +
+
Executing agent_harness.py against 127.0.0.1:19101...
+
+ `; + try { + const res = await fetch("/api/act2/run-agent", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ task: elTaskInput.value }), + }); + const data = await res.json(); + elAct2Steps.innerHTML = ` +
+
+ Step 1 · Local MCP Discovery (http://127.0.0.1:19101/mcp) + ALLOW +
+
${escapeHtml(data.step1_discovery)}
+
+
+
+ Step 2 · Self-Hosted Reasoning Plan (inference://private-llm → deepseek-r1:1.5b) + ALLOW +
+
<think>\n${escapeHtml(data.step2_think)}\n</think>
+
${escapeHtml(data.step2_plan)}
+
+
+
+ Step 3 · Mesh Tool & Internal API Execution (mcp://erp-db + egress://compliance.internal) + ALLOW + SECRET INJECTED +
+
${escapeHtml(data.step3_results)}
+
+
+
+ Step 4 · Final Audit Synthesis (deepseek-r1:1.5b) + VERIFIED +
+
<think>\n${escapeHtml(data.step4_think)}\n</think>
+
${escapeHtml(data.step4_decision)}
+
+ `; + await refreshState(); + } finally { + btn.disabled = false; + } + } + + async function runGuardrailCheck(checkId) { + const resultEl = document.getElementById(`result-${checkId}`); + if (resultEl) { + resultEl.textContent = "Testing policy guardrail against live Vault sidecar..."; + } + highlightTopology("deny-vault"); + const res = await fetch("/api/act3/test", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ check: checkId }), + }); + const data = await res.json(); + if (resultEl) { + resultEl.textContent = data.output; + resultEl.classList.add("is-denied"); + } + await refreshState(); + } + + async function runAct4Ban() { + const btn = document.getElementById("btn-act4-ban"); + btn.disabled = true; + highlightTopology("ban"); + try { + await fetch("/api/act4/ban", { method: "POST" }); + await refreshState(); + } finally { + btn.disabled = false; + } + } + + async function runAllActsSequentially() { + const btn = document.getElementById("btn-run-all-acts"); + btn.disabled = true; + try { + await runAct1(); + await runAct2(); + await runGuardrailCheck("3a"); + await runGuardrailCheck("3b"); + await runGuardrailCheck("3c"); + await runGuardrailCheck("3d"); + await runAct4Ban(); + } finally { + btn.disabled = false; + } + } + + document.getElementById("btn-act1-discover").addEventListener("click", runAct1); + document.getElementById("btn-act2-run").addEventListener("click", runAct2); + document.getElementById("btn-test-3a").addEventListener("click", () => runGuardrailCheck("3a")); + document.getElementById("btn-test-3b").addEventListener("click", () => runGuardrailCheck("3b")); + document.getElementById("btn-test-3c").addEventListener("click", () => runGuardrailCheck("3c")); + document.getElementById("btn-test-3d").addEventListener("click", () => runGuardrailCheck("3d")); + document.getElementById("btn-act3-run-all").addEventListener("click", async () => { + await runGuardrailCheck("3a"); + await runGuardrailCheck("3b"); + await runGuardrailCheck("3c"); + await runGuardrailCheck("3d"); + }); + document.getElementById("btn-act4-ban").addEventListener("click", runAct4Ban); + document.getElementById("btn-run-all-acts").addEventListener("click", runAllActsSequentially); + document.getElementById("btn-refresh-state").addEventListener("click", refreshState); + + refreshState(); + setInterval(refreshState, 4000); +})(); diff --git a/development/examples/private-diy-stack/static/index.html b/development/examples/private-diy-stack/static/index.html new file mode 100644 index 00000000..dab4cafc --- /dev/null +++ b/development/examples/private-diy-stack/static/index.html @@ -0,0 +1,254 @@ + + + + + + Private DIY Enterprise Stack — Agent Mesh Live Workbench + + + + + + + +
+
+
SAM
+
+

Private DIY Enterprise Stack — Live Mesh Workbench

+
+ Self-Hosted Reasoning (deepseek-r1:1.5b / gemma3) + Agent Harness + agentmesh-node Sidecars (Safely On-Premises & in Cloud) +
+
+
+
+
+ + Mesh Online · 4 Sidecars Enrolled +
+ + +
+
+ +
+ +
+ +
+
+
+ Act 1 +

The "Sidecar" Node Architecture & P2P Discovery

+
+ +
+
+ + + + + + + + + + + Control Plane & Router (agentmesh-one) + Biscuit Authority · Datalog RBAC policy.json + + + + 1. Cloud / Workstation (node-agent) + agent_harness.py → 127.0.0.1:19101 + • Loopback MCP (/mcp) + • Loopback OpenAI (/v1) + residency=on-prem · dept=finance + + + + 2. Cloud / On-Prem GPU (node-inference) + inference://private-llm (Gemma/DeepSeek) + check if label("residency", "on-prem") + + + + 3. On-Prem Vault Zone (node-tools) + mcp://erp-db · mcp://payroll-vault + egress://compliance.internal (+Secret) + check if label("dept", "finance") + + +
+
Click "Discover Mesh Catalog (/mcp)" or "Run All 4 Acts Automatically" to inspect live Kademlia DHT & GossipSub discovery from 127.0.0.1:19101/mcp.
+
+
+ + +
+
+
+ Act 2 +

Private DIY Execution — DeepSeek Reasoning + Harness + Mesh

+
+ +
+
+
+ +
+
+
+
+ Ready to Execute Self-Hosted ReAct Loop (agent_harness.py) + 127.0.0.1:19101 +
+
+ The agent process holds zero database credentials and zero peer IP addresses. It queries its local sidecar at 127.0.0.1:19101/mcp for tools and 127.0.0.1:19101/v1/chat/completions for deepseek-r1:1.5b reasoning. +
+
+
+
+
+
+ + +
+ +
+
+
+ Act 3 +

Zero-Trust Identity & Default-Deny Policy Simulator

+
+ +
+
+
+ +
+
+

3a. Default-Deny Service Name

+

+ Call mcp://payroll-vault hosted on the same Vault sidecar as mcp://erp-db. +

+
+
Not tested yet.
+ +
+ + +
+
+

3b. HTTP Method/Path Guardrail

+

+ policy.json allows GET /v1/vendors/* on egress://compliance.internal, blocking POST. +

+
+
Not tested yet.
+ +
+ + +
+
+

3c. Department Isolation Boundary

+

+ Caller enrolled with dept=external attempts to invoke mcp://erp-db on the Finance Vault node. +

+
+
Not tested yet.
+ +
+ + +
+
+

3d. Per-Task Sealed Biscuit (tar_block)

+

+ Mint RFC 8693 Task Biscuit narrowed to read tools; block prompt-injected execute_wire_transfer. +

+
+
Not tested yet.
+ +
+
+
+
+ + +
+
+
+ Act 4 +

Correlated Sidecar Audit Trail & Mesh-Wide Kill-Switch

+
+ +
+
+
+
+
ERP Invoices (SQLite)
+
2 rows
+
+
+
Wire Transfers Executed
+
0 rows (Protected)
+
+
+
External Peer Status
+
Enrolled
+
+
+ +
+ + + + + + + + + + + + + + +
DecisionCaller / Policy LayerMethod / OperationTarget Service
Waiting for mesh activity...
+
+
+
+
+
+ + + + diff --git a/development/examples/private-diy-stack/static/styles.css b/development/examples/private-diy-stack/static/styles.css new file mode 100644 index 00000000..d0e6c794 --- /dev/null +++ b/development/examples/private-diy-stack/static/styles.css @@ -0,0 +1,557 @@ +:root { + --bg-page: hsl(210, 20%, 97%); + --bg-surface: hsl(0, 0%, 100%); + --bg-subtle: hsl(210, 18%, 94%); + --bg-terminal: hsl(215, 28%, 10%); + --bg-terminal-header: hsl(215, 25%, 15%); + --text-primary: hsl(215, 28%, 12%); + --text-secondary: hsl(215, 16%, 38%); + --text-muted: hsl(215, 14%, 52%); + --text-terminal: hsl(210, 25%, 92%); + --border-subtle: hsl(214, 18%, 86%); + --border-strong: hsl(214, 18%, 74%); + --accent-primary: hsl(212, 82%, 38%); + --accent-primary-hover: hsl(212, 85%, 31%); + --accent-primary-soft: hsl(212, 80%, 94%); + --status-allow: hsl(152, 68%, 28%); + --status-allow-bg: hsl(152, 60%, 93%); + --status-deny: hsl(354, 72%, 40%); + --status-deny-bg: hsl(354, 78%, 95%); + --status-warn: hsl(34, 84%, 34%); + --status-warn-bg: hsl(38, 90%, 93%); + --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.05); + --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.07); + --radius-sm: 6px; + --radius-md: 10px; + --font-sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + --font-mono: "JetBrains Mono", "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + background-color: var(--bg-page); + color: var(--text-primary); + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} + +/* Header */ +.topbar { + background: var(--bg-surface); + border-bottom: 1px solid var(--border-subtle); + padding: 14px 24px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + flex-wrap: wrap; + position: sticky; + top: 0; + z-index: 20; + box-shadow: var(--shadow-sm); +} + +.brand-group { + display: flex; + align-items: center; + gap: 14px; +} + +.brand-mark { + width: 34px; + height: 34px; + border-radius: var(--radius-sm); + background: var(--accent-primary); + color: #fff; + font-family: var(--font-mono); + font-weight: 700; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; + letter-spacing: -0.03em; +} + +.brand-title h1 { + font-size: 17px; + font-weight: 600; + letter-spacing: -0.015em; + color: var(--text-primary); +} + +.brand-subtitle { + font-size: 12px; + color: var(--text-secondary); +} + +.topbar-actions { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +.mesh-health-badge { + display: inline-flex; + align-items: center; + gap: 7px; + padding: 6px 11px; + border-radius: var(--radius-sm); + font-family: var(--font-mono); + font-size: 12px; + font-weight: 500; + background: var(--status-allow-bg); + color: var(--status-allow); + border: 1px solid rgba(22, 120, 74, 0.22); +} + +.status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--status-allow); +} + +/* Buttons */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 7px; + font-family: var(--font-sans); + font-size: 13px; + font-weight: 600; + padding: 7px 14px; + border-radius: var(--radius-sm); + border: 1px solid var(--border-strong); + background: var(--bg-surface); + color: var(--text-primary); + cursor: pointer; + transition: background-color 0.14s ease, border-color 0.14s ease, transform 0.08s ease; +} + +.btn:hover:not(:disabled) { + background: var(--bg-subtle); +} + +.btn:active:not(:disabled) { + transform: translateY(1px); +} + +.btn:disabled { + opacity: 0.55; + cursor: not-allowed; +} + +.btn-primary { + background: var(--accent-primary); + color: #ffffff; + border-color: var(--accent-primary); +} + +.btn-primary:hover:not(:disabled) { + background: var(--accent-primary-hover); + border-color: var(--accent-primary-hover); +} + +.btn-danger { + background: var(--status-deny-bg); + color: var(--status-deny); + border-color: rgba(176, 28, 46, 0.35); +} + +.btn-danger:hover:not(:disabled) { + background: hsl(354, 78%, 90%); +} + +/* Main Workspace Grid */ +.workspace { + max-width: 1480px; + margin: 0 auto; + padding: 20px 24px 40px; + display: grid; + grid-template-columns: 1.15fr 1fr; + gap: 20px; +} + +@media (max-width: 1120px) { + .workspace { + grid-template-columns: 1fr; + } +} + +.column { + display: flex; + flex-direction: column; + gap: 18px; +} + +/* Panels */ +.panel { + background: var(--bg-surface); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-md); + box-shadow: var(--shadow-sm); + overflow: hidden; +} + +.panel-header { + padding: 12px 16px; + border-bottom: 1px solid var(--border-subtle); + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + background: hsl(210, 20%, 98.5%); +} + +.panel-title-group { + display: flex; + align-items: center; + gap: 9px; +} + +.act-tag { + font-family: var(--font-mono); + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + padding: 2px 7px; + border-radius: 4px; + background: var(--accent-primary-soft); + color: var(--accent-primary); +} + +.panel-header h2 { + font-size: 14px; + font-weight: 600; + letter-spacing: -0.01em; +} + +.panel-body { + padding: 16px; +} + +/* Topology Map */ +.topology-wrap { + display: flex; + flex-direction: column; + gap: 12px; +} + +.topology-svg { + width: 100%; + height: auto; + background: hsl(210, 22%, 98%); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-sm); +} + +.topo-node-box { + fill: #ffffff; + stroke: hsl(214, 18%, 74%); + stroke-width: 1.5; + transition: stroke 0.2s ease, fill 0.2s ease; +} + +.topo-node-box.active-node { + stroke: var(--accent-primary); + stroke-width: 2.5; + fill: hsl(212, 85%, 98%); +} + +.topo-node-box.denied-node { + stroke: var(--status-deny); + stroke-width: 2.5; + fill: var(--status-deny-bg); +} + +.topo-link { + stroke: hsl(214, 16%, 76%); + stroke-width: 2; + stroke-dasharray: 5 4; + fill: none; + transition: stroke 0.2s ease, stroke-width 0.2s ease; +} + +.topo-link.link-active { + stroke: var(--accent-primary); + stroke-width: 3; + stroke-dasharray: none; +} + +.topo-link.link-deny { + stroke: var(--status-deny); + stroke-width: 3; + stroke-dasharray: none; +} + +.node-cards-row { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 10px; +} + +@media (max-width: 720px) { + .node-cards-row { + grid-template-columns: repeat(2, 1fr); + } +} + +.node-mini-card { + padding: 10px; + border-radius: var(--radius-sm); + border: 1px solid var(--border-subtle); + background: hsl(210, 20%, 99%); + font-size: 12px; +} + +.node-mini-header { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: 600; + margin-bottom: 4px; +} + +.peer-id-mono { + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-secondary); + word-break: break-all; +} + +.label-chips { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-top: 6px; +} + +.chip { + font-family: var(--font-mono); + font-size: 10px; + padding: 1px 5px; + border-radius: 3px; + background: var(--bg-subtle); + color: var(--text-secondary); + border: 1px solid var(--border-subtle); +} + +/* Act 2 Prompt & ReAct Trace */ +.prompt-bar { + display: flex; + gap: 8px; + margin-bottom: 12px; +} + +.prompt-input { + flex: 1; + font-family: var(--font-sans); + font-size: 13px; + padding: 8px 11px; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + color: var(--text-primary); + background: var(--bg-surface); +} + +.prompt-input:focus { + outline: 2px solid var(--accent-primary-soft); + border-color: var(--accent-primary); +} + +.react-steps { + display: flex; + flex-direction: column; + gap: 10px; +} + +.step-card { + border: 1px solid var(--border-subtle); + border-radius: var(--radius-sm); + padding: 10px 12px; + background: hsl(210, 20%, 99%); +} + +.step-card-header { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: 600; + font-size: 12px; + margin-bottom: 6px; +} + +.think-box { + font-family: var(--font-mono); + font-size: 12px; + background: hsl(38, 65%, 96%); + border-left: 3px solid hsl(35, 80%, 48%); + padding: 8px 10px; + border-radius: 4px; + color: hsl(30, 50%, 22%); + margin: 6px 0; + white-space: pre-wrap; +} + +.code-output { + font-family: var(--font-mono); + font-size: 11.5px; + background: var(--bg-terminal); + color: var(--text-terminal); + padding: 9px 11px; + border-radius: 5px; + overflow-x: auto; + white-space: pre-wrap; + word-break: break-word; +} + +.decision-banner { + padding: 10px 12px; + border-radius: var(--radius-sm); + background: var(--status-allow-bg); + color: var(--status-allow); + border: 1px solid rgba(22, 120, 74, 0.28); + font-weight: 600; + font-size: 13px; +} + +/* Act 3 Guardrail Grid */ +.guardrail-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 10px; +} + +@media (max-width: 680px) { + .guardrail-grid { + grid-template-columns: 1fr; + } +} + +.guardrail-card { + border: 1px solid var(--border-subtle); + border-radius: var(--radius-sm); + padding: 11px 12px; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 8px; + background: hsl(210, 20%, 99%); +} + +.guardrail-card h3 { + font-size: 13px; + font-weight: 600; +} + +.guardrail-desc { + font-size: 12px; + color: var(--text-secondary); +} + +.guardrail-result { + font-family: var(--font-mono); + font-size: 11px; + padding: 7px 9px; + border-radius: 4px; + background: var(--bg-subtle); + color: var(--text-primary); + border: 1px solid var(--border-subtle); + min-height: 44px; + white-space: pre-wrap; + word-break: break-word; +} + +.guardrail-result.is-denied { + background: var(--status-deny-bg); + color: var(--status-deny); + border-color: rgba(176, 28, 46, 0.25); +} + +/* SQLite Inspector */ +.db-summary-row { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 10px; + margin-bottom: 12px; +} + +.metric-box { + padding: 10px 12px; + border-radius: var(--radius-sm); + border: 1px solid var(--border-subtle); + background: hsl(210, 20%, 99%); +} + +.metric-label { + font-size: 11px; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.03em; + font-weight: 600; +} + +.metric-value { + font-family: var(--font-mono); + font-size: 16px; + font-weight: 700; + margin-top: 2px; +} + +/* Audit Stream Table */ +.audit-table-wrap { + max-height: 330px; + overflow-y: auto; + border: 1px solid var(--border-subtle); + border-radius: var(--radius-sm); +} + +.audit-table { + width: 100%; + border-collapse: collapse; + font-family: var(--font-mono); + font-size: 11.5px; +} + +.audit-table th, +.audit-table td { + padding: 7px 10px; + text-align: left; + border-bottom: 1px solid var(--border-subtle); +} + +.audit-table th { + background: var(--bg-subtle); + color: var(--text-secondary); + font-weight: 600; + position: sticky; + top: 0; +} + +.badge-allow, +.badge-deny { + display: inline-block; + padding: 1px 6px; + border-radius: 3px; + font-weight: 700; + font-size: 10.5px; +} + +.badge-allow { + background: var(--status-allow-bg); + color: var(--status-allow); +} + +.badge-deny { + background: var(--status-deny-bg); + color: var(--status-deny); +} diff --git a/site/content/docs/use-cases/private-diy-stack.md b/site/content/docs/use-cases/private-diy-stack.md new file mode 100644 index 00000000..2f1ccbe0 --- /dev/null +++ b/site/content/docs/use-cases/private-diy-stack.md @@ -0,0 +1,199 @@ +--- +title: "Private DIY Enterprise Stack (On-Prem & Cloud)" +weight: 26 +description: "Run a zero-trust AI workforce safely across on-premises infrastructure and cloud by combining self-hosted reasoning (Gemma / DeepSeek), an open-source Agent Harness, and Agent Mesh sidecar networking." +--- + + + +Enterprises adopting AI agents rarely run everything in a single place: sensitive ERP databases and compliance APIs often remain **on-premises**, while agents and elastic GPU reasoning run across **both on-premises servers and Google Cloud** (Cloud Run, GKE, or Compute Engine). Connecting those pieces traditionally forced teams to choose between brittle site-to-site VPNs, opening inbound firewall ports into the data center, or copying raw database credentials into cloud agent containers. + +By combining three composable layers, an enterprise can run a **zero-trust AI workforce safely across on-premises infrastructure and cloud** with one cryptographic identity and one Default-Deny policy plane: + +| Layer | Role in the Hybrid DIY Stack | Example Technology | +| :--- | :--- | :--- | +| **1. Reasoning (Open-Weights Intelligence)** | Chain-of-thought and tool planning on Cloud Run GPU, GKE, or on-prem GPUs | **Gemma 3** / **DeepSeek-R1** via Ollama or vLLM (`inference://private-llm`) | +| **2. Orchestration (Open Harness)** | ReAct loop, context management, and task execution without hardcoded tool logic or network routes | **Harness²** / custom Python MCP Harness (`agent_harness.py`) | +| **3. Networking & Policy (Agent Mesh)** | Cryptographic Biscuit identities across on-prem and cloud, Default-Deny service routing, secret brokering, and per-task `tar_block` guardrails | **`agentmesh-one`** (control plane + router) & **`agentmesh-node`** sidecars | + +The runnable end-to-end implementation lives in [`development/examples/private-diy-stack/`](https://github.com/google/agentmesh/tree/main/development/examples/private-diy-stack). + +--- + +## How Agent Mesh Connects On-Premises and Cloud Safely + +``` +┌─────────────────────────────────────────┐ ┌──────────────────────────────────────────┐ +│ Agent Zone: Cloud Run / Workstation │ │ Control Plane & Router (agentmesh-one) │ +│ (dept=finance) │ │ Issues Biscuit credentials & distributes│ +│ ┌───────────────────────────────────┐ │ │ compiled Datalog RBAC policy.json │ +│ │ Self-Hosted Agent Harness │ │ └────────────────────┬─────────────────────┘ +│ │ (Zero DB creds, zero network code)│ │ │ +│ └─────────┬───────────────┬─────────┘ │ │ +│ │ 127.0.0.1 │ 127.0.0.1 │ ▼ +│ │ :19101/mcp │ :19101/v1 │ ┌──────────────────────────────────────────┐ +│ ▼ ▼ │ │ GPU Zone: Cloud / On-Prem GPU Pool │ +│ ┌───────────────────────────────────┐ │ mTLS │ ┌────────────────────────────────────┐ │ +│ │ agentmesh-node (node-agent.yaml) ├──┼──────►│ │ agentmesh-node (node-inference) │ │ +│ │ Mint sealed task Biscuits (RFC8693│ │ + │ │ check if label("residency",...) │ │ +│ └─────────────────┬─────────────────┘ │Biscuit│ └─────────────────┬──────────────────┘ │ +└────────────────────┼────────────────────┘ │ │ 127.0.0.1:18892 │ + │ │ ▼ │ + │ mTLS + Biscuit │ ┌────────────────────────────────────┐ │ + │ (/mesh/mcp/1.0.0) │ │ Gemma 3 / DeepSeek-R1 (Ollama/vLLM)│ │ + ▼ │ └────────────────────────────────────┘ │ +┌─────────────────────────────────────────┐ └──────────────────────────────────────────┘ +│ On-Prem Vault Zone (zone=vault) │ +│ ┌───────────────────────────────────┐ │ +│ │ agentmesh-node (node-tools.yaml) │ │ +│ │ • Publishes mcp://erp-db │ │ +│ │ • Publishes mcp://payroll-vault │ │ +│ │ • Serves egress://compliance... │ │ +│ │ • Enforces tar_block + Datalog │ │ +│ └─────────┬───────────────┬─────────┘ │ +│ │ │ Injects │ +│ 127.0.0.1 │ │ Vault Key │ +│ :18890 ▼ ▼ :18891 │ +│ ┌──────────────────┐ ┌──────────────┐ │ +│ │ On-Prem ERP & │ │ Internal │ │ +│ │ Payroll SQLite │ │ Compliance │ │ +│ │ MCP Servers │ │ REST API │ │ +│ └──────────────────┘ └──────────────┘ │ +└─────────────────────────────────────────┘ +``` + +### 1. The "Sidecar" Node Architecture + +Instead of hardcoding database drivers, API keys, or service IP addresses into your agent code—or opening inbound firewall holes into your on-premises network—Agent Mesh deploys an `agentmesh-node` sidecar next to each workload: + +* **For the Agent (`node-agent.yaml` in Cloud Run, GKE, or Workstation):** The sidecar exposes the authorized mesh to your local agent as a loopback **Model Context Protocol (MCP)** server (`http://127.0.0.1:19101/mcp`) and a loopback **OpenAI-compatible inference endpoint** (`http://127.0.0.1:19101/v1`). The agent harness does not know whether a tool or model is running in Google Cloud or in an on-premises vault; it simply queries its local MCP server (`find_remote_tools`, `describe_remote_tool`, `call_remote_tool`) and sends chat completions to `127.0.0.1:19101/v1/chat/completions`. +* **For the Reasoning Engine (`node-inference.yaml` on Cloud GPU or On-Prem GPU):** A sidecar next to the GPU server publishes `inference://private-llm` backed by Ollama or vLLM (`deepseek-r1:1.5b` / `gemma3`) and verifies the caller's Biscuit attributes before serving completions. +* **For the Private Tools (`node-tools.yaml` in the On-Prem Vault):** A sidecar in the on-premises vault zone dials out to the mesh and registers private enterprise databases (`mcp://erp-db`, `mcp://payroll-vault`) and internal REST APIs (`egress://compliance.internal`). Raw API credentials (`secrets/compliance-api-key`) remain on the vault node and are injected at the egress boundary—never transmitted to the cloud or placed inside the agent container. + +```yaml +# development/examples/private-diy-stack/node-tools.yaml +version: "v1alpha1" + +labels: + residency: on-prem + zone: vault + dept: finance + +attenuation: + checks: + - 'check if label("residency", "on-prem");' + - 'check if label("dept", "finance");' + +services: + - type: mcp + name: erp-db + description: "Private Enterprise ERP SQLite Database (Invoices, Inventory, Wire Transfers)" + target_url: "http://127.0.0.1:18890/mcp" + protocol: "streamable-http" + - type: mcp + name: payroll-vault + description: "Restricted Executive Payroll Database (Default-Deny test target)" + target_url: "http://127.0.0.1:18890/payroll-mcp" + protocol: "streamable-http" +``` + +### 2. Zero Trust Identity & Default-Deny Policy + +When you build a private agent network, you cannot let an LLM roam free across the corporate LAN. `agentmesh-control-plane` (`agentmesh-one`) issues short-lived cryptographic **Biscuit** credentials to every node and distributes compiled Datalog RBAC policy across the mesh: + +1. **Default-Deny on Service Names:** Nothing is reachable by default. An agent cannot dial an arbitrary IP address; it can only invoke a logical service name (`mcp://erp-db`, `inference://private-llm`, `egress://compliance.internal`) that the control plane's [`policy.json`](https://github.com/google/agentmesh/blob/main/development/examples/private-diy-stack/policy.json) explicitly grants. Even though `mcp://payroll-vault` runs on the exact same vault sidecar as `mcp://erp-db`, calls to `mcp://payroll-vault` are rejected at the Biscuit authorizer (`biscuit: denied by no matching policies`). +2. **HTTP Method & Path Guardrails on Internal APIs:** `policy.json` restricts `egress://compliance.internal` to `GET /v1/vendors/*`. Any attempt by the agent to mutate compliance records via `POST` is rejected with `HTTP 403`. +3. **Data Residency & Department Labels:** Both the control plane and the node-local Datalog policy verify caller attributes (`residency=on-prem`, `dept=finance`). A node enrolled in `dept=external` is cryptographically blocked from calling `mcp://erp-db`. +4. **Per-Task Sealed Biscuits (`tar_block`):** Before executing an untrusted user prompt, the harness calls its local sidecar's RFC 8693 `/oauth/token` endpoint to append and seal a `TaskAuthorizationRule` (`tar_block`) onto its Biscuit, narrowing authority to read-only tools (`lookup_invoice`, `check_inventory`). If a prompt injection tricks the LLM into calling `execute_wire_transfer`, the vault node's Biscuit verifier rejects the call before it ever reaches SQLite. + +--- + +## Running the 4-Act Demo Locally + +The example requires zero external Python packages (`stdlib` only) and runs locally in ~12 seconds. If you have a local or Cloud Run Ollama/vLLM server running, pass `USE_LIVE_OLLAMA=1` to route `inference://private-llm` to your live GPU model. + +```bash +# Default CLI run (uses built-in deterministic deepseek-r1:1.5b engine) +make -C development/examples/private-diy-stack run + +# Launch the interactive browser workbench on http://127.0.0.1:18899 +make -C development/examples/private-diy-stack ui + +# Or connect to a live Ollama / vLLM instance: +USE_LIVE_OLLAMA=1 OLLAMA_MODEL=deepseek-r1:8b \ + make -C development/examples/private-diy-stack ui +``` + +### Act 1: Sidecar Enrollment & P2P Service Discovery + +`run.sh` starts the private SQLite ERP/Payroll MCP server, the internal Compliance API, the OpenAI-compatible reasoning backend, the `agentmesh-one` control plane, and three `agentmesh-node` sidecars (`node-tools`, `node-inference`, `node-agent`). Over Kademlia DHT and GossipSub, the agent's local sidecar discovers both peers automatically: + +```text +--> Enrolling 3 independent agentmesh-node sidecars into the private mesh: + 1. Vault Tool Sidecar (node-tools.yaml) -> publishes mcp://erp-db, mcp://payroll-vault & egress://compliance.internal + 2. GPU Reasoning Sidecar (node-inference.yaml) -> publishes inference://private-llm (deepseek-r1:1.5b) + 3. Agent Harness Sidecar (node-agent.yaml) -> exposes 127.0.0.1:19101/mcp and 127.0.0.1:19101/v1 to the local agent + + Discovered via Kademlia DHT / GossipSub from Agent's local sidecar: + • Vault Tool Node PeerID : 12D3KooWSKdz7xN3SEyx4coAo8mwRoqceeUNKcTpnCfSX8GkeSaF (mcp://erp-db, egress://compliance.internal) + • Bare-Metal GPU Node PeerID : 12D3KooWJnonWvLLU4vn2dRPrAZ59qr4JuQwBXF3CHFgxuANUCuo (inference://private-llm -> deepseek-r1:1.5b) +``` + +### Act 2: End-to-End Private Agent Execution + +`agent_harness.py` connects **only** to `http://127.0.0.1:19101/mcp` and `http://127.0.0.1:19101/v1`. It discovers the remote ERP tools, asks `deepseek-r1:1.5b` (routed over the mesh to `node-inference`) for a tool plan, queries the SQLite ERP database and the internal Compliance API (where `node-tools` injects `secrets/compliance-api-key`), and synthesizes the final audit decision: + +```text +--> Running self-hosted agent_harness.py (talks ONLY to 127.0.0.1:19101/mcp and /v1): + [Harness] Task: "Audit Invoice INV-2026-089 for Acme Robotics, verify SKU-GPU-H200 warehouse stock, and check vendor ACME-01 compliance." + [Harness] Step 1 -> Asking local MCP server (http://127.0.0.1:19101/mcp) for remote tools on the mesh... + Discovered 3 tools on Vault Peer 12D3KooWSKdz7xN3…: mcp://erp-db/lookup_invoice, mcp://erp-db/check_inventory, mcp://erp-db/execute_wire_transfer + Inspected schema for mcp://erp-db/lookup_invoice (required=['invoice_id']) + [Harness] Step 2 -> Consulting self-hosted reasoning model (deepseek-r1:1.5b) via http://127.0.0.1:19101/v1/chat/completions... + + The user wants to audit Invoice INV-2026-089, verify warehouse stock for SKU-GPU-H200, and check vendor ACME-01 compliance. Looking at the local Agent Mesh MCP catalog, I should invoke mcp://erp-db/lookup_invoice and mcp://erp-db/check_inventory, then query egress://compliance.internal/v1/vendors/ACME-01. + + [Harness] Step 3 -> Executing tool calls & internal API checks through local sidecar... + [mcp://erp-db/lookup_invoice] -> Invoice INV-2026-089: vendor=Acme Robotics GmbH (ACME-01), sku=SKU-GPU-H200, qty=4, amount=$48,500.00, status=PENDING_APPROVAL + [mcp://erp-db/check_inventory] -> SKU SKU-GPU-H200 (NVIDIA H200 Bare-Metal Server Blade): on_hand=14 units, warehouse=Munich-Vault-B + [egress://compliance.internal] -> vendor=Acme Robotics GmbH, sanctions=PASSED, iso27001=True (brokered secret verified=True) + [Harness] Step 4 -> Sending tool observations back to deepseek-r1:1.5b for final synthesis... + AUDIT DECISION: APPROVED_FOR_RECEIVING — Invoice INV-2026-089 ($48,500.00, 4x SKU-GPU-H200) matches Munich-Vault-B inventory (14 on hand) and vendor ACME-01 is compliance-verified. +``` + +### Act 3: Zero-Trust Policy Enforcement & Task-Scoped Attenuation + +Act 3 proves that an LLM or compromised harness cannot bypass enterprise guardrails: + +1. **3a. Unpermitted Service Name (`mcp://payroll-vault`):** Denied by control-plane Datalog policy (`biscuit: denied by no matching policies`). +2. **3b. Unpermitted HTTP Mutation (`POST /v1/vendors/ACME-01`):** Denied with `HTTP 403`. +3. **3c. Cross-Department Call (`dept=external` $\rightarrow$ `mcp://erp-db`):** Denied by the Vault node's local Datalog check (`failed to verify check #3: check if label("dept", "finance")`). +4. **3d. Prompt-Injected Wire Transfer (`execute_wire_transfer`):** Blocked by the sealed `tar_block` on the task Biscuit while `lookup_invoice` continues to succeed: + +```text +--> [3d. Per-Task Sealed Biscuit (tar_block) — Blocking Prompt-Injected Wire Transfers] + Minting a sealed Task Biscuit via RFC 8693 POST /oauth/token narrowed to read-only tools: + 1. Allowed read tool (lookup_invoice) -> Invoice INV-2026-089: vendor=Acme Robotics GmbH (ACME-01), sku=SKU-GPU-H200, qty=4, amount=$48,500.00, status=PENDING_APPROVAL + 2. Prompt-injected tool (execute_wire_transfer) -> failed after 3 retries: failed to call tool mcp://erp-db/execute_wire_transfer: calling "tools/call": task authorization denied tool "execute_wire_transfer": tar_block[1] ("oauth-task") denied request to mcp://erp-db + 3. SQLite wire_transfers table row count -> 0 (database untouched!) +``` + +### Act 4: Correlated Audit Trail & Mesh-Wide Revocation + +Every `ALLOW` and `DENY` decision across the GPU and Vault sidecars is emitted as structured JSON (`Audit Traceability`) and summarized by `audit.py`, followed by an immediate mesh-wide ban of the unauthorized external peer via `POST /admin/ban`: + +```text +--> Correlated ALLOW / DENY decisions across GPU and Vault Sidecars (audit.py): + ALLOW mesh:role:node 12D3KooWDTg5… POST /v1/chat/completions inference://private-llm + ALLOW mesh:role:node 12D3KooWDTg5… /mesh/mcp/1.0.0 mcp://erp-db + ALLOW mesh:role:node 12D3KooWDTg5… GET /v1/vendors/ACME-01 egress://compliance.internal + DENY - 12D3KooWDTg5… /mesh/mcp/1.0.0 mcp://payroll-vault + DENY - 12D3KooWDTg5… POST /v1/vendors/ACME-01 egress://compliance.internal + DENY - 12D3KooWGZN8… /mesh/mcp/1.0.0 mcp://erp-db + DENY tar_block (oauth-task) tools/call execute_wire_transfer mcp://erp-db + +--> Revoking unauthorized external node (12D3KooWGZN8uKXSgD2ASM4B7CgbzEQZ6kJUUediHEMVaT7nFsEH) mesh-wide via agentmesh-one admin ban: + Peer 12D3KooWGZN8uKXSgD2ASM4B7CgbzEQZ6kJUUediHEMVaT7nFsEH banned +``` diff --git a/site/static/demo-private-diy-stack.mp4 b/site/static/demo-private-diy-stack.mp4 new file mode 100644 index 00000000..86265ad1 Binary files /dev/null and b/site/static/demo-private-diy-stack.mp4 differ