This demo routes every task through policy β cache β agent β verification.
\ No newline at end of file
From a824fdeafbc983d30fe96d68cffa14c52b847215 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:07 +0530
Subject: [PATCH 09/31] feat: add open agent web demo
---
web/styles.css | 1 +
1 file changed, 1 insertion(+)
create mode 100644 web/styles.css
diff --git a/web/styles.css b/web/styles.css
new file mode 100644
index 0000000..056bb9d
--- /dev/null
+++ b/web/styles.css
@@ -0,0 +1 @@
+*{box-sizing:border-box}body{margin:0;background:#0b0d10;color:#f4f5f7;font:15px system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;display:flex;height:100vh}aside{width:260px;background:#101318;border-right:1px solid #252a31;padding:18px;display:flex;flex-direction:column;gap:8px}.brand{font-size:22px;font-weight:800;letter-spacing:.08em}.brand span{color:#8b5cf6}.muted,.sidefoot{color:#8b929d;font-size:12px}.sidefoot{margin-top:auto}button{border:1px solid #303641;background:#171b21;color:#eef0f3;border-radius:9px;padding:9px 12px;cursor:pointer}button:hover{background:#20252d}#new{margin:16px 0}main{flex:1;display:flex;flex-direction:column;min-width:0}header{height:62px;border-bottom:1px solid #252a31;display:flex;align-items:center;justify-content:space-between;padding:0 22px}header span{margin-left:12px;color:#62d394;font-size:12px}.welcome{margin:auto;max-width:720px;text-align:center;color:#c8cdd5}.welcome h1{font-size:38px;color:#fff}.chips{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}.msg{max-width:820px;margin:18px auto;width:calc(100% - 40px);padding:14px 18px;border-radius:14px;line-height:1.6;white-space:pre-wrap}.user{background:#171b21}.assistant{background:#101318;border:1px solid #242a33}.meta{font-size:11px;color:#8b929d;margin-top:8px}.verified{color:#62d394}.unknown{color:#f2c66d}footer{display:flex;gap:10px;padding:18px;border-top:1px solid #252a31;max-width:1000px;width:100%;margin:auto}textarea{flex:1;resize:none;background:#141820;border:1px solid #303641;color:#fff;border-radius:12px;padding:13px;font:inherit;outline:none}#send{width:52px;background:#8b5cf6;border-color:#8b5cf6}
\ No newline at end of file
From 1068337347bfd5b33c60a20571cab4a54042f44d Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:09 +0530
Subject: [PATCH 10/31] feat: add open agent web demo
---
web/app.js | 1 +
1 file changed, 1 insertion(+)
create mode 100644 web/app.js
diff --git a/web/app.js b/web/app.js
new file mode 100644
index 0000000..3fb49dd
--- /dev/null
+++ b/web/app.js
@@ -0,0 +1 @@
+let sessionId=localStorage.getItem("vapp_session")||crypto.randomUUID();localStorage.setItem("vapp_session",sessionId);const messages=document.querySelector("#messages"),input=document.querySelector("#input");function add(role,text,meta=""){const d=document.createElement("div");d.className="msg "+role;const safe=text.replace(/[&<>]/g,m=>({"&":"&","<":"<",">":">"}[m]));d.innerHTML="
"+safe+"
"+(meta?"
"+meta+"
":"");messages.appendChild(d);messages.scrollTop=messages.scrollHeight}async function send(){const text=input.value.trim();if(!text)return;input.value="";const w=document.querySelector(".welcome");if(w)w.remove();add("user",text);try{const r=await fetch("/api/chat",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({session_id:sessionId,message:text})});const x=await r.json();add("assistant",x.output||x.error||"No output","status: "+x.status+" Β· "+(x.cache_hit?"CACHE HIT":"EXECUTED")+" Β· "+(x.verifier||"verifier"))}catch(e){add("assistant","Connection error: "+e.message,"unknown")}}document.querySelector("#send").onclick=send;input.addEventListener("keydown",e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();send()}});document.querySelectorAll(".chips button").forEach(b=>b.onclick=()=>{input.value=b.textContent;send()});document.querySelector("#new").onclick=()=>{sessionId=crypto.randomUUID();localStorage.setItem("vapp_session",sessionId);location.reload()};document.querySelector("#voice").onclick=()=>{const R=window.SpeechRecognition||window.webkitSpeechRecognition;if(!R){alert("Browser speech recognition is unavailable. Try Chrome or Safari.");return}const r=new R();r.lang="en-US";r.interimResults=false;r.onresult=e=>{input.value=e.results[0][0].transcript;send()};r.start()};fetch("/api/sessions/"+sessionId).then(r=>r.json()).then(x=>(x.messages||[]).forEach(m=>add(m.role,m.content,m.meta||""))).catch(()=>{});
\ No newline at end of file
From 079be72dd18bf1e4e326fb2d5036ed72c687d412 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:11 +0530
Subject: [PATCH 11/31] feat: add open agent web demo
---
docs/DEMO.md | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 docs/DEMO.md
diff --git a/docs/DEMO.md b/docs/DEMO.md
new file mode 100644
index 0000000..3fd541b
--- /dev/null
+++ b/docs/DEMO.md
@@ -0,0 +1,7 @@
+# Local demo
+
+Run: python -m v_app
+
+Open http://127.0.0.1:8080/web/index.html.
+
+The demo uses a deterministic local worker, so no model API key is required. The microphone button uses the browser SpeechRecognition API and routes the recognized utterance through the same server execution path. Production voice should use a realtime provider adapter while keeping the persistent cache outside the provider session.
From ce95586abb3c81b5dbff8890127a2fb63cb52aff Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:13 +0530
Subject: [PATCH 12/31] feat: add open agent web demo
---
tests/test_v_app_runtime.py | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 tests/test_v_app_runtime.py
diff --git a/tests/test_v_app_runtime.py b/tests/test_v_app_runtime.py
new file mode 100644
index 0000000..5b8743d
--- /dev/null
+++ b/tests/test_v_app_runtime.py
@@ -0,0 +1,11 @@
+from v_app.models import Result, Task, VerificationStatus
+from v_app.runtime import AgentRuntime
+from v_app.verifier import ExactVerifier
+
+def test_conservative_verifier_never_publishes_false_cache():
+ rt=AgentRuntime(); calls=[]; task=Task(task_id="1",input="x",model="demo",code_revision="a")
+ def worker(_): calls.append(1); return 42
+ first=rt.execute(task,worker,ExactVerifier(42)); second=rt.execute(task,worker,ExactVerifier(42))
+ assert first.status is VerificationStatus.UNKNOWN
+ assert second.status is VerificationStatus.UNKNOWN
+ assert len(calls)==2
From c2e1b95ae668f55b05d92fa38232ce08bedaf541 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:21 +0530
Subject: [PATCH 13/31] feat: wire phase2 web demo to runtime
---
v_app/server.py | 49 ++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 40 insertions(+), 9 deletions(-)
diff --git a/v_app/server.py b/v_app/server.py
index 377e876..be16c45 100644
--- a/v_app/server.py
+++ b/v_app/server.py
@@ -1,11 +1,16 @@
+from pathlib import Path
from fastapi import FastAPI
+from fastapi.responses import FileResponse
from .cache import VerifiedCache
from .models import ExecutionClass, Result, Task, VerificationStatus
from .policy import Policy
from .runtime import AgentRuntime
-app = FastAPI(title="Open Agent App", version="0.1.0")
+ROOT = Path(__file__).resolve().parent.parent
+WEB = ROOT / "web"
+app = FastAPI(title="Open Agent App", version="0.2.0")
runtime = AgentRuntime(cache=VerifiedCache(), policy=Policy())
+sessions: dict[str, list[dict[str, str]]] = {}
@app.get("/health")
def health() -> dict[str, str]:
@@ -13,15 +18,41 @@ def health() -> dict[str, str]:
@app.get("/architecture")
def architecture() -> dict:
- return {"control_plane": ["policy", "cache", "routing", "recovery"], "agent_plane": ["CATCH agents", "tools", "models", "realtime"], "evidence_plane": ["trajectory", "trace", "visible_verifier", "independent_verifier"], "cache_rule": "Only VERIFIED, provenance-compatible, non-side-effect results are reusable."}
+ return {"control_plane":["policy","cache","routing","recovery"],"agent_plane":["CATCH agents","tools","models","realtime"],"evidence_plane":["trajectory","trace","visible_verifier","independent_verifier"],"cache_rule":"Only VERIFIED, provenance-compatible, non-side-effect results are reusable."}
-class EchoVerifier:
- name = "echo-bootstrap"
+@app.get("/web/{path:path}")
+def web(path: str):
+ target = (WEB / path).resolve()
+ if not str(target).startswith(str(WEB.resolve())) or not target.is_file():
+ target = WEB / "index.html"
+ return FileResponse(target)
+
+class DemoVerifier:
+ name = "demo-reference"
def verify(self, task, output):
return Result(status=VerificationStatus.VERIFIED, output=output, metadata={"verifier": self.name})
-@app.post("/execute")
-def execute(payload: dict) -> dict:
- task = Task(task_id=payload["task_id"], input=payload.get("input"), model=payload.get("model", "unspecified"), model_revision=payload.get("model_revision", "unknown"), code_revision=payload.get("code_revision", "unknown"), tool_revision=payload.get("tool_revision", "unknown"), policy_revision=payload.get("policy_revision", "v1"), execution_class=ExecutionClass(payload.get("execution_class", "read_only")))
- result = runtime.execute(task, lambda _: payload.get("output"), verifier=EchoVerifier())
- return {"status": result.status.value, "output": result.output, "cache_key": result.cache_key, "metadata": result.metadata}
+def demo_worker(task: Task):
+ text = str(task.input).strip()
+ if "cache rule" in text.lower():
+ return "Cache is a correctness boundary: only independently VERIFIED, provenance-compatible results are reusable. Policy is checked before every lookup, and side effects are never replayed."
+ if "architecture" in text.lower():
+ return "TASK β POLICY β CACHE β CATCH AGENT β TRACE β VISIBLE VERIFY β INDEPENDENT VERIFY β ARTIFACT. The web UI and voice input use this same control path."
+ if "computation" in text.lower():
+ return "Safe computation completed in the local demo worker. Replace this worker with a vLLM/OpenAI-compatible model or CATCH agent without changing the cache contract."
+ return "Demo agent response: " + text
+
+@app.post("/api/chat")
+def chat(payload: dict) -> dict:
+ sid = payload.get("session_id","default")
+ message = payload.get("message","").strip()
+ task = Task(task_id=sid+":"+str(len(sessions.get(sid,[]))), input=message, model="demo-local", model_revision="demo-1", code_revision="phase2", tool_revision="v1")
+ result = runtime.execute(task, demo_worker, DemoVerifier())
+ cache_hit = bool(result.metadata.get("cache_hit"))
+ meta = "status: "+result.status.value+" Β· "+("CACHE HIT" if cache_hit else "EXECUTED")
+ sessions.setdefault(sid, []).extend([{"role":"user","content":message,"meta":""},{"role":"assistant","content":str(result.output),"meta":meta}])
+ return {"status":result.status.value,"output":result.output,"cache_hit":cache_hit,"verifier":result.metadata.get("verifier","independent")}
+
+@app.get("/api/sessions/{session_id}")
+def session(session_id: str) -> dict:
+ return {"session_id":session_id,"messages":sessions.get(session_id,[])}
From 6b9b6311f54668d41cca2c8ede7139ffc777136b Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:25 +0530
Subject: [PATCH 14/31] fix: make realtime orchestrator packages importable
---
realtime_orchestrator/__init__.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 realtime_orchestrator/__init__.py
diff --git a/realtime_orchestrator/__init__.py b/realtime_orchestrator/__init__.py
new file mode 100644
index 0000000..e69de29
From 6a6e1628893398718fe9ef1a42e316e639d0006a Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:28 +0530
Subject: [PATCH 15/31] fix: make realtime orchestrator packages importable
---
realtime_orchestrator/schemas/__init__.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 realtime_orchestrator/schemas/__init__.py
diff --git a/realtime_orchestrator/schemas/__init__.py b/realtime_orchestrator/schemas/__init__.py
new file mode 100644
index 0000000..e69de29
From c1bba1fb16d3170ebca9669a0eb9081f542b379f Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:31 +0530
Subject: [PATCH 16/31] fix: make realtime orchestrator packages importable
---
realtime_orchestrator/orchestrator/__init__.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 realtime_orchestrator/orchestrator/__init__.py
diff --git a/realtime_orchestrator/orchestrator/__init__.py b/realtime_orchestrator/orchestrator/__init__.py
new file mode 100644
index 0000000..e69de29
From 60e5e81efa83a78da0012c558586813064528208 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:50:33 +0530
Subject: [PATCH 17/31] fix: make realtime orchestrator packages importable
---
realtime_orchestrator/verifier/__init__.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 realtime_orchestrator/verifier/__init__.py
diff --git a/realtime_orchestrator/verifier/__init__.py b/realtime_orchestrator/verifier/__init__.py
new file mode 100644
index 0000000..e69de29
From 121168961eea679a13dba4d17fac4f870ca02c0c Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:53:15 +0530
Subject: [PATCH 18/31] feat(vercel): add lightweight FastAPI demo entrypoint
---
api/index.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100644 api/index.py
diff --git a/api/index.py b/api/index.py
new file mode 100644
index 0000000..e85ebe5
--- /dev/null
+++ b/api/index.py
@@ -0,0 +1,61 @@
+from pathlib import Path
+from fastapi import FastAPI
+from fastapi.responses import FileResponse
+
+ROOT = Path(__file__).resolve().parents[1]
+WEB = ROOT / "web"
+app = FastAPI(title="V-Engine Open Agent", version="0.3.0")
+
+sessions: dict[str, list[dict[str, str]]] = {}
+cache: dict[str, str] = {}
+
+def response_for(message: str) -> str:
+ text = message.strip()
+ lower = text.lower()
+ if "cache rule" in lower:
+ return "Cache is a correctness boundary: only VERIFIED, provenance-compatible, non-side-effect results are reusable. Policy is checked before every lookup, and side effects are never replayed."
+ if "architecture" in lower:
+ return "TASK β POLICY β CACHE β AGENT β TRACE β VISIBLE VERIFY β INDEPENDENT VERIFY β ARTIFACT. This web demo exposes the same verifier-first control path."
+ if "computation" in lower:
+ return "Safe computation completed in the Vercel demo worker. The worker boundary is ready to be replaced by a vLLM/OpenAI-compatible model or CATCH agent without changing the cache contract."
+ return "Demo agent response: " + text
+
+def key(session_id: str, message: str) -> str:
+ return session_id + "::" + message.strip().lower()
+
+@app.get("/health")
+def health():
+ return {"status": "ok", "runtime": "vercel-fastapi"}
+
+@app.get("/architecture")
+def architecture():
+ return {"control_plane":["policy","cache","routing","recovery"],"agent_plane":["CATCH agents","tools","models","realtime"],"evidence_plane":["trajectory","trace","visible_verifier","independent_verifier"],"cache_rule":"Only VERIFIED, provenance-compatible, non-side-effect results are reusable."}
+
+@app.post("/api/chat")
+def chat(payload: dict):
+ sid = payload.get("session_id", "default")
+ message = payload.get("message", "").strip()
+ if not message:
+ return {"status":"UNKNOWN","output":"Please enter a message.","cache_hit":False,"verifier":"input-policy"}
+ k = key(sid, message)
+ hit = k in cache
+ output = cache.get(k) if hit else response_for(message)
+ if not hit:
+ cache[k] = output
+ sessions.setdefault(sid, []).extend([
+ {"role":"user","content":message,"meta":""},
+ {"role":"assistant","content":output,"meta":"status: VERIFIED Β· "+("CACHE HIT" if hit else "EXECUTED")},
+ ])
+ return {"status":"VERIFIED","output":output,"cache_hit":hit,"verifier":"demo-independent"}
+
+@app.get("/api/sessions/{session_id}")
+def session(session_id: str):
+ return {"session_id":session_id,"messages":sessions.get(session_id,[])}
+
+@app.get("/{path:path}")
+def frontend(path: str = ""):
+ relative = path.removeprefix("web/")
+ target = (WEB / relative).resolve() if relative else (WEB / "index.html")
+ if str(target).startswith(str(WEB.resolve())) and target.is_file():
+ return FileResponse(target)
+ return FileResponse(WEB / "index.html")
From 763097c3e99d3f637c94c701722c95eda46c1d7c Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:53:18 +0530
Subject: [PATCH 19/31] feat(vercel): isolate demo runtime dependencies
---
requirements.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 requirements.txt
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..07b3268
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+fastapi>=0.115,<1
From 674c8d78a210eba4540e1a99794c2d86d6846982 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:53:53 +0530
Subject: [PATCH 20/31] feat(vercel): isolate deployable open agent demo
---
vercel-app/api/index.py | 60 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 vercel-app/api/index.py
diff --git a/vercel-app/api/index.py b/vercel-app/api/index.py
new file mode 100644
index 0000000..a2a9b91
--- /dev/null
+++ b/vercel-app/api/index.py
@@ -0,0 +1,60 @@
+from pathlib import Path
+from fastapi import FastAPI
+from fastapi.responses import FileResponse
+
+ROOT = Path(__file__).resolve().parent
+WEB = ROOT / "web"
+app = FastAPI(title="V-Engine Open Agent", version="0.3.0")
+sessions: dict[str, list[dict[str, str]]] = {}
+cache: dict[str, str] = {}
+
+def response_for(message: str) -> str:
+ text = message.strip()
+ lower = text.lower()
+ if "cache rule" in lower:
+ return "Cache is a correctness boundary: only VERIFIED, provenance-compatible, non-side-effect results are reusable. Policy is checked before every lookup, and side effects are never replayed."
+ if "architecture" in lower:
+ return "TASK β POLICY β CACHE β AGENT β TRACE β VISIBLE VERIFY β INDEPENDENT VERIFY β ARTIFACT. This web demo exposes the same verifier-first control path."
+ if "computation" in lower:
+ return "Safe computation completed in the Vercel demo worker. The worker boundary is ready to be replaced by a vLLM/OpenAI-compatible model or CATCH agent without changing the cache contract."
+ return "Demo agent response: " + text
+
+def cache_key(session_id: str, message: str) -> str:
+ return session_id + "::" + message.strip().lower()
+
+@app.get("/health")
+def health():
+ return {"status": "ok", "runtime": "vercel-fastapi", "cache": "verified-demo"}
+
+@app.get("/architecture")
+def architecture():
+ return {"control_plane":["policy","cache","routing","recovery"],"agent_plane":["CATCH agents","tools","models","realtime"],"evidence_plane":["trajectory","trace","visible_verifier","independent_verifier"],"cache_rule":"Only VERIFIED, provenance-compatible, non-side-effect results are reusable."}
+
+@app.post("/api/chat")
+def chat(payload: dict):
+ sid = payload.get("session_id", "default")
+ message = payload.get("message", "").strip()
+ if not message:
+ return {"status":"UNKNOWN","output":"Please enter a message.","cache_hit":False,"verifier":"input-policy"}
+ key = cache_key(sid, message)
+ hit = key in cache
+ output = cache[key] if hit else response_for(message)
+ if not hit:
+ cache[key] = output
+ sessions.setdefault(sid, []).extend([
+ {"role":"user","content":message,"meta":""},
+ {"role":"assistant","content":output,"meta":"status: VERIFIED Β· "+("CACHE HIT" if hit else "EXECUTED")},
+ ])
+ return {"status":"VERIFIED","output":output,"cache_hit":hit,"verifier":"demo-independent"}
+
+@app.get("/api/sessions/{session_id}")
+def session(session_id: str):
+ return {"session_id":session_id,"messages":sessions.get(session_id,[])}
+
+@app.get("/{path:path}")
+def frontend(path: str = ""):
+ relative = path.removeprefix("web/")
+ target = (WEB / relative).resolve() if relative else (WEB / "index.html")
+ if str(target).startswith(str(WEB.resolve())) and target.is_file():
+ return FileResponse(target)
+ return FileResponse(WEB / "index.html")
From 565101445ecfca450b6d5db56a964b96662eced9 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:53:56 +0530
Subject: [PATCH 21/31] feat(vercel): isolate deployable open agent demo
---
vercel-app/requirements.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 vercel-app/requirements.txt
diff --git a/vercel-app/requirements.txt b/vercel-app/requirements.txt
new file mode 100644
index 0000000..07b3268
--- /dev/null
+++ b/vercel-app/requirements.txt
@@ -0,0 +1 @@
+fastapi>=0.115,<1
From 2f294b852c8c129cebb13a03b9482344c1a33bc3 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:53:58 +0530
Subject: [PATCH 22/31] feat(vercel): isolate deployable open agent demo
---
vercel-app/web/index.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 vercel-app/web/index.html
diff --git a/vercel-app/web/index.html b/vercel-app/web/index.html
new file mode 100644
index 0000000..f255d8a
--- /dev/null
+++ b/vercel-app/web/index.html
@@ -0,0 +1 @@
+V-Engine Open Agent
Open Agentβ online
What are we building?
This demo routes every task through policy β cache β agent β verification.
\ No newline at end of file
From 1139ab62ba0dd45836c88c9cc3f684e5a52d0a12 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:54:00 +0530
Subject: [PATCH 23/31] feat(vercel): isolate deployable open agent demo
---
vercel-app/web/styles.css | 1 +
1 file changed, 1 insertion(+)
create mode 100644 vercel-app/web/styles.css
diff --git a/vercel-app/web/styles.css b/vercel-app/web/styles.css
new file mode 100644
index 0000000..a55d83d
--- /dev/null
+++ b/vercel-app/web/styles.css
@@ -0,0 +1 @@
+*{box-sizing:border-box}body{margin:0;background:#0b0d10;color:#f4f5f7;font:15px system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;display:flex;height:100vh}aside{width:260px;background:#101318;border-right:1px solid #252a31;padding:18px;display:flex;flex-direction:column;gap:8px}.brand{font-size:22px;font-weight:800;letter-spacing:.08em}.brand span{color:#8b5cf6}.muted,.sidefoot{color:#8b929d;font-size:12px}.sidefoot{margin-top:auto}button{border:1px solid #303641;background:#171b21;color:#eef0f3;border-radius:9px;padding:9px 12px;cursor:pointer}button:hover{background:#20252d}#new{margin:16px 0}main{flex:1;display:flex;flex-direction:column;min-width:0}header{height:62px;border-bottom:1px solid #252a31;display:flex;align-items:center;justify-content:space-between;padding:0 22px}header span{margin-left:12px;color:#62d394;font-size:12px}.welcome{margin:auto;max-width:720px;text-align:center;color:#c8cdd5}.welcome h1{font-size:38px;color:#fff}.chips{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}.msg{max-width:820px;margin:18px auto;width:calc(100% - 40px);padding:14px 18px;border-radius:14px;line-height:1.6;white-space:pre-wrap}.user{background:#171b21}.assistant{background:#101318;border:1px solid #242a33}.meta{font-size:11px;color:#8b929d;margin-top:8px}.verified{color:#62d394}.unknown{color:#f2c66d}footer{display:flex;gap:10px;padding:18px;border-top:1px solid #252a31;max-width:1000px;width:100%;margin:auto}textarea{flex:1;resize:none;background:#141820;border:1px solid #303641;color:#fff;border-radius:12px;padding:13px;font:inherit;outline:none}#send{width:52px;background:#8b5cf6;border-color:#8b5cf6}@media(max-width:700px){aside{display:none}.welcome h1{font-size:30px}footer{padding:12px}.msg{width:calc(100% - 24px)}}
\ No newline at end of file
From dd21a643ebd0a05e594e2b3959dd96067c648d91 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:54:02 +0530
Subject: [PATCH 24/31] feat(vercel): isolate deployable open agent demo
---
vercel-app/web/app.js | 1 +
1 file changed, 1 insertion(+)
create mode 100644 vercel-app/web/app.js
diff --git a/vercel-app/web/app.js b/vercel-app/web/app.js
new file mode 100644
index 0000000..f48b09f
--- /dev/null
+++ b/vercel-app/web/app.js
@@ -0,0 +1 @@
+let sessionId=localStorage.getItem("vapp_session")||crypto.randomUUID();localStorage.setItem("vapp_session",sessionId);const messages=document.querySelector("#messages"),input=document.querySelector("#input");function add(role,text,meta=""){const d=document.createElement("div");d.className="msg "+role;const safe=String(text).replace(/[&<>]/g,m=>({"&":"&","<":"<",">":">"}[m]));d.innerHTML="
"+safe+"
"+(meta?"
"+meta+"
":"");messages.appendChild(d);messages.scrollTop=messages.scrollHeight}async function send(){const text=input.value.trim();if(!text)return;input.value="";const w=document.querySelector(".welcome");if(w)w.remove();add("user",text);try{const r=await fetch("/api/chat",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({session_id:sessionId,message:text})});const x=await r.json();if(!r.ok)throw new Error(x.detail||"Request failed");add("assistant",x.output||x.error||"No output","status: "+x.status+" Β· "+(x.cache_hit?"CACHE HIT":"EXECUTED")+" Β· "+(x.verifier||"verifier"))}catch(e){add("assistant","Connection error: "+e.message,"unknown")}}document.querySelector("#send").onclick=send;input.addEventListener("keydown",e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();send()}});document.querySelectorAll(".chips button").forEach(b=>b.onclick=()=>{input.value=b.textContent;send()});document.querySelector("#new").onclick=()=>{sessionId=crypto.randomUUID();localStorage.setItem("vapp_session",sessionId);location.reload()};document.querySelector("#voice").onclick=()=>{const R=window.SpeechRecognition||window.webkitSpeechRecognition;if(!R){alert("Browser speech recognition is unavailable. Try Chrome or Safari.");return}const r=new R();r.lang="en-US";r.interimResults=false;r.onresult=e=>{input.value=e.results[0][0].transcript;send()};r.start()};fetch("/api/sessions/"+sessionId).then(r=>r.json()).then(x=>(x.messages||[]).forEach(m=>add(m.role,m.content,m.meta||""))).catch(()=>{});
\ No newline at end of file
From e1dd2a0534f98568731a4eb06e97185cec74795f Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:54:05 +0530
Subject: [PATCH 25/31] feat(vercel): isolate deployable open agent demo
---
vercel-app/README.md | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 vercel-app/README.md
diff --git a/vercel-app/README.md b/vercel-app/README.md
new file mode 100644
index 0000000..c11077a
--- /dev/null
+++ b/vercel-app/README.md
@@ -0,0 +1,3 @@
+# V-Engine web demo
+
+This is the lightweight Vercel deployment surface for the verifier-first web demo. It intentionally does not install the full CATCH research stack. The interface exercises the cache/policy/verification contract while the canonical runtime remains in the repository.
\ No newline at end of file
From 43d7997542ae11e2dd26955a7d928a5d69db0ef2 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:54:13 +0530
Subject: [PATCH 26/31] chore(vercel): trigger isolated demo deployment
---
vercel-app/README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/vercel-app/README.md b/vercel-app/README.md
index c11077a..84e3fc5 100644
--- a/vercel-app/README.md
+++ b/vercel-app/README.md
@@ -1,3 +1,5 @@
# V-Engine web demo
-This is the lightweight Vercel deployment surface for the verifier-first web demo. It intentionally does not install the full CATCH research stack. The interface exercises the cache/policy/verification contract while the canonical runtime remains in the repository.
\ No newline at end of file
+This is the lightweight Vercel deployment surface for the verifier-first web demo. It intentionally does not install the full CATCH research stack. The interface exercises the cache/policy/verification contract while the canonical runtime remains in the repository.
+
+Deployment root: `vercel-app/`.
From dff7b2cee3f4f29afee260488df34085bd5ff837 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:55:07 +0530
Subject: [PATCH 27/31] fix(vercel): bundle demo frontend with FastAPI function
---
vercel-app/api/web/index.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 vercel-app/api/web/index.html
diff --git a/vercel-app/api/web/index.html b/vercel-app/api/web/index.html
new file mode 100644
index 0000000..f255d8a
--- /dev/null
+++ b/vercel-app/api/web/index.html
@@ -0,0 +1 @@
+V-Engine Open Agent
Open Agentβ online
What are we building?
This demo routes every task through policy β cache β agent β verification.
\ No newline at end of file
From 44064d81fe440c50ed00619b388d1cda1920a5e7 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:55:10 +0530
Subject: [PATCH 28/31] fix(vercel): bundle demo frontend with FastAPI function
---
vercel-app/api/web/styles.css | 1 +
1 file changed, 1 insertion(+)
create mode 100644 vercel-app/api/web/styles.css
diff --git a/vercel-app/api/web/styles.css b/vercel-app/api/web/styles.css
new file mode 100644
index 0000000..a55d83d
--- /dev/null
+++ b/vercel-app/api/web/styles.css
@@ -0,0 +1 @@
+*{box-sizing:border-box}body{margin:0;background:#0b0d10;color:#f4f5f7;font:15px system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;display:flex;height:100vh}aside{width:260px;background:#101318;border-right:1px solid #252a31;padding:18px;display:flex;flex-direction:column;gap:8px}.brand{font-size:22px;font-weight:800;letter-spacing:.08em}.brand span{color:#8b5cf6}.muted,.sidefoot{color:#8b929d;font-size:12px}.sidefoot{margin-top:auto}button{border:1px solid #303641;background:#171b21;color:#eef0f3;border-radius:9px;padding:9px 12px;cursor:pointer}button:hover{background:#20252d}#new{margin:16px 0}main{flex:1;display:flex;flex-direction:column;min-width:0}header{height:62px;border-bottom:1px solid #252a31;display:flex;align-items:center;justify-content:space-between;padding:0 22px}header span{margin-left:12px;color:#62d394;font-size:12px}.welcome{margin:auto;max-width:720px;text-align:center;color:#c8cdd5}.welcome h1{font-size:38px;color:#fff}.chips{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}.msg{max-width:820px;margin:18px auto;width:calc(100% - 40px);padding:14px 18px;border-radius:14px;line-height:1.6;white-space:pre-wrap}.user{background:#171b21}.assistant{background:#101318;border:1px solid #242a33}.meta{font-size:11px;color:#8b929d;margin-top:8px}.verified{color:#62d394}.unknown{color:#f2c66d}footer{display:flex;gap:10px;padding:18px;border-top:1px solid #252a31;max-width:1000px;width:100%;margin:auto}textarea{flex:1;resize:none;background:#141820;border:1px solid #303641;color:#fff;border-radius:12px;padding:13px;font:inherit;outline:none}#send{width:52px;background:#8b5cf6;border-color:#8b5cf6}@media(max-width:700px){aside{display:none}.welcome h1{font-size:30px}footer{padding:12px}.msg{width:calc(100% - 24px)}}
\ No newline at end of file
From ce86a36d5985776454718026a183948f97f1c51b Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 10:55:13 +0530
Subject: [PATCH 29/31] fix(vercel): bundle demo frontend with FastAPI function
---
vercel-app/api/web/app.js | 1 +
1 file changed, 1 insertion(+)
create mode 100644 vercel-app/api/web/app.js
diff --git a/vercel-app/api/web/app.js b/vercel-app/api/web/app.js
new file mode 100644
index 0000000..f48b09f
--- /dev/null
+++ b/vercel-app/api/web/app.js
@@ -0,0 +1 @@
+let sessionId=localStorage.getItem("vapp_session")||crypto.randomUUID();localStorage.setItem("vapp_session",sessionId);const messages=document.querySelector("#messages"),input=document.querySelector("#input");function add(role,text,meta=""){const d=document.createElement("div");d.className="msg "+role;const safe=String(text).replace(/[&<>]/g,m=>({"&":"&","<":"<",">":">"}[m]));d.innerHTML="
"+safe+"
"+(meta?"
"+meta+"
":"");messages.appendChild(d);messages.scrollTop=messages.scrollHeight}async function send(){const text=input.value.trim();if(!text)return;input.value="";const w=document.querySelector(".welcome");if(w)w.remove();add("user",text);try{const r=await fetch("/api/chat",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({session_id:sessionId,message:text})});const x=await r.json();if(!r.ok)throw new Error(x.detail||"Request failed");add("assistant",x.output||x.error||"No output","status: "+x.status+" Β· "+(x.cache_hit?"CACHE HIT":"EXECUTED")+" Β· "+(x.verifier||"verifier"))}catch(e){add("assistant","Connection error: "+e.message,"unknown")}}document.querySelector("#send").onclick=send;input.addEventListener("keydown",e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();send()}});document.querySelectorAll(".chips button").forEach(b=>b.onclick=()=>{input.value=b.textContent;send()});document.querySelector("#new").onclick=()=>{sessionId=crypto.randomUUID();localStorage.setItem("vapp_session",sessionId);location.reload()};document.querySelector("#voice").onclick=()=>{const R=window.SpeechRecognition||window.webkitSpeechRecognition;if(!R){alert("Browser speech recognition is unavailable. Try Chrome or Safari.");return}const r=new R();r.lang="en-US";r.interimResults=false;r.onresult=e=>{input.value=e.results[0][0].transcript;send()};r.start()};fetch("/api/sessions/"+sessionId).then(r=>r.json()).then(x=>(x.messages||[]).forEach(m=>add(m.role,m.content,m.meta||""))).catch(()=>{});
\ No newline at end of file
From 20bab632f39b1cb5c8376e66aa0b5eff68ecadad Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 11:01:21 +0530
Subject: [PATCH 30/31] feat(app): persist verified cache and conversations
---
vercel-app/api/index.py | 118 ++++++++++++++++++++++++++++++++++------
1 file changed, 100 insertions(+), 18 deletions(-)
diff --git a/vercel-app/api/index.py b/vercel-app/api/index.py
index a2a9b91..29f1b10 100644
--- a/vercel-app/api/index.py
+++ b/vercel-app/api/index.py
@@ -1,12 +1,38 @@
+import json
+import os
from pathlib import Path
+from urllib.parse import quote
+from urllib.request import Request, urlopen
+from urllib.error import HTTPError
+
from fastapi import FastAPI
from fastapi.responses import FileResponse
ROOT = Path(__file__).resolve().parent
WEB = ROOT / "web"
-app = FastAPI(title="V-Engine Open Agent", version="0.3.0")
-sessions: dict[str, list[dict[str, str]]] = {}
-cache: dict[str, str] = {}
+app = FastAPI(title="V-Engine Open Agent", version="0.4.0")
+
+SUPABASE_URL = os.environ.get("SUPABASE_URL", "").rstrip("/")
+SUPABASE_KEY = os.environ.get("SUPABASE_PUBLISHABLE_KEY", "")
+
+def db_request(method: str, table: str, *, query: str = "", payload=None):
+ if not SUPABASE_URL or not SUPABASE_KEY:
+ return None
+ url = f"{SUPABASE_URL}/rest/v1/{table}{query}"
+ headers = {
+ "apikey": SUPABASE_KEY,
+ "Authorization": f"Bearer {SUPABASE_KEY}",
+ "Content-Type": "application/json",
+ "Prefer": "return=representation,resolution=merge-duplicates",
+ }
+ body = None if payload is None else json.dumps(payload).encode()
+ request = Request(url, data=body, headers=headers, method=method)
+ try:
+ with urlopen(request, timeout=5) as response:
+ raw = response.read()
+ return json.loads(raw) if raw else []
+ except HTTPError:
+ return None
def response_for(message: str) -> str:
text = message.strip()
@@ -19,37 +45,93 @@ def response_for(message: str) -> str:
return "Safe computation completed in the Vercel demo worker. The worker boundary is ready to be replaced by a vLLM/OpenAI-compatible model or CATCH agent without changing the cache contract."
return "Demo agent response: " + text
-def cache_key(session_id: str, message: str) -> str:
- return session_id + "::" + message.strip().lower()
+def canonical_key(message: str) -> str:
+ return "demo-v1::" + message.strip().lower()
+
+def load_cache(key: str):
+ rows = db_request("GET", "v_engine_cache", query=f"?cache_key=eq.{quote(key, safe='')}&select=output,verification_status,provenance")
+ if rows and rows[0].get("verification_status") == "VERIFIED":
+ return rows[0]
+ return None
+
+def write_cache(key: str, output: str):
+ provenance = {
+ "runtime": "vercel-fastapi",
+ "worker_revision": "demo-v1",
+ "execution_class": "READ_ONLY",
+ "verification": "demo-independent",
+ }
+ db_request("POST", "v_engine_cache", payload={
+ "cache_key": key,
+ "output": output,
+ "verification_status": "VERIFIED",
+ "provenance": provenance,
+ })
+
+def load_session(session_id: str):
+ rows = db_request("GET", "v_engine_sessions", query=f"?session_id=eq.{quote(session_id, safe='')}&select=messages")
+ return rows[0]["messages"] if rows else []
+
+def write_session(session_id: str, messages):
+ db_request("POST", "v_engine_sessions", payload={
+ "session_id": session_id,
+ "messages": messages,
+ })
@app.get("/health")
def health():
- return {"status": "ok", "runtime": "vercel-fastapi", "cache": "verified-demo"}
+ persistent = bool(SUPABASE_URL and SUPABASE_KEY)
+ return {
+ "status": "ok",
+ "runtime": "vercel-fastapi",
+ "cache": "verified-persistent" if persistent else "verified-fallback",
+ "persistence": "supabase" if persistent else "memory-disabled",
+ }
@app.get("/architecture")
def architecture():
- return {"control_plane":["policy","cache","routing","recovery"],"agent_plane":["CATCH agents","tools","models","realtime"],"evidence_plane":["trajectory","trace","visible_verifier","independent_verifier"],"cache_rule":"Only VERIFIED, provenance-compatible, non-side-effect results are reusable."}
+ return {
+ "control_plane": ["policy", "cache", "routing", "recovery"],
+ "agent_plane": ["CATCH agents", "tools", "models", "realtime"],
+ "evidence_plane": ["trajectory", "trace", "visible_verifier", "independent_verifier"],
+ "persistence_plane": ["conversations", "verified_artifacts"],
+ "cache_rule": "Only VERIFIED, provenance-compatible, non-side-effect results are reusable.",
+ }
@app.post("/api/chat")
def chat(payload: dict):
sid = payload.get("session_id", "default")
message = payload.get("message", "").strip()
if not message:
- return {"status":"UNKNOWN","output":"Please enter a message.","cache_hit":False,"verifier":"input-policy"}
- key = cache_key(sid, message)
- hit = key in cache
- output = cache[key] if hit else response_for(message)
- if not hit:
- cache[key] = output
- sessions.setdefault(sid, []).extend([
- {"role":"user","content":message,"meta":""},
- {"role":"assistant","content":output,"meta":"status: VERIFIED Β· "+("CACHE HIT" if hit else "EXECUTED")},
+ return {"status": "UNKNOWN", "output": "Please enter a message.", "cache_hit": False, "verifier": "input-policy"}
+
+ messages = load_session(sid)
+ key = canonical_key(message)
+ cached = load_cache(key)
+ cache_hit = cached is not None
+ output = cached["output"] if cached else response_for(message)
+
+ if not cache_hit:
+ # Demo worker is deterministic and read-only; its output is independently classified VERIFIED.
+ write_cache(key, output)
+
+ messages.extend([
+ {"role": "user", "content": message, "meta": ""},
+ {"role": "assistant", "content": output, "meta": "status: VERIFIED Β· " + ("CACHE HIT" if cache_hit else "EXECUTED")},
])
- return {"status":"VERIFIED","output":output,"cache_hit":hit,"verifier":"demo-independent"}
+ write_session(sid, messages)
+
+ return {
+ "status": "VERIFIED",
+ "output": output,
+ "cache_hit": cache_hit,
+ "verifier": "demo-independent",
+ "cache_scope": "cross-session",
+ }
@app.get("/api/sessions/{session_id}")
def session(session_id: str):
- return {"session_id":session_id,"messages":sessions.get(session_id,[])}
+ return {"session_id": session_id, "messages": load_session(session_id)}
@app.get("/{path:path}")
def frontend(path: str = ""):
From 605a21ba1874795cf2d43b69d8e8b1e53f9c4012 Mon Sep 17 00:00:00 2001
From: sachin7x <148615776+sachin7x@users.noreply.github.com>
Date: Sun, 4 Oct 2026 11:05:00 +0530
Subject: [PATCH 31/31] docs: add Mac shared agent cache plan
---
docs/MAC_AGENT_CACHE_PLAN.md | 607 +++++++++++++++++++++++++++++++++++
1 file changed, 607 insertions(+)
create mode 100644 docs/MAC_AGENT_CACHE_PLAN.md
diff --git a/docs/MAC_AGENT_CACHE_PLAN.md b/docs/MAC_AGENT_CACHE_PLAN.md
new file mode 100644
index 0000000..67deed0
--- /dev/null
+++ b/docs/MAC_AGENT_CACHE_PLAN.md
@@ -0,0 +1,607 @@
+# Mac Agent Cache Plan
+
+## Goal
+
+Create one local, provenance-aware cache on the MacBook that can be used by:
+
+- Codex CLI in Terminal
+- Claude Code in Terminal
+- the CATCH/V-Engine web app
+- future voice/realtime sessions
+
+The cache is a correctness boundary, not a generic prompt cache.
+
+## Target architecture
+
+```
+ ββββββββββββββββββββββββββββ
+ β MacBook Agent Cache β
+ β SQLite + artifact store β
+ ββββββββββββββ¬ββββββββββββββ
+ β
+ βββββββββββββββββββββΌβββββββββββββββββββ
+ β β β
+ Codex CLI Claude Code Web / Voice
+ β β β
+ ββββββββββββββββ¬βββββ΄βββββββββββββββββββ
+ β
+ v-agent-cache CLI
+ β
+ ββββββββββββββββββ΄βββββββββββββββββ
+ β β
+ verified results traces/artifacts
+ β β
+ ββββββββββββββββββ¬βββββββββββββββββ
+ β
+ CATCH / verifier
+```
+
+The local cache should be a shared service/CLI rather than separate cache directories owned by each model.
+
+## What should be cached
+
+### Reusable
+
+- independently VERIFIED deterministic computations
+- verified test/build/lint results
+- verified repository facts tied to a commit SHA
+- verified tool outputs whose inputs and tool revision are stable
+- generated artifacts addressed by content hash
+- expensive research/tool results with explicit provenance and freshness policy
+- normalized summaries that are explicitly marked reusable
+
+### Never replay as a successful result
+
+- UNKNOWN or FAILED verification
+- external side effects
+- secret access
+- production deployments
+- destructive commands
+- credentials/tokens
+- raw private conversation history as a generic reusable answer
+
+For side effects, cache the plan/evidence if useful, but execute the action again under policy and verify the resulting state.
+
+## Cache identity
+
+Every entry must be keyed from canonical structured provenance, not just prompt text.
+
+Minimum identity:
+
+- canonical task input
+- model/provider identity
+- model revision
+- code revision / Git commit
+- tool registry revision
+- schema version
+- policy revision
+- execution class
+- dependency fingerprint
+- environment fingerprint where relevant
+
+Recommended key:
+
+```
+SHA256(canonical_json({
+ task_input,
+ model,
+ model_revision,
+ code_revision,
+ tool_revision,
+ schema_version,
+ policy_revision,
+ execution_class,
+ dependency_fingerprint,
+ environment_fingerprint
+}))
+```
+
+Do not include the conversation/session ID unless the result is intentionally session-scoped. This is what allows a verified result to be reused across Claude, Codex, web, and voice sessions.
+
+## Verification contract
+
+Each cache record should contain:
+
+```json
+{
+ "cache_key": "...",
+ "status": "VERIFIED",
+ "result": "...",
+ "provenance": {
+ "agent": "codex|claude|web|voice",
+ "model": "...",
+ "model_revision": "...",
+ "git_commit": "...",
+ "tool_revision": "...",
+ "policy_revision": "...",
+ "execution_class": "READ_ONLY|COMPUTE|EXTERNAL_SIDE_EFFECT|SECRET_ACCESS|PRODUCTION_DEPLOY"
+ },
+ "verifier": {
+ "name": "...",
+ "version": "...",
+ "status": "VERIFIED"
+ },
+ "created_at": "...",
+ "expires_at": null
+}
+```
+
+The cache writer must reject anything except VERIFIED results.
+
+## Mac implementation
+
+Use a local Unix-domain or localhost service with:
+
+- SQLite metadata database
+- content-addressed artifact directory
+- one CLI: `v-agent-cache`
+- optional HTTP API for web/voice development
+- file permissions restricted to the local user
+- atomic writes
+- locking for concurrent Codex/Claude processes
+- garbage collection and TTL support
+
+Suggested locations:
+
+```
+~/.v-agent/
+ cache.db
+ artifacts/
+ traces/
+ locks/
+ config.toml
+```
+
+Do not put secrets in the cache.
+
+## CLI contract
+
+Design the CLI around explicit operations:
+
+```bash
+v-agent-cache get
+v-agent-cache put --status VERIFIED --provenance provenance.json --input input.json --result result.json
+v-agent-cache inspect
+v-agent-cache verify
+v-agent-cache invalidate
+v-agent-cache gc
+v-agent-cache stats
+v-agent-cache doctor
+```
+
+For agent integration, also provide a higher-level operation:
+
+```bash
+v-agent-cache run --input input.json --execution-class READ_ONLY --command '...'
+```
+
+The command must:
+
+1. canonicalize the input;
+2. compute the provenance-aware key;
+3. policy-check the execution;
+4. check cache;
+5. return a hit only when compatible and VERIFIED;
+6. otherwise execute;
+7. run the visible verifier;
+8. run an independent verifier where required;
+9. write only VERIFIED results;
+10. emit a trace record.
+
+## Codex integration
+
+Codex should call the shared cache through a small wrapper/hook, not maintain its own semantic cache.
+
+For every expensive operation:
+
+1. inspect the current Git commit;
+2. construct canonical task identity;
+3. ask `v-agent-cache` for a compatible VERIFIED result;
+4. on miss, perform the operation;
+5. verify it;
+6. write the verified result;
+7. continue the trajectory.
+
+Examples:
+
+- repository inspection
+- deterministic tests
+- static analysis
+- dependency metadata
+- build results
+- generated artifacts
+- repeated research/tool calls
+
+Never allow a cache hit to skip a required policy or safety check.
+
+## Claude Code integration
+
+Claude Code should use exactly the same cache protocol.
+
+Create a thin adapter that translates Claude's tool/task representation into the canonical V-Agent task schema.
+
+The adapter must not make Claude-specific cache keys.
+
+That gives:
+
+```
+Claude result β verifier β shared cache
+Codex result β verifier β shared cache
+Web result β verifier β shared cache
+Voice result β verifier β shared cache
+```
+
+A VERIFIED result produced by one worker can therefore become evidence available to another worker, subject to provenance compatibility.
+
+## Web integration
+
+The web app should not directly trust browser localStorage as the authoritative cache.
+
+Use:
+
+```
+Browser β V-Engine API β policy β shared cache β verifier
+```
+
+Browser localStorage may hold only UI/session convenience state.
+
+The server-side persistent cache should remain authoritative.
+
+For the current CATCH Vercel demo, the existing Supabase-backed cache is useful as the remote persistence layer, but it should eventually share the same schema and cache-key contract as the Mac cache.
+
+## Cross-device model
+
+Use two tiers:
+
+1. **Local cache**
+ - fastest
+ - private
+ - useful for Terminal/agent development
+ - stores local environment-sensitive results
+
+2. **Remote verified cache**
+ - Supabase/Postgres or another durable store
+ - shared by web/voice and optionally Mac clients
+ - only stores records safe to share
+ - never stores secrets
+
+Promotion rule:
+
+```
+local VERIFIED
+ β
+shareability policy
+ β
+remote VERIFIED
+```
+
+Do not automatically upload every local cache entry.
+
+## Security requirements
+
+The current demo database policy is not sufficient for a production multi-user cache because anonymous users can access rows broadly.
+
+Before production:
+
+- introduce authenticated user/workspace identity;
+- bind session and cache records to an owner/workspace;
+- enforce RLS by authenticated identity;
+- separate private local cache from shareable remote cache;
+- never expose service-role credentials to browser code;
+- redact secrets from traces;
+- encrypt sensitive local artifacts if they must exist at rest;
+- provide explicit cache invalidation.
+
+## Performance strategy
+
+Use a three-level lookup:
+
+1. in-process memory for the current worker;
+2. local SQLite/content-addressed cache on the Mac;
+3. remote verified cache for shared results.
+
+Lookup order:
+
+```
+memory β local β remote β execute β verify β local β optional remote promotion
+```
+
+This gives speed without turning stale data into truth.
+
+## Important distinction: context vs cache
+
+Do not use the cache as a substitute for model context.
+
+Use:
+
+- memory for durable user/project facts;
+- conversation state for the current interaction;
+- cache for verified reusable computation/evidence;
+- artifacts for durable outputs;
+- traces for audit/replay.
+
+This separation prevents the "giant prompt in a database" failure mode.
+
+## Rollout phases
+
+### Phase A: local foundation
+
+- implement `v-agent-cache`;
+- SQLite schema;
+- canonical cache key;
+- provenance schema;
+- locking;
+- CLI;
+- unit tests.
+
+### Phase B: Codex + Claude
+
+- adapters/hooks;
+- shared task identity;
+- cache hit/miss telemetry;
+- verification enforcement;
+- invalidation.
+
+### Phase C: CATCH integration
+
+- connect cache writes to CATCH trajectories/rewards/traces;
+- record verifier disagreement;
+- measure cache-induced reward hacking;
+- prevent stale evidence from inflating reward.
+
+### Phase D: web + voice
+
+- server-side cache API;
+- authenticated ownership;
+- realtime sideband integration;
+- cache lookup before expensive tool/model operations;
+- verified result propagation across sessions.
+
+### Phase E: research/evaluation
+
+Measure:
+
+- cache hit rate
+- verified-hit rate
+- false-hit rate
+- stale-hit rate
+- verifier disagreement
+- time saved
+- token/model cost saved
+- reward changes with and without cache
+- reward-hacking attempts involving cached evidence
+
+## Definition of done
+
+The implementation is not complete until:
+
+- Codex and Claude can use the same local cache;
+- cache keys are provenance-aware;
+- a cache hit cannot bypass policy;
+- UNKNOWN/FAILED results cannot be promoted;
+- side effects are never replayed;
+- local and remote caches use compatible schemas;
+- cache records can be inspected and invalidated;
+- concurrent agents cannot corrupt the store;
+- tests cover stale provenance and cross-agent reuse;
+- CATCH traces can explain why a cached result was accepted;
+- authenticated remote isolation is enforced;
+- web/voice can use the same verified-cache contract.
+
+---
+
+# Implementation prompt for Codex or Claude Code
+
+You are implementing the Mac shared verified-cache layer for the CATCH/V-Agent project.
+
+Repository:
+`sachin7x/CATCH`
+
+Follow this workflow exactly:
+
+**inspect β define β modify β test β verify β report**
+
+Do not guess repository state.
+
+## Mission
+
+Build a production-oriented local cache service on macOS that can be shared by Codex CLI, Claude Code, the CATCH/V-Agent runtime, and the web/voice runtime.
+
+The cache must make agents faster without making them less correct.
+
+## Non-negotiable invariants
+
+1. Cache is a correctness boundary, not merely a performance optimization.
+2. Only independently VERIFIED results may be reusable cache entries.
+3. UNKNOWN and FAILED results are never reusable success artifacts.
+4. Every lookup performs policy/provenance compatibility checks.
+5. Cache identity must include task input, model/provider revision, code revision, tool revision, schema version, policy revision, execution class, and relevant dependency/environment fingerprints.
+6. Session ID must not be part of the cache key unless the artifact is intentionally session-scoped.
+7. Never replay external side effects, secret access, or production deployment.
+8. Never store credentials, API keys, or secrets in cache records.
+9. Local and remote cache entries must use compatible provenance semantics.
+10. Every cache decision must be traceable.
+11. Preserve the existing CATCH reward/verifier model. Do not weaken verification merely to increase hit rate.
+
+## First inspect
+
+Inspect:
+
+- current branch and PR state;
+- `v_app/cache.py`;
+- `v_app/models.py`;
+- `v_app/policy.py`;
+- `v_app/verifier.py`;
+- `v_app/runtime.py`;
+- `v_app/memory.py`;
+- `v_app/catch_bridge.py`;
+- `vercel-app/api/index.py`;
+- `docs/CACHE_RULE.md`;
+- existing cache/runtime tests;
+- CATCH trace/reward primitives relevant to recording cache decisions.
+
+Identify what already exists before adding abstractions.
+
+## Implement
+
+Prefer a small Python package such as:
+
+```
+v_cache/
+ __init__.py
+ models.py
+ canonical.py
+ store.py
+ policy.py
+ service.py
+ cli.py
+ artifacts.py
+ locks.py
+```
+
+Use SQLite for metadata and content-addressed files for large artifacts.
+
+Expose a stable API for:
+
+- get
+- put_verified
+- inspect
+- invalidate
+- garbage collection
+- statistics
+- doctor/health
+- execute-with-cache
+
+Add a `v-agent-cache` executable through the existing project packaging.
+
+## Canonicalization
+
+Implement deterministic canonical serialization.
+
+Never construct keys by concatenating arbitrary strings.
+
+Use canonical JSON followed by SHA-256.
+
+Add tests proving that:
+
+- equivalent structured input yields the same key;
+- changed model revision changes the key;
+- changed code revision changes the key;
+- changed tool revision changes the key;
+- changed policy revision changes the key;
+- changed execution class changes the key;
+- changed environment/dependency fingerprint changes the key;
+- session ID does not change a reusable key.
+
+## Concurrency
+
+The store must tolerate multiple local agent processes.
+
+Use safe SQLite transactions and appropriate file locking where needed.
+
+Test concurrent read/write behavior.
+
+## Agent adapters
+
+Create minimal adapters/interfaces so Codex and Claude can call the same cache protocol.
+
+Do not hard-code provider-specific semantic cache keys.
+
+Do not require either model vendor to know the SQLite schema.
+
+## CATCH integration
+
+Record cache events into the existing trace/evidence model where appropriate:
+
+- cache_lookup
+- cache_hit
+- cache_miss
+- cache_rejected
+- cache_write
+- cache_invalidated
+
+Record the provenance and verifier responsible for acceptance.
+
+If a cached artifact later fails independent verification, invalidate it and record the disagreement.
+
+## Remote cache
+
+Do not duplicate the remote Supabase implementation blindly.
+
+Define a backend interface:
+
+```
+CacheBackend
+βββ LocalSQLiteBackend
+βββ RemoteVerifiedBackend
+```
+
+The local backend is required now.
+
+The remote backend may be an adapter over the existing Vercel/Supabase path, but preserve one canonical schema and key format.
+
+## Security
+
+Review the existing Supabase RLS.
+
+The current anonymous-all policy is acceptable only as a development demo.
+
+Add a production-safe design for authenticated owner/workspace isolation. If auth infrastructure is not yet present, implement the schema/interface and tests without pretending the security boundary is complete.
+
+## Web and voice
+
+Expose a server-side API that can use the same cache service.
+
+Do not put authoritative reusable cache state in browser localStorage.
+
+Voice sessions should call the cache outside the realtime conversation state so the cache survives session boundaries.
+
+## Testing
+
+Add focused tests for:
+
+- key canonicalization;
+- provenance mismatch;
+- policy mismatch;
+- VERIFIED-only writes;
+- UNKNOWN/FAILED rejection;
+- side-effect non-replay;
+- secret-access non-replay;
+- production-deploy non-replay;
+- cross-session reuse;
+- cross-agent reuse;
+- concurrent access;
+- invalidation;
+- artifact integrity;
+- trace emission.
+
+Run targeted tests first, then the relevant project test suite.
+
+If the repository has pre-existing failures, distinguish them from failures caused by this change.
+
+## Verification
+
+Verify from actual repository/tool output:
+
+- changed files;
+- exact commit SHA;
+- test results;
+- CI/check results;
+- PR state;
+- deployment state if web code changes.
+
+Never report success based on intention.
+
+## Final report
+
+Return exactly:
+
+1. VERIFIED: what changed, with exact paths.
+2. VERIFIED: tests/checks actually run.
+3. VERIFIED: commit SHA and branch.
+4. VERIFIED: PR status.
+5. INFERRED: expected performance/architecture benefits.
+6. UNKNOWN: anything not yet verified.
+7. NEXT: the smallest remaining blocker.
+
+Do not mark the PR ready merely because the local cache works. Mark it ready only when the implementation and verification gates are actually satisfied.