# Project export: AgriBroker

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: You need 500 tomatoes under $250? AgriBroker's agents optimize prices and pays the best order. Farmer's produce surplus reduced and customers happy with cheap organic food.
- Devpost: https://devpost.com/software/agribroker
- GitHub: https://github.com/Ai-Hackathon-2026-Berk/AgriBroker
- Demo: https://asi1.ai/shared-chat/58d63d68-cfb0-4407-8292-1711398be12f
- Video: https://www.youtube.com/embed/oDr4soAX2kM?enablejsapi=1&hl=en_US&rel=0&start=1&version=3&wmode=transparent
- Result: winner (Best Use of The Agentverse by Fetch AI)
- Team: 1 GitHub contributor(s) — Caden Minami (6 commits)

## Devpost submission (written by the team)

### Inspiration

Produce procurement is still surprisingly manual. A restaurant, co-op, or bulk buyer may know they need 500 tomatoes, but they still have to find suppliers, compare prices, check inventory, split orders, and coordinate payments. We saw this as a coordination problem that autonomous agents are well-suited to solve, as working with small farmers to reduce waste, produce can be optimized in bulk. USDA's Economic Research Service (ERS) estimates that about 30 percent of food in the United States goes uneaten at the retail and consumer level. Promoting locally grown and organic food, we wanted to build a system where a buyer could simply state their intent and let agents handle the discovery, optimization, and transaction workflow.

### What it does

AgriBroker is an autonomous produce procurement marketplace built on the Fetch.ai ecosystem. A buyer can ask for produce in natural language, such as "I need 500 tomatoes under $250." AgriBroker discovers seller agents, gathers inventory and pricing information, computes the cheapest feasible split across suppliers, coordinates payment, and returns a single transparent receipt. In live agent mode, the orchestrator communicates with a Registry agent and multiple Farmer agents to source the order through agent-to-agent messaging.

### How we built it

We built AgriBroker in Python using Fetch.ai uAgents, ASI, and Agentverse. The system consists of an orchestrator agent, a registry agent for seller discovery, and farmer agents that manage inventory, pricing, invoices, and receipts. We implemented a deterministic optimizer that selects the lowest-cost supplier combination, integrated Stripe Checkout for buyer funding, added simulated Stripe Connect-style payouts for sellers, and created onboarding tools that allow new farms to join the marketplace without modifying the orchestrator.

### Challenges we ran into

The biggest challenge was balancing reliability with live integrations. ASI, Agentverse, Stripe, Business Agents, and agent networking all introduce external dependencies that can fail during a demo. To address this, we built a deterministic local workflow and layered live integrations on top of it. We also had to make agent coordination visible to judges, so we added progress updates and an agent trace that shows discovery, quoting, purchasing, and receipt generation across multiple agents.

### Accomplishments we're proud of

We're proud that AgriBroker demonstrates a complete intent-to-action workflow. A buyer can start with a simple natural-language request, and the system autonomously discovers suppliers, gathers quotes, optimizes an order split, coordinates payment, and returns a final receipt. We also successfully implemented live Registry and Farmer agent communication, farmer self-onboarding, Stripe Checkout integration, and visible agent traces that make the multi-agent architecture easy to understand.

### What we learned

We learned that building agentic commerce is about more than making agents communicate. The system also needs to be reliable, transparent, and auditable. Designing clear protocols, deterministic optimization logic, fallback mechanisms, and user-facing receipts was just as important as integrating ASI and Agentverse. We also gained experience coordinating multiple independent agents within a marketplace workflow.

### What's next

Our next steps are to deploy the agents in a hosted environment, enable fully automated payment confirmation, expand beyond tomatoes into broader produce catalogs, add seller reputation and quality metrics, support delivery and logistics workflows, and make seller onboarding completely self-service. The long-term goal is to create an autonomous procurement network where buyers can source produce from a large ecosystem of independent farm agents.

## README (from the GitHub repository)

# AgriBroker

Autonomous produce procurement for the Fetch.ai ecosystem.

AgriBroker lets a buyer ask for produce in natural language, then uses agents to discover sellers, gather quotes, compute the cheapest split, fund the order, pay selected farms, and return a single itemized receipt.

Demo prompt:

```text
I need 500 tomatoes under $250.
```

Expected result:

- Farm A supplies 200 tomatoes at $0.40 each.
- Green Valley supplies 300 tomatoes at $0.42 each.
- Total cost is $206.
- The buyer stays under the $250 budget.

## Why It Matters

Bulk buyers should not manually compare suppliers, check stock, split orders, and send separate payments. AgriBroker turns one procurement intent into an agent-run marketplace workflow:

1. Understand the buyer's request.
2. Discover farms selling the requested item.
3. Ask each farm for a live quote.
4. Optimize the cheapest feasible split.
5. Fund the order through the orchestrator.
6. Pay the winning farms.
7. Return a combined receipt.

The current repo includes the local deterministic core plus uAgent entry points. The local flow is intentionally runnable before Agentverse, ASI:One, and live testnet payment credentials are configured.

## Architecture

| Component | Role |
|---|---|
| Orchestrator | Buyer-facing agent. Parses intent, asks for quotes, optimizes, coordinates payment, returns receipt. |
| Registry | Tracks which agents sell which catalog items. |
| Farmer agents | Hold inventory, quote prices, invoice orders, confirm paid purchases. |
| Sunny Acres | Demo verified-brand seller. Use Flockx Business Agent when available; local config includes a code fallback. |
| Optimizer | Pure greedy optimizer for per-unit pricing with no fixed shipping cost. |
| Payment layer | Buyer funds orchestrator; orchestrator pays selected farms. Uses simulated Stripe locally, with optional testnet FET as a Fetch-native stretch. |

## Repo Structure

```text
agents/
  protocols.py             Shared uAgent message models
  optimizer.py             Pure cheapest-split optimizer
  farm_state.py            Farm inventory and pricing behavior
  workflow.py              End-to-end local procurement flow
  llm.py                   ASI:One intent parser with local fallback
  payments.py              Testnet/simulated payment helpers
  registry_agent.py        Registry uAgent
  farmer_agent.py          Parameterized farmer uAgent
  orchestrator_agent.py    Structured orchestrator uAgent
config/
  farms.json               Demo farms, stock, prices, seeds, ports
scripts/
  run_local_demo.py        Local tomatoes procurement demo
tests/
  test_optimizer.py
  test_llm.py
  test_workflow.py
docs/
  api-notes.md             Fetch integration notes and verification checklist
```

## Quickstart

Create a virtual environment:

```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
```

Run tests:

```bash
pytest
```

Run the local demo:

```bash
python scripts/run_local_demo.py
```

You should see a transcript showing intent parsing, quote collection, optimization, buyer funding, farm payouts, and receipts.

Preview the ASI-style response without Agentverse:

```bash
python scripts/preview_asi_response.py
```

Run the demo readiness check:

```bash
python scripts/check_demo_ready.py
```

Print every Agentverse profile, handle, README, and run command:

```bash
python scripts/print_agentverse_profiles.py
```

## ASI:One And Agentverse

The ASI:One entry point is:

```bash
python -m agents.asi_chat_agent
```

This starts a Chat Protocol-compatible uAgent with `mailbox=True` and `publish_agent_details=True`. Keep this process running while testing from ASI:One.

Supporting Registry and Farmer agents also publish Agentverse metadata and README profiles. See [docs/agentverse/setup.md](docs/agentverse/setup.md) for the full profile checklist.

Setup steps:

1. Create `.env` from `.env.example` if needed.
2. Add `ASI_ONE_API_KEY` when you want live ASI:One intent parsing.
3. Keep `AGRIBROKER_INTENT_MODE=local`, `AGRIBROKER_BUYER_PAYMENT_MODE=simulated`, and `AGRIBROKER_FARM_PAYMENT_MODE=simulated` for the first ASI:One test.
4. Run `python -m agents.asi_chat_agent`.
5. Open the Agent Inspector URL printed in the terminal.
6. If logs say `Agent mailbox not found`, that is expected before the first setup. In Inspector, click **Connect** and choose **Mailbox**.
7. Open the Agent Profile in Agentverse.
8. Set the public profile:
   - Name: `AgriBroker`
   - Handle: `@agribroker`
   - Description: `Autonomous produce procurement agent that discovers farms, compares tomato quotes, optimizes split orders, and returns payment receipts.`
   - Tags: `procurement`, `produce`, `marketplace`, `payments`, `Fetch.ai`
9. Click **Chat with Agent** from Agentverse.
10. Send:

```text
I need 500 tomatoes under $250.
```

Expected ASI:One response:

```text
AgriBroker found 5 sellers for tomatoes.

Quotes:
- Farm A: 200 @ $0.40
- Farm B: 400 @ $0.45
- Farm C: 100 @ $0.50
- Sunny Acres: 300 @ $0.48
- Green Valley: 300 @ $0.42

Optimal split:
- Farm A: 200 tomatoes = $80.00
- Green Valley: 300 tomatoes = $126.00

Receipt:
- Total: $206.00
- Budget: $250.00
- Status: confirmed
- Buyer payment: Stripe Checkout (simulated)
- Farm payout mode: Stripe Connect (simulated/local demo)
```

Troubleshooting:

- If the agent cannot bind to `0.0.0.0:8200`, run it from a normal terminal instead of a restricted sandbox, or change `ORCHESTRATOR_PORT`.
- The app automatically points Python at the `certifi` certificate bundle. If Agentverse mailbox logs still show `CERTIFICATE_VERIFY_FAILED`, fix local Python certificates. On macOS python.org installs, run `/Applications/Python 3.13/Install Certificates.command` if present. You can also run:

```bash
export SSL_CERT_FILE="$(python3 -c 'import certifi; print(certifi.where())')"
python -m agents.asi_chat_agent
```

## Payment Model

The intended marketplace payment flow is:

1. Buyer approves the optimized plan.
2. Buyer funds the order through Stripe Checkout.
3. Orchestrator acts as a neutral purchasing agent for that order.
4. Orchestrator pays or marks payout to each winning farm.
5. Farms confirm payment, decrement inventory, and return receipts.
6. Orchestrator returns one combined buyer receipt.

Buyer payment and farm payout are separate modes:

```env
AGRIBROKER_BUYER_PAYMENT_MODE=stripe     # simulated | stripe
AGRIBROKER_FARM_PAYMENT_MODE=simulated   # simulated | testnet | stripe_connect
```

**Buyer funding (Stripe Checkout).** For the organizer-preferred Stripe path, set `AGRIBROKER_BUYER_PAYMENT_MODE=stripe`. With no `STRIPE_SECRET_KEY`, AgriBroker creates a simulated Checkout reference like `cs_simulated_...` and displays dollars in the receipt. With a real test key, it can create a hosted Stripe Checkout Session.

**Farm payouts.** These can remain simulated for demo reliability, use testnet FET as a Fetch-native settlement stretch, or use **Stripe Connect** transfers to pay sellers in fiat. The Connect model is: the buyer funds the platform via Checkout, then the platform transfers each seller's share to their Stripe **connected account** (`acct_...`). Enable it with:

```env
AGRIBROKER_FARM_PAYMENT_MODE=stripe_connect
STRIPE_CONNECT_TRANSFERS_ENABLED=true
```

Connect payouts are off by default and demo-safe: a real `stripe.Transfer.create` only runs when `STRIPE_SECRET_KEY` is set **and** `STRIPE_CONNECT_TRANSFERS_ENABLED=true`. Real payouts also require genuinely onboarded connected accounts. The workflow now carries each farm's `stripe_connected_account_id` from `config/farms.json` into invoices, but the seeded `acct_demo_*` ids are placeholders. Replace them with real Stripe test connected accounts before enabling live Connect transfers. If the network/faucet/Stripe fails during judging, simulated farm payout keeps the workflow alive while making the status explicit.

Useful payment setup commands:

```bash
python scripts/print_agent_addresses.py
python scripts/che

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 58 recognized source files, 273 KB.
- Python (language) — detected in the code

## Codebase structure (from repository index)

### Files (62 of 62)

```
.env.example
.gitignore
agents/__init__.py
agents/agent_network.py
agents/agentverse_profiles.py
agents/asi_chat_agent.py
agents/business_seller.py
agents/farm_state.py
agents/farmer_agent.py
agents/llm.py
agents/onboarding.py
agents/optimizer.py
agents/orchestrator_agent.py
agents/order_store.py
agents/payments.py
agents/protocols.py
agents/registry_agent.py
agents/settings.py
agents/workflow.py
config/farms.json
docs/agentverse-profile.md
docs/agentverse/farm-a.md
docs/agentverse/farm-b.md
docs/agentverse/farm-c.md
docs/agentverse/farmer-template.md
docs/agentverse/green-valley.md
docs/agentverse/orchestrator.md
docs/agentverse/registry.md
docs/agentverse/setup.md
docs/agentverse/sunny-acres.md
docs/api-notes.md
docs/devpost-summary.md
docs/presentation-guide.md
README.md
requirements.txt
scripts/__init__.py
scripts/check_demo_ready.py
scripts/check_stripe_ready.py
scripts/check_testnet_payment_ready.py
scripts/onboard_farmer.py
scripts/preview_asi_response.py
scripts/print_agent_addresses.py
scripts/print_agentverse_profiles.py
scripts/run_asi_live_demo.py
scripts/run_live_demo.py
scripts/run_local_bureau.py
scripts/run_local_demo.py
scripts/serve_checkout_pages.py
scripts/showcase.py
scripts/validate_config.py
tests/conftest.py
tests/test_agent_network.py
tests/test_agentverse_profiles.py
tests/test_asi_chat_agent.py
tests/test_business_seller.py
tests/test_llm.py
tests/test_onboarding.py
tests/test_optimizer.py
tests/test_payments.py
tests/test_settings.py
tests/test_validate_config.py
tests/test_workflow.py
```

### Dependencies

- requirements.txt: pytest@>=8.0, python-dotenv@>=1.0, requests@>=2.31, stripe@>=13.0, uagents-core@>=0.3, uagents[all]@>=0.22

### Recent commits (newest first)

- Polish demo modes and Agentverse profiles
- Add live Flockx Business Agent quote integration
- Polish agents and finalize simulated marketplace flow
- Agentverse Readme
- Add simulated Stripe marketplace flow and farmer onboarding
- The starter code for Fetch Ai project

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

### docs/agentverse-profile.md

```markdown
# AgriBroker Agentverse Profile

## Name

AgriBroker

## Handle

@agribroker

## Short Description

Autonomous produce procurement agent that discovers farms, compares tomato quotes, optimizes split orders, coordinates buyer funding, and returns payment receipts.

## Tags

procurement, produce, marketplace, payments, Fetch.ai, ASI:One, uAgents

## Profile README

AgriBroker turns one buyer intent into a multi-agent procurement workflow.

Try:

```text
I need 500 tomatoes under $250.
```

What happens:

1. AgriBroker parses the produce request.
2. It discovers tomato sellers.
3. It gathers live quotes from farm agents.
4. It computes the cheapest split order.
5. It coordinates buyer funding through simulated demo funding or Stripe Checkout.
6. It pays selected farms through simulated payouts, Fetch testnet FET, or a Stripe Connect integration path.
7. It returns a receipt with allocations and transaction ids.

Demo result:

- Farm A: 200 tomatoes at $0.40
- Green Valley: 300 tomatoes at $0.42
- Total: $206
- Budget: $250

AgriBroker is a neutral buyer-side broker. It does not charge a broker fee in this MVP.

```

### docs/api-notes.md

```markdown
# Fetch Integration Notes

This file tracks the external Fetch.ai API details that must be verified before the live demo.

## Current Assumptions

- Code agents use `uagents.Agent`, `uagents.Context`, and `uagents.Model`.
- Local development can use custom `Model` messages for registry, quotes, invoices, payments, and receipts.
- ASI:One is used for buyer intent parsing.
- Agentverse hosts/discovers the final code agents.
- The buyer funds the order first through Stripe Checkout or simulated buyer funding; the orchestrator then marks or pays selected farms.
- Local payment simulation is acceptable as a fallback, but the target demo should show at least orchestrator-to-farm testnet transfers.

## Current Verified Shapes

- ASI:One-compatible agents use the Agent Chat Protocol from `uagents_core.contrib.protocols.chat`.
- The manual wrapper should import `ChatMessage`, `ChatAcknowledgement`, `TextContent`, `EndSessionContent`, and `chat_protocol_spec`.
- The ASI-facing agent should run with `mailbox=True` and `publish_agent_details=True`.
- The chat protocol should be included with `agent.include(protocol, publish_manifest=True)`.
- Current token-send examples use `ctx.ledger.send_tokens(wallet_address, amount, denom, wallet)` and `atestfet`.
- Local startup check succeeded with `uagents 0.25.2` and `uagents-core 0.4.7`: the ASI chat agent published the `AgentChatProtocol` manifest and registered active. The remaining manual setup is creating/connecting the mailbox in Agent Inspector.
- `AGRIBROKER_INTENT_MODE=local` is the default for demo determinism. Use `asi` once the ASI:One key and response format are verified.
- `AGRIBROKER_DISCOVERY_MODE=agent` enables the real Registry/Farmer message path through `ctx.send_and_receive`. Keep `local` as the fallback for live demos.
- Stripe Checkout Sessions are the organizer-preferred buyer payment path. The implementation creates a Checkout Session with `mode=payment`, `client_reference_id=order_id`, metadata, one line item, and success/cancel URLs. If `STRIPE_SECRET_KEY` is missing or Stripe fails, buyer funding falls back to simulated mode.
- Stripe Connect transfers are the farm/seller payout path. The buyer funds the platform via Checkout; the platform then transfers each seller's share to their Stripe **connected account** (`acct_...`) with `stripe.Transfer.create(amount, currency, destination, metadata)`. This is gated behind `AGRIBROKER_FARM_PAYMENT_MODE=stripe_connect` and is demo-safe: a real transfer only runs when BOTH `STRIPE_SECRET_KEY` is set AND `STRIPE_CONNECT_TRANSFERS_ENABLED=true`. Any other state, a recipient that is not an `acct_...` id, or any Stripe error falls back to a clearly labeled simulated `PaymentResult`.
- The workflow now carries each farm's `stripe_connected_account_id` from `config/farms.json` into invoices and uses it when `AGRIBROKER_FARM_PAYMENT_MODE=stripe_connect`. The seeded `acct_demo_*` ids are placeholders; replace them with real Stripe test connected accounts b
[truncated — 3218 more characters]
```

### requirements.txt

```
pytest>=8.0
python-dotenv>=1.0
requests>=2.31
stripe>=13.0
uagents[all]>=0.22
uagents-core>=0.3

```

### agents/__init__.py

```python
"""AgriBroker agent package."""


```

### scripts/__init__.py

```python
"""Utility scripts for AgriBroker."""


```

### tests/test_settings.py

```python
import pytest

from agents.settings import discovery_mode


def test_discovery_mode_accepts_business() -> None:
    assert discovery_mode("business") == "business"


def test_discovery_mode_rejects_unknown() -> None:
    with pytest.raises(ValueError):
        discovery_mode("unknown")

```

### scripts/run_local_demo.py

```python
from pathlib import Path
import sys

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

try:
    from dotenv import load_dotenv

    load_dotenv(ROOT / ".env")
except Exception:
    pass

from agents.workflow import run_procurement_locally


def main() -> None:
    run = run_procurement_locally("I need 500 tomatoes under $250.")
    print("AgriBroker local demo")
    print("====================")
    for line in run.transcript:
        print(f"- {line}")


if __name__ == "__main__":
    main()

```

### scripts/preview_asi_response.py

```python
from pathlib import Path
import os
import sys

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

try:
    from dotenv import load_dotenv

    load_dotenv(ROOT / ".env")
except Exception:
    pass

from agents.workflow import format_procurement_response, run_procurement_locally


def main() -> None:
    prompt = " ".join(sys.argv[1:]).strip() or "I need 500 tomatoes under $250."
    run = run_procurement_locally(
        prompt,
        payment_mode=os.getenv("AGRIBROKER_FARM_PAYMENT_MODE"),
        intent_mode="local",
    )
    print(format_procurement_response(run))


if __name__ == "__main__":
    main()

```

### tests/test_llm.py

```python
from agents.llm import extract_json_content, parse_buyer_intent_locally, use_mock_intent_parser


def test_local_parser_extracts_tomato_order() -> None:
    intent = parse_buyer_intent_locally("I need 500 tomatoes under $250.")

    assert intent.item == "tomatoes"
    assert intent.qty == 500
    assert intent.budget == 250


def test_intent_mode_mapping() -> None:
    assert use_mock_intent_parser("local") is True
    assert use_mock_intent_parser("asi") is False
    assert use_mock_intent_parser("auto") is None


def test_extract_json_content_from_markdown_fence() -> None:
    assert extract_json_content('```json\n{"item":"tomatoes"}\n```') == '{"item":"tomatoes"}'

```

### agents/settings.py

```python
"""Runtime settings shared by AgriBroker agents."""

from __future__ import annotations

import os
from typing import Literal

FetchNetwork = Literal["mainnet", "testnet"]
DiscoveryMode = Literal["local", "agent", "business"]


def fetch_network() -> FetchNetwork:
    value = os.getenv("FETCH_NETWORK", "testnet").strip().lower()
    if value not in {"mainnet", "testnet"}:
        raise ValueError("FETCH_NETWORK must be 'mainnet' or 'testnet'")
    return value  # type: ignore[return-value]


def discovery_mode(value: str | None = None) -> DiscoveryMode:
    mode = (value or os.getenv("AGRIBROKER_DISCOVERY_MODE") or "local").strip().lower()
    if mode not in {"local", "agent", "business"}:
        raise ValueError("AGRIBROKER_DISCOVERY_MODE must be 'local', 'agent', or 'business'")
    return mode  # type: ignore[return-value]


def registry_address(value: str | None = None) -> str | None:
    address = (value or os.getenv("AGRIBROKER_REGISTRY_ADDRESS") or "").strip()
    return address or None

```

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