# Project export: baymax

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: Baymax is a network of hospital AI agents that supports abrupt crises using weather, disease, and inventory data, then coordinates hospital-to-hospital supply transfers before crises peak.
- Devpost: https://devpost.com/software/baymax-1wumi3
- GitHub: https://github.com/apollo-ullah/Baymax
- Video: https://www.youtube.com/embed/uRPyS_SuhiA?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (Best Use of The Agentverse by Fetch AI)
- Team: 6 GitHub contributor(s) — Claude Opus 4.8 (1M context) (19 commits), Adyan Ullah (14 commits), egomez714 (11 commits), Tvesha Shah (9 commits), Cursor (8 commits), Daksh Kumar (5 commits)

## Devpost submission (written by the team)

### Overview

When a heatwave strikes, a disease outbreak surges, or a mass casualty event unfolds, hospitals are suddenly competing for the same scarce supplies, and the phone-call coordination that's supposed to fix it is far too slow. Baymax is a network of hospital AI agents built on Fetch.ai that sees crises coming by fusing live weather, disease, and inventory signals. Using Claude for reasoning, it autonomously negotiates and settles inter-facility transfers on-chain before shortages peak. Every decision is traced through Arize Phoenix, allowing the system to learn from each event and improve future responses. Baymax doesn't just respond to emergencies - it learns to anticipate them. At a Glance Baymax predicts shortages before they happen, negotiates inventory transfers between hospitals, settles them on-chain, and learns from every crisis it handles.

### Inspiration

The supply crisis starts long before a hospital runs out. It starts hours earlier, when a weather forecast converges with rising illness signals and a facility that's already running lean. By the time a supply manager notices the pattern—let alone makes phone calls to neighboring facilities, negotiates terms, and arranges a transfer—the shortage has already peaked. The perception problem (counting what's on a shelf) is largely solved. The harder problem is autonomous coordination under surge conditions: seeing a crisis before it happens, negotiating transfers across institutions under real constraints, settling them quickly, and improving the system after every event. That's a multi-agent systems problem. Fetch.ai provides the agent network. Claude provides the reasoning layer. Arize Phoenix closes the learning loop. Baymax is what happens when all three work together. What it Does Baymax runs one agent per hospital. Each agent continuously combines: Live inventory from edge vision systems Weather forecasts and disease-burden signals Historical surge patterns and outcomes When a shortage is predicted: Claude detects a surge risk before inventory reaches critical levels. The requesting hospital broadcasts a transfer request through the Fetch.ai agent network. Nearby hospitals respond with constrained offers. Claude evaluates quantity, urgency, ETA, distance, and expiry dates. If no single offer satisfies demand, Baymax automatically creates a split transfer plan. The transfer is settled through the Fetch Payment Protocol on Dorado testnet. Arize Phoenix traces the entire decision process and outcome. The result is a system that can identify shortages earlier, coordinate faster, and continuously improve over time. How We Built It Baymax has two user-facing surfaces: ASI:One for natural-language interaction and approvals A live Flask dashboard for real-time monitoring and visualization Both are powered by the same Fetch.ai agent network and synchronized through Redis. Core Stack Agent Network Negotiation Flow Challenges We Ran Into ASI:One Echo Loops ASI:One occasionally interpreted our own agent narration as new user intent. We built filtering, cooldowns, and heuristics to prevent agents from responding to themselves. Payment Card Rendering The Fetch payment card depended on very specific metadata fields. Missing metadata caused silent failures with no visible error messages. Python 3.14 Event Loop Changes uAgents still relied on behavior removed in Python 3.14. We had to carefully manage initialization order to ensure a valid event loop existed before agent creation. Long-Running On-Chain Verification Transaction verification could stall agent execution for up to 20 seconds. We moved verification into background threads using asyncio.to_thread(). Accomplishments We're Proud Of Live End-to-End Settlement We successfully demonstrated: Natural-language intent → surge prediction → multi-hospital negotiation → on-chain payment → confirmed transfer Real Predictive Signals Baymax combines: Live weather data Real illness data Current inventory levels to generate structured shortage forecasts before a shortage is declared. Constraint-Aware Negotiation Baymax doesn't simply match one requester to one provider. It can automatically compose split transfers when multiple facilities are required to satisfy demand. Full Decision Traceability Every prediction, ranking decision, transfer proposal, and outcome is captured in Arize Phoenix. Parallel Development The forecasting, vision, dashboard, observability, and agent teams all built independently against a shared Redis schema and integrated successfully. What We Learned The defensible technology isn't the camera. The real value comes from creating a network that can detect, negotiate, and settle across institutional boundaries before a crisis peaks. We also learned that observability is essential for autonomous systems. The ability to trace every decision made by the system transforms Baymax from a coordination tool into a platform that can improve with experience. Finally, we learned that fail-closed design makes live demos possible. Every major dependency has deterministic fallbacks, allowing the system to remain reliable even when external services are unavailable. What's Next Predictive Pre-Positioning Move inventory before shortages occur when confidence in an incoming surge becomes sufficiently high. Disaster Response Coordination Extend the network to support regional responses for mass-casualty incidents and natural disasters. Ambulance & Patient Routing Apply the same negotiation framework to patient transfers and hospital capacity balancing. Blood & Biologics Logistics Support temperature-sensitive and blood-type-constrained transfers. Cross-System Federation Allow independent health systems to participate in a regional mutual-aid network without exposing internal inventory systems. Supplier-Side Agents Bring distributors into the negotiation process so Baymax can choose the globally optimal resolution between purchasing and transfer options. Baymax sits on top of existing hospital workflows. It doesn't replace clinical decision-making—it helps ensure critical supplies arrive where they're needed before shortages impact patient care. ## Built with fetch.ai · uagents · agentverse · asi:one · chat-protocol · payment-protocol · claude · claude-code · anthropic · redis · arize-phoenix · opencv · open-meteo · disease.sh · flask · python

## README (from the GitHub repository)

# Baymax

**A network of hospital AI agents that detect supply shortfalls and autonomously negotiate and settle inter-facility transfers — before anyone runs out.**

A supply manager states an intent in plain English through ASI:One — *"Hospital A is short on IV fluids"* — and the network takes it from there: it broadcasts the need, collects constrained offers from facilities with surplus, ranks them with Claude, composes a (possibly split) transfer, and settles it as a real on-chain testnet FET transaction — narrating every step back into the chat.

> Built at Cal Hacks for the Fetch.ai **"From Intent to Action"** challenge.
> Operational logistics only — *what to move, how much, by when.* Never clinical guidance.

---

## The problem

Hospitals run lean on consumable supplies and absorb uneven demand shocks. One facility runs critically short on an item while another a few miles away sits on a surplus of the exact same thing. Inside multi-facility health systems and regional mutual-aid compacts, this imbalance already gets reconciled — but slowly, by phone, and only if someone catches it in time.

The perception problem (counting what's on the shelf) is a solved commodity. The hard, unsolved problem is **coordination across organizational boundaries**: detecting the imbalance, matching surplus to shortfall under real constraints, and settling the transfer — autonomously, before the shortage becomes a crisis. That's a multi-agent systems problem, and it's exactly what Fetch.ai's agent mesh and Claude's reasoning make possible.

---

## What it does

Baymax runs one agent per hospital. Each agent knows its live stock (from edge vision) and its forecast demand (from weather and illness signals). The end-to-end chain:

1. **Shortfall detected** — falling stock converges with rising forecast demand.
2. **The front agent broadcasts a request** to the network over uAgents messaging.
3. **Surplus facilities answer with constrained offers** — quantity available, distance/ETA, expiry, urgency.
4. **Claude ranks the offers and composes a resolution.** When no single facility covers the need, it splits the order (e.g. **150 units from the near hospital + 50 from the far one**) or trades ETA against expiry, and re-plans on partial rejections.
5. **The transfer settles as a real transaction** via the Fetch Payment Protocol on Dorado testnet — `RequestPayment → CommitPayment → CompletePayment` — with the payment card surfacing right in the ASI:One chat for the user to sign.
6. **Everything is shown live** — a Redis-backed dashboard renders inventory, the shortfall alert, and the negotiation resolving in real time.

The moment that proves it's real: the negotiation handles a constraint — a partial offer plus a re-plan into a split transfer — and then settles an actual on-chain payment. That's what separates this from scripted message-passing.

---

## Why this is hard

Vision-based inventory monitoring and demand forecasting are rising but those platforms are single-tenant by design: each customer's data is walled off.

Baymax is a different layer entirely: **coordination across the wall**. A perception platform could sit underneath Baymax as its camera layer — it's a component, that extends and automates. The hard problem is agent-to-agent negotiation and settlement across organizational boundaries, a multi-agent systems problem, not a computer-vision one. 

---

## Tools and technologies

| Layer | What we used |
| :-- | :-- |
| **Agent mesh, chat, settlement** | Fetch.ai **uAgents** + **Chat Protocol** (v0.3.0) + **Payment Protocol** (v0.1.0), registered on Agentverse, reachable in **ASI:One** |
| **Reasoning + offer ranking** | **Claude Sonnet 4.6** via the Anthropic API — multi-constraint offer ranking and natural-language narration; entire codebase built with **Claude Code** |
| **Edge inventory (vision)** | MacBook/Pi camera → **Claude Vision** counts saline units across a green-straw divider, writing qty/surplus straight to Redis |
| **State + pub/sub** | **Redis Stack** — inventory, surplus, forecast, transfer audit stream, live event channels |
| **Forecast inputs** | Open-Meteo weather agent + a CDC/WHO illness signal agent, both writing to `forecast:{region}` in Redis |
| **Observability** | **Arize Phoenix** traces the full decision chain: inventory → forecast → reasoning → transfer → outcome |
| **Human-in-the-loop** | iMessage approval pipeline with tappable Accept/Reject links via Messages.app (AppleScript) |
| **Dashboard** | **Flask** UI auto-refreshing every 3s from Redis; SSE stream for live narration |

---

## Architecture

### The agent network

Three Fetch.ai uAgents run the negotiation:

| Agent | Facility | Role |
| :-- | :-- | :-- |
| `baymax_front` | Hospital A | **Requester + ASI:One surface.** Carries the Chat and Payment protocols; detects the shortfall, broadcasts the request, ranks offers with Claude, composes the transfer, settles it, narrates back. |
| `baymax_hospital_b` | Hospital B | **Surplus facility** — responds with constrained offers, accepts/rejects transfer legs. |
| `baymax_hospital_c` | Hospital C | Same. |

### The negotiation state machine

```
shortfall_detected → requesting → collecting_offers → evaluating
   → (re_planning if no single offer covers the need) → proposing → settling → confirmed
```

### How the layers connect

Two surfaces, one engine. **ASI:One** is the Fetch-qualifying conversational surface; the **live dashboard** is the visual story. Both are driven by the same agents and the same **Redis** state bus — the integration seam that let each track build in parallel without coupling.

```
ASI:One chat ──► front agent (uAgents)
                     │   ▲
          broadcast  │   │ narration
                     ▼   │
              hospital B & C agents
                     │
                  Redis ──► Dashboard (Flask)
                     │
              Dorado testnet (Fetch Payment Protocol)
```

![System architecture](final_diagram.png)

**The wire contract is frozen.** `protocol.py` is the single source of truth for every cross-agent message model and the negotiation state machine. The official Fetch Chat/Payment protocol classes are re-exported unchanged — ASI:One matches by schema digest, so a local redefinition would be an incompatible protocol. No module ever redefines these.

**Every live dependency has a fail-closed fallback.** Redis, the camera, and the chain are each behind a seam in `interfaces.py` with a deterministic mock. The system is testnet-only by construction: mainnet is refused at startup; payment verification is pinned to `fetchai_stable_testnet`.

---

## How Claude is used

Claude does two jobs:

**Offer ranking.** When surplus offers arrive, Claude weighs quantity, distance, expiry date, and urgency against the shortfall. It selects a resolution — single-source if one facility covers the need, or a split transfer (e.g. 150 + 50) when none can alone. The ranking seam in `interfaces.py` sits behind a deterministic mock for offline testing.

**Shelf vision.** The camera pipeline sends a JPEG of the supply shelf to Claude Vision, which counts units per hospital across a colored divider. The count writes directly into Redis as `qty` and `surplus`, feeding the same inventory the agents read for negotiation.

The intent parser (`front_agent.parse_intent`) is currently a deterministic keyword/regex parser. A commented ASI:One-LLM seam sits behind the same signature, ready to swap in.

---

## Repository layout

| Path | What it is |
| :-- | :-- |
| `agent-communication-layer/` | The Fetch agent mesh — negotiation core, front/ASI:One agent, Payment Protocol settlement, Mailbox runners |
| `redis/` | The Redis integration seam — schema, inventory/forecast/alerts/transfers, pub/sub |
| `fetch/` | Forecast input agents (weather, illness) + the iMessage human-approval pipeline |
| `hardware/camera connection/` | Claude Vision shelf-counting → Redis |
| `arize/` | Arize Phoenix decisio

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 113 recognized source files, 656 KB.
- Anthropic (technology) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- Python (language) — detected in the code
- Redis (technology) — detected in the code
- JavaScript (language) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository; commit authorship or trailers
- AI coding agent: Cursor — evidence: commit authorship or trailers

## Codebase structure (from repository index)

### Files (120 of 144)

```
__init__.py
.env.example
.gitattributes
.gitignore
agent-communication-layer/.env.example
agent-communication-layer/.gitignore
agent-communication-layer/agent_base.py
agent-communication-layer/agent_network_mvp_roadmap.md
agent-communication-layer/baymax_agents.py
agent-communication-layer/camera_worker.py
agent-communication-layer/check_interfaces_order.py
agent-communication-layer/check_parse_decision.py
agent-communication-layer/dashboard_bus.py
agent-communication-layer/DELIVERABLES.md
agent-communication-layer/DEMO_SCRIPT.md
agent-communication-layer/docs/superpowers/plans/2026-06-20-admin-approval-and-supplier-order.md
agent-communication-layer/docs/superpowers/plans/2026-06-20-two-camera-scan-dashboard.md
agent-communication-layer/docs/superpowers/specs/2026-06-20-admin-approval-and-supplier-order-design.md
agent-communication-layer/docs/superpowers/specs/2026-06-20-two-camera-scan-dashboard-design.md
agent-communication-layer/front_agent.py
agent-communication-layer/hello_world_agent.py
agent-communication-layer/interfaces.py
agent-communication-layer/protocol.py
agent-communication-layer/README.md
agent-communication-layer/redis_inventory.py
agent-communication-layer/requirements.txt
agent-communication-layer/run_dashboard_demo.py
agent-communication-layer/run_front.py
agent-communication-layer/run_hospital_b.py
agent-communication-layer/run_hospital_c.py
agent-communication-layer/scan_dashboard.py
agent-communication-layer/scripts/free_demo_ports.sh
agent-communication-layer/scripts/single_mac_demo.sh
agent-communication-layer/scripts/tailscale_env.sh
agent-communication-layer/scripts/tailscale_peer_b.sh
agent-communication-layer/scripts/tailscale_server.sh
agent-communication-layer/settlement.py
agent-communication-layer/stockpile_agents.py
agent-communication-layer/supplier_order.py
agent-communication-layer/tailscale_hosts.py
agent-communication-layer/tailscale_smoke_test.py
agent-communication-layer/two_agent_payment_spike.py
agent-communication-layer/vision_count.py
agent-communication-layer/wave2_e2e_check.py
agent-communication-layer/wave3_order_e2e_check.py
agent-communication-layer/wave4_dashboard_e2e_check.py
agent-communication-layer/wave5_handshake_e2e_check.py
anthropic/README.md
arize/.env.example
arize/.gitignore
arize/HANDOFF.md
arize/README.md
arize/requirements.txt
arize/src/__init__.py
arize/src/demo_trace.py
arize/src/phoenix_client.py
arize/src/trace_decision_chain.py
arize/src/trace_decision_outcome.py
arize/src/trace_forecast.py
arize/src/trace_inventory.py
arize/src/trace_reasoning.py
arize/src/trace_schema.py
arize/src/trace_store.py
arize/src/trace_transfer.py
baymax_PRD_v2.md
CLAUDE.md
dump.rdb
fetch/__init__.py
fetch/agents/__init__.py
fetch/agents/illness_agent/__init__.py
fetch/agents/illness_agent/agent.py
fetch/agents/illness_agent/mock_cdc_feed.json
fetch/agents/illness_agent/mock_illness_feed.json
fetch/agents/illness_agent/models.py
fetch/agents/README.md
fetch/agents/requirements.txt
fetch/agents/weather_agent/__init__.py
fetch/agents/weather_agent/agent.py
fetch/agents/weather_agent/models.py
fetch/agents/who_agent/__init__.py
fetch/agents/who_agent/agent.py
fetch/agents/who_agent/fetcher.py
fetch/agents/who_agent/models.py
fetch/approval/__init__.py
fetch/approval/imessage_client.py
fetch/approval/README.md
fetch/approval/serve_with_ngrok.sh
fetch/scripts/__init__.py
fetch/scripts/redis_smoke_test.py
fetch/shared/__init__.py
fetch/shared/protocol.py
fetch/shared/README.md
fetch/shared/redis_io.py
hardware/camera connection/bottle_counter.py
hardware/camera connection/camera.py
hardware/camera connection/capture_1782006619.json
hardware/camera connection/capture_1782006867.json
hardware/camera connection/capture_single.py
hardware/camera connection/README.md
hardware/camera connection/sync_to_redis.py
hardware/camera connection/take_photo.py
hardware/requirements.txt
hardware/test folder/BUTTON_TEST_README.md
hardware/test folder/monitor.py
hardware/test folder/pico_code/main.py
kill_all.sh
README.md
redis/.env.example
redis/.gitignore
redis/docker-compose.redis.yml
redis/HANDOFF.md
redis/README.md
redis/redis_contract.md
redis/requirements.txt
redis/src/__init__.py
redis/src/alerts.py
redis/src/demo_run.py
redis/src/forecast.py
redis/src/inventory.py
redis/src/ping.py
[24 more files omitted for size]
```

### Dependencies

- agent-communication-layer/requirements.txt: anthropic, cosmpy@>=0.11.0, fastapi, httpx, opencv-python, python-dotenv@>=1.0.0, redis@>=5.0.0, uagents@==0.25.2, uagents-core@==0.4.7, uvicorn[standard]
- arize/requirements.txt: arize-phoenix, openinference-instrumentation, opentelemetry-exporter-otlp-proto-http, opentelemetry-sdk, python-dotenv
- fetch/agents/requirements.txt: anthropic, fastapi, httpx, python-dotenv, redis, uagents, uvicorn[standard]
- hardware/requirements.txt: anthropic, opencv-python, python-dotenv, redis
- redis/requirements.txt: numpy, python-dotenv, redis, sentence-transformers

### Recent commits (newest first)

- Merge PR #7 (revamp-ui): soft-care UI redesign
- feat(ui): Baymax soft-care redesign of the live Flask dashboard
- Fix missing _emit narration helper + demo launch scripts
- push
- Strip ASI:One @agent1 mention prefix before parsing decisions
- Dashboard fixes + UI: working Bureau, live narration, Arize slide, Red Bull vision proxy
- Two-tap human approval handshake on the real agent negotiation
- changes
- changes
- changes to 2 cams
- two capture
- combining
- Wire ngrok authtoken through .env (NGROK_AUTHTOKEN)
- Add ngrok launcher for approval service so accept/reject links are phone-tappable
- Merge remote-tracking branch 'origin/main'
- changes
- changes
- Add project README (from DEVPOST writeup) for GitHub
- Merge poke-approval: Hospital A<->B human approval pipeline (FR15) over iMessage
- Pivot approval notifications from Poke to iMessage (osascript)

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

### CLAUDE.md

```markdown
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What this is

**Stockpile** — a network of Fetch.ai uAgents that detect hospital supply shortfalls and autonomously negotiate + settle inter-facility transfers. A supply manager states an intent in natural language via ASI:One ("Hospital A is short on IV fluids"); the FRONT agent broadcasts the need, ranks offers from surplus facilities, composes a (possibly split) transfer, and settles it as a real Fetch **testnet** FET transaction — narrating each step back into the chat. Built for the Fetch.ai "From Intent to Action" challenge.

**All code lives in `adyan-agent-communication-layer/`.** The repo root holds only that directory, `stockpile_PRD_v2.md` (the product spec), and an image. Run every command from inside `adyan-agent-communication-layer/`; the virtualenv is at `adyan-agent-communication-layer/.venv`.

## Commands

```bash
cd adyan-agent-communication-layer
python -m venv .venv && source .venv/bin/activate     # Python 3.12+ (developed on 3.14)
pip install -r requirements.txt
```

There is **no test runner, linter, or build step.** The verification harnesses below *are* the test suite — each is a self-contained, self-exiting script. Prefer `./.venv/bin/python <script>` so the right interpreter is used.

| Goal | Command |
| :-- | :-- |
| Run the full 3-agent negotiation in one process (Bureau) | `STOCKPILE_EXIT_WHEN_DONE=1 ./.venv/bin/python stockpile_agents.py` |
| Pick the scenario | prefix with `STOCKPILE_ITEM="IV fluids"` (split, default) / `"saline"` (full cover) / `"sutures"` (no offer → escalation) |
| FRONT chat→negotiate→narrate loop, no network | `STOCKPILE_SELFTEST=1 ./.venv/bin/python front_agent.py` |
| Offline end-to-end incl. settlement (chat→negotiate→settle→pay), no ASI:One/wallet | `./.venv/bin/python wave2_e2e_check.py` |
| Payment-protocol handshake in isolation (2 agents, fake tx) | `PAYMENT_VERIFY_ONCHAIN=false ./.venv/bin/python two_agent_payment_spike.py` |
| Re-derive agent addresses from seeds | `./.venv/bin/python -c "import agent_base; print(*(f'{f}: {agent_base.address_for(f)}' for f in ('Hospital A','Hospital B','Hospital C')), sep=chr(10))"` |
| Negotiation against **live Redis** inventory (split sourced from `tracks/redis`) | `STOCKPILE_REDIS=1 STOCKPILE_ITEM="IV fluids" STOCKPILE_NEED=200 STOCKPILE_EXIT_WHEN_DONE=1 ./.venv/bin/python stockpile_agents.py` |

**Live Redis bring-up** (needed once before the Redis-backed row above; `redis` + `python-dotenv` must be in `.venv`):

```bash
docker compose -f ../tracks/redis/docker-compose.redis.yml up -d        # redis-stack on :6379
(cd ../tracks/redis/src && REDIS_URL=redis://localhost:6379 \
   ../../../adyan-agent-communication-layer/.venv/bin/python seed_demo_data.py)   # seed hospitals/inventory/surplus/forecast
```

**Camera as the inventory source** (optional): `hardware/camera connection/sync_to_redis.py`
counts saline per hospital via C
[truncated — 9939 more characters]
```

### baymax_PRD_v2.md

```markdown
# Baymax — Product Requirements Document

| | |
| :-- | :-- |
| **Product** | Baymax |
| **One-liner** | A network of hospital agents that detect supply shortfalls and autonomously negotiate and settle transfers across facilities, before anyone runs out. |
| **Version** | 0.2 (Cal Hacks build, supersedes 0.1) |
| **Status** | In active build |
| **Main track** | Ddoski's Lab (science, engineering, health tech, hardware) |
| **Qualifying surface** | Fetch.ai ASI:One chat (Chat Protocol + Payment Protocol) |

---

## 1. Overview

Hospitals run lean on consumable supplies and absorb uneven demand shocks: one facility runs critically short on an item while another nearby sits on surplus of the same item. Today that imbalance is reconciled slowly and manually, by phone, if it is caught at all.

Baymax is an autonomous coordination layer across a network of facilities. Each hospital runs an agent that knows its real-time stock (from edge vision and sensors) and its projected demand (from weather and illness signals). When a facility is detected heading into a shortfall, its agent is reachable through ASI:One, negotiates with the other facilities' agents, and settles a transfer as an on-chain transaction. The output is operational and routes into existing transfer and procurement workflows. It never makes clinical decisions.

The novel work is the coordination between institutions, not the perception inside one. Vision-based inventory monitoring is a commodity. The defensible system is the agent network that detects, negotiates, and settles cross-facility imbalance autonomously.

---

## 2. Goals and non-goals

### Goals
- Detect a projected shortfall from the convergence of falling stock and rising forecast demand.
- Resolve it by autonomous agent-to-agent negotiation, reachable and demonstrable through ASI:One.
- Settle the resolved transfer as a real transaction (Fetch Payment Protocol).
- Make the loop legible: ASI:One for the qualifying interaction, a live dashboard for the visual story.

### Non-goals (explicit, and load-bearing for the Q&A)
- **No clinical decision-making.** Operational outputs only: what to move, how much, by when.
- **No autonomous movement of controlled substances.** Scope is non-scheduled consumables; recommendations route to existing custody and procurement protocols rather than executing them.
- **No ambulance or patient routing.** Future direction only.
- **No doctor-to-agent interface.** Future direction only.
- **Not an ERP or procurement replacement.** Baymax sits on top of existing systems and hands off.
- **No real hospital integration.** The network is simulated for the demo; the agent logic, negotiation, and transaction are real.

---

## 3. Background and premise

The premise is scoped to survive a healthcare-literate judge.

**Real-world grounding.** Within a single health system (multi-facility operators) and within regional hospital mutual-aid compacts, facilities already load-balance supplies across sites, manu
[truncated — 15639 more characters]
```

### redis/requirements.txt

```
redis
python-dotenv
numpy
sentence-transformers

```

### arize/requirements.txt

```
arize-phoenix
openinference-instrumentation
opentelemetry-sdk
opentelemetry-exporter-otlp-proto-http
python-dotenv

```

### hardware/requirements.txt

```
# Hardware / vision track.
# Camera capture + Claude Vision counting (bottle_counter.py):
anthropic
opencv-python
python-dotenv

# Pushing detected counts into the Baymax Redis (sync_to_redis.py). The
# --counts / --from-json paths need only this (no anthropic/opencv/API key).
redis

```

### agent-communication-layer/requirements.txt

```
# Baymax agent-communication layer — pinned to the versions verified in Wave 0.
# Python 3.12+ (developed/verified on 3.14).

# Fetch.ai agent framework + protocol models (chat + payment).
uagents==0.25.2
uagents-core==0.4.7

# On-chain FET transaction verification for the Payment Protocol (testnet).
# Ships transitively with uagents, pinned here because settlement.py imports it
# directly (LedgerClient / NetworkConfig.fetchai_stable_testnet()).
cosmpy>=0.11.0

# Local env config (seeds, network) — never commit the filled-in .env.
python-dotenv>=1.0.0

# Live inventory seam (Workstream C): redis_inventory.py reads the teammates'
# Redis (tracks/redis) when BAYMAX_REDIS=1, falling back to the mock when
# absent. Optional at runtime — the offline harnesses do not need Redis.
redis>=5.0.0

# Optional, Wave 1 FRONT stream only: intent parsing via the ASI:One LLM
# (OpenAI-compatible client, base_url=https://api.asi1.ai/v1). The Wave 0
# contract + negotiation do not require it.
# openai>=1.40.0

# --- Two-camera live scan + dashboard ----------------------------------------
# Web layer for camera_worker.py (one per MacBook) and scan_dashboard.py (the
# MacBook-A server). httpx is the dashboard's client to the workers.
fastapi
uvicorn[standard]
httpx
# Camera worker vision: OpenCV capture + Claude Vision (single-shelf count). Same
# deps as hardware/requirements.txt, needed in THIS venv to run camera_worker.py.
anthropic
opencv-python
# --- Wave 3 (optional): external-supplier order via Browserbase --------------
# Only needed when BAYMAX_BROWSERBASE=1. The order seam falls back to a
# deterministic mock when these are absent, so offline harnesses don't need them.
# stagehand
# playwright
# browserbase

```

### fetch/agents/requirements.txt

```
uagents
httpx
python-dotenv
redis
anthropic
fastapi
uvicorn[standard]

```

### ui/app.py

```python
"""
Baymax Pipeline Dashboard — Flask UI.

Reads the live Redis state for every pipeline stage and serves a dashboard
that auto-refreshes every 3 seconds. Also manages the Baymax Bureau subprocess
and bridges iMessage approval notifications.

Endpoints:
    GET  /              dashboard HTML
    GET  /api/state     JSON snapshot of all pipeline data
    GET  /image/latest  latest capture JPEG (or placeholder)
    POST /api/capture   run mock capture (--counts a=4,b=2) → Redis
    POST /api/refresh_who   re-run WHO fetch + Claude reasoning → Redis
    POST /api/negotiate     push trigger to bureau (non-blocking)
    POST /api/bureau/start  start/restart the bureau subprocess
    GET  /api/narration     SSE stream of narration events
    GET  /req/<rid>/approve  approve a pending transfer
    GET  /req/<rid>/order    order externally
    GET  /req/<rid>/reject   reject a pending transfer

Run:
    python ui/app.py
    open http://localhost:5001
"""

from __future__ import annotations

import json
import logging
import os
import subprocess
import sys
import threading
import time
from datetime import datetime, timezone
from pathlib import Path

from dotenv import load_dotenv
from flask import Flask, Response, jsonify, render_template, request, send_file

load_dotenv(Path(__file__).resolve().parents[1] / ".env")

# ── Bridge to redis/src ──────────────────────────────────────────────────────
_REDIS_SRC = Path(__file__).resolve().parents[1] / "redis" / "src"
if str(_REDIS_SRC) not in sys.path:
    sys.path.insert(0, str(_REDIS_SRC))

# ── Bridge to who_agent fetcher and fetch.approval ───────────────────────────
_FETCH_ROOT = Path(__file__).resolve().parents[1]
if str(_FETCH_ROOT) not in sys.path:
    sys.path.insert(0, str(_FETCH_ROOT))

log = logging.getLogger("baymax_ui")
logging.basicConfig(level=logging.INFO, format="%(message)s")

app = Flask(__name__)

UI_PORT = int(os.getenv("UI_PORT", "5001"))
REGION = os.getenv("FORECAST_REGION", "san_francisco")
HARDWARE_DIR = Path(__file__).resolve().parents[1] / "hardware" / "camera connection"
SYNC_SCRIPT = HARDWARE_DIR / "sync_to_redis.py"
AGENT_DIR = Path(__file__).resolve().parents[1] / "agent-communication-layer"
# Prefer the agent-local venv; fall back to the repo-root .venv, then to whatever
# interpreter is running this UI. (In this checkout the venv lives at the repo
# root, not under agent-communication-layer/.)
_AGENT_VENV = AGENT_DIR / ".venv" / "bin" / "python"
_ROOT_VENV = Path(__file__).resolve().parents[1] / ".venv" / "bin" / "python"
AGENT_VENV_PYTHON = (
    _AGENT_VENV if _AGENT_VENV.exists()
    else _ROOT_VENV if _ROOT_VENV.exists()
    else Path(sys.executable)
)

# ── Bureau subprocess ─────────────────────────────────────────────────────────
_bureau_proc: subprocess.Popen | None = None


BUREAU_LOG = Path("/tmp/baymax_bureau.log")
BUREAU_PORT = 8000  # uAgents Bureau internal ASGI port


def _free_bureau_port():
    """Kill anything holding the Bureau's port so a fresh spawn can bind."""
    try:
        result = subprocess.run(
            ["lsof", "-ti", f":{BUREAU_PORT}"],
            capture_output=True, text=True,
        )
        pids = result.stdout.strip().split()
        for pid in pids:
            try:
                os.kill(int(pid), 9)
                log.info("Killed stale process %s on port %s", pid, BUREAU_PORT)
            except (ProcessLookupError, ValueError):
                pass
    except Exception as exc:
        log.warning("_free_bureau_port: %s", exc)


def _ensure_bureau():
    """Spawn the Bureau subprocess if not already running.

    Raises RuntimeError with a clear message on misconfiguration (missing script
    or interpreter) so callers can surface a clean JSON error instead of a 500.
    """
    global _bureau_proc
    if _bureau_proc and _bureau_proc.poll() is None:
        return
    script = AGENT_DIR / "run_dashboard_demo.py"
    if not script.exists():
        raise RuntimeError(f"Bureau script not found: {script}")
    if not Path(AGENT_VENV_PYTHON).exists():
        raise RuntimeError(f"Python interpreter not found: {AGENT_VENV_PYTHON}")
    _free_bureau_port()
    env = {**os.environ,
           "BAYMAX_REDIS": "1",
           "BAYMAX_OFFER_TIMEOUT": "4.0",
           "BAYMAX_SPARSE_NARRATION": "0",
           "BAYMAX_DASHBOARD_PORT": "8079",  # avoid conflict with Flask
           # Two-tap handshake: providers hold each leg for their doctor's tap.
           "BAYMAX_PROVIDER_APPROVAL": os.getenv("BAYMAX_PROVIDER_APPROVAL", "1"),
           "REDIS_URL": os.getenv("REDIS_URL", "redis://localhost:6379")}
    log_fh = open(BUREAU_LOG, "w")
    _bureau_proc = subprocess.Popen(
        [str(AGENT_VENV_PYTHON), "run_dashboard_demo.py"],
        cwd=str(AGENT_DIR), env=env,
        stdout=log_fh, stderr=log_fh,
    )
    log.info("Bureau started (pid %s) — log: %s", _bureau_proc.pid, BUREAU_LOG)


# ── In-memory narration state ─────────────────────────────────────────────────
_narration_log: list[dict] = []    # last 50 events
_awaiting_approval: dict = {}      # req_id -> {"detail": str, "notified": bool}
_awaiting_release: dict = {}       # pid -> {"facility": str, "detail": str}

# Facility display name -> hospital id (for IMESSAGE_TO_HOSPITAL_* + release routing).
_FACILITY_TO_HID = {
    "Hospital A": "hospital_a", "Hospital B": "hospital_b", "Hospital C": "hospital_c",
}


def _send_release_imessage(pid: str, facility: str, detail: str):
    """Tap 2: text the PROVIDER facility's doctor an approve/deny link for one
    held transfer leg. Routes to IMESSAGE_TO_HOSPITAL_B / _C via the facility's
    hospital id; falls back to the shared IMESSAGE_TO if that's all that's set."""
    base = os.getenv("APPROVAL_BASE_URL", f"http://localhost:{UI_PORT}").rstrip("/")
    approve_url = f"{base}/release/{pid}/approve"
    deny_url    = f"{base}/release/{pid}/deny"
    msg = (
        f"🏥 {facility}: release approval needed.\n"
        f"{detail[:220]}\n\n"
        f"✅ Approve release: {ap
[truncated — 31865 more characters]
```

### hardware/test folder/pico_code/main.py

```python
import rp2
from machine import Pin
import time

led = Pin(25, Pin.OUT)  # onboard LED

print("Pico ready — press the BOOTSEL button!")

was_pressed = False

while True:
    pressed = rp2.bootsel_button() == 1

    if pressed and not was_pressed:
        print("Button pressed!")
        led.on()

    if not pressed and was_pressed:
        led.off()

    was_pressed = pressed
    time.sleep(0.02)

```

### kill_all.sh

```shell
#!/usr/bin/env bash
# kill_all.sh — stop every Baymax/Stockpile process so a clean launch can't
# collide with a stray one. By default it leaves Redis running (it's the shared
# foundation); pass --redis to kill Redis too.
#
#   ./kill_all.sh            # kill app processes, keep Redis
#   ./kill_all.sh --redis    # also kill Redis on :6379
set -u

KILL_REDIS=0
[ "${1:-}" = "--redis" ] && KILL_REDIS=1

# App-layer process patterns (NOT redis — handled separately by port).
PATTERNS=(
  "serve_with_ngrok"
  "ngrok http 5001"
  "ui/app.py"
  "run_dashboard_demo"
  "run_front.py"
  "run_hospital_b.py"
  "run_hospital_c.py"
  "capture_single.py"
  "camera_worker.py"
  "scan_dashboard"
)

echo "=== killing app processes ==="
for pat in "${PATTERNS[@]}"; do
  pids=$(pgrep -f "$pat" | tr '\n' ' ')
  if [ -n "$pids" ]; then
    pkill -f "$pat" 2>/dev/null
    echo "  killed [$pat]: $pids"
  fi
done

if [ "$KILL_REDIS" = "1" ]; then
  rpid=$(lsof -nP -iTCP:6379 -sTCP:LISTEN -t 2>/dev/null)
  if [ -n "$rpid" ]; then kill $rpid 2>/dev/null; echo "  killed redis: $rpid"; else echo "  no redis on 6379"; fi
fi

sleep 2

echo "=== verify ==="
left=$(ps -ax -o pid,command | grep -iE "ui/app.py|run_dashboard|run_front|run_hospital|capture_single|camera_worker|scan_dashboard|ngrok http 5001" | grep -v grep)
if [ -n "$left" ]; then echo "  STILL RUNNING:"; echo "$left"; else echo "  all app processes stopped"; fi
[ "$KILL_REDIS" = "1" ] && { lsof -nP -iTCP:6379 -sTCP:LISTEN >/dev/null 2>&1 && echo "  redis STILL up" || echo "  redis stopped"; }

```

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