Check a target before you install, connect, pay or trade
onchain_agent_preflightUSE WHEN you are about to install a package, clone a repo, connect to an MCP endpoint, pay an agent, or trade a token, and you want to know what is on record about it FIRST — every evidence line, with the field it was read from and its date. Pass exactly one of repo, package, endpoint, agent, token, skill, x402 or address; with none (or a template placeholder) nothing is checked and the answer is { needs_input: true, accepted_forms, example_calls }.
NOT FOR a stack pick's summary (onchain_agent_recommend_stack and onchain_agent_get_deploy_spec already carry a records-only preflight_summary), whether an install command or MCP config takes your key (use onchain_agent_check_install instead), or a recipient-address reading on its own (use onchain_agent_scan_recipient). Call this for the full evidence, for any target that is not a pick (a repo, package, token, skill or ERC-8004 agent you were handed), or for a live handshake with an unlisted MCP endpoint.
RETURNS a verdict — go | caution | no | unknown — with one evidence line per check, each naming the field it was read from and when that field was written. The rules are written down in lib/preflight.ts and cited by id in rule.
RULE ENFORCED: a verdict names WHAT WAS CHECKED AND WHEN. It is never a security review, a quality judgment or a statement about returns, and unknown means Sato Hub holds no record — not that something is wrong. An unlisted endpoint gets ONE live handshake (initialize + tools/list, 8 s cap) and can never come back go: a handshake is not a record. For agent=: we confirm the ERC-8004 registration exists, fetch its registration file, and report the services it DECLARES; only a declared MCP service is probed.
TOKEN LANE (token + chain; the EVM chains listed, and Solana): keyless chain reads. EVM: bytecode presence and size, the ERC-20 views, the Clanker v4 factory's OWN deployment record, and the Uniswap v3 factory across the four standard fee tiers against wrapped native. Solana (token = the mint): token program (SPL or Token-2022), decimals, supply, mint and freeze authority (revoked is a known fact, distinct from unread), Token-2022 extensions (PermanentDelegate, TransferHook, transfer fee, NonTransferable), the ten largest token accounts as a share of supply, and pump.fun bonding-curve state. A PermanentDelegate, TransferHook or transfer fee is a caution; a NonTransferable mint is a no; there is no go for Solana. Every field is nullable and a null carries its reason. Holder concentration on EVM and Uniswap v4 pools are permanently null and said so. A pool existing is not depth. Nothing in this lane says safe, audited, rug or scam: those are not readings.
SKILL LANE (skill): a skill is a DOCUMENT an agent follows, which is why it is worth checking first. Evidence is the static disclosure the weekly sweep produced: hosts the text names, whether it generates or handles keys, asks for a credential, pipes a remote script into a shell or grants itself tools, each finding WITH the lines that produced it. Nothing is fetched from a registry and no skill is executed. A DISCLOSURE DESCRIBES: it never says safe or malicious, and an empty flag list is "nothing matched", not a pass.
RETURNS (json): { verdict, rule, target: { kind, value, slug, name, sato_url, verify_url }, evidence: [{ check, result, source_field, checked_at }], checked_at, caveat, rules, token?, skill?, solana_receipt? }. token and skill are the raw reports for those lanes; solana_receipt (present with a custody reading) is where that reading is recorded on Solana, or null. Read-only.
X402 LANE (x402): one unpaid request to the resource URL; reports whether it answered 402 and the payment terms it states (network, asset, amount, payTo), against its catalogue entry and our daily record when we hold one. It describes the payee — it is never a reputation score. CUSTODY: repo, package, endpoint and skill results carry custody (Sato Check: does it take your key, does the key leave, can it move funds, what changed) when a profile is on record; custody can only lower a verdict, never raise it.
ADDRESS LANE (address + chain, optional origin and from): the Sato Scan recipient check before a payment, five dated questions (look-alike, issuer's token contract, declared payee, structural mark, address poisoning), rules A1-A7. go is declared, canonical and nothing found within the stated limits, never a clearance. Nothing is stored. The reading on its own: onchain_agent_scan_recipient.
Example: { repo: "coinbase/agentkit" } · { endpoint: "https://mcp.example.com/v1" } · { x402: "https://api.example.com/paid" } · { agent: "base:42" } · { token: "0x1bc0c42215582d5A085795f4baDbaC3ff36d1Bcb", chain: "Base" } · { skill: "clawhub/solana-wallet" } · { address: "0x1bc0c42215582d5A085795f4baDbaC3ff36d1Bcb", chain: "Base" }
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | With `address`: the paying wallet. Lets the reading compare against its own history and say whether it is being targeted by address poisoning. Never stored. | |
| repo | No | A GitHub repository: a URL or bare owner/name, e.g. 'coinbase/agentkit'. | |
| x402 | No | An https x402 resource URL. ONE unpaid request reads its 402 payment terms (v1 body or v2 PAYMENT-REQUIRED header); no payment is ever sent or signed. | |
| agent | No | An ERC-8004 agent reference, <chain>:<id>, e.g. 'base:42'. Chains: Ethereum, Base, Arbitrum, Optimism, Polygon, BNB Chain, Avalanche, Gnosis, Robinhood Chain, Celo. | |
| chain | No | Chain for `token`: Base, Ethereum, Arbitrum, Robinhood Chain, BNB Chain, Polygon, Solana. Anything else answers 'unknown' with the reason, never a guess. For `address` it is the chain the payment would settle on: Base, Solana, Tempo, Polygon, BNB Chain, Arbitrum, Avalanche, Optimism, Ethereum, SKALE Base, Sei, X Layer, Monad, Robinhood Chain, World Chain, Abstract. | |
| skill | No | An agent skill: '<registry>/<id>' (registries: clawhub, skillssh, skills.sh, skills-sh, github), or the skill id alone when it is unique. Reads the static disclosure already on record — nothing is fetched from a registry and no skill is ever executed. | |
| token | No | An ERC-20 token contract address, e.g. '0x1bc0c42215582d5A085795f4baDbaC3ff36d1Bcb', or with chain Solana a mint (base58). Needs `chain`. | |
| origin | No | With `address`: the https URL whose 402 response named the address (a public host; no credentials). Lets the reading say whether that origin declared it. Never stored. | |
| address | No | A recipient address the caller is about to pay (Sato Scan): 0x + 40 hex on an EVM chain, or a Solana address. Needs `chain`. Never stored. | |
| package | No | An npm or PyPI package name, e.g. 'solana-agent-kit'. A trailing @version is ignored. | |
| endpoint | No | An https MCP endpoint URL. If it is not in the directory it gets a live initialize + tools/list handshake, capped at 8 seconds. | |
| x402_method | No | With x402: the method the paid request uses; the unpaid probe uses the same one (a body method sends an empty JSON body, never yours). Default: GET, then POST on a 405. | |
| response_format | No | Text format; structuredContent is JSON either way. | markdown |