Real-Time World State Engine for Hermes AI Agents
Your AI knows everything up to its training cutoff — and nothing after.
Every Hermes agent you deploy is, by default, blind to the present moment.
It knows the history of Bitcoin. It doesn't know today's price.
It knows what the VIX measures. It doesn't know what it's reading right now.
It can reason about DeFi protocols. It can't tell you if gas is 12 or 120 gwei.
This is the Blind Agent Problem — and it silently corrupts every market analysis, trading recommendation, and news summary your agents produce. They confidently answer questions about a world that no longer exists.
ORACLE solves this. It's a standalone FastAPI service that continuously monitors multiple data streams and exposes a single /state endpoint returning a rich, structured snapshot of the world right now — ready for direct injection into Hermes agent context.
One GET /state/prompt call gives your agent everything it needs to reason about current market conditions, breaking news, on-chain activity, and macro sentiment — in a single formatted context block.
┌─────────────────────────────────────────────────────────────────┐
│ HERMES AGENT │
│ │
│ "What should I know before I analyze this portfolio?" │
│ │ │
│ ▼ GET /state/prompt │
│ ┌─────────────┐ │
│ │ ORACLE │◄──── context injected into system prompt │
│ │ Skill │ │
│ └─────────────┘ │
└───────────────────────┬─────────────────────────────────────────┘
│ HTTP
▼
┌─────────────────────────────────────────────────────────────────┐
│ ORACLE FastAPI Service │
│ │
│ GET /state ──► Full WorldState JSON │
│ GET /state/{domain} ──► crypto | macro | news | onchain │
│ GET /state/prompt ──► Hermes-ready context string │
│ GET /state/summary ──► Compact signal summary │
│ GET /health ──► Source health + latencies │
│ WS /stream ──► Real-time push updates │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ REFRESH ENGINE │ │
│ │ (APScheduler — independent interval per source) │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │ │
│ │ │ crypto │ │ macro │ │ news │ │onchain │ │ │
│ │ │ 30sec │ │ 15min │ │ 5min │ │ 60sec │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └───┬────┘ │ │
│ └───────┼─────────────┼─────────────┼─────────────┼───────┘ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ REDIS CACHE │ │
│ │ oracle:crypto oracle:macro oracle:news oracle:.. │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
CoinGecko yfinance CryptoPanic Etherscan
alt.me API (thread NewsAPI Gas Oracle
(Fear/Greed) pool) RSS Feeds Block API
| Domain | Source | Data | Refresh Rate |
|---|---|---|---|
| Crypto | CoinGecko v3 | Top 20 coins: price, 24h/7d change, market cap, volume, rank | 30 seconds |
| Crypto | alternative.me | Fear & Greed Index (0–100) with previous day comparison | 30 seconds |
| Macro | yfinance | SPY, NVDA, TSLA, BTC-USD, ETH-USD, SOL-USD + % change | 15 minutes |
| Macro | yfinance | DXY (Dollar Index), VIX (Volatility Index) | 15 minutes |
| News | CryptoPanic | Hot crypto headlines with community sentiment voting | 5 minutes |
| News | NewsAPI | Top general tech/finance/crypto headlines | 5 minutes |
| News | RSS (CoinDesk, CoinTelegraph, Decrypt) | Fallback when API keys absent | 5 minutes |
| On-Chain | Etherscan | ETH gas: slow/standard/fast Gwei, base fee | 60 seconds |
| On-Chain | Etherscan | Latest block number, mempool size estimate | 60 seconds |
git clone https://github.com/onurkavi/oracle
cd oracle
cp .env.example .env
# Optionally add your API keys to .env
docker-compose upORACLE is live at http://localhost:8000
Interactive docs at http://localhost:8000/docs
# Install dependencies
pip install -r requirements-dev.txt
# Start Redis
docker run -d -p 6379:6379 redis:7-alpine
# Run ORACLE
uvicorn oracle.api.main:app --reload --port 8000
# In another terminal — run the demo (no API keys needed)
python scripts/demo.pyCopy the skill file and point it at your ORACLE instance:
cp hermes_skill/ORACLE.md ~/.hermes/skills/ORACLE.md
export ORACLE_API_URL=http://localhost:8000The skill tells Hermes to call ORACLE before any market analysis, trading decision, or news-related task. See hermes_skill/ORACLE.md for the full skill specification and example invocations.
import httpx
async def get_oracle_context() -> str:
"""Fetch ORACLE world state as a Hermes-ready context string."""
async with httpx.AsyncClient() as client:
resp = await client.get("http://localhost:8000/state/prompt")
return resp.text
# Inject into your Hermes agent system prompt:
context = await get_oracle_context()
system_prompt = f"""You are a crypto market analyst.
{context}
Based on this live data, answer the user's question."""Returns the full aggregated WorldState as structured JSON.
curl http://localhost:8000/stateReturns data for a specific domain.
Valid values: crypto | macro | news | onchain
curl http://localhost:8000/state/crypto
curl http://localhost:8000/state/macroReturns the WorldState formatted as a prompt-ready context string for Hermes injection.
curl http://localhost:8000/state/promptReturns a compact JSON summary of the most critical market signals.
curl http://localhost:8000/state/summaryTriggers an immediate data refresh for a specific source.
curl -X POST http://localhost:8000/state/refresh/cryptoReturns per-source health status, latencies, and uptime percentages.
curl http://localhost:8000/healthWebSocket endpoint that pushes WorldState updates every WS_PUSH_INTERVAL seconds.
import asyncio, websockets, json
async def stream():
async with websockets.connect("ws://localhost:8000/stream") as ws:
async for msg in ws:
data = json.loads(msg)
if data["type"] == "summary":
print(data["data"]["mood"], data["data"]["btc"])
asyncio.run(stream()){
"schema_version": "1.0",
"generated_at": "2024-01-15T14:32:00.000Z",
"overall_market_mood": "bullish",
"data_freshness_pct": 100.0,
"key_signals": [
"Fear & Greed: 72/100 (Greed)",
"BTC ▲2.34% 24h @ $67,234",
"VIX 14.2 (low volatility)",
"ETH gas: 28 gwei (fast) — moderate congestion",
"News sentiment: 58% positive, 22% negative across 20 headlines"
],
"crypto": {
"coins": [
{
"id": "bitcoin",
"symbol": "BTC",
"name": "Bitcoin",
"price_usd": 67234.50,
"change_24h_pct": 2.34,
"change_7d_pct": 8.10,
"market_cap_usd": 1315000000000,
"volume_24h_usd": 28000000000,
"rank": 1,
"ath_usd": 73750.00,
"ath_change_percentage": -8.82
},
{
"id": "ethereum",
"symbol": "ETH",
"name": "Ethereum",
"price_usd": 3451.20,
"change_24h_pct": 1.87,
"change_7d_pct": 5.40,
"market_cap_usd": 414000000000,
"rank": 2
}
],
"fear_greed": {
"value": 72,
"category": "Greed",
"previous_value": 68,
"previous_category": "Greed",
"timestamp": "2024-01-15T14:32:00Z"
},
"total_market_cap_usd": 2400000000000,
"total_volume_24h_usd": 120000000000,
"btc_dominance_pct": 54.79,
"market_trend": "bullish",
"top_gainers": ["SOL", "AVAX", "LINK"],
"top_losers": ["XRP", "DOGE", "ADA"]
},
"macro": {
"stocks": {
"SPY": {
"symbol": "SPY",
"name": "SPDR S&P 500 ETF",
"price": 487.30,
"change_pct": 0.82,
"change_abs": 3.96,
"volume": 67000000
},
"NVDA": {
"symbol": "NVDA",
"name": "NVIDIA Corp",
"price": 875.40,
"change_pct": 1.24
},
"TSLA": {
"symbol": "TSLA",
"name": "Tesla Inc",
"price": 248.70,
"change_pct": -0.43
}
},
"macro": {
"^VIX": {
"symbol": "^VIX",
"name": "CBOE Volatility Index",
"price": 14.20,
"change_pct": -3.10
},
"DX-Y.NYB": {
"symbol": "DX-Y.NYB",
"name": "US Dollar Index (DXY)",
"price": 103.40,
"change_pct": 0.18
}
},
"crypto_yf": {
"BTC-USD": {"price": 67234.50, "change_pct": 2.34},
"ETH-USD": {"price": 3451.20, "change_pct": 1.87},
"SOL-USD": {"price": 178.90, "change_pct": 4.21}
},
"market_open": true,
"spy_trend": "bullish",
"risk_sentiment": "risk-on"
},
"news": {
"crypto_headlines": [
{
"title": "Bitcoin Surges Past $67K as ETF Inflows Hit Weekly Record",
"url": "https://coindesk.com/...",
"source": "CoinDesk",
"published_at": "2024-01-15T13:45:00Z",
"sentiment": "positive",
"currencies": ["BTC"]
},
{
"title": "Ethereum Validators Set New All-Time High as Staking Yields Rise",
"source": "CoinTelegraph",
"sentiment": "positive",
"currencies": ["ETH"]
}
],
"general_headlines": [
{
"title": "NVIDIA Reports Record Revenue, Credits AI Chip Demand",
"source": "Reuters",
"sentiment": "positive"
}
],
"trending_topics": ["Bitcoin", "ETF", "Ethereum", "NVIDIA", "FederalReserve", "DeFi"],
"dominant_sentiment": "positive",
"positive_count": 12,
"negative_count": 4,
"neutral_count": 4
},
"onchain": {
"gas": {
"slow": 12.0,
"standard": 18.0,
"fast": 28.0,
"base_fee": 11.50,
"suggest_base_fee": 11.72
},
"network_congestion": "moderate",
"last_block": 19500142,
"mempool_size_estimate": 125400
},
"source_health": {
"crypto": {
"source": "crypto",
"status": "ok",
"last_success": "2024-01-15T14:31:58Z",
"consecutive_failures": 0,
"avg_latency_ms": 342.5,
"uptime_pct": 99.8
},
"macro": {"status": "ok", "avg_latency_ms": 1842.0},
"news": {"status": "ok", "avg_latency_ms": 512.3},
"onchain": {"status": "ok", "avg_latency_ms": 198.7}
}
}oracle/
├── oracle/
│ ├── __init__.py
│ ├── config.py # Pydantic Settings — all env vars
│ ├── models.py # Pydantic v2 domain models
│ ├── collectors/
│ │ ├── crypto.py # CoinGecko + Fear & Greed
│ │ ├── macro.py # yfinance (stocks, macro, crypto)
│ │ ├── news.py # CryptoPanic + NewsAPI + RSS
│ │ └── onchain.py # Etherscan gas + block data
│ ├── cache/
│ │ └── redis_store.py # Async Redis client + memory fallback
│ ├── workers/
│ │ └── refresh_engine.py # APScheduler background workers
│ └── api/
│ ├── main.py # Uvicorn entrypoint + logging config
│ ├── routes.py # FastAPI routes + WebSocket
│ └── formatter.py # WorldState → Hermes prompt string
├── hermes_skill/
│ └── ORACLE.md # Hermes-compatible skill file
├── scripts/
│ └── demo.py # Rich-formatted demo (no API keys needed)
├── tests/
│ ├── test_collectors.py # Collector unit tests (mocked HTTP)
│ ├── test_cache.py # Redis store tests (mocked + fallback)
│ └── test_routes.py # API + model + formatter tests
├── docker-compose.yml # Redis + ORACLE service
├── Dockerfile # Multi-stage, non-root build
├── requirements.txt
├── requirements-dev.txt
└── .env.example
All settings can be overridden via environment variables or a .env file:
| Variable | Default | Description |
|---|---|---|
REDIS_URL |
redis://localhost:6379/0 |
Redis connection URL |
COINGECKO_API_KEY |
(empty) | Optional — free tier works without |
CRYPTOPANIC_API_KEY |
(empty) | Required for crypto news |
NEWSAPI_KEY |
(empty) | Required for general headlines |
ETHERSCAN_API_KEY |
(empty) | Required for real gas prices |
REFRESH_INTERVAL_CRYPTO |
30 |
Seconds between crypto refreshes |
REFRESH_INTERVAL_MACRO |
900 |
Seconds between macro refreshes |
REFRESH_INTERVAL_NEWS |
300 |
Seconds between news refreshes |
REFRESH_INTERVAL_ONCHAIN |
60 |
Seconds between on-chain refreshes |
WS_PUSH_INTERVAL |
10 |
WebSocket push interval (seconds) |
CRYPTO_TOP_N |
20 |
Number of top coins to track |
LOG_LEVEL |
INFO |
Loguru log level |
ENVIRONMENT |
development |
development or production |
pip install -r requirements-dev.txt
pytest tests/ -v --cov=oracle --cov-report=term-missingpython scripts/demo.py # Single snapshot with Rich formatting
python scripts/demo.py --watch # Auto-refresh every 5 seconds
python scripts/demo.py --json # Raw JSON output
python scripts/demo.py --live # Connect to running ORACLE instanceMIT — built by Onur Kavi as part of his AI portfolio.