# Project export: RAVEN: Verified Context Passports for the Agentic Web

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2026
- Tagline: RAVEN gives every AI agent a tiny, recipient-aware context passport instead of your whole memory — 80-90% fewer tokens, every standing rule preserved. Live on Fetch.ai Agentverse.
- Devpost: https://devpost.com/software/s-9ikm1b
- GitHub: https://github.com/thesantoshpant/raven
- Video: https://www.youtube.com/embed/l_4wXr0HFp0?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Santosh Pant (28 commits)

## Devpost submission (written by the team)

### Inspiration

Every agent demo we tried had the same dirty secret: to make an agent "smart," people dump the entire user memory into every model call, and into every agent in a multi-agent system. It's expensive, it's slow, and — worse — it's unsafe. We watched a perfectly capable model, handed 1,700 tokens of someone's notes, confidently recommend an Italian restaurant for a vegetarian because the dietary rule was buried in the middle and got lost. That's the real problem we wanted to reframe. The bottleneck of the agentic web isn't model intelligence — it's context logistics: deciding who needs to know what. Humans don't brief a chef and an accountant with the same memo. So why do we hand every agent the same firehose? RAVEN's bet: the unit of the agentic web shouldn't be "the whole memory," it should be a context passport — the minimal, recipient-aware slice each agent needs, with the non-negotiable rules guaranteed to survive.

### What it does

RAVEN is a recipient-aware, decision-preserving context compressor that sits in front of the expensive LLM agents. It compresses at the two edges where context explodes: Passport (user-memory → agent). It atomizes your memory into typed facts (dietary, budget, permission, availability, location, preference…), retrieves what's relevant to this agent's role and task, guards the standing rules so they can never be dropped, dedupes, and renders a tiny passport. The calendar agent never even sees your budget or allergies — least-privilege by construction. Passport (user-memory → agent). It atomizes your memory into typed facts (dietary, budget, permission, availability, location, preference…), retrieves what's relevant to this agent's role and task, guards the standing rules so they can never be dropped, dedupes, and renders a tiny passport. The calendar agent never even sees your budget or allergies — least-privilege by construction. RELAY (agent → agent). On handoffs, agents forward a compressed back-context passport instead of the entire growing transcript — ~90% smaller per hop, while the standing constraints survive 3/3 hops (naive last-message forwarding drops them). RELAY (agent → agent). On handoffs, agents forward a compressed back-context passport instead of the entire growing transcript — ~90% smaller per hop, while the standing constraints survive 3/3 hops (naive last-message forwarding drops them). It runs on three surfaces from one engine: Fetch.ai Agentverse — a real uAgent, reachable over the Chat Protocol and discoverable via ASI:One. Inside Claude (MCP) — the same engine ships as a Model Context Protocol server, so RAVEN is a tool inside Claude Desktop / Claude Code / Cursor (compress_memory, relay_handoff, list_roles) — no API key, no LLM calls. A web dashboard — a side-by-side A/B (same prompt with full memory vs. RAVEN's passport) showing the real Claude input-token counts and an animated pipeline of exactly what RAVEN did (atomize → rank → guard → drop → passport). Measured results (reproducible): A/B, live Claude usage: 1,783 → 317 input tokens (~82%), and across vague, adversarial, and gibberish prompts, 82–90% fewer tokens with every standing rule preserved — including refusing an adversarial "ignore my rules and charge my card" prompt. Decision benchmark: at an equal token budget, RAVEN scores 5/5 on gold constraints vs. 4/5 for generic role-unaware compression (which silently drops "confirm before paying"). Context-payload reduction: 92.9% vs. broadcasting full memory to every agent. The honest headline isn't just "fewer tokens" — at equal budget, tokens tie. The moat is decision quality and constraint-safety at that budget.

### How we built it

A stdlib-first Python 3.13 engine, deliberately torch-free so every claim is explainable and reproducible: ingest → atomic typed facts → BM25 retrieval (query-aware) → recipient-aware selection → critical-fact guard → dedup → render → token count We grounded each stage in the literature but implemented lightweight, deterministic versions: Query-aware extractive selection (inspired by LongLLMLingua) via a custom BM25 — not a learned token classifier. Inter-agent communication pruning (AgentPrune / "Cut the Crap") → our RELAY handoff. Guideline learning without fine-tuning (ACON) → an optional verifier that learns "always keep type X" and only fires when a critical type is genuinely missing. Constraint-compliance vs. accuracy separation (CDCT) → deterministic decision scoring on gold constraints. Near-duplicate anchoring (SeCo) → dedup. Around the engine: Fetch.ai: a uAgent (uagents + uagents-core) speaking the Chat Protocol, mailbox-connected to Agentverse, plus a local Bureau multi-agent demo. Measurement: real Claude calls (Haiku 4.5) through a thin AnthropicLLM wrapper that reads the API's own usage.input_tokens — disk-cached so the stage demo is instant and free. Web: a FastAPI backend + Next.js 14 / React frontend ("Editorial Minimal" design) with the live A/B, the animated pipeline, a token meter, the decision benchmark, and PDF/doc ingestion (markitdown). Rigor: 116 offline tests (2 skipped), with a strict invariant that the test suite imports no uagents/fastapi/markitdown/mcp/network — the core stays pure. The savings number we show is literally: $$\text{saved}\% = \left(1 - \frac{T_{\text{RAVEN}}}{T_{\text{full}}}\right)\times 100$$ where $T$ are the model's real input tokens, not estimates.

### Challenges we ran into

Compression is lossy by math, not by mistake. Turning $N$ tokens into $M < N$ forces a bet about what matters. Our first selector kept the dietary rule but dropped the actual restaurant suggestion and, in another pass, dropped "confirm before paying." The fix wasn't "compress better" — it was to make the loss principled: a hard guard that never drops standing rules, plus soft guards for schedule/location/preference, so the loss only ever lands on low-relevance facts. Relevance has no perfect oracle. BM25 mismatches vocabulary ("Italian place" vs. "where to eat"). We tuned a relevance floor and a recipient model rather than reaching for a heavyweight learned compressor we couldn't explain. Honest measurement is hard. It's tempting to quote a self-counted number. We forced ourselves to report the API's own usage.input_tokens, to disclose that tokens tie at equal budget, and to make the real win (decision quality) the headline. Live latency & demo safety. Real calls were slow under load, so we built disk caching, a "live Xs / cached" badge for transparency, and a cooldown so a demo can't accidentally burn quota. Keeping the agent dependency-free. The Agentverse agent itself makes zero LLM calls (pure deterministic compression), so it needs no API key to run — which took discipline to preserve as the codebase grew.

### Accomplishments we're proud of

Three deploy surfaces from one engine — a live Agentverse agent, an MCP server inside Claude, and a provable web A/B demo — all reusing the same pure compression core. A live agent on Agentverse that's genuinely useful infrastructure, not a toy — it makes other agents cheaper. A provable demo: real token counts, side-by-side, with an animation that teaches the mechanism — and it survives adversarial prompts (it refused to bypass the "confirm before paying" and "no steakhouse" rules). Constraint-safety as a feature: RAVEN keeps the rules a bloated full-memory model drops. We turned "lost in the middle" from a risk into our demo's punchline. 80–90% token reduction with preserved decisions, reproducible from a clean checkout, backed by 116 tests. A design that's explainable end-to-end — every kept fact has a reason (guard vs. relevant).

### What we learned

More context is not safer context. Past a point, extra tokens hurt — the model loses the critical rule. The relevant slice beats the whole memory on both cost and safety. Generic compression solves a different problem than ours. The papers optimize "shrink a prompt, keep generic answer quality." The agentic, constraint-sensitive use case needs "compress for a recipient without dropping the rules" — and bridging that gap (recipient-awareness + a constraint guard + a verifier) is the actual contribution. The limitations are mostly the problem talking back. Lossiness, imperfect relevance, and constraint-vs-relevance tension are fundamental; the value is in managing them honestly, not pretending to eliminate them. Least-privilege context is a privacy story, not just a cost story.

### What's next

for RAVEN Publish the MCP server to PyPI so anyone adds RAVEN to Claude with one line (uvx raven-mcp), plus a persistent memory store and more tools (the MCP server already works locally inside Claude Desktop / Code / Cursor). An LLM API proxy (one-line base_url swap) so any existing app gets the savings with no rewrite. Learned relevance as an optional upgrade (embeddings / a small classifier) behind the same explainable interface, for users who'll trade a dependency for higher recall. Cross-agent passport caching and KV-level compression (Cache-to-Cache) for repeat back-context. Framework adapters (LangChain / CrewAI) so multi-agent builders get RELAY for free.

## README (from the GitHub repository)

# RAVEN — Verified Context Passports for the Agentic Web

![tests](https://img.shields.io/badge/tests-116%20passing-brightgreen)
![python](https://img.shields.io/badge/python-3.10%2B-blue)
![MCP](https://img.shields.io/badge/MCP-ready-7c3aed)
![Fetch.ai](https://img.shields.io/badge/Fetch.ai-Agentverse-000)
![license](https://img.shields.io/badge/license-MIT-green)

**RAVEN gives each AI agent a tiny, recipient-aware "context passport" instead of your whole memory — ~80–93% fewer context tokens, with every standing rule guaranteed to survive.**

Most agent stacks make agents "smart" by dumping the **entire** user memory into **every** model call and **every** agent in a multi-agent system. It's expensive, slow, and unsafe: hand a capable model 1,700 tokens of notes and it will confidently recommend an *Italian restaurant for a vegetarian* — because the dietary rule was buried in the middle and got lost.

The bottleneck of the agentic web isn't model intelligence — it's **context logistics**: deciding *who needs to know what*. You don't brief a chef and an accountant with the same memo. RAVEN is the layer that gives each agent only the slice it needs, with the non-negotiable rules force-kept.

> *Same memory, two agents:* the **budget** agent gets `under $40` + `confirm before paying`; the **calendar** agent gets only `free Friday after 7pm`. Neither sees the other's facts. That's recipient-aware, least-privilege context — by construction.

---

## Try it 3 ways

### 1. Inside Claude (MCP) — one line, no clone
Add this to your Claude Desktop config (`%APPDATA%\Claude\claude_desktop_config.json` on Windows, `~/Library/Application Support/Claude/` on macOS), then restart Claude:
```json
{
  "mcpServers": {
    "raven": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/thesantoshpant/raven", "raven-mcp"]
    }
  }
}
```
Then ask Claude: *"Use raven to compress this for the budget agent: Maya is vegetarian, keep dinner under $40, free Friday after 7pm, always confirm before paying."*
Tools exposed: `compress_memory`, `relay_handoff`, `list_roles`. No API key — RAVEN does pure, deterministic compression; the host model is the LLM. (Details: [`raven/mcp/README.md`](raven/mcp/README.md).)

### 2. On Fetch.ai Agentverse — a live uAgent
RAVEN runs as a Chat-Protocol uAgent discoverable from ASI:One.
- **Hosted (24/7):** paste [`raven/fetch/raven_hosted_agent.py`](raven/fetch/raven_hosted_agent.py) (a single self-contained file) into an Agentverse *Blank Agent* and press Start.
- **Local (mailbox):** `pip install -r requirements-fetch.txt`, set `RAVEN_AGENT_SEED`, run `python raven/fetch/raven_agent.py`, connect the mailbox.

Then chat it: `role: budget | memory: Maya is vegetarian. Keep dinner under $40. Confirm before paying.`

### 3. Locally — the visual demo dashboard
A side-by-side **A/B** (same prompt with full memory vs. RAVEN's passport) showing the model's **real input-token usage** and an animated pipeline of exactly what RAVEN did.
```bash
git clone https://github.com/thesantoshpant/raven && cd raven
python -m venv .venv && .venv/Scripts/python -m pip install -r requirements-web.txt
.venv/Scripts/python -m uvicorn raven.web.api:app --port 8000      # backend
cd frontend && npm install && npm run dev                          # UI -> http://localhost:3000
```
> ⚠️ The dashboard's live A/B calls the Claude API (needs `ANTHROPIC_API_KEY`) and Next 14 has known advisories — it's **local-demo-only; don't deploy as-is**. The engine, gate, and tests need none of this.

---

## What it does

RAVEN compresses at the **two edges** where context explodes:

1. **Passport (user memory → agent).** Atomize memory into typed facts (dietary, budget, permission, availability, location, preference…), retrieve what *this* role needs, **guard** the standing rules so they're never dropped, dedup, and render a tiny passport.
2. **RELAY (agent → agent).** On handoffs, forward the latest message verbatim + a compressed back-context passport instead of the whole growing transcript — **~90% smaller per hop**, while standing constraints survive **3/3 hops** (naive last-message forwarding drops them).

## Results (reproducible from a clean checkout)

| Measure | Result |
|---|---|
| **Context-payload reduction** (vs broadcasting full memory to every agent) | **92.9%** |
| **A/B, real Claude input tokens** (one prompt) | **1,783 → 317 (~82%)** |
| **Decision benchmark** at an *equal* token budget | **RAVEN 5/5** vs generic role-unaware **4/5** (drops "confirm before paying") |
| **RELAY** handoff vs full transcript | **8,560 → 889 (~90%)**, constraints kept 3/3 hops |
| **Offline test suite** | **116 passing** (stdlib, no network) |

*Corpus: 38 memory items / 127 facts. Model: Claude Haiku 4.5, temperature 0, disk-cached. Numbers from `bench/run_gate.py`, `bench/run_m2.py`, `bench/run_relay.py`.*

**The honest headline:** at an *equal* token budget RAVEN ties a generic fact-store baseline on raw token count — that part isn't the moat. The moat is **decision quality and constraint-safety at that budget**: the guard routes "confirm before paying" to the budget agent even though the request never lexically mentions it, so RAVEN scores 5/5 where the role-unaware blob drops to 4/5.

## How it works

Deterministic, **stdlib-first**, torch-free — so every claim is explainable and reproducible:
```
raw memory → split into atomic typed facts → BM25 retrieval (query-aware)
           → recipient-aware selection (keep the role's types)
           → critical-fact GUARD (force-keep standing-rule types, even at score 0)
           → dedup → render passport → count tokens
```
The **guard** is the key idea: a constraint can be lexically *irrelevant* to a query ("vegetarian" vs "where to eat") yet decision-critical. Pure relevance compression drops it — exactly the "lost in the middle" failure. The guard force-keeps standing-rule *types*, so the loss only ever lands on low-relevance facts, never a rule. Every kept fact carries a reason (`guard` vs `relevant`), so the output is fully auditable — no black-box compressor.

## Architecture

One pure engine, three surfaces:
- **Engine** (`raven/`): a custom BM25 retriever + typed-fact compression + the critical guard + an optional ACON-style verifier. Pure stdlib; no ML downloads.
- **MCP server** (`raven/mcp/`): the engine as a tool for Claude Desktop / Code / Cursor.
- **Fetch.ai uAgent** (`raven/fetch/`): Chat-Protocol agent for Agentverse / ASI:One + a single-file hosted build.
- **Web** (`raven/web/` + `frontend/`): FastAPI + Next.js dashboard with the live A/B and animated pipeline.

**Engineering discipline:** 116 offline tests with a strict isolation invariant — the test suite imports no `uagents`/`fastapi`/`markitdown`/`mcp`/network; the heavy transports are the *sole* importers of their SDKs, and the pure logic is tested separately.

### Research grounding (lightweight, explainable variants)
| Implemented | Grounded in |
|---|---|
| Query-aware extractive selection (custom BM25, not a learned classifier) | LongLLMLingua |
| Inter-agent comms pruning (RELAY) | AgentPrune / "Cut the Crap" |
| Guideline learning without fine-tuning (the verifier) | ACON |
| Constraint-compliance vs. accuracy separation (deterministic gold scoring) | CDCT |
| Near-duplicate anchoring (dedup) | SeCo |

Deliberately **not** used: a learned token classifier (LLMLingua-2) or KV-cache compression (Cache-to-Cache) — extractive + deterministic is *why* RAVEN can **prove** decision-preservation (it can point at the exact kept fact and its reason).

## Honest limitations
- **Compression is lossy by definition** — RAVEN bounds the loss to low-relevance facts and never to standing rules (the guard).
- **BM25 has vocabulary-mismatch failures**; mitigated by the recipient model + guard. Learned relevance is an optional future upgrade behind the same interface.
- **Single hand-authored scenario** for the decision benchmark — an *existence proof* of 

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 67 recognized source files, 279 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- FastAPI (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (81 of 81)

```
.gitignore
bench/run_gate.py
bench/run_m2.py
bench/run_relay.py
bench/smoke_fastembed.py
bench/warm_cache.py
conftest.py
data/corpus_friday_dinner.json
data/task_friday_dinner.json
data/venues_friday_dinner.json
DEMO.md
DEVPOST_SUBMISSION.md
DEVPOST.md
frontend/.env.local.example
frontend/app/globals.css
frontend/app/layout.js
frontend/app/page.js
frontend/lib/api.js
frontend/next.config.mjs
frontend/package.json
LICENSE
pyproject.toml
raven/__init__.py
raven/agents.py
raven/baselines.py
raven/compress.py
raven/fetch/__init__.py
raven/fetch/AGENT_README.md
raven/fetch/bureau_demo.py
raven/fetch/chat_smoke.py
raven/fetch/raven_agent.py
raven/fetch/raven_hosted_agent.py
raven/guidelines.py
raven/handlers.py
raven/ingest_docs.py
raven/ingest.py
raven/llm.py
raven/mcp/__init__.py
raven/mcp/_logic.py
raven/mcp/README.md
raven/mcp/server.py
raven/mcp/smoke.py
raven/relay.py
raven/retrieve.py
raven/roles.py
raven/schemas.py
raven/score.py
raven/store.py
raven/tokens.py
raven/verifier.py
raven/web/__init__.py
raven/web/api.py
raven/web/pricing.py
raven/web/services.py
README.md
requirements-docs.txt
requirements-fetch.txt
requirements-mcp.txt
requirements-web.txt
requirements.txt
stitch.md
tests/test_ab_selection.py
tests/test_agents.py
tests/test_baselines.py
tests/test_compress.py
tests/test_gate.py
tests/test_handlers.py
tests/test_ingest_docs.py
tests/test_ingest_subtypes.py
tests/test_ingest.py
tests/test_llm.py
tests/test_mcp_logic.py
tests/test_passport_counts_actual_prompt_tokens.py
tests/test_relay.py
tests/test_retrieve.py
tests/test_score_structured.py
tests/test_score.py
tests/test_store_factory.py
tests/test_tokens.py
tests/test_verifier.py
tests/test_web_services.py
```

### Dependencies

- frontend/package.json: next@14.2.15, react@18.3.1, react-dom@18.3.1
- pyproject.toml: mcp@>=1.0
- requirements.txt: pytest@>=8,<10

### Recent commits (newest first)

- fix(agentverse): drop future-import from single-file hosted agent (fixes sandbox @dataclass crash code 15005)
- feat: single-file Agentverse hosted agent + uvx/pip packaging (raven-mcp) + MIT LICENSE + resume-ready README + DevPost MCP updates
- fix(audit): newline/bullet ingest split, anchored chat markers (prose-safe), A/B saved floor + unique-fact trace, cooldown-after-success, ack guard, exact-span render, list_roles typing; +3 tests; doc refresh
- docs(agent): optimize AGENT_README for ASI:One discovery (natural-language phrasings, realistic savings, multi-role)
- feat(mcp): RAVEN as an MCP server (compress_memory / relay_handoff / list_roles) for Claude Desktop/Code/Cursor
- docs: DevPost submission (name, pitch, full project story, built-with, ethics)
- feat(ab): personal-assistant recipient (guard + context types) surfaces venue/schedule, anti-embellish prompt, live/cached badge, +9 weird-condition tests
- feat(ab): animated pipeline showing RAVEN's steps (atomize/rank/guard/drop/passport) during the live call
- fix(ab): guard standing-rule facts in A/B compression + render markdown bold + clean default memory
- feat(ui): A/B with-vs-without-RAVEN live token-savings demo (real Claude input_tokens, side-by-side)
- test+polish: baselines/calendar/3-hop-relay coverage, optional role colon, per-1k \$ display
- fix(round2): _parse separators/punct/prose-safety, README redis wording, AA contrast, stitch.md numbers, +6 tests
- fix: address all 5-agent audit findings (chat parse, writer constraints, 24h times, verifier 0-cost, UI/doc polish)
- fix: 'per person' is a price observation not a budget cap; per-constraint dots; docstring/README refresh; footer dead-link cleanup
- ui: human-readable missed-constraint labels in the benchmark
- fix(ui): token-meter label/bar overlap; benchmark dots green=kept/red=missed; footer + divider polish
- feat(ui): re-skin to Stitch Editorial Minimal theme (paper/teal, Fraunces/Inter/IBM Plex Mono)
- docs: add stitch.md design brief for the minimal UI redesign
- fix: require RAVEN_AGENT_SEED for mailbox runs; soften chat_smoke/DEMO network wording
- feat(round-b): M5 document ingestion (PDF -> memory) + bug-hunt fixes

## Key source files (fetched from GitHub, selected and truncated for size)

### DEVPOST.md

```markdown
# RAVEN — Verified Context Passports for the Agentic Web

## Inspiration
AI is becoming everyone's daily driver, and multi-agent systems are exploding. But every
agent gets handed the *same firehose* — your entire memory — on every call. That's expensive
(tokens scale with users × agents × turns) and it's a privacy problem (each agent sees
everything, not just what it needs). Summarizing naively is worse: it silently drops the one
fact that flips the decision. We wanted to fix the **plumbing** of the agentic web.

## What it does
RAVEN gives every agent a **context passport**: only the facts that agent's role actually
needs, at **both** edges of a multi-agent system — user-memory → first agent, and agent →
agent (we call the second edge **RELAY**). It is **recipient-aware** (least privilege) and
**decision-preserving** (a verifier + learnable role priors keep the load-bearing facts).

## How it works
1. **Ingest** messy memory → atomic, typed facts (dietary, budget_limit, availability,
   permission, …; multi-label for combined sentences).
2. **Retrieve** per role with BM25 over the fact store.
3. **Compress** into a passport: positive-relevance selection + a guard that force-keeps the
   role's critical types + near-dup dedup, rendered as the exact prompt text.
4. **Verify** (optional, one-time): probe the passport vs full context; re-add + learn a
   guideline if a load-bearing fact is missing (ACON-style, no fine-tune).
5. **RELAY**: at each handoff, forward the latest message + a compressed back-context passport
   instead of the whole transcript.

## Proven results (in the repo, reproducible)
- **Context-payload reduction (M1):** ~93% fewer query-time tokens vs broadcasting full
  memory to every agent (ratio-gated, tokenizer-measured, 4 baselines incl. a fair
  equal-budget one).
- **Decision preservation (M2):** with real Claude agents, at an equal per-agent budget —
  **raw 5/5, generic compression 4/5 (drops the standing "confirm before paying" rule),
  RAVEN 5/5** — deterministic, structured gold-constraint scoring.
- **RELAY (M3):** agent→agent handoffs ~90% smaller than forwarding the transcript, and it
  preserves the standing back-context constraints last-message passing drops (3/3 vs 1/3).
- **Live demo (M4):** a three-pane dashboard — memory → passports → live benchmark → RELAY.

## Built with
Python (stdlib-first engine: dataclasses, BM25, deterministic scoring), Anthropic Claude
(role agents, temp 0, disk-cached), **Fetch.ai uAgents + Agentverse + ASI:One** (RAVEN runs
as a Chat-Protocol agent), optional **Redis** fact store, **FastAPI** + **Next.js** demo UI.
80+-test offline suite; honest, ratio-based benchmarks throughout.

## Sponsor fit
- **Fetch.ai:** RAVEN is a first-class uAgent on Agentverse, discoverable from ASI:One via the
  standard Chat Protocol — and it makes *every* multi-agent system on the network cheaper
  (RELAY cuts inter-agent comms cost).
- **The Token Company:** a measured, decision-preserving compression
[truncated — 571 more characters]
```

### DEMO.md

```markdown
# RAVEN — Demo Runbook

A rehearsable, can't-fail script for judging. ~3 minutes.

## 0. Pre-flight (do this BEFORE you present)
```
# terminal 1 — backend (requirements-docs is needed for PDF/docx/html upload; .md/.txt work without it)
.venv\Scripts\python -m pip install -r requirements-web.txt -r requirements-docs.txt
.venv\Scripts\python -m uvicorn raven.web.api:app --port 8000

# terminal 2 — warm the live cache so the on-stage benchmark is instant
.venv\Scripts\python bench\warm_cache.py

# terminal 3 — frontend
cd frontend && npm install && npm run dev -- -p 3000
```
Open http://localhost:3000. Click **Run benchmark** once now (it's cached after) so it's snappy live.

Optional (the Fetch/ASI:One live moment — see §4): start the agent and connect its mailbox.

## 1. The hook (20s)
"AI is becoming everyone's daily driver, and every agent gets handed your *entire* memory —
expensive and over-exposed. RAVEN gives each agent a **context passport**: only the facts
that agent's role needs, at every edge of a multi-agent system."

## 2. Dashboard — three panes (70s)
- **Left (User memory):** "38 messy items — chats, notes, receipts. Five decision-critical
  facts are buried in here (highlighted): Maya's vegetarian, the $40 cap, the lab schedule,
  'no loud places', and a standing 'confirm before paying' rule."
- **Middle (Agents · passports):** click **budget** → "Instead of all 127 facts, the budget
  agent gets a 3-line passport: the $40 cap + the confirm rule. It's *denied* the rest —
  least privilege by construction." Click **restaurant** → "different agent, different slice."
- **Right (Token meter + live benchmark):** "Across the workflow that's ~94% fewer context
  tokens." Click **Run benchmark** → "Now the punchline — does compression hurt the decision?
  **raw** (full memory) gets 5/5 but is expensive. **generic** compression at the same budget
  drops to **4/5** — it loses the payment rule. **RAVEN** keeps **5/5** at a fraction of the
  cost. Same budget, better decision."

## 3. RELAY tab (30s)
"Compression isn't just at the front door — it's every agent-to-agent handoff. Naively you
forward the whole growing transcript. RELAY forwards the latest message + a compressed
back-context passport: **~90% smaller** than broadcasting the transcript, and it *keeps* the
standing constraints that last-message-passing silently drops (3/3 hops vs 1/3)."

## 4. Fetch / ASI:One — "it's live on the agentic web" (30s)
"RAVEN runs as a real **uAgent** on **Agentverse**, discoverable from **ASI:One** over the
standard Chat Protocol." Then EITHER:
- **(best) live:** in ASI:One chat, message the RAVEN agent with a memory blob → it returns a
  passport. (Have this pre-tested; see mailbox steps below.)
- **(fallback) local:** `python raven/fetch/bureau_demo.py --once` — two real uAgents hand off
  with RAVEN compressing the wire; or `python raven/fetch/chat_smoke.py` for the chat round-trip.

## 5. Close (10s)
"RAVEN: verified context passports for the agenti
[truncated — 1485 more characters]
```

### requirements.txt

```
# --- M1 core: stdlib only, nothing required to run the gate ---
# Tests + benchmark run with ZERO of the below installed (pure stdlib path).
#
# Optional upgrades (install for nicer numbers; the gate never depends on them):
#   pip install tiktoken      # exact GPT-family token counts (downloads encoding once)
#   pip install fastembed     # ONNX embeddings, no torch (downloads a model once)
#
# Dev:
pytest>=8,<10

```

### pyproject.toml

```
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "raven-mcp"
version = "0.1.0"
description = "RAVEN — recipient-aware context-passport compression, packaged as an MCP server (and the underlying engine)."
readme = "README.md"
requires-python = ">=3.10"
dependencies = ["mcp>=1.0"]

[project.scripts]
raven-mcp = "raven.mcp.server:main"

[project.urls]
Homepage = "https://github.com/thesantoshpant/raven"

[tool.setuptools]
packages = ["raven", "raven.mcp", "raven.fetch", "raven.web"]

[tool.pytest.ini_options]
# Makes `raven` importable and tests runnable from ANY directory (not just repo root),
# which the root conftest.py shim alone did not guarantee.
pythonpath = ["."]
testpaths = ["tests"]
addopts = "-p no:cacheprovider"   # no .pytest_cache -> clean, professional output anywhere

```

### frontend/package.json

```
{
  "name": "raven-frontend",
  "version": "0.4.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "14.2.15",
    "react": "18.3.1",
    "react-dom": "18.3.1"
  }
}

```

### frontend/app/layout.js

```javascript
import "./globals.css";

export const metadata = {
  title: "RAVEN — Context Passports for the Agentic Web",
  description: "Recipient-aware, decision-preserving context compression for multi-agent systems.",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <link rel="preconnect" href="https://fonts.googleapis.com" />
        <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
        <link
          href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=Inter:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap"
          rel="stylesheet"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}

```

### raven/mcp/server.py

```python
"""RAVEN as an MCP server -- the ONLY module that imports `mcp` (mirrors web/api.py for fastapi,
so the offline test suite never pulls in the MCP SDK).

RAVEN makes NO LLM calls and needs NO API key: the host model (Claude) is the LLM; RAVEN just
returns a compressed, recipient-aware "context passport".

Run (stdio transport, for Claude Desktop / Claude Code / Cursor):
    python -m raven.mcp.server
"""

from __future__ import annotations

from mcp.server.fastmcp import FastMCP

from . import _logic

mcp = FastMCP("raven")


@mcp.tool()
def compress_memory(memory: str, task: str = "general task", role: str = "writer") -> str:
    """Compress a memory/context blob into a tiny, recipient-aware RAVEN 'context passport' for a
    downstream agent role. Keeps only what that role needs, force-keeps standing rules
    (dietary / budget / permission), and drops the rest -- typically 80-95% fewer tokens.
    Deterministic, no LLM, no API key. `role` is one of: restaurant, calendar, budget, writer."""
    return _logic.compress_response(memory, task, role)


@mcp.tool()
def relay_handoff(prior_context: str, latest_message: str, role: str = "writer") -> str:
    """Compress an agent->agent handoff: forward `latest_message` VERBATIM plus a compressed
    recipient-aware passport of `prior_context` -- ~90% smaller than forwarding the whole
    transcript, while standing constraints survive. Deterministic, no LLM."""
    return _logic.relay_response(prior_context, latest_message, role)


@mcp.tool()
def list_roles() -> list[str]:
    """List the recipient roles RAVEN can compress for (restaurant, calendar, budget, writer)."""
    return _logic.roles_list()


def main() -> None:
    mcp.run()  # stdio transport by default


if __name__ == "__main__":
    main()

```

### frontend/app/page.js

```javascript
"use client";

import { useEffect, useRef, useState } from "react";
import { api } from "../lib/api";

function escapeRe(s) {
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

// Build a fresh highlight regex. Word boundaries are added only where a phrase edge is a
// word char (so "loud" doesn't match inside "cloud", but "$40"/"5:30" still match).
function highlightRegex(phrases) {
  const list = (phrases || []).filter(Boolean).slice().sort((a, b) => b.length - a.length);
  if (!list.length) return null;
  const term = (p) => (/^\w/.test(p) ? "\\b" : "") + escapeRe(p) + (/\w$/.test(p) ? "\\b" : "");
  return new RegExp(`(${list.map(term).join("|")})`, "gi");
}

function Highlighted({ text, phrases }) {
  const re = highlightRegex(phrases);
  if (!re) return <>{text}</>;
  const low = new Set((phrases || []).filter(Boolean).map((p) => p.toLowerCase()));
  const parts = String(text).split(re);
  return (
    <>
      {parts.map((p, i) =>
        low.has(p.toLowerCase()) ? <mark key={i}>{p}</mark> : <span key={i}>{p}</span>
      )}
    </>
  );
}

function Rich({ text }) {
  // minimal markdown: render **bold** as <strong> and keep line breaks.
  const lines = String(text).split("\n");
  return lines.map((line, i) => (
    <span key={i}>
      {line.split(/(\*\*[^*]+\*\*)/g).map((seg, j) =>
        /^\*\*[^*]+\*\*$/.test(seg) ? <strong key={j}>{seg.slice(2, -2)}</strong> : seg
      )}
      {i < lines.length - 1 && <br />}
    </span>
  ));
}

const svg = (children) => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">{children}</svg>
);
const ROLE_ICON = {
  restaurant: svg(<><path d="M4 3v8M7 3v8M5.5 3v8M5.5 11v10M18 3c-1.6 0-2.5 2.2-2.5 5.5S16.4 13 18 13v8" /></>),
  calendar: svg(<><rect x="3" y="5" width="18" height="16" rx="2" /><path d="M3 9h18M8 3v4M16 3v4" /></>),
  budget: svg(<><rect x="3" y="6" width="18" height="13" rx="2" /><path d="M3 10h18M16 14.5h2" /></>),
  writer: svg(<><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z" /></>),
};

function MemoryPane({ scenario, onUpload, uploading, uploadErr, uploadMsg }) {
  if (!scenario) return <div className="panel"><h2>User memory</h2><div className="muted">loading…</div></div>;
  const phrases = scenario.highlights || [];
  const hasGold = (t) => { const r = highlightRegex(phrases); return r ? r.test(t) : false; };
  return (
    <div className="panel">
      <h2>User memory <span className="count">{scenario.counts.items} items · {scenario.counts.facts} facts</span></h2>
      <div className="muted" style={{ marginBottom: 10 }}>Everything you&apos;d dump into an agent. The 5 decision-critical facts are buried (highlighted).</div>
      <div style={{ marginBottom: 10 }}>
        <label className="btn secondary" style={{ display: "inline-block", width: "auto", padding: "7px 12px", fontSize: 13, cursor: uploading ? "not-allowed" : "pointer" }}>
          {uploading ? <><span className="spinner" />ingesting…</> : "+ Upload a PDF / doc → memory"}
          <input type="file" accept=".pdf,.docx,.md,.txt,.html" style={{ display: "none" }} disabled={uploading}
            onChange={(e) => { const f = e.target.files && e.target.files[0]; if (f) onUpload(f); e.target.value = ""; }} />
        </label>
        {uploadErr && <div className="toast">⚠ {uploadErr}</div>}
        {uploadMsg && <div className="muted" style={{ marginTop: 6 }}>✓ {uploadMsg}</div>}
      </div>
      <div className="memlist">
        {scenario.memory_items.map((it) => (
          <div key={it.id} className={"memitem" + (hasGold(it.text) ? " gold" : "")}>
            <span className="kind">{it.kind}</span>{" · "}
            <Highlighted text={it.text} phrases={phrases} />
          </div>
        ))}
      </div>
    </div>
  );
}

function AgentsPane({ passports, error }) {
  const [open, setOpen] = useState(null);
  if (!passports) return <div className="panel"><h2>Agents · passports</h2><div className="muted">{error ? "⚠ " + error : "loading…"}</div></div>;
  return (
    <div className="panel">
      <h2>Agents · recipient-aware passports</h2>
      <div className="muted" style={{ marginBottom: 10 }}>
        Raw: every agent gets all {passports.n_facts} facts (~{passports.full_tokens} tok). RAVEN: each gets only its slice.
      </div>
      {passports.roles.map((r) => (
        <div key={r.role} className={"agentcard" + (open === r.role ? " open" : "")} onClick={() => setOpen(open === r.role ? null : r.role)}>
          <div className="row">
            <span className="role">{ROLE_ICON[r.role] || null}{r.role}</span>
            <span className="pill">{r.tokens} tok · −{r.saved_pct}%</span>
          </div>
          <div className="sub">sees {r.facts.length} facts · denied {r.excluded_count} · ~${(Number(r.est_usd_per_send) * 1000).toFixed(2)}/1k sends</div>
          {open === r.role && (
            <div className="passport">
              {r.facts.map((f, i) => (
                <div className="fact" key={i}><span className="ftype">{f.type}</span>{f.text}</div>
              ))}
              <pre style={{ marginTop: 8 }}>{r.passport_text}</pre>
            </div>
          )}
        </div>
      ))}
    </div>
  );
}

function Meter({ passports, error }) {
  if (!passports) return <div className="muted">{error ? "⚠ " + error : "loading…"}</div>;
  const n = passports.roles.length || 1;
  const rawBroadcast = passports.full_tokens * n;
  const ravenTotal = passports.roles.reduce((a, r) => a + r.tokens, 0);
  const savedPct = rawBroadcast ? Math.round((1 - ravenTotal / rawBroadcast) * 100) : 0;
  const ravenW = rawBroadcast ? Math.max(6, Math.round((ravenTotal / rawBroadcast) * 100)) : 6;
  return (
    <div className="meter">
      <div className="meter-row"><span>Raw — full memory to all {n} agents</span><span className="v">{rawBroadcast.toLocaleString()} tok</span></div>
      <div className="bar raw" style={{ width: "100%" }} />
      <div className="meter-row
[truncated — 18265 more characters]
```

### conftest.py

```python
import os
import sys

# Make the `raven` package importable when running pytest / scripts from the repo root.
sys.path.insert(0, os.path.dirname(__file__))

```

### raven/__init__.py

```python
"""RAVEN: recipient-aware verified context passports for the agentic web.

Milestone 1 = the core engine + the context-payload (input-token) reduction gate.
Stdlib-only by default; tiktoken / fastembed are optional upgrades.
"""

__version__ = "0.1.0"

```

[57 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]