# Oracle

**Oracle is a self-custody multichain agent control plane.** The public data,
policy, and control planes read, quote, simulate, and prepare unsigned artifacts.
Your wallet signs, or you explicitly initialize the optional owner-local signer
with an encrypted vault and sealed policy. The public plane never signs or
broadcasts.

Specialist agent profiles, real protocol intents, self-custody by default,
receipts or it didn't happen.

## Quickstart (standalone CLI)

```bash
curl -fsSL https://oracle.demi.la/install.sh | bash   # preferred
# or: npm i -g @oracle-agent/oracle                     # Node >= 20.19
oracle --version
oracle setup model                     # choose OAuth or API-key access
oracle                                  # native Oracle chat
oracle doctor                           # verify local posture
```

For a guided first answer, run `oracle setup` on a TTY: model login, optional
Telegram token, watch-only EVM address, sourced BTC price, and an alert-only
watch. Enter skips; rerun resumes and keeps a ready model unless `--model`
requests a change. Saved watches are not monitored; no evaluator delivers them
yet. Bare non-TTY setup prints read-only status. Scripts must pass `--yes` to
run the wizard; it writes state and defaults to a BTC answer and a watch 5%
above a fresh price (`--skip-answer` / `--skip-watch` opt out).
Use `oracle setup menu` for the legacy model/messaging menu.

`oracle setup model` offers Anthropic, OpenAI Codex, and Grok OAuth plus secure
API-key setup for OpenRouter, OpenAI, Anthropic, xAI, DeepSeek, Gemini, Kimi,
Mistral, Nous Portal, Qwen, GLM, and custom OpenAI-compatible providers. `oracle auth status` reports
providers without printing credentials. Linux, Windows, and macOS apps are in beta.

The CLI, source, and desktop beta are public to everyone. Locals Only holders
receive a 0% Oracle integrator fee; the NFT does not gate product access.

The package also installs `oracle-investigate`, a bounded report-only forensic CLI:

```bash
oracle-investigate --help
oracle-investigate capabilities
oracle-investigate wallet --family evm --address 0xabc... --chain-id 8453 --limit 20
oracle-investigate wallet --family evm --address 0xabc... --chain-id 8453 --include-opensea
oracle-investigate analyze --input ./components.json
oracle-investigate overlap --input ./opensea-snapshots.json
```

Every successful investigator command emits one JSON document. It has no signer,
prepare, broadcast, arbitrary RPC URL, provider URL, key argument, fetch, transport,
or clock option. OpenSea v2 enrichment reads only `OPENSEA_API_KEY`, only after the
valueless `--include-opensea` opt-in, and never paginates. Offline `overlap` accepts
strict bounded snapshots and performs no fetch. Unsupported or incomplete coverage
stays explicit as `NOT_REQUESTED`, `UNAVAILABLE`, `PARTIAL`, or `UNKNOWN`.

Hyperliquid core perpetual orders use a 2 bps builder fee; HIP-3 and HIP-4 use 1 bps.
The private operator configuration, approval flow, wire units, and holder waiver are documented in
[Hyperliquid builder code](docs/hyperliquid-builder-code.md).


Oracle runs its own agent loop. `oracle chat` starts the Oracle-native agent
directly - no external agent runtime required.

Any MCP-capable harness can drive it instead: run `oracle mcp install <target>`
for Claude Code, Claude Desktop, Codex, ChatGPT, Cursor, VS Code, or Copilot, or
install it as an [Agent Plugin](https://agent-plugins.org/). In that direction
the harness calls Oracle as a tool and Oracle's native loop stays in charge.
Run `oracle harness detect` to see what is installed and how to wire it.
Oracle is listed in the [official MCP registry](https://registry.modelcontextprotocol.io)
as `io.github.demi-hl/oracle`; any registry-aware client can launch it with
`npx -y --package @oracle-agent/oracle oracle-data-mcp` (stdio).

[Hermes](https://github.com/NousResearch/hermes-agent) is one such harness, and
also remains available as a legacy delegate that takes over the model loop
entirely: `ORACLE_CHAT_BACKEND=hermes oracle chat`.

Oracle can run standalone model auth directly with API keys or Claude, Codex,
and Grok OAuth. OAuth credentials use the OS keychain when available, with a
private `0600` local fallback when keychain storage is unavailable.

Wallet-sign and the local `oracle signer` are both first-class. The signer
stays off until the owner initializes an encrypted vault and sealed policy.
Every sign needs one-use confirmation. Autonomous trading additionally requires
`ORACLE_AUTONOMOUS_TRADING=1`. Never paste a seed, key, passphrase, or signer
token into Oracle chat or argv. The private `@oracle-agent/agent` package is
not included here.

---

## Start safely

1. Install the public CLI and authenticate a model provider as shown above.
2. Run `oracle chain list`, then `oracle chain use <name>`.
3. Use reads, research, quotes, simulations, and unsigned preparation.
4. Review every prepared artifact in the wallet that will sign it.
5. Treat only a confirmed transaction hash plus receipt as execution.

Hermes is optional. To add its isolated runtime, specialist profiles, and local
read plane later:

```bash
oracle bootstrap
oracle init --apply        # writes profiles + local HMAC attestation config; no wallet key
oracle data serve          # loopback only: 127.0.0.1:8787
oracle doctor
```

Library users can prepare directly:

```js
import { data } from "@oracle-agent/oracle";
const prepared = await data.call("hl-perps", "prepareOrder", {
  /* coin, side, size, owner wallet address */
});
// Oracle stops here. The user's wallet reviews, signs, and submits.
```

Hosts that need a prepare-only task turn can import
`createTaskAdapter` and its shared request/result types from
`@oracle-agent/oracle/task`. The entrypoint advertises only `oracle_cli` and
`trade_lifecycle`; the host injects both its model provider and read/prepare CLI
runner. It does not install an HTTP route or UI. See
[docs/task-adapter.md](docs/task-adapter.md).

See [SETUP.md](SETUP.md) for clean installation and troubleshooting,
[docs/locals-only-fee-waiver.md](docs/locals-only-fee-waiver.md) for the 0% holder fee, and
[docs/buzz-integration.md](docs/buzz-integration.md) for the Buzz HTTP contract.

---

## What Oracle is

Most "AI crypto agent" projects give a model a hot wallet and hope. Oracle does
the opposite: the model *proposes*, the owner *authorizes*, and the policy layer
decides what may even be asked.

Three properties define it:

1. **Self-custody by default.** Hosted/keyless Oracle never accepts your
   private key. Those surfaces build unsigned transactions and typed-data
   intents; your wallet signs them. A self-host install may import a key into
   the encrypted local vault and arm execution through `oracle signer`.
2. **Bound grants.** A grant is a signed, scoped permission: max value,
   chain, venue, destination allowlist, plus either a TTL or an explicit trigger
   condition such as `mint-opens`. Oracle canonicalizes it, renders it for
   review, and refuses to prepare anything outside it. Runtime enforcement is
   the wallet's or smart account's job, or the optional local signer's sealed
   policy when that signer is explicitly enabled.
3. **Receipts or it didn't happen.** A claim without a transaction hash, a
   receipt is not a result. If a transport cannot verify a balance delta, the receipt must say `balanceDeltaVerified: false`.

Default posture is `DISARMED`.

### Context and lifecycle governance

Oracle includes the two organization-scale governance layers directly in the
public self-hosted package:

- `@oracle-agent/oracle/context-graph`: tenant/domain-scoped nodes and edges with
  mandatory caller-asserted provenance explicitly marked `unverified`, evidence
  hashes, freshness TTLs, stale exclusion, trusted domain assignments and RBAC,
  immutable revision history, private atomic storage, and a hash chain that
  detects corruption and un-rehashed edits. The local hash chain is not an
  external anti-rollback anchor against a same-UID writer.
- `@oracle-agent/oracle/agent-lifecycle`: inventory for agents, tools, workflows,
  first-class expiring credentials, and external credential references, with
  last-use/eval health, credential expiry,
  inactivity retirement, regression quarantine, and owner-reviewed reactivation.

Use `oracle context --help` and `oracle lifecycle --help`, or import the APIs.
These are local governance surfaces: they add no public HTTP endpoint, expose no
credential-value field, reject recognized secret-shaped input, and grant no signing authority. Public self-hosted and
operator/admin installations use the same capabilities, safety checks, and
execution flow; operator fee configuration is the product-rate difference, not
a capability fork.

## Why it's different

The differentiators are **policy, custody, and receipts** - not a smarter chat
loop.

| | Typical agent | Oracle |
|---|---|---|
| Custody | house wallet holds keys | user signs, no house custody |
| Authority | prompt-level "be careful" | signed grant: chain, spend, targets, TTL - enforced by your wallet, not by us |
| Destinations | whatever the model emits | reviewed per-chain allowlist, fail-closed |
| Slippage | fixed % | live guard recomputed per leg, hard 100 bps cap |
| Proof | model says "done" | hash + verified successful on-chain receipt, with `balanceDeltaVerified` true only when snapshots prove the expected delta |
| Surface | swap only | swaps, bridges, perps, vaults, yield, NFTs, intents |

## Architecture

```
        you
         |
       Task
         |
      oracle            <- routes, never authorizes custody
         |
  +------+------+------+------+------+------+------+
  |      |      |      |      |      |      |      |
 poly   hyper  robin  solana bitcoin stable protocol
 market liquid hood                         builder
```

Each lane is a Hermes **profile**: its own system prompt, skills, memory, and
sessions. The `oracle` lane routes intent to the right specialist. Adding a lane
is adding a directory.

Three planes, and the boundary between them is mechanically enforced:

- **Data plane** (public) - read/quote across chains and protocols. No keys.
- **Policy plane** (public) - destination allowlists, slippage guards, route and
  vault attestations, grant schema. Holds no keys; constrains what a signer may
  be asked to do.
- **Exec plane** (self-hosted, optional) - signing and broadcast live only in an
  explicitly initialized loopback local signer using the user's keys, or in
  separately operated owner infrastructure. Hosted/keyless Oracle has no active
  signer. The local-signer module ships policy-bound and grants no holder
  privilege.

`test/custody-boundary.test.mjs` walks the import graph and fails if any public
module reaches wallet key material or a house signer. The split is a test, not a
promise.

## Coverage

### Universal NFT lifecycle readiness

The public package exposes one canonical NFT lifecycle vocabulary - `mint`,
`buy`, `list`, `cancel_listing`, and `send` - for deterministic route discovery.
The lifecycle module is `ROUTE_ONLY`: an advertised operation is not itself an
unsigned transaction or an execution-readiness claim. Concrete provider
adapters separately return reviewed unsigned artifacts where implemented. The
same capabilities and safety checks apply to public and admin callers. Admin
configuration may set other product fees, but these NFT routes and preparations
charge zero Oracle fee by default.

Current readiness is deliberately adapter-specific:

- EVM has OpenSea SeaDrop mint, listing, and cancellation preparation plus exact
  ERC-721/ERC-1155 safe-transfer preparation. OpenSea buy and sweep preparation
  are disabled until canonical Seaport target and calldata decoding is shipped;
  read-only best-listing discovery remains available. Other EVM launchpad routes
  retain their own declared tiers.
- Solana has the separate Magic Eden buy/list/mint provider plus exact, verified
  Metaplex NFT/Core transfer preparation. The generic universal Solana mint
  adapter is `RESEARCH_ONLY` and fails closed until canonical serialized-message
  decoding exists. Marketplace listing cancellation is not currently exposed.
- Ordinals has Satflow buy/list, reviewed inscription mint planning, and exact
  PSBT transfer-plan preparation. Marketplace listing cancellation is not
  currently exposed.

Concrete public data-plane preparation routes stop at unsigned reviewed
artifacts; lifecycle route discovery stops earlier at `ROUTE_ONLY`. Solana and
Ordinals transfers are prepare-stage plans, and adapter capability tiers must
be checked per route. This is not a claim of universal signing, broadcasting,
or end-to-end execution readiness.

**12 EVM chains** built in as scanner configs: Ethereum, Optimism, BNB, Polygon, Stable, HyperEVM,
Abstract, Robinhood Chain, Base, Arbitrum, Avalanche, and **Kinetiq Elysium Testnet (99801)**. Plus Solana, Bitcoin L1,
and a read-only Canton Coin (CC) lane. Solana covers Jupiter quote/prepare, SPL account research, live
simulation of the prepared swap, and Magic Eden NFT reads with unsigned
buy/list/mint tickets. Bitcoin covers Esplora fee/UTXO reads, Ordinals/runes
research, Satflow PSBT intents, and inscription PSBT preparation. Canton is not
EVM: Oracle reads Canton Coin via Scan and explains onboarding; quote/prepare stay
fail-closed. Hyperliquid
adds HyperCore HYPE staking: validator reads plus EIP-712 stake, delegate,
undelegate, and unstake preparation. User wallets sign.

**Any other EVM chain is config, not code:**

```js
import { registerCustomChain } from "@oracle-agent/oracle/scanner";

registerCustomChain({
  key: "mychain",
  chainId: 7777,
  name: "My Chain",
  rpcEnv: ["MYCHAIN_RPC_URL"],
  nativeCurrency: { symbol: "MYC", decimals: 18 },
});
```

That chain immediately has block reads, balances, on-chain token resolution, log
scanning, and structural risk checks. See
[`docs/adding-a-chain.md`](docs/adding-a-chain.md).

```bash
oracle-scan chains                    # coverage matrix
oracle-scan token base 0x8335...2913  # on-chain identity
oracle-scan pools base 0x4200...0006  # pools ranked by liquidity
oracle-scan risk  base 0x8335...2913  # structural checks + sell simulation
oracle-scan sell  base 0x8335...2913  # round trip: can you actually exit?
```

The 11 established EVM scanner chains currently report the full 10-capability scanner
matrix, including live quote, sell simulation, and unsigned preparation where
the selected provider supports that operation. Capability coverage is not a
claim that every protocol supports every action; unsupported paths still fail
closed.

Two unrelated chains share the Elysium name. **Elysium (Vulcan Forged)** is chain 1339, key `elysium`, PYR gas, `ELYSIUM_RPC_URL`, read-only. **Kinetiq Elysium Testnet** is chain 99801, key `kinetiq-elysium-testnet` (aliases `kinetiq-elysium`, `elysium-l2`, `99801`; never bare `elysium`): Kinetiq’s Arbitrum Nitro/Orbit L2 for Hyperliquid, with HyperEVM testnet (998) as parent and native HYPE. It is testnet only; no Kinetiq Elysium mainnet is registered until a chain id is published. Testnet balances are excluded from USD totals and never priced, including the USD figures the Kinetiq Blockscout explorer shows for testnet tokens. The chain runs a single sequencer with AnyTrust data availability (committee undisclosed). Kinetiq’s planned HyperCore market data is attested by the sequencer, not proven by HyperCore, and is not integrated. Execution is unsupported: Oracle never prepares, offers, queues or routes 99801 or 998 (swap, bridge, mint, launch and signer-queue paths refuse every spelling of the chain id), and `oracle sign policy` refuses to seal either; the local signer executes only what the owner’s sealed policy allows. Reads are generic EVM native/ERC-20 balances, Blockscout token discovery, `elysium_status`, the `/chainstatus` card renderer (not yet connected to a status read in hosted account messaging), and `kinetiq_elysium_bridge_quote`: a quote-only, non-executable HyperEVM testnet (998) ↔ 99801 bridge quote that returns no transaction, prices nothing, and refuses mainnet. Bridge quotes read `KINETIQ_ELYSIUM_TESTNET_RPC_URL` for 99801 and `HYPEREVM_TESTNET_RPC_URL` for 998. `kinetiq_elysium_chainzy_quote` (provider `kinetiq-elysium-chainzy-quote`) is a quote-only Chainzy V3 QuoterV2 read on 99801: Chainzy is a third-party testnet venue, not Kinetiq. It returns raw token amounts with no transaction or router calldata, re-verifies the chain id and the quoter's factory and WHYPE binding on every quote, resolves only the symbols WHYPE and USDC (to the official addresses) and refuses look-alike tokens. The swap router and prepare paths still refuse 99801. Native 18 decimals are an unverified Orbit convention. Set `KINETIQ_ELYSIUM_TESTNET_RPC_URL` (or `ELYSIUM_TESTNET_RPC_URL`); `ELYSIUM_RPC_URL` only ever points at Vulcan Forged 1339.

Every venue address was verified **functionally, not by codesize** - a re-runnable
prober (`scripts/verify-v3-venues.mjs`) asks each candidate to price a pair with a
known answer. This matters: the canonical QuoterV2 address also has bytecode on
Base, but does not price that chain's pairs. A codesize check would have
allowlisted the wrong contract.

**171 provider modules** and **731 operations** in the read/quote catalog, covering **221 unique
protocols/venues** across EVM, Solana, Bitcoin, and Canton (115 EVM + cross-chain, 98
Solana venues backed by 101 verified Jupiter program IDs, 6 Bitcoin surfaces).
One module can cover many protocols: the Jupiter module alone routes 98 Solana
venues, so provider-module count and protocol count are different numbers.

| Class | Providers |
|---|---|
| Chain / explorer | EVM JSON-RPC, Blockscout, Solana RPC, Bitcoin Esplora, Canton Scan (CC) |
| Market data | DexScreener, GeckoTerminal, DeFiLlama |
| DEX / aggregator | Uniswap V3/V4, Aerodrome, Curve, Balancer, LI.FI, ParaSwap, Odos, 0x, 1inch, HyperEVM DEXes |
| Solana | Jupiter (98 venue labels, 101 verified program IDs) |
| Intents | CoW Protocol, RFQ |
| Perps / lending / yield | GMX v2, Morpho, Pendle |
| Bridges | Across, Hop, Relay |
| Venues | Hyperliquid (core perps + HIP-3 builder dexs, including EntropyIO `io` + HIP-4 outcomes), Polymarket (read + local CLOB prepare) |
| NFT | OpenSea, Satflow, Magic Eden (Solana); additive owner-local P2 catalog; opt-in held-NFT pump alerts |
| Alerts | Opt-in, one-recipient monitoring for eligible OpenSea-held collection floors through Telegram, Discord, or WhatsApp |
| Bitcoin | mempool/Esplora, Ordinals, Runes, UniSat, Best-in-Slot, Satflow |

Every provider and every scanner capability declares an honest tier -
`read-only`, `quote-only`, `prepare`, or `intent`. **API coverage is not execution
support**, and the catalog says which is which. A chain with no verified venue is
fail-closed for routing value: read and research work, moving money does not. That
is a safe default, not a gap.

### Crypto threshold perp hedge analysis

`dataCall("prediction-hedge", "hedge", args)` and the data MCP tool
`prediction_hedge` calculate a read-only Hyperliquid hedge. The native feature
of the same name is available through an explicit operator tool-policy allowlist.
They never create orders, signing payloads, or preparation artifacts.
The provider's standard `health` op reports local capability only, with upstream
health explicitly `unknown`; use `hedge` to perform and validate market reads.

Required arguments: `asset` (main-perp crypto symbol such as BTC/ETH/SOL),
`strike` (>0 USD/coin), `direction` (`above`/`below`), future `expiryMs`, `side`
(`YES`/`NO`), and `entryPrice` strictly between 0 and 1 for the held side. Supply
exactly one of `contracts` (>0, each paying $1 when correct) or `usdNotional`
(>0 entry cost, converted to contracts by dividing by the held-side entry price).
Optional `impliedVol` is a positive annualized decimal: 0.6 means 60%.

The model is a Black-Scholes cash-or-nothing digital with zero interest/carry,
a 365-day year, and the Hyperliquid mark as a proxy for the resolution price:
`d2 = (ln(S/K) - sigma²*T/2)/(sigma*sqrt(T))`,
`delta = sign * phi(d2)/(S*sigma*sqrt(T))` per contract. Above YES and below NO
have positive exposure; the other sides have negative exposure. The opposing
perp size is `abs(contracts*delta)`, with a separate nearest-size rounded value
using venue `szDecimals`. The unrounded USD size and rounded USD size are both
shown; no leverage or margin recommendation is inferred from `maxLeverage`.

Without `impliedVol`, existing public `hl-info` readers request seven days of
hourly candles. The estimate is the sample standard deviation of closed hourly
log returns times `sqrt(365*24)`, requiring at least 24 consecutive returns and
a last close no older than two hours. This historical estimate is labelled `~`;
missing, stale, short, or zero-variance history leaves volatility and hedge
unknown and asks for an explicit positive volatility. Invalid candles fail.

The result contains `position`, `market`, `volatility`, `timeToExpiryYears`,
`deltaPerContract`, `positionDeltaCoin`, `hedge`, `funding`, and `scenarios` at
-5%, -2%, +2%, +5% of the caller's current mark. Numeric observations and derived
values use `{ value, source, asOf, estimate, label, reason? }`; `asOf` is fetched-at
milliseconds (caller inputs use the evaluation time), and derived estimates use
the oldest contributing observation. Unknown values are null with reasons.
`ok:true, empty:true` marks a healthy empty catalog, absent/delisted asset, or
empty candle history. Outages, non-2xx responses and malformed schemas throw.

Funding is signed cost on the rounded size: positive pays, negative receives.
Current hourly funding is multiplied by 8 or 24, using the oracle price when
present and an explicitly labelled mark proxy otherwise. See the official
[Hyperliquid funding convention](https://hyperliquid.gitbook.io/hyperliquid-docs/trading/funding).
These `~` estimates exclude unknown fees/slippage and future rate changes.
Delta changes with price and time; the sensitivity scenarios hold volatility
and time fixed. A local delta hedge does not guarantee the settlement payout.
All output is analysis only with `execution:"read-only"`, `actionMode:"alert_only"`.
No new environment variables or authenticated endpoints are introduced.

## Capability pack

Oracle's default pack is deliberately broad but disarmed:

- **Trader** - best-execution route comparison, quote/prepare, simulation, and
  receipt checks; no set-and-forget custody.
- **Builder** - chain-family fungible-token and NFT-collection launch plans,
  protocol, gacha, DEX, and launchpad scaffolds with unsigned deploy/admin actions.
  Unsupported chain adapters fail closed instead of pretending one deploy fits all.
- **Analyzer** - token, contract, venue, portfolio, market, and risk research with
  evidence labels. `/balance` or plain `balance` runs one deterministic snapshot
  across every configured EVM chain plus Solana, Bitcoin, Hyperliquid, and
  discoverable NFTs. Profile-local observations power history and SVG value graphs;
  unavailable values stay null instead of becoming fake zeroes.
- **On-chain scanner** - chain-config scanners for tokens, pools, launches,
  risk, exits, and smart-wallet boards.
- **Meme-token sniper** - fast launch/liquidity monitoring across configured
  chains, guarded by identity checks, sell-sim/reverse-route proof, caps, and
  unsigned user-wallet tickets.
- **Per-chain graphs + Telegram cards** - charted scanner alerts, route cards,
  meme-launch cards, Hyperliquid HIP-3/HIP-4 cards, and Polymarket cards. User
  API-key actions activate only when self-hosted keys are configured.
- **NFT mint gas-war limits** - public mint bots enforce chain-bound gas caps,
  per-unit fee caps, and optional priority-fee caps before returning unsigned
  mint transactions. Import `validateNftMintGasWar` from the package root or
  `@oracle-agent/oracle/nft-gas-war`.
- **Cross-chain RFQ + tokenized assets** - RFQ/intent venues are compared across
  supported chains where configured, and tokenized Robinhood-style assets can be
  bought only after exact contract, venue, route, and sellability checks.
- **Solana** - SPL accounts, Jupiter quotes, unsigned swap transactions, and
  simulation.
- **Bitcoin** - L1 reads, Ordinals/runes, Satflow PSBT intents, and inscription
  PSBT preparation.

Every money-moving path stays prepare/simulate first. Signing and broadcast are
wallet/grant actions, not model authority. Meme-token sniping defaults to fast
scan + prepared ticket; blind broadcast requires a separate capped local signer
loop and explicit opt-in. NFT mint bots must also honor gas-war caps before any
wallet-signable transaction is returned. RFQ and tokenized-asset routes are
capability-labeled per chain; unconfigured venues stay unavailable instead of faked.

## Research and bounded automation

Autopilot ships **DISARMED**. Autonomous intent submission requires
`ORACLE_AUTOPILOT_ENABLED=1` plus an owner grant with `mode: "autopilot"`,
passing guards, and a recorded decision. Otherwise eligible intents require
confirmation; failed guards can refuse them entirely. The engine prepares
unsigned intents for an injected submit function. Its grant does not authorize
the signer or replace the signer's sealed policy. See [autopilot](docs/autopilot.md).

The release adds these modules; a built engine is not a claim that every CLI,
MCP, or app surface is wired:

- **Learning and profiles** - grade journaled outcomes, graduate evidence-backed
  rules, and retain risk preferences, behavior tags, and custom instructions.
  [Learning](docs/learning.md) and [profiles](docs/profile.md) are context only,
  never grants or signing authority.
- **Strategy research and Teams** - factor and basket backtests, a limited Pine
  import, grid planning, trailing exit intents, cited scanner observations, and
  a bull/bear [roundtable](docs/teams.md). The local
  [strategy marketplace](docs/strategy-marketplace.md) verifies creator
  signatures and imports drafts; it does not collect fees or start strategies.
- **Portfolio mandates** - target weights, drift checks, and unsigned rebalance
  or de-risk proposals with a shadow window. [Eligibility is not authorization](docs/mandates.md).
- **Data and reports** - sentiment, Bitcoin-cycle, unlock, equity, macro, trader
  cohort, and options research modules; read-only [dashboard snapshots](docs/dashboards.md);
  XLSX, DOCX, HTML, and local-browser PDF export. Missing data stays unavailable.
- **Access and delivery** - five language catalogs, voice draft and spoken-reply
  components, outbound alert adapters, and [fiat on-ramp links](docs/onramp.md)
  to the user's address. Provider configuration and surface wiring still apply.
- **Local operation** - an encrypted [content-sync engine](docs/sync.md) that
  excludes keys and authority, opt-in computer use with approval on every call,
  and [Docker self-hosting](docs/docker.md) without a signer. The
  [Alpaca modules](docs/brokerage-alpaca.md) provide read-only stock and ETF
  market data. Brokerage execution is held for separate security review and is not in this release.
- **User-state checks** - caution and pause assessments with a second confirmation
  and optional cooling-off delay. Clearing a pause never authorizes a trade.
- **Strategy drafts, best of N** - `oracle strategy draft "<rule>" --attempts 3
  --bars bars.json` scores up to four deterministic parameter variants of one
  rule on a holdout and keeps every candidate in the output. `--pick` only
  returns the chosen draft. No provider spend; nothing is applied or armed.
- **Live track records** - `oracle track-record live` seals a per-strategy report
  labelled live: receipt-verified from saved receipt snapshots. It fetches,
  signs, prepares and publishes nothing. See [live track records](docs/track-record-live.md).
- **Answer review** - off by default. `"answerReview": true` in `model.json`
  appends one independent PASS or REVISE review to research and analysis answers
  in the native standalone client. Hosted processes skip it. See
  [answer review](docs/answer-review.md).
- **Tool scoping** - local native sessions advertise a small core of tools plus
  `tool_search` and `tool_describe`, which load other schemas on demand. Loading
  a schema grants no permission; signer, kill, approval and vault tools stay
  advertised. See [tool scoping](docs/tool-scoping.md).
- **Search filters** - `web_search` accepts `recency` (`day`, `week`, `month`,
  `year`) and `domains` (up to 20; `-example.com` denies). Oracle applies both to
  the returned results, and a search filtered to nothing fails with the counts.
  See [connectors](docs/connectors.md).
- **Skills as slash commands** - a skill whose frontmatter sets
  `user-invocable: true` runs as `/name [args]` in the TUI and on the owner
  gateway. It is an ordinary user turn: no frontmatter field widens the session's
  tools, and names of built-in commands are refused.
- **Skills catalog budget** - the skills list in the native prompt has a hard
  character budget (at most 8,192). `ORACLE_MAX_SKILLS_PROMPT_CHARS` can only
  lower it.

The [Minara-parity capability matrix](docs/minara-parity.md) links each
capability to repository evidence and records integration limits.

## Install

```bash
curl -fsSL https://oracle.demi.la/install.sh | bash
oracle setup model
oracle chat
```

Requires Node `20.19.0` or newer (the curl installer checks). npm still works:

```bash
npm i -g @oracle-agent/oracle
```

Desktop betas: https://oracle.demi.la/downloads/

Or from source, if you want to run the suite:

```bash
git clone https://github.com/demi-hl/oracle.git
cd oracle
npm install
npm test
```

**-> [SETUP.md](./SETUP.md) covers public data credentials and the separate
owner-local source lane.** The short version:

- Reads and quotes need **no keys**.
- Hosted/keyless Oracle exposes no cloud signer, key vault, or broadcast path.
- User wallets authorize prepared actions outside the public data plane, or the
  self-host local signer executes them under local policy.
- The npm package includes an optional self-hosted loopback signer for the user's
  own keys. It stays inert until local initialization and sealed policy setup.
  Private Administrator modules remain separate and are not published on npm.
- The documented `oracle signer` path permits built-in bounded native EVM
  transfers, recognized approvals, decoded EVM swaps and bridges, EVM NFT mint
  envelopes, Bitcoin PSBTs, and Solana messages under the user's encrypted local
  vault and sealed policy. `hl` and `poly` are not public local-signer families.

### Action vocabulary and execution planes

Oracle keeps capability and authorization separate:

- Public Oracle reads, quotes, simulates, and prepares artifacts. Self-host
  installs can execute supported artifacts through the local signer.
- **Path A:** owner/main, browser, smart-account, hardware, or protocol-native
  wallets sign the prepared artifact. This is the default self-custody path.
- **Path B:** the optional public local signer may sign on the same host after
  explicit init, sealed policy, and loopback start. Private Administrator
  modules remain unpublished and are not a holder install.
- The optional local signer decodes and binds bounded native EVM transfers,
  recognized approvals, strict EVM swap/bridge calldata, EVM NFT mint envelopes,
  Bitcoin PSBTs, and Solana messages. It refuses while required allowlists,
  local keys, RPC URLs, simulation, signed-byte verification, receipt binding,
  or ledger accounting are missing.
- Ordinary EVM preparation remains user-wallet signed unless a trusted
  owner-controlled direct-exec process is explicitly installed and armed.
- `ORACLE_AUTONOMOUS_TRADING=1` is direct execution for trusted owner-controlled
  local code only. It is never model/agent authority and should not be framed as
  equivalent to the `oracle-signer` agent-process path.
- `ORACLE_AUTONOMOUS_MINT=1` is a separate switch for fail-closed NFT mint
  one-shots only. It does not unlock swaps, bridges, or perps. Trading does not
  imply mint.
- `ORACLE_PINNED_SESSION_LIVE=1` cannot arm an on-chain session module. The
  merge fuse `PINNED_SESSION_MODULE_LIVE` stays off until every desk chain is
  pinned or explicit-unsupported and a privileged review issues GO. Default is
  off. Setting the env var alone is a refuse, not an enable. The optional
  session vault is per-user: they supply owner + recovery; Oracle prepares
  unsigned deploy/initialize; their wallet signs. No house recovery default.
  Native-only execute: user names EOA pay targets. Contracts and routers are refused.
  After they opt in, `prepareOptInVaultSpend` builds unsigned vault.execute (agent signs).
  Skip = Oracle unchanged. 7702 is not seed-theft protection.
- A deployment may separately install a same-host, owner-gated EVM executor.
  Oracle must verify that executor before describing bounded EVM execution as
  available. Missing deployment capability means "unavailable here," not
  "Oracle can never execute EVM."
- `watch`, `watch this`, and `ping me` always create `active: true, actionMode: alert_only`.
- `arm` creates `active: true, actionMode: execute` only for one exact owner-authorized action. It is never inferred from a watch.

The package exports this binding as `@oracle-agent/oracle/action-semantics`. Legacy watch stores can migrate `status: watching|armed` with `migrateLegacyWatchRecord()`; because it is specifically a watch-store migration, both statuses become `alert_only`, never execution authority.

Run the read-only data plane:

```bash
npm run start:data
npm run health
```

Run the public console (wallet connect, grant editor, receipts):

```bash
npm run start:public
# http://127.0.0.1:8799/
```

This is an unauthenticated loopback development server, not a holder gate or a
public deployment. Keep it off LAN/tailnet/public interfaces and place a tested
admission gateway in front of any hosted beta.

## Model providers

Oracle is a library. Drive it with Claude, GPT, Gemini, Grok, a local model, or
a plain script - the tools are ordinary functions plus an MCP server:

```bash
npx -y --package @oracle-agent/oracle oracle-data      # local read plane on 127.0.0.1:8787
npx -y --package @oracle-agent/oracle oracle-data-mcp  # MCP stdio server (any MCP client); needs oracle-data up
```

Per-profile routing is worth setting up under a multi-profile harness such as
[Hermes](https://hermes-agent.nousresearch.com/docs), because a trading stack is
several workloads with opposite needs and **per-profile routing** gives each its
own model, tools, and key scope: cheap wide context for research, a fast model
for execution where latency is money, the strongest model for risk review,
something small for unattended crons. The research profile can hold no signing
key at all. Oracle's native loop covers the single-agent case on its own.

Oracle's own pre-release audit ran four model lineages - Grok 4.5, Opus 5,
Fable 5, GPT-5.6 - and **each found a critical bug the others missed**. One
model reviewing its own work would have shipped three of them.


## Agent profiles

Oracle ships an installable 9-lane mesh for Hermes:

```bash
oracle-init            # dry run -- shows exactly what it would do
oracle-init --apply    # create profiles, install SOULs + skills, wire MCP config
npx -y --package @oracle-agent/oracle oracle-data  # keep running - MCP tools call the local read plane on :8787
oracle                 # premium boxed TTY on the same oracle profile as messaging
oracle model           # choose provider/model; persona stays oracle
oracle chain use hyperliquid
oracle setup menu      # legacy model / messaging menu; text status off-TTY
```

Terminal and configured messaging channels are untrusted proposers into the
same Hermes `oracle` profile. They cannot self-confirm or directly invoke the
optional signer. Signing stays in the user wallet or in the explicitly enabled,
loopback-only public local signer after independent local confirmation and
sealed-policy checks. Private Administrator execution remains separate.

Lanes: `oracle` (router), `polymarket-agent`, `hyperliquid-agent`,
`robinhood-agent`, `solana-agent`, `bitcoin-agent`, `canton-agent`, `near-agent`,
`stable-agent`,
`protocol-builder`, plus `_template` for your own. Details in
[`docs/profiles.md`](docs/profiles.md).

Every model lane remains unable to authorize signing. It may only read,
simulate, and prepare; local key initialization arms user-initiated actions,
while Disarm is globally dominant. An existing `SOUL.md` is never overwritten without
`--force`, and `--force` writes a timestamped backup first.

Oracle does not issue its own model credential. Standalone chat uses the OAuth
login or API key the user configured; a delegate harness uses whichever provider
that installation already supports.

**What you get where:** Oracle's read plane is an MCP server, so any MCP client
can call it, and the native loop brings its own memory, skills, scheduler, and
bounded tools. The multi-lane *mesh* in the diagram above - per-lane memory,
skills, sessions, and a separate model choice per specialist - is profile
machinery from a multi-profile harness such as Hermes. Use Oracle from any
agent, or on its own; add a profile mesh only if you want that topology.

## Teams

A team is a compiled, hash-pinned pipeline of specialist agents that turns public
evidence into an operator handoff. It never signs and never broadcasts.

```js
import { TEAM_TEMPLATES, compileTeamDefinition } from "@oracle-agent/oracle";

const compiled = compileTeamDefinition(TEAM_TEMPLATES[0], { nowMs: Date.now() });
compiled.team.agents.map((a) => a.role);
// scanner -> sentiment -> strategy -> risk -> executor
```

Seven templates ship in the box (`hyperliquid-alpha`, `perp-market-breadth`,
`perp-technical-strategy`, `basket-relative-value`, `wallet-watch`,
`evm-launch-radar`, `nft-mint-guard`) across six modes: `draft`, `shadow`,
`confirm`, `armed`, `autonomous`, `halted`.

The shape is enforced at compile time. A definition is refused if the executor is
not the terminal agent, if any non-executor holds executor tools, if the policy
omits wallet confirmation or a kill switch, if the chain allowlist is unbounded,
if the policy has already expired, or if `autonomous` is requested without an
explicit opt-in. Secret-like values and DAG cycles are rejected outright.

Compilation is deterministic: key insertion order does not change the `teamHash`,
so the same team is the same identity across machines. Every handoff reports
`executionAllowed: false`, `backendSigner: false`, `signingReady: false`, and
`broadcastReady: false`.

Teams are a library surface. They run in the **Oracle desktop app** - the CLI
stays a single-agent shell. Drive them from the desktop, your own harness, or a
service. Full reference in [`docs/teams.md`](docs/teams.md).

## Best-execution routing

The highest quote is not the cheapest swap. Oracle ranks on **net received after
gas and fees**, comparing every available source in parallel:

```bash
oracle-route swap   base 0x4200...0006 0x8335...2913   # WETH -> USDC
oracle-route bridge arbitrum base                       # ETH across chains
```

```
  source           net out           gross  cost
* paraswap    1,903.880867    1,903.893053  $0.01
  cow         1,903.693798    1,903.693798  gasless (solver)
  lifi        1,894.432632     1,899.20966  $4.78
```

Sources: **LI.FI, CoW, ParaSwap, 0x, 1inch** for swaps; **LI.FI, Relay, Across**
for bridges. 0x and 1inch activate when their API key is present; the rest need
none.

Why net matters:

- **Gas is part of the price.** A route quoting 0.2% more but costing $14 more in
  gas loses on a $500 swap and wins on a $50k one. The crossover depends on trade
  size, so any fixed preference is wrong on one side of it.
- **Intents can beat AMMs.** CoW's solver pays the gas, so a slightly lower gross
  quote often wins on net - the case naive ranking always gets backwards.
- **Sources disagree about what they mean.** Some report gas in USD, some in native
  wei, some not at all. Oracle normalizes, and marks what was measured.

**Unknown cost is never scored as zero.** A source that does not report gas is
ranked on gross and flagged, because scoring an unknown as free is how the worst
route wins a comparison. When the top two routes measure cost differently, Oracle
quotes **no spread at all** rather than a number that compares different things.

Then prepare the winner in one step:

```bash
oracle-route prepare base <tokenIn> <tokenOut> <yourWallet>
```

You get back an **unsigned transaction** (LI.FI, ParaSwap, 0x) or **EIP-712 typed
data** for an off-chain order (CoW). `artifactKind` says which - they need different
wallet actions, and one is not broadcast at all. Prepare **re-quotes** and reports
`driftBps` against the comparison, because a minimum computed from a stale quote is
not a minimum.

Bridges prepare too:

```bash
oracle-route prepare-bridge arbitrum base <yourWallet>
```

Bridge artifacts are always a **list** of transactions - some routes need an approval
and a deposit signed in order, and signing only the first leaves funds approved but
not bridged. Both chains are reported, and a transaction whose chain does not match
the origin is refused. Oracle states plainly that **bridging is not atomic**: the
origin transaction confirming does not mean funds arrived.

Routing never signs. `taker` must be the real wallet; placeholder addresses are
rejected, since quoting is anonymous but preparing is not. Signing happens in
the user's wallet or in a separately operated source-only execution lane.

Individual source failures degrade the comparison by one source instead of breaking
it - verified in practice when Odos sunset their public API mid-development
(HTTP 410); the router kept ranking and the provider was marked `unavailable`.

## On-chain equities - Crossbook (HIP-3 / Arcus / RH / Solana / TON)

Tokenized equities span multiple venues. Oracle ranks them the same way as swaps:
net of known costs, with unknown costs never scored as free.

```bash
oracle equities venues
oracle equities quote NVDA --size 1000
oracle equities quote SPY --size 500 --json
oracle equities prepare NVDA --recipient 0xYourWallet
# or: oracle-equities quote NVDA --size 1000
```

Import surface: `@oracle-agent/oracle/equities` (`bestEquityRoute`, `equityVenues`,
`prepareEquityRoute`). MCP tools: `equity_venues`, `equity_quote`, `equity_prepare`.

Only Robinhood-chain Uniswap is prepare-tier in v1. HIP-3, Arcus, Solana xStocks,
and TON ston.fi are quote-only discovery. `bestPreparable` is separate from the
overall winner so a quote-only mid is never presented as actionable.

## Examples

These run from a **repo clone**, not from the installed npm package: they import
`../src/` directly, and the published tarball ships the bundled `dist/` instead of
`src/`. Clone the repo, `npm install`, then:

```bash
node examples/add-a-chain.mjs             # register an unseen chain, no code
node examples/research-a-token.mjs        # honest token research on live data
node examples/oracle-pack-template.mjs    # skeleton for a safe Oracle protocol pack
```

## MCP

Oracle exposes its read plane over the Model Context Protocol, so any MCP client
(Hermes, Claude Code, others) can use it:

```bash
npx -y --package @oracle-agent/oracle oracle-data-mcp
```

## Security

- Hosted/keyless Oracle cannot hold keys. Self-host imports write only to the
  local encrypted vault.
- The router can propose, simulate, explain, and draft. It cannot authorize.
- Public default modules may not import house-signer or executor code
  (enforced by test). The optional `./local-signer` export is the self-host path.
- Destination allowlists are per-chain and fail-closed: an empty allowlist
  refuses everything rather than allowing everything.
- Report vulnerabilities per [SECURITY.md](SECURITY.md). Please do not open a
  public issue for a live exploit.

## What Oracle is not

- No unbounded trading authority. Autopilot is disarmed until explicitly enabled
  with an owner grant; unsigned intents still face independent signer checks.
- Not custodial. If a design needs your key on our server, that design is wrong.
- Not a guarantee. Crypto execution carries real risk; read the code you run.

## License

[Business Source License 1.1](LICENSE) - source-available, not open source.

You may read, modify, self-host, and use Oracle freely for internal use,
evaluation, research, and personal use. What you may not do is offer Oracle,
or substantially its functionality, to third parties as a competing product
or hosted service without a commercial license.

Each version converts to **Apache-2.0** on its Change Date (four years after
release). Versions `0.1.0` through `0.11.0` were published under Apache-2.0
and remain under those terms.

The **Oracle** name and marks are reserved; please don't imply endorsement by
an official deployment when shipping a fork.

For commercial licensing, contact the maintainer.

### Cross-venue prediction-market scan (alert only)

`prediction-xvenue` (`scan`, `health`) is exposed as the `prediction_xvenue`
MCP and native tool and through `dataCall("prediction-xvenue", "scan", args)`.
It reads Polymarket (Gamma markets plus CLOB books), Kalshi (`kalshiMarkets`
top of book) and Hyperliquid outcomes (`outcomeMeta` plus `l2Book`). Keyless; no
new environment variables.

Title similarity only proposes candidates. A pair is ranked only when every
match attribute is known on both sides and `matchPredictionEvents` matches
resolution source, outcome semantics, denomination, void rule and close window.
Other candidates are listed under `notComparable` with reasons and are never
priced. Ranked pairs buy YES on one venue and NO on the other at executable asks
for `sizeUsd` shares (one share pays 1 at resolution). Polymarket fees follow the
published `C x feeRate x p x (1 - p)` schedule; Kalshi and Hyperliquid outcome
fees are unknown until those providers expose a fee quote. An unknown fee makes
net edge unknown: the pair is labelled `cost unknown` and ranks below every
known-net pair. Every leg carries its source, fetched-at time and book age. A
failed venue is reported and marks the scan `partial` (a partial scan is never
marked empty); if fewer than two venues are healthy the scan fails. Output is `actionMode: "alert_only"`. Kalshi is US-regulated, and
Oracle never routes orders to any of these venues.

### Hyperliquid cohort analytics (bring your own key)

Set `HYPERTRACKER_API_TOKEN` in the self-hosted data-server environment to use
`hypertracker` through MCP or `dataCall("hypertracker", op, args)`. Source:
HyperTracker. The API origin is pinned to `ht-api.coinmarketman.com`.

Operations: `cohortPositioning` (requires `coin`), `cohortSummary`,
`cohortHistory` (requires `coin`, `segmentId`, UTC ISO `start`), `liquidationRisk`
(requires `segmentId`), `walletProfile` and `closedTrades` (require exact
`address`), `biggestPositions`, `freshness`, and `health`. Pages default to 25
rows and cap at 100; heatmap output is limited to one coin's 16 cohorts.
Closed-trade date parameters are `startTime`/`endTime`. The provider never reads
an owner's configured/default wallet. There are no fills or order-download
operations. Unsupported operation-specific filters are rejected before egress.
`coin` is required for positioning/history and optionally filters the returned
page for liquidation risk, closed trades and biggest positions; it is rejected
for summary/profile/status reads. `segmentId` optionally narrows positioning or
summary, is required for history/risk, and is rejected elsewhere. Cursor pages
are history/closed trades; offset pages are risk/biggest positions.

API usage is charged according to the user's paid plan. A completed read makes
one API request for `health`/`freshness`, two for `closedTrades`/`biggestPositions`,
and three for the other operations. These counts include a separate
`/hypertracker/state/status` read for every non-status operation and a
`/segments` read for positioning, summary, history, risk and profile. State
redirects can add an S3 download. Calls can stop early on errors or deadlines;
the provider does not estimate monetary cost or treat unknown cost as zero.

`cohortHistory`, `liquidationRisk`, `closedTrades` and `biggestPositions` have
only synthetic response fixtures and have **not been verified against the live
API**. Their offline tests prove normalization and refusal behavior for those
examples, not production response compatibility. See the
[fixture provenance and endpoint evidence](fixtures/hypertracker/README.md).
The `cohortSummary` path, `/state/summary`, matches the upstream
[API reference](https://github.com/Coin-Market-Man/hypertracker-skills/blob/main/SKILL.md#L175).
Live availability remains unverified because the original request log is
missing; a 404 conservatively says `route unverified`.

Results include `Source: HyperTracker`, the upstream timestamp and labelled age
at fetch, with `null` for unknown values. Rows without timestamps inherit a labelled response snapshot timestamp when
available, otherwise `state/status.lastUpdate` is labelled a state freshness proxy.
Auxiliary status/segment failures retain `status` and `retry_after` in `sourceErrors`.
Coin symbols preserve exact case, including the lowercase kilo prefix (`kPEPE`).
Main state updates about every 31 minutes; repeated metric rows are not evidence
of fresh positions. `stale` means the timestamp is over 35 minutes old, and is
`null` when its age is unknown. Size and PnL cohorts overlap: do not sum across
the two dimensions. Definitions and thresholds come from `/segments`.
Positioning and summary compare returned IDs with the requested cohort scope:
`coverage` and `omittedCohorts` disclose missing, invalid or unusable rows.
Incomplete definitions leave coverage unknown unless a missing cohort is known.

Missing credentials, empty/unusable responses and upstream errors return
`available:false` with a reason; missing credentials also return `configured:false`.
Invalid or incomplete wallet cohort membership stays `null`, including mixed
valid/invalid IDs. Biggest-position pages disclose unusable rows with
`omittedRows` and warnings, preserving each usable row's upstream rank.
Reads share one deadline below the desk's 15-second limit;
auxiliary timeouts retain primary data with explicit `sourceErrors`.
Unusable pages retain the normalized `request`,
`nextCursor` or `totalCount`/`offset`, snapshot age, and page-filter notes;
`pageStatus` distinguishes empty, malformed and no-usable-match pages.
State downloads allow one HTTPS S3 redirect: global/regional path-style or
virtual-hosted endpoints, legacy `s3-<region>` endpoints, and regional
`s3.dualstack.<region>` endpoints. Other AWS services remain refused. Downloads
carry only the fixed JSON Accept header and require public DNS addresses,
with no userinfo, nondefault port or fragment. Responses cap at 2 MiB.
The original capture notes report an approximately 1 MB unfiltered heatmap;
only a three-coin extract is stored here, so that is not a current size
measurement. The cap provides roughly twice that reported size. A larger
response returns `available:false` with `response exceeded the 2 MiB body limit`;
it is never truncated into a partial successful answer. Offline tests cover
valid bodies at 1 MiB and exactly 2 MiB, plus rejection above the cap.
Hosted processes and public API mode refuse this provider by default. An operator may explicitly
set `ORACLE_HYPERTRACKER_HOSTED_ENABLED=1` after deciding whether their data
license permits redistribution; caller arguments cannot enable it. Existing
public-mode server-key allowlists still apply. Self-hosted/CLI/MCP use with the
user's own key is the supported mode. The keyless `smart_money` tool retains its
existing leaderboard-sample semantics.
The `public-app` tool surface is gated too. `ORACLE_PUBLIC_DESKTOP` alone is
not a hosted signal: the owner's local `owner-desk` runtime also sets it.

### Trading leak report

`oracle leak-report <Hyperliquid-address>` estimates oversized-loser, revenge, fee-churn, and funding-bleed costs from public history. Read-only; partial history and unknown totals are explicit. See [Leak Report](docs/leak-report.md).

## TxFlow and RISEx native perp data

`provider: "txflow"` supports `health`, `markets`, `fundingSnapshot`, `book`
and `fees`; `provider: "risex"` supports `health`, `markets`,
`fundingSnapshot`, `book` and `fundingHistory`. Both are keyless public reads
through `dataCall`, desk `/data/call` and the `txflow` / `risex` data MCP
tools. Requests go only to the fixed origins `https://rpc.txflow.com/info`
(POST, `x-api-version: 2026-08-16`) and `https://api.rise.trade` (GET), with
no retries or redirects, a 2 MiB body limit, a 10-second default timeout and a
maximum 15-second timeout. No orders, signing, account reads or referral
codes.

`fundingSnapshot` takes `coins` (1 to 20); `book` takes `coin` and `depth`
(1 to 20); RISEx `fundingHistory` takes `market`, `limit` (1 to 1000) and
`pages` (1 to 5). Every coin must be in the reviewed TxFlow/RISEx mapping
(`src/strategy/xvenue-coin-map.mjs`). Each row pins the TxFlow instrument
index and RISEx market id, and the venue metadata (name, base, quote) is
re-checked on every call. A coin that is unmapped or whose metadata drifted
is excluded. Coins are never matched by ticker alone. Equities, ETFs and
commodities listed on both venues are excluded until reviewed.

Funding is reported raw and normalized to decimal per hour. TxFlow publishes
percent per settlement interval (`activeAssetCtx` `nodeCtx.funding`,
`marketTicker` `fundingRate`; `0.01` means 0.01%), scaled by
`settlementIntervalMs`. RISEx `current_funding_rate` is a decimal per
`funding_interval` nanoseconds; its `funding_rate_8h` is documented as eight
times that rate. Empty or malformed values stay null, never zero. TxFlow has no
public market funding history, and none is synthesized. TxFlow `markets` lists
every tradable instrument but fetches tickers (one request each) only for
mapped instruments, so it stays within the 50 requests/second `/info` limit.
Other rows are unavailable with funding null.

Source time comes from TxFlow `blockTime`/`time` (ms) and RISEx `cached_at`
(observed as seconds). Rows are labelled stale after 120 s (TxFlow) or 600 s
(RISEx markets, cached up to 5 minutes); these thresholds are Oracle policy,
not a venue SLA. The RISEx order book carries no timestamp, so its time and
staleness are null. `fetchedAt` is the time Oracle made the request, not the
source time.

`ORACLE_TXFLOW_HOSTED_ENABLED` and `ORACLE_RISEX_HOSTED_ENABLED` default off.
The six hosted/public flags and `ORACLE_TOOL_SURFACE=public-app` refuse these
providers unless the process owner sets the matching opt-in to `1`. Caller
options can restrict this but cannot unlock it.

`computeFundingGaps` in `src/strategy/xvenue-funding.mjs` is a pure analysis
over these envelopes. It picks the short leg (the higher funding rate) and the
long leg, and reports the gross spread per hour and as APR (x24x365). It also
estimates the round-trip cost: walked top-of-book depth for the notional plus
four taker fills, using TxFlow `feeTierRates` and the cited RISEx Tier 1 doc
schedule. It then reports break-even hold hours and liquidity flags. A coin
with any unknown or stale input is excluded with reasons and never ranked. It
has no execution or turnover logic. Index parity between the venues is
unverified for every coin, so each ranked row carries `indexParity` (verdict,
sample count, window) and `actionable`. `actionable` is true only for a coin
the owner accepted with a per-coin evidence stamp (`acceptParity`), which is
the same gate the txrx paper engine applies to entries. Rows with `actionable`
false are research output, not a trade signal.

References: docs.txflow.com `/api/info/perpMeta.md`, `/api/info/marketTicker.md`,
`/api/info/activeAssetCtx.md`, `/api/info/l2Book.md`,
`/api/info/feeTierRates.md`, `/trade/funding.md`, `/api/rate-limits.md`;
developer.rise.trade `/reference/marketservice_getmarkets.md`,
`/reference/getorderbooklevels.md`, `/reference/getfundingratehistory.md`,
`/reference/apiservice_getsystemconfig.md`,
`/reference/general-information.md`; RISEx fees at
docs.risechain.com `/docs/risex/trading/fees.mdx`. Verified against the live
APIs on 2026-10-23.

## Hypedexer native REST data

`provider: "hypedexer"` supports `health`, `hip3Dexs`, and `recentLiquidations`
through `dataCall`, desk `/data/call`, and the `hypedexer` data MCP tool.
All three accept an empty argument object only. Set `HYPEDEXER_API_KEY` in the
self-hosted data-server environment; it is sent as `X-API-Key` to the fixed
`https://api.hypedexer.com` origin. `HYPEDEXER_MCP_KEY` and the hosted Hypedexer
MCP are separate and are not used by this adapter.

Local desk `/data/call` Hypedexer and HyperTracker operations are key-backed
reads that spend the owner's configured key quota. Any local process that can
reach the loopback desk can call them without `x-oracle-local-control-token`,
even when that token is configured. Cross-origin browser requests, cross-site
fetch metadata and DNS-rebinding Hosts are refused. Hosted/public restrictions
still apply; this local token exemption does not enable hosted key use.

`health` and `hip3Dexs` GET `/hip3/dexs`; `recentLiquidations` GETs
`/liquidations/recent`. Each call makes one GET with no retries or redirects,
a 2 MiB body limit, a 10-second default timeout, and a maximum 15-second timeout.
Responses above 10,000 rows are unavailable. The key must be 4–8192 printable
ASCII characters (no spaces, commas, or reserved selector words such as `none`,
`true`, `default`, or `mainnet`). Each `health`, including `oracle data health`,
spends one authenticated request from your quota. Rows are retained under
`items[].data`; no financial field normalization is claimed. Oversized or
malformed responses are unavailable rather than silently truncated.
`pagination.complete` is null; this recent window has no verified continuation
contract. No limit, filter, cursor, URL or path arguments are accepted.

Only integer `time_ms` supplies a row source timestamp. A timezone-less `time`
is preserved as upstream data but not interpreted. Response source time and
feed staleness remain unknown (null), even when an event time is available.
`fetchedAt` is request observation time, not source freshness. Missing keys
return unavailable, never an empty market or zero value.

`ORACLE_HYPEDEXER_HOSTED_ENABLED` defaults off. The same six hosted/public
flags and `ORACLE_TOOL_SURFACE=public-app` used by HyperTracker refuse use of
the host key unless the process owner explicitly sets this opt-in to `1`.
Caller arguments/options cannot enable it. An injected `opts.env` hosted flag
also restricts access without changing `process.env` or supplying credentials. Enabling it shares the host's
REST quota with that plane; leave it off on shared/public deployments.

The official [DEX list](https://docs.hypedexer.com/api-reference/hip-3/list-dexs)
and [recent liquidations](https://docs.hypedexer.com/api-reference/liquidations/recent-liquidations)
references document these routes. Routes follow the official API reference;
`health`, `hip3Dexs`, and `recentLiquidations` were verified against the live API
on 2026-10-23. No additional operations or pagination/freshness guarantees are
exposed here.
