Sato Hub
Methodology

How Preflight decides

Every rule a verdict can cite, and what each verdict is not.

  • Rules40
  • Lanes6
How to read the rulesShowHide

First match wins within a lane. Each rule names what it reads, and every verdict Preflight returns cites the rule that decided it. This page is rendered from the same table the verdict functions decide from, so it cannot drift away from the code it describes.

A verdict is a description of evidence

A Preflight verdict names what was checked and when, from Sato Hub's own records and probes. It is not a security review, a quality judgment, or a statement about returns. Unknown means we hold no record — not that anything is wrong.

What each verdict is — and what it is not

go

Active, scored High, and at least one check we ran ourselves came back.

Not an endorsement, not a security review, not an audit, and not a statement that the thing will work for you. It describes readings, on a date.

caution

We hold a record, and it does not meet all of R5 at once.

Not an allegation and not a warning about conduct. Most listings sit here, including good ones that are simply young or thinly documented.

no

Something we read came back negative: retired, did not answer, unregistered, mostly failing, or nothing token-shaped at the address.

Not a claim about intent, honesty or risk. It names the reading that failed and nothing beyond it.

unknown

We hold no record, or too few readings completed.

Not a negative verdict. Unknown never becomes no — absence of a record is absence of a record.

Unknown never becomes no

Unknown never becomes no. A reading we could not take, a chain we do not cover, a listing we have never seen — each of these produces `unknown`, and `unknown` is never silently downgraded into a negative verdict. A null is unknown, never zero.

The rules for a repository, package, endpoint or agent

Applied in order to whatever resolved: a directory listing, a live probe, an on-chain registration, or nothing at all.

  1. R1noThe listing is retired.

    A listing carries status "Deprecated" after a sweep found no public activity across website, repository and social over 90 days. A retirement is an observation about silence, not a judgment about the project or the people who built it.

    reads: resources.status

  2. R2noA probed endpoint did not answer, or a claimed ERC-8004 id is not registered.

    The endpoint was asked for an MCP handshake and did not complete one, or the identity registry holds no record for the agent id given (ownerOf reverted). Both are readings taken at checked_at: an endpoint that answers an hour later was still not answering when we asked. A registry read that did not complete is not this rule — see R4.

    reads: probe.ok · registration.registered

  3. R3noOur own daily checks mostly failed, and the failures were attributed to the host, over at least 14 days.

    Below 50% success across at least 14 days observed, with at least one day attributed to the host rather than to us. This is the share of OUR checks that succeeded — never uptime. A failure we could not attribute never lands here.

    reads: resources.uptime_observed.rate_days · resources.uptime_observed.success_rate_pct · resources.uptime_observed.attributed_down_days

  4. R4unknownNothing resolved and nothing was probed — we hold no record of this target.

    Unknown is a real answer and the honest one. It says Sato Hub has no record, not that anything is wrong with the target. An unknown never hardens into a no. An ERC-8004 registry read that did not complete (RPC error or timeout), with no stored per-agent check and nothing probed, lands here too: our outage is not the agent's failure.

    reads: resources.slug · registration.registry_read · erc8004_agents

  5. R5goActive, scored in tier High, and carrying at least one earned check.

    All three at once. An earned check is one of: the documented install re-run in an isolated container; a successful daily check within 14 days; or at least 95% success across our own checks over at least 14 days. A provisional score never promotes.

    reads: resources.last_commit_at · resources.last_release_at · resources.trust_score · resources.trust_tier · resources.trust_provisional · resources.deploy_spec.deploy_status · resources.live_check · resources.uptime_observed

  6. R6cautionEverything else that resolved or probed.

    The default once we hold a record. Caution is not an accusation — it is the absence of the three things R5 wants at once. A live handshake against an unlisted endpoint also lands here: a handshake is not a record.

    reads: resources.slug · probe.ok · registration.registered

The rules for an agent skill

A skill is a document an agent follows, so these rules read what the document declares and does — the static disclosure the weekly sweep produced, with the lines that produced each finding. A disclosure describes; it never says safe, and it never says malicious. Where the hosting registry published its own scan, that reading is quoted as the registry's. Evaluated in the order S1, S2, S3, S6, S4, S5.

  1. S1noThe skill is gone from its registry.

    Checked first. The skill's own record is more than 45 days behind the most recent sweep we hold of that registry — so we looked at the registry after that date and this skill was not in what came back. Without a sweep to compare against, this rule cannot fire: "we did not check" never rounds up to "it is gone".

    reads: skills.last_seen · skills.source · preflight.skill.registry_last_seen

  2. S2unknownNo disclosure was produced for this skill.

    Checked second. Either the skills axis holds no record of this identifier, or the static scan did not complete and named no method. An empty flag list from a scan that DID run is a finding and never lands here — the two must not be allowed to look alike.

    reads: skills.id · skills.disclosure.method · preflight.skill.disclosed

  3. S3cautionThe disclosure records a remote-to-shell pipe or a request for a credential.

    Checked third. One of pipes_remote_to_shell or solicits_credentials appears in the static scan, and the matching lines are named in the evidence. It describes what the skill's own text does; it is not an allegation about the author, and a skill can have a perfectly ordinary reason for either.

    reads: skills.disclosure.flags · skills.disclosure.evidence

  4. S6cautionThe registry's own scan is recorded with a warning.

    Checked fourth. The registry that hosts the skill ran its own scan and recorded a warning or a status other than a clean one. That reading belongs to the registry and is attributed to it by name — Sato Hub neither repeats it as its own nor overrides it.

    reads: skills.registry_scan.status · skills.registry_scan.has_warnings · skills.registry_scan.source

  5. S4goDisclosed, with no credential, shell or key findings, a clean registry scan, and seen recently.

    Checked fifth, and all four at once: the static scan ran; none of pipes_remote_to_shell, solicits_credentials, generates_or_handles_keys, executes_fetched_code appears in it; the registry's own scan is recorded without a warning; and the skill was seen in its registry within 30 days. It describes four readings on a date. It does not say the skill is safe, and no reading here could.

    reads: skills.disclosure.flags · skills.registry_scan · skills.last_seen · preflight.skill.disclosed

  6. S5cautionEverything else that resolved to a skill.

    The default once a disclosure exists. Most skills sit here: a key-handling wallet skill, one the registry has not scanned, one we have not seen in a month. Caution is the absence of all of S4 at once, not an accusation.

    reads: skills.disclosure · skills.registry_scan · skills.last_seen

The rules for an x402 resource

One unpaid request (GET, POST on 405). Both wire formats are read — the v1 JSON body and the v2 PAYMENT-REQUIRED header — and the terms are reported as the seller stated them, beside our own answered-history. It describes the payee; it is never a reputation score, and nothing is paid. Evaluated in the order X1, X5, X3, X4, X2.

  1. X1noThe resource did not answer an unpaid request with 402 and parseable payment terms.

    Checked first. No HTTP answer, a status other than 402, or a 402 whose v1 body and v2 PAYMENT-REQUIRED header both failed to decode. It names the reading that failed; a seller that is down today is not a claim about the seller.

    reads: x402.probe.status · x402.probe.accepts

  2. X5cautionThe payTo address differs from the one first recorded for this resource.

    Checked second. Sellers rotate addresses for ordinary reasons; the line names both addresses so the caller can decide. Without a first-seen payTo on record this rule cannot fire.

    reads: x402.probe.accepts.payTo · x402.history.first_pay_to

  3. X3cautionThe price it answered with differs from the price its listing states.

    Checked third. Amounts are compared verbatim, in the asset's own atomic units, and only when the asset matches — a number without its asset is not a price, and no conversion is attempted.

    reads: x402.probe.accepts.amount · x402.listing.amount

  4. X4goAnswered with terms now, and our own record shows it answering for at least 14 days.

    Checked fourth. The first answer on record is at least 14 days old, the most recent stored check succeeded, and today's probe answered. It describes a payee that kept answering; it says nothing about what the resource delivers once paid.

    reads: x402.probe.answered · agent_endpoints.first_answered · agent_endpoints.last_ok

  5. X2cautionAnswered 402 with payment terms — described, no record long enough for X4.

    The default once terms decode. The evidence lists every accepted network, asset, amount and payTo as the seller stated them.

    reads: x402.probe.accepts

The rules for a recipient address (Sato Scan)

Before an agent pays or transfers to an address: does it only look like an address the payer deals with, is the token the issuer's own contract, did the paid party declare this address, and is the paying wallet targeted by address poisoning. The rules mirror Sato Scan's S1 to S7 as A1 to A7 and are evaluated in order, first match wins. Every evidence line carries its date and its own gaps. No record is unknown, and go means declared, canonical and nothing found within the stated limits: a description, never a judgement.

  1. A1noThe token names itself like a canonical stablecoin but is not the issuer's contract.

    Mirrors S1. The token at the address given is not the contract the issuer names for that stablecoin on this chain, yet its symbol or name reads like one. It does not say who deployed it or why.

    reads: scan.token.state

  2. A2noThe recipient only looks like an address the paying wallet already pays.

    Mirrors S2. The recipient shares the start and the end of an address in the paying wallet's history or a payee declared before, without being that address. It does not say the recipient acted on purpose, only that the two are easy to confuse.

    reads: scan.lookalike.state · scan.lookalike.matches

  3. A3noThe recipient carries a structural mark.

    Mirrors S3. We hold a structural record of this address acting as a fake-token contract, a batch dispatcher of poison transfers or a sender of them, with the transaction that shows it. The record describes what the address did, not who controls it.

    reads: scan.marks.marks

  4. A4cautionThe payee differs from what this origin served before.

    Mirrors S4. The origin named a different payee earlier. Rotating deposit addresses is routine, and this reading cannot tell a routine change from any other cause.

    reads: scan.declared.state · scan.declared.previous

  5. A5cautionFirst seen under 24 hours ago and not declared.

    Mirrors S5. The earliest activity we know of for the address is under 24 hours old and neither the origin nor an identity declares it. New addresses are common; this only means there is no history to read.

    reads: scan.marks.first_seen · scan.declared.state

  6. A6goToken in the canonical table, declared payee, nothing found in the stated limits.

    Mirrors S6. The token is an entry in our canonical table, the origin or an identity declares the payee, and no look-alike or mark was found inside the stated window, chains and detectors. It is a statement about those limits, not about what the payee does after this payment.

    reads: scan.token.state · scan.declared.state · scan.lookalike.state · scan.marks.marks

  7. A7unknownAnything else — we hold no record either way.

    Mirrors S7. Some of the five questions were not answered, or were answered without a declaration. That is not a clearance and it is not a warning.

    reads: scan.token.state · scan.declared.state · scan.lookalike.state · scan.marks.marks

The custody rules (Sato Check)

When a stored custody profile exists for a repository, package, endpoint or skill, its four answers are added as evidence. A deciding rule can move the verdict down — never up, and never to go. Evaluated C1 to C6, first match wins.

  1. C1noA planted test key was seen leaving during a sandbox run.

    The observed lane planted test key material and saw it sent to an outside host during install or start-up. The line names the host. It is a reading of one run, not a statement about intent.

    reads: custody.key_egress · custody.key_egress_hosts

  2. C2cautionThe code reads key material its setup does not ask for.

    Traced analysis found a private-key read while the declared setup names no key. Undeclared is the finding; a wallet reading a key it declares is normal and lands in C5.

    reads: custody.key_access · custody.evidence

  3. C3cautionAn action that can sign or send funds has no configurable limit we could find.

    At least one fund action has limit_configurable = false. Could-not-tell (null) does not fire this rule.

    reads: custody.fund_actions

  4. C4cautionAn install script was added since the previous profiled version.

    The version-to-version diff records install_script_added. The line quotes the change.

    reads: custody.changes

  5. C5describes · verdict unchangedIt reads a key, and no key was observed leaving.

    Local signing is what a wallet does. The four answers are added as evidence and the verdict is unchanged. Not observed carries its limit: install and start-up only, under our test conditions.

    reads: custody.key_access · custody.key_egress

  6. C6describes · verdict unchangedNothing above fired, or custody could not be read.

    The four answers are added as evidence and the verdict is unchanged. Unknown custody is not a finding in either direction.

    reads: custody.key_access · custody.key_egress · custody.fund_actions

The rules for a token address

Six keyless chain readings, and six rules over them. The lane is EVM-shaped and Uniswap v3-scoped, which is why a rule that would fire on silence needs two silent legs, not one.

  1. T1noNothing at the address holds bytecode, so there is no token there.

    An address with no code is an address with no code. Nothing further was read.

    reads: contract.is_contract

  2. T2unknownFewer than 3 of the six lanes returned a determinate reading.

    An unsupported chain, or reads that did not complete. Unknown, never zero: a reading we could not take says nothing about the thing we were reading.

    reads: contract · erc20 · deployer · venue · liquidity · holders

  3. T3noBytecode is present but not one ERC-20 view answered.

    Whatever is deployed at the address does not present as an ERC-20 to a standard call. It may be something else entirely; this lane only reads tokens.

    reads: contract.name · contract.symbol · contract.decimals · contract.total_supply

  4. T4noNo Uniswap v3 pool against wrapped native at any standard fee tier, no known launch venue deployed it, and DexScreener lists no pool either.

    Three legs, all silent. The Uniswap v3 lookup covers v3 only, so when it and the launch-venue match both come back empty the lane asks DexScreener's public API for any pool at all (Aerodrome, Uniswap v2 or v4, a bonding-curve venue). Only a determinate answer of none lets this fire; a DexScreener read that did not complete leaves the verdict at caution (T6), because one venue's silence is not a market's absence.

    reads: liquidity.pools · venue.name · market.pool_count

  5. T5goAn ERC-20 that reads back, deployed by a known launch venue, with at least one pool found and its LP position held by a known locker or burn address.

    A locker holds a position on the terms its own code enforces. Read that contract for those terms: this line says where the position sits, and stops there.

    reads: contract · venue.name · liquidity.pools · liquidity.lp_holder

  6. T6cautionEverything else that resolved.

    Enough lanes answered to say something, not enough to satisfy T5. A Solana mint with none of T7 to T9 lands here too: this lane has no `go` for Solana, because nothing keyless reads who controls the liquidity.

    reads: contract · venue.name · liquidity.pools

  7. T7noSolana: no account at the address, or the account is not a token mint.

    The node answered and said either that nothing exists at this address or that the account is not an SPL or Token-2022 mint (a wallet, a token account or a program, for example). There is no token here to read. A node that did not answer is not this rule — that is T2.

    reads: solana.program · solana.account_absent · solana.not_a_mint_reason

  8. T8noSolana: the mint carries the Token-2022 NonTransferable extension.

    A non-transferable token cannot be moved out of the token account it was minted to, so it cannot be sold, swapped or sent on. This is the extension doing what its name says; it is read from the mint, not guessed from behaviour.

    reads: solana.extensions · solana.flags.non_transferable

  9. T9cautionSolana: the mint carries a Token-2022 PermanentDelegate, a TransferHook, or a transfer fee.

    A permanent delegate is an address that can move or burn tokens out of ANY holder's account without that holder signing. A transfer hook runs another program on every transfer, and that program can refuse the transfer. A transfer fee takes a share of every transfer, so a buy followed by a sell returns less than it cost by more than the venue's fee. Each is a capability written on the mint, read now; none says it has been used, and a hook program's code was not read.

    reads: solana.extensions · solana.flags.has_permanent_delegate · solana.flags.has_transfer_hook · solana.flags.transfer_fee_newer_bps

  10. T10cautionSolana: a freeze authority is set on a mint that is not in Sato Hub's token table.

    A freeze authority is an address that can freeze any holder's token account, which stops that account sending or receiving the token. It is a capability written on the mint, read now, and it says nothing about whether it has been used. Stablecoins and SOL in Sato Hub's tables carry one too and are not named here, because the table already says what they are. This is the same caution T6 gives, with the reason named so it can be quoted.

    reads: solana.freeze_authority

The numbers the rules turn on

NameValueWhat it decides
MIN_DAYS14Days of our own checks before an observed record is allowed to rank or decide anything.
GO_SUCCESS_PCT95%Success across our checks, over at least 14 days, that counts as an earned check under R5.
NO_SUCCESS_PCT50%Success below this, with at least one failure attributed to the host, is R3.
PROBE_FRESH_MS14 daysAfter this, a daily check is history rather than a current reading.
MIN_TOKEN_CHECKS3Determinate token readings required before the token lane says anything but unknown.
X402_CONSISTENT_DAYS14 daysHow long our own record must show an x402 resource answering before X4 fires.
SKILL_FRESH_DAYS30 daysHow recently a skill must have been seen in its registry for S4 to fire.
SKILL_GONE_DAYS45 daysHow far a skill's record must fall behind its registry's latest sweep before S1 reads it as gone.

Worked examples

Each block below is a hand-built record put through the real verdict engine at render time, with a frozen clock. The listings are invented; they are not real projects, and none of them says anything about a real one.

goR5go — active, High tier, one earned check

?repo=example-org/example-kit

  • ▸Last commit three days ago.
  • ▸Sato Score 82, tier High, not provisional.
  • ▸The documented install was re-run in a container and completed.

Evidence returned

  • Directory record: Listed as Example Kit (Framework).resources.slug · 2026-09-11
  • Code activity: Last commit 2mo ago (recent).resources.last_commit_at · 2026-09-09
  • Sato Score: 82 of 100, tier High. The score measures how open, active and verifiable the project is, not safety or quality.resources.trust_score · 2026-09-11
  • Reproduced install: The documented install path was re-run in an isolated container and completed. Proves installability, not runtime behaviour.resources.deploy_spec.deploy_status · 2026-09-03
cautionR6caution — a record, but not all three at once

?repo=example-org/example-mcp

  • ▸Last commit two days ago.
  • ▸Sato Score 55, tier Medium.
  • ▸No reproduced install, no fresh successful daily check, no observed record.

Evidence returned

  • Directory record: Listed as Example MCP (Framework).resources.slug · 2026-09-11
  • Code activity: Last commit 2mo ago (recent).resources.last_commit_at · 2026-09-10
  • Sato Score: 55 of 100, tier Medium. The score measures how open, active and verifiable the project is, not safety or quality.resources.trust_score · 2026-09-11
noR1no — the listing is retired

?repo=example-org/example-retired

  • ▸Status "Deprecated" — a sweep found no public activity across website, repository and social over 90 days.

Evidence returned

  • Directory record: Listed as Example Retired (Framework).resources.slug · 2026-09-11
  • Listing status: Retired (Deprecated) — no public activity found across website, repository and social over 90 days. A retirement is an observation, not a verdict on the project.resources.status · 2026-09-11
unknownR4unknown — we hold no record

?repo=example-org/never-seen

  • ▸Nothing resolved against the directory, and nothing was probed.

Evidence returned

  • Directory record: No listing matches this identifier.resources.slug · no date on this field
goT5go — the token lane, with all four legs

?token=0x…&chain=base

  • ▸Bytecode present; all four ERC-20 views answered.
  • ▸Deployed through a known launch venue.
  • ▸One Uniswap v3 pool against wrapped native, LP position at a burn address.
  • ▸Deployer and holder concentration read as unknown, and say why.

Evidence returned

  • Chain: Read on Base (chain id 8453).preflight.token.chain · 2026-09-12
  • Contract at the address: Bytecode is present (4821 bytes). Code exists at the address; what the code does was not analysed.eth_getCode · 2026-09-12
  • ERC-20 reads: name "Example Token", symbol "EXMPL", 18 decimals, total supply 1000000000000000000000000 base units. Read from the contract now; a supply can change later if the contract allows it.eth_call erc20.name/symbol/decimals/totalSupply · 2026-09-12
  • Deployer: Unknown (no explorer key configured)contract creation record · 2026-09-12
  • Deployer age: Unknown (no explorer key configured)contract creation record · 2026-09-12
  • Launch venue: Deployed through Clanker v4 — deployed through the documented v4 factory. Names the factory that created it, nothing about the launch's terms.factory match · 2026-09-12
  • Uniswap v3 liquidity: 1 Uniswap v3 pool(s) against wrapped native: fee tier 10000 at 0x00000000000000000000000000000000000po0l. A pool existing is not depth — no reserves were read.uniswap v3 factory getPool · 2026-09-12
  • LP position holder: The liquidity position is held by burn address (0x000000000000000000000000000000000000dEaD) — a burn address. It holds that position on the terms that address enforces; read the contract for those terms.ownerOf(positionId) · 2026-09-12
  • Holder concentration: Not checked (no keyless public source; explorers are not scraped)none · 2026-09-12
  • Directory record: Neither the token nor its deployer matches a Sato Hub listing — unknown, not disqualifying.resources.onchain_address · no date on this field
cautionS3caution — the disclosure records a credential request

?skill=clawhub/example-wallet-skill

  • ▸The static scan ran and recorded two findings, each with the line that produced it.
  • ▸One of them asks the user to paste an API key, which is what S3 reads.
  • ▸The registry's own scan is recorded clean — attributed to the registry, and it does not override the finding.

Evidence returned

  • Skills axis record: Example Wallet Skill on clawhub. A skill is a document an agent follows; this is what the weekly sweep recorded about it.skills.id · 2026-09-10
  • Last seen in its registry: Present in the clawhub sweep 2 day(s) ago; that registry as a whole was last swept 1 day(s) ago.skills.last_seen · 2026-09-10
  • Installs: 412 reported by clawhub; 401 at the 2026-09-10 snapshot. A count the registry reports rather than one we verified, and how many people installed a document is not a property of what the document says.skills.installs · 2026-09-10
  • Disclosure: A static scan ran (static scan of SKILL.md and its scripts) and recorded 2 finding(s): Generates or handles private keys; Asks the user to paste a credential. A finding describes what the text declares or does; several of them are ordinary for the job a skill is written to do.skills.disclosure · 2026-09-10
  • Disclosure finding: Generates or handles private keys: Matched in the skill's own files: “SKILL.md: run `solana-keygen new` and keep the keypair at ~/.config/agent/id.json”. The line is the evidence — read it and decide for yourself.skills.disclosure.evidence.generates_or_handles_keys · 2026-09-10
  • Disclosure finding: Asks the user to paste a credential: Matched in the skill's own files: “SKILL.md: paste your RPC provider api key when the agent asks for it”. The line is the evidence — read it and decide for yourself.skills.disclosure.evidence.solicits_credentials · 2026-09-10
  • Hosts contacted: 1 third-party host(s): relay.example.invalid. Hosts named in the text, not traffic anyone watched.skills.disclosure.hosts_contacted · 2026-09-10
  • Credential names in the text: 1 environment variable(s) that read like secrets: EXAMPLE_RPC_API_KEY. Named, not necessarily requested — a name in a document is not a demand.skills.disclosure.declared_env · 2026-09-10
  • Declared hosts against the directory: None of the hosts this skill names belongs to a Sato Hub listing — unknown, not disqualifying.resources.website_url / docs_url / mcp_endpoint_url · 2026-09-10
  • The registry's own scan: clawhub recorded status "ok" without warnings. That reading belongs to clawhub — Sato Hub neither repeats it as its own nor overrides it.skills.registry_scan · 2026-09-10
unknownS2unknown — no disclosure was produced

?skill=clawhub/never-scanned

  • ▸The skills axis holds no record under this identifier, so there is no disclosure to read. Unknown is the answer, and it is not a warning.

Evidence returned

  • Skills axis record: No skill in the Sato Hub skills axis matches "clawhub/never-scanned".skills.id · no date on this field
unknownT2unknown — too few lanes answered

?token=0x…&chain=base

  • ▸Bytecode present, and nothing else completed. Two readings is under the minimum, so the lane says unknown rather than guessing.

Evidence returned

  • Chain: Read on Base (chain id 8453).preflight.token.chain · 2026-09-12
  • Contract at the address: Bytecode is present (1200 bytes). Code exists at the address; what the code does was not analysed.eth_getCode · 2026-09-12
  • ERC-20 reads: name "Unnamed". Read from the contract now; a supply can change later if the contract allows it.eth_call erc20.name/symbol/decimals/totalSupply · 2026-09-12
  • Deployer: Unknown (no explorer key configured)contract creation record · 2026-09-12
  • Deployer age: Unknown (no explorer key configured)contract creation record · 2026-09-12
  • Launch venue: No known launch venue matched (no known factory matched)factory match · 2026-09-12
  • Uniswap v3 liquidity: Not read (the read did not complete)uniswap v3 factory getPool · 2026-09-12
  • LP position holder: Unknown (no pool to read a position from)ownerOf(positionId) · 2026-09-12
  • Holder concentration: Not checked (no keyless public source; explorers are not scraped)none · 2026-09-12
  • Directory record: Neither the token nor its deployer matches a Sato Hub listing — unknown, not disqualifying.resources.onchain_address · no date on this field

Where the readings come from

EvidenceFieldMethodRefreshed
Directory recordresources.slugThe identifier is resolved against Sato Hub's own listings by repository, package name or host.On every listing edit; re-checked by the daily pipeline.
Listing statusresources.statusWeekly hygiene sweep of website, repository and social over 90 days; confirmed-silent listings are retired as "Deprecated".Weekly.
Code activityresources.last_commit_at / last_release_atNewer of the last commit and last release dates read from public sources. Posts are not counted.Daily.
Sato Scoreresources.trust_score / trust_tier / trust_provisionalRecomputed from evidence fields only — how open, active and verifiable the project is. Not safety, quality or returns.Daily.
Reproduced installresources.deploy_spec.deploy_statusThe documented install path re-run in an isolated container. Proves installability, not runtime behaviour.Weekly.
Daily checkresources.live_checkOne MCP handshake or HTTP check per day. A refusal of an anonymous check is recorded as a refusal, not as a failure.Daily.
Observed recordresources.uptime_observedThe daily checks rolled up: days observed, share that succeeded, and how many failures we could attribute to the host.Daily.
Live endpoint probeprobe.mcp_probeAn initialize + tools/list handshake run at request time against the endpoint given.At request time.
ERC-8004 registrationerc8004.identity_registry.ownerOf / tokenURIA keyless chain read of the identity registry, plus a fetch of the registration file when one resolves.At request time.
Daily agent checks (ERC-8004)erc8004_agents / agent_endpoints / erc8004_attestationsSato Hub's own daily per-agent checks on chains that have them (Celo today): the registration file as last resolved, what it declares, whether each declared endpoint answered, each endpoint's first and last answer, and any onchain attestation Sato Hub posted of those readings. Evidence only — no stored reading moves a verdict by itself, and no stored row is unknown, not a failure.Daily.
Token contract and ERC-20 readseth_call erc20.name/symbol/decimals/totalSupplyKeyless RPC reads against the address given, on the chain given.At request time.
Launch venue and liquiditypreflight.token.venue / liquidityFactory match against the known launch-venue table, plus Uniswap v3 pool lookups against wrapped native at the standard fee tiers. When both are empty, one DexScreener lookup for any listed pool.At request time.
Solana mint, extensions and holdersgetAccountInfo(jsonParsed) / getTokenLargestAccounts / pump.fun bonding-curve accountKeyless public Solana RPC against the mint given: the program (SPL or Token-2022), decimals, supply, mint and freeze authority, the Token-2022 extensions as the node parses them, the ten largest token accounts as a share of supply, and, for a mint with pump.fun's vanity suffix, the bonding-curve account's reserves and completion flag.At request time.
Skill disclosureskills.disclosureA static scan of the skill's own files: which hosts it contacts, whether it generates or handles keys, whether it asks the user to paste a credential, whether it pipes a remote script into a shell, what tools it grants itself. Each finding carries the matching lines. It describes; it never says safe, and it never says malicious.Weekly.
Registry scanskills.registry_scanThe hosting registry's OWN scan result, stored as the registry recorded it and attributed to it by name. Sato Hub does not repeat it as its own reading and does not override it.Weekly, when the registry publishes one.
Skill presenceskills.last_seen / skill_snapshotsThe weekly sweep of each registry. A skill's last_seen compared against the newest last_seen we hold for that whole registry is what separates “gone” from “not looked at”.Weekly.
Recipient readingscan.recipient (sato.scan.recipient/v1)Sato Scan's five questions about an address about to be paid: whether the token is the issuer's contract, whether the recipient only looks like an address the paying wallet pays, whether the origin or an identity declared it, whether a structural mark is held for it, and whether the paying wallet is targeted. Each answer names its window, chains and detectors.At request time, over the watchlist the daily scan keeps.

What Preflight cannot see

Printed, because a gap that is never mentioned reads as “nothing to report” — which is the one thing a preflight must never imply.

  • ▸EVM holder concentration — there is no keyless public source for it, and we do not scrape explorers. (On Solana the node's own largest-token-accounts call is read; those are token accounts, not wallets, so a pool or bonding-curve vault counts.)
  • ▸Uniswap v4 and every non-Uniswap venue on EVM chains, beyond a single DexScreener lookup made only when the v3 and launch-venue readings are both empty. Depth, volume and who controls the liquidity are not read.
  • ▸Every chain except the EVM chains named and Solana. On Solana: Token-2022 extensions, authorities, supply, largest token accounts and a pump.fun curve are read; a transfer hook's program code, who controls a pool's liquidity, and token metadata are not.
  • ▸The deployer address without an Etherscan key, for a contract Sourcify holds no deployment record for — a contract-creation record is not a keyless RPC read. Where Sourcify does hold one (BNB Chain, Arbitrum, Polygon and others) the deployer is read from it; the deployer's age is read only with an Etherscan key. An unknown deployer is not a finding; it only lowers the count of lanes that resolved (T2), so with too few other readings the verdict stays unknown.
  • ▸What the code does. Bytecode existing is not bytecode read.
  • ▸Anything after checked_at. A reading is a reading at a moment, not a subscription.
  • ▸What a skill does when it runs. The disclosure is a static read of the skill's own text — it never executes it, and text that reads plainly can still be followed somewhere we cannot see.
  • ▸Whether a skill is malicious. That is not a reading, and no rule in the skill lane produces it. A registry that publishes its own scan is quoted as the registry.
  • ▸Skills outside the registries we sweep, and any skill the sweep marks as not crypto-relevant.
  • ▸A recipient address is read inside the window, chains and detectors its reading states. A nothing-found there is not a statement about anything outside them, and it never says who controls the address.

Questions

How does Preflight decide a verdict?

By the first rule that matches, in order, within the lane the target belongs to. There are 6 rules for repositories, packages, endpoints and agents (R1–R6), 10 for the token lane (T1–T6), 6 for the skill lane (S1–S6), 5 for an x402 resource (X1–X5), 7 for a recipient address (A1–A7), and 6 custody rules (C1–C6) that ride on repository, package, endpoint and skill results and can only move a verdict down. Each returned verdict names the rule that decided it, so the reasoning can be looked up rather than taken on faith.

Does a Preflight verdict mean something is safe?

No. A verdict describes readings Sato Hub holds or took, and the date each was written. It is not a security review, a code audit, a quality judgment or a statement about returns — for any of the four verdicts.

What does unknown mean in Preflight?

Unknown never becomes no. A reading we could not take, a chain we do not cover, a listing we have never seen — each of these produces `unknown`, and `unknown` is never silently downgraded into a negative verdict. A null is unknown, never zero.

What can Preflight not see?

Several things it states rather than hides: EVM holder concentration — there is no keyless public source for it, and we do not scrape explorers. (On Solana the node's own largest-token-accounts call is read; those are token accounts, not wallets, so a pool or bonding-curve vault counts.) Uniswap v4 and every non-Uniswap venue on EVM chains, beyond a single DexScreener lookup made only when the v3 and launch-venue readings are both empty. Depth, volume and who controls the liquidity are not read. Every chain except the EVM chains named and Solana. On Solana: Token-2022 extensions, authorities, supply, largest token accounts and a pump.fun curve are read; a transfer hook's program code, who controls a pool's liquidity, and token metadata are not. The deployer address without an Etherscan key, for a contract Sourcify holds no deployment record for — a contract-creation record is not a keyless RPC read. Where Sourcify does hold one (BNB Chain, Arbitrum, Polygon and others) the deployer is read from it; the deployer's age is read only with an Etherscan key. An unknown deployer is not a finding; it only lowers the count of lanes that resolved (T2), so with too few other readings the verdict stays unknown.

Can I reproduce a Preflight verdict myself?

Yes. Every evidence line carries the field it was read from and the date that field was written, and every threshold the rules turn on is published on this page (MIN_DAYS = 14, GO_SUCCESS_PCT = 95%, NO_SUCCESS_PCT = 50%, PROBE_FRESH_MS = 14 days, MIN_TOKEN_CHECKS = 3, X402_CONSISTENT_DAYS = 14 days, SKILL_FRESH_DAYS = 30 days, SKILL_GONE_DAYS = 45 days). The free exports and the MCP server serve the same records the verdict read.

Related: Run a Preflight · House rules · How Sato Route chooses · Sato Score