Guides

Agent Integration

Wire Philidor risk checks into your AI agent workflow for pre-trade screening, portfolio monitoring, and automated alerts.

AI agents making DeFi decisions should check risk before executing. Philidor provides the data layer for risk-aware autonomous agents.

Architecture

User Request → AI Agent → Philidor MCP/API → Risk Data → Decision

The agent receives a request (e.g., "deposit USDC into highest-yield vault"), queries Philidor for risk scores, and makes an informed decision rather than optimizing purely for yield.

MCP Integration (Preferred)

The fastest path is connecting your agent to the MCP server:

claude mcp add philidor --transport http https://mcp.philidor.io/api/mcp

The agent automatically gets access to 14 tools, 3 resources, and 4 prompts. Copy-paste protocol and chain workflows (including Aave V4 looping) are on MCP Examples. For a loop, prefer check_loop_venue before any protocol MCP preview_action.

Example Agent Workflow

  1. User: "Find USDC vaults ranked by net APY"
  2. Agent calls search_vaults with asset=USDC, sortBy=apr_net, sortOrder=desc
  3. Agent calls get_vault_risk_breakdown for the top-ranked result
  4. Agent checks if risk tier is acceptable (Prime or Core)
  5. Agent surfaces the vault with its risk context

REST API Integration

For agents that don't support MCP, use the REST API directly:

async function checkVaultRisk(network: string, address: string) {
  const res = await fetch(`https://api.philidor.io/v1/vault/${network}/${address}`);
  const { data } = await res.json();
  const vault = data.vault;

  return {
    score: Number(vault.total_score),
    tier: vault.risk_tier,
    isAudited: vault.is_audited,
    // deposit_status is the canonical tri-state signal - read this, not the
    // boolean. 'open' = confirmed accepting deposits, 'closed' = maxDeposit
    // is zero on chain, 'unknown' = not yet probed (typically non-ERC4626).
    depositStatus: vault.deposit_status as 'open' | 'closed' | 'unknown',
    capacityUsd: vault.deposit_capacity_usd, // null = no cap observed (uncapped, unpriced or unread)
    isSafe:
      Number(vault.total_score) >= 8.0 && vault.is_audited && vault.deposit_status !== 'closed',
  };
}

// Agent decision logic
const risk = await checkVaultRisk('ethereum', '0x8eB67...');
if (risk.depositStatus === 'closed') {
  return 'This vault is currently rejecting new deposits on-chain (caps reached, paused, or queue saturated). Pick a different vault.';
}
if (risk.depositStatus === 'unknown') {
  // Optional: do a pre-flight maxDeposit call from the user's wallet here
  // before composing the deposit tx, to avoid the rare revert path.
}
if (!risk.isSafe) {
  return "This vault doesn't meet the minimum safety threshold (Prime tier, audited).";
}

Pre-trade screening at the list level

When routing capital across many vaults - picking the best USDC vault, for example - exclude confirmed-closed vaults at the server with ?depositable=true, then apply your strictness policy on the response:

const res = await fetch(
  'https://api.philidor.io/v1/vaults?asset=USDC&depositable=true&sortBy=apr_net&sortOrder=desc&limit=20'
);
const { data: candidates } = await res.json();

// Server-side `depositable=true` drops `closed` but keeps `unknown`. Conservative
// routers should additionally require deposit_status === 'open' here.
const safe = candidates.filter((v) => v.deposit_status === 'open');

// Size each candidate against its remaining cap. A null headroom is NOT
// "unlimited": it means no cap was observed (uncapped, unpriced, or unread),
// so pre-flight the amount on-chain (maxDeposit / a simulated supply) before
// committing size.
for (const v of safe) {
  const headroom = v.deposit_capacity_usd; // number | null
  if (headroom != null && headroom < myDepositSize) continue;
  if (headroom == null && !(await preflightDeposit(v, myDepositSize))) continue;
  // ...
}

This is the single most common foot-gun for yield-seeking agents: a vault can show 20%+ APY but have maxDeposit == 0 at the contract level - the yield is residual interest on the existing position and new principal cannot enter.

Risk Guardrails

Agents should enforce risk guardrails before executing DeFi operations:

GuardrailCheckThreshold
Accepts depositsdeposit_statusMust be "open" (strict) or not "closed"
Withdrawals workwithdraw_statusMust be "open" for symmetric round-trip routing
Data is freshfreshness_seconds< 3600 (or your tolerance) - never route on stale state
Minimum risk tierrisk_tierPrime or Core
Audit requirementis_auditedMust be true
Minimum TVLtvl_usdAbove your minimum liquidity threshold
Capacity availabledeposit_capacity_usd≥ planned size; null = no cap observed, pre-flight first
Oracle qualityAsset vector score>= 7
No recent incidentsCheck events endpointNo incidents in 90 days
No recent state flapping/v1/vault/{network}/{address}/eventsSanity-check the last 24h before routing large size

Portfolio-Level Checks

Before adding a new position, check portfolio concentration:

const positions = await fetch(`https://api.philidor.io/v1/address/${wallet}/positions`);
const { data } = await positions.json();

// Check if adding this vault would exceed protocol concentration
const protocolExposure = data.positions
  .filter((p) => p.protocol_name === newVault.protocol_name)
  .reduce((sum, p) => sum + parseFloat(p.balance_usd), 0);

const totalValue = Number(data.aggregates.total_value_usd) + depositAmount;
const concentration = (protocolExposure + depositAmount) / totalValue;

if (concentration > 0.5) {
  return 'Adding this position would exceed 50% concentration in one protocol.';
}

CLI For Agents

The CLI supports structured output for agent workflows.

philidor vaults --asset USDC --risk-tier prime --json
philidor screen conservative --json
philidor schema vault --json

Use --enable-commands to run the CLI in sandbox mode with an explicit comma-separated allowlist.

philidor --enable-commands stats,vaults,search stats

The packaged OpenClaw skill wraps the CLI for agent runtimes that use skill files.

Signals And Alerts

The public /v1/signals feed exposes published risk signals from The Wire. Use it alongside events for market and protocol monitoring.

Webhook delivery exists for basket subscriptions on eligible plans. Risk Graph simulation and personalized agent policy surfaces remain roadmap items.

Persisting Agent Configuration Per Wallet

GET and PUT /v1/users/{address}/agents store an agent roster and its configuration for a wallet without an account: the wallet proves ownership by signing a message (EIP-191 personal_sign). No API key is needed.

  1. Ask the API for the message to sign. For a PUT, pass the hash of the body you are about to send so the signature covers it:
# bodySha256 = SHA-256 (hex) of the canonical JSON of the payload as sent:
# an object with only those of agents, linkWaypoints, mainWalletName,
# mainWalletPosition that your body carries, keys sorted recursively.
curl "https://api.philidor.io/v1/users/0xabc.../agents/auth-message?method=PUT&bodySha256=<hash>"
{
  "message": "Philidor agents\nPUT /v1/users/0xabc.../agents\nTimestamp: 1789200000\nNonce: 7f3c...\nBody-SHA256: 9b1e..."
}
  1. Sign the message exactly as returned, with the wallet.
  2. Send it. GET takes the message (base64) and signature in x-philidor-agents-message and x-philidor-agents-signature; PUT takes message and signature in the JSON body beside the payload.

The message is valid for five minutes and its nonce for one use: a second request with the same signed message answers 401, as does a PUT whose body differs from the hash that was signed. Each request therefore starts with a fresh auth-message call; the response is Cache-Control: no-store for that reason.

A message built without the nonce and body hash (the original three-line format) is still accepted today so existing integrations keep working; it is logged on the server, and it will stop being accepted once every caller has moved to the issued message. Build the message from auth-message now and nothing changes for you at that point.

On this page

Raw