Host capabilities (capability broker)

A skill can use host capabilities — web search, market prices, Robinhood Chain data, GitHub data, AI completions — without holding a key or opening a socket. It declares them in its manifest and calls them through the capability broker; the Splice host runs each call with its own provider configuration and hands back the result.

"permissions": {
  "fs": { "read": [], "write": [] },
  "network": [],
  "env": [],
  "capabilities": ["web.search", "market.price"]
}
// tools/research.ts
export default async function research(input: { query: string }, ctx) {
  const results = await ctx.capability("web.search", { query: input.query, limit: 5 });
  const eth = await ctx.capability("market.price", { token: "ETH" });
  return { results, eth };
}

How a call flows

tool (sandbox: no network, empty env)
  └─ ctx.capability(name, args) ── IPC ──► Splice host (SpliceRuntime)
                                             ├─ declared in permissions.capabilities?   else PERMISSION_DENIED
                                             ├─ call budget (25 / execution), ≤ 4 concurrent, args ≤ 256 KiB / 32 levels
                                             └─ broker (@spliceloom/data) ── validated args ──► data layer ──► real providers
  ◄──────────── result (LIVE / CACHED / UNAVAILABLE / ERROR with provenance, ≤ 4 MiB) ──────────────┘
  • The check happens in the host process, not only in the tool: a package that writes to the IPC channel directly is refused the same way (tested).
  • The host's provider keys are read only by the host (provider environment variables, .env.local / .env). The tool process keeps its empty environment and its network guard; a capability never widens network, env or fs.
  • Arguments are validated against a strict schema per capability (additionalProperties: false) before any provider is contacted. Skills cannot bypass the cache or change AI fallback routing; ai.generate output is capped at 2,048 tokens (default 512) per call.
  • Results are the data layer's own objects (see data-providers.md): never an invented value. Without a broker (e.g. a custom runtime) calls answer CAPABILITY_UNAVAILABLE.

Capabilities are permissions: splice info lists them (billed ones are marked "may spend provider credits/money"), splice add refuses them without --accept-permissions, and the grant is stored in splice.lock. An installed package whose manifest later requests a capability that was not granted is refused at load (PERMISSIONS_NOT_GRANTED). The capabilities key is omitted when empty, so manifests, registry metadata and lockfiles of earlier packages are unchanged. MCP clients see tools with capabilities as openWorldHint: true.

Capabilities

CapabilityArgumentsData layer call
onchain.balanceaddressnative balance on Robinhood Chain (block-pinned)
onchain.transactionhashtransaction + receipt
onchain.blockblock? (latest, number, hash)block
onchain.tokenaddresstoken composite (metadata, supply, holders, price, pools, security)
onchain.contractaddresscontract composite
onchain.transfersaddress, limit?token transfers
onchain.logsaddress?, fromBlock?, toBlock?, topics?event logs
market.pricetoken (ETH or address), network?, vs?CoinGecko / GeckoTerminal price
market.token, market.pairs, market.pairnetwork, addressDexScreener / GeckoTerminal
market.ohlcvnetwork, pool, timeframe?, aggregate?, limit?GeckoTerminal candles
market.tradesnetwork, poolGeckoTerminal trades
market.searchqueryDexScreener search
security.token, security.addressaddressGoPlus
wallet.portfolioaddressZerion
web.searchquery, limit?, content?, maxCharacters?, includeDomains?, excludeDomains?Tavily → Exa → Firecrawl
web.extracturls (1–10), maxCharacters?Tavily → Firecrawl → Exa
web.map, web.similarurl, limit?Firecrawl/Tavily, Exa
web.answerqueryTavily → Exa (with citations)
github.repositoryrepoGitHub REST
github.searchquery, page?, perPage?repository search
github.contentsrepo, path?, ref?contents API
github.commitsrepo, ref?, path?, page?, perPage?commits
github.releasesrepo, release?, page?, perPage?releases / one release
github.rawurl, maxBytes?raw.githubusercontent.com
ai.generateprompt, system?, model?, provider?, maxTokens? (≤ 2048), temperature?, responseSchema?OpenRouter / Gemini
ai.modelsprovider?, search?model list
tokens.rankkind (trending, hot, new, gainers, losers, volume, holders, mcap, txns, buyers), window?, minLiquidity?, limit?Codex
tokens.searchquery, limit?Codex
tokens.detailstoken (symbol or address)Codex (composite)
tokens.whalestoken, minUsd?Codex
tokens.reporttokenCodex + GoPlus + Blockscout (report with flags)
stock.quotesymbol, session?Robinhood, Chainlink, DEX, Codex, DefiLlama, Finnhub (composite)
stock.listsearch?Robinhood / CoinGecko
perps.marketsvenue?, type?, sort?, search?, limit?Lighter
perps.fundingvenue?, search?, limit?Lighter
defi.overview, defi.protocols, defi.yieldssee the SDK (splice.defi)DefiLlama
global.overview—CoinGecko, alternative.me, Chainlink (composite)
macro.overview—FRED
equity.profile, equity.newssymbol, days?Finnhub

Composite results (one section per source) reach skills with an overall status: LIVE when at least one section is live, otherwise UNAVAILABLE.

Billed per call: ai.generate and every web.* capability.

Official broker skills

PackageToolsCapabilities
@splice/webweb.search, web.read, web.answerweb.search, web.extract, web.answer
@splice/marketmarket.price, market.pairs, market.candlesmarket.price, market.pairs, market.ohlcv
@splice/onchainonchain.balance, onchain.transaction, onchain.tokenonchain.balance, onchain.transaction, onchain.token
@splice/robinhoodrobinhood.trending, .rank, .token, .report, .whales, .stock, .perps, .funding, .defi, .marketstokens.rank, tokens.details, tokens.report, tokens.whales, stock.quote, perps.markets, perps.funding, defi.overview, global.overview

Sources: skills/web, skills/market, skills/onchain, skills/robinhood (0.1.0).

SDK

new Splice() attaches the data-layer broker automatically (created on first use). Pass broker: false to disable it, or your own CapabilityBroker ({ call({ package, tool, capability, args }) }) to serve capabilities differently. createCapabilityBroker(data) from @spliceloom/data builds the default one.