@ crawlcheck/ sdk (英语)
CrawlCheck API 及其证据的离线验证符的打出客户端,在一个没有依赖性的包中.
npm i @crawlcheck/sdk
动作前检查
import { CrawlCheck } from "@crawlcheck/sdk";
const cc = new CrawlCheck();
const { proceed, receipt } = await cc.guard("example.com", "read", { agent: "MyAgentBot" });
// proceed is true on allow; warn proceeds only with { allowWarn: true }; require_confirmation only if confirm(receipt) resolves true.
// The receipt is a signed crawlcheck-decision; guard() verified it here and checked its key against the published directory.
自1.11.0起 guard() ưμ㼯a acceptance:单独的问题中,一个单一的"核实"曾经一次回答,所以没有什么能够错误地将"签名有效"误作"安全进行".
| 字段 | 问题 |
|---|---|
integrity_valid | 字节是否不变( 字母、 签名、 证明路径) ? |
issuer_trusted | crawlCheck 出版的签名密钥是吗 ? (null 无被绑定键的下线) |
key_policy_valid | 该密钥能否在签名时签名此对象 ? |
freshness_valid | 在它的有效性窗口内,未来没有日期,没有比动作允许的更长的寿命? |
subject_matches | 对于这个领域,这个行动, 一个已知的决定, 绑定一个解决答案? |
operation_matches 编号 : replay_safe | 具体操作和未发出这一要求? (null 当时,没有任何人被派遣 |
baseline_matches | 这些工具是否与核准的基准相匹配? (null 未给出基准时) |
assessment_complete | 每一个检查运行, 一个完全测量的答案? |
policy_source | 由何种政策产生决定crawlcheck_default, (中文(简体) ), caller_policy, (中文(简体) ), template:<name>, (中文(简体) ), policy_file:<id>(中文(简体) ) |
evidence_level | A 记录完整性, B 可复制的决定, C 证实读取(收据) evidence_assurance(中文(简体) ) |
policy_result | proceed, (中文(简体) ), pause 或者说 deny· ; accepted 实值 policy_result === "proceed" |
acceptanceOf(receipt, verification, checkDecision(receipt, want)) 计算你持有的收据的相同分数。 收据是证据和建议:你的代理人的行为是否由你的部署政策决定,每份收据都注明产生它的政策名称(authority) (中文(简体) ). POST https://crawlcheck.io/api/v1/preflight/replay 收件从存档答复中重新管理决定,并输入收件内容; GET /api/v1/preflight/rules 为散列规则表服务 engine.rules_sha256。 。 。 .
每个核查结果 integrity_valid, (中文(简体) ), issuer_trusted 财务报告和审定财务报表 accepted. 行动 accepted: 需要签名密钥为 CrawlCheck 发布, 所以用自己的密钥签名的文件是 verified 离线但永远不会 accepted客户方法(verifyDocument, (中文(简体) ), verifyOffline, (中文(简体) ), verifyReceiptOffline, (中文(简体) ), guard)为您检查已发布的密钥目录.
由于1.9.1 已退休的轮换记录清单在预期目的确定后仍算作自己的签字窗口:在决定钥匙轮换后,收到在窗口内签署的旧决定钥匙将核实,其他任何钥匙都不得在该钥匙启用期间签署所作决定(关键政策套案为退休决定钥匙*).
自1.9.0起 logCheck 阅读每个请求200个签名头的链条(/api/v1/log/sths),而不是每批一个,所以对一个没有头的客户端进行第一次检查,会接受一到两个请求;一个更老的服务器仍然每个请求行走一个头.
自1.8.0起,一个MCP将决定名称连接到服务器上,并用锁文件将其批准 tools_sha256 (单位:千美元)preflight(domain, "connect", { mcp: { url, tools_sha256 } })· ; withPreflight 送给你。 CrawlCheck从自己的网络读取活的工具:一个已更改的工具列表会重新变成 block,和签名的收据 assessed block 表示它覆盖的哪个终点和工具.
自1.8.0起,它们还实行签字政策(https://crawlcheck.io/keys#policy (英语):哪个关键目的可以签署哪个对象的时间(决定收款在协调世界时2026-11-09 17:00移动到决定密钥),退役密钥(仅对停止前签署的文件有效)和失密密密钥(仅在其签名上从未有效). 结果是 key_policy_valid,以及 accepted 需要这个 下行,从您保存的副本中构建相同的输入 : keyPolicyFrom(savedDirectory, savedRotationRecord),则 applyKeyPolicy(result, doc, kp) 或者说 guard(domain, action, { onlineKeys: false, keyPolicy })。保存的复制本无法知道您保存后已保存或已损坏的密钥 .
accepted 说谁签了文件 不允许采取行动:有效的收据可以说 block, (中文(简体) ), warn 或者说 require_confirmation。 。 。 . guard() 决定该部分.
preflight(domain, action, { agent, template, policy }) 返回签名的收据而不为您作出决定; verifyDocument(doc) 核查任何经签名的解答或决定收件. resolve(domain) 返回完整的已签名的 ResolutionV1 答案.
将支票作为工具给你的经纪人
三个工具 你的经纪人可以自称: crawlcheck_check_site (经签字和核实的关于在一个网站采取行动的决定,包括该网站公布的商业事实,以及AI引擎将其误解), crawlcheck_verify_fact (一个在您持有的电话号码、地址、时数或服务区上签名的判决:企业是否公布、做过一次、或者是谁的)和 crawlcheck_fetch (fetches a page only after it domain, 并且允许每一次重定向跳出). 所有故障关闭.
import { CrawlCheck, agentTools, toolsFor, vercelTools, langchainTools } from "@crawlcheck/sdk";
const tools = agentTools(new CrawlCheck(), { agent: "MyAgentBot" });
// OpenAI function calling
const oa = toolsFor("openai", tools); // oa.tools → tools: [...]; on a tool call: await oa.call(name, argumentsJson)
// Anthropic tool use
const an = toolsFor("anthropic", tools); // an.tools → tools: [...]; on tool_use: await an.call(block.name, block.input)
// Vercel AI SDK (1.10.0): one call; the "ai" module is passed in, so this package keeps no dependency
import * as ai from "ai";
const vt = vercelTools(new CrawlCheck(), ai); // generateText({ model, tools: vt, ... })
// LangChain.js (1.10.0)
import * as lc from "@langchain/core/tools";
const lt = langchainTools(new CrawlCheck(), lc); // createAgent({ model, tools: lt }) or model.bindTools(lt)
// An MCP server you run
const mc = toolsFor("mcp", tools); // list mc.tools; answer tools/call with mc.call(name, args)
读取记录
import { CrawlCheck } from "@crawlcheck/sdk";
const cc = new CrawlCheck(); // { key: "cc_…" } for licence-gated fields
const mr = await cc.machineRecord({ domain: "example.com" });
mr.findings; // gated exactly like the website: the top finding without a licence
mr.score_ledger; // what each row and finding does to the grade
每个请求和响应类型来自 https://crawlcheck.io/openapi.json 页面存档备份,存于互联网档案馆任何有文件记录的路线都可以调用,其类型与合同相符:
await cc.get("/api/explain", { domain: "example.com", code: "NO_LLMS_TXT" });
await cc.get("/api/explain", { website: "x" }); // compile error: not a parameter of this operation
使用网站的主食
一个网站可以服务 自己的签名判决在 CrawlCheck-Staple 页眉(和 /.well-known/crawlcheck-staple.json) (中文(简体) ). resolveFor 核查时使用它,没有向CrawlCheck提出要求,在它缺失、过期、为另一个域或被篡改时返回到已签名的查询中:
const res = await fetch("https://shop.example.com/");
const v = await client.resolveFor("shop.example.com", { response: res });
v.source; // "staple" or "network"
v.decisions.transact; // allow | warn | require_confirmation | block | unsupported
stapleCheck(record, { host, publishedKids }) 进行线下检查。 谱: https://crawlcheck.io/ spec/staple 页面存档备份,存于互联网档案馆
将撤销列表停放
CrawlCheck 签下一个域列表,其连接或交易决定现在被屏蔽:由所有者宣布的事件,被怀疑冒用顶级一万个品牌,或者未经证实的更改为付款,退票,钱包,登录,邮件或MCP域. syncRevocations() 获取(a) ?since= 第一次同步后三角洲,检查签名和已公布的密钥,并应用. 从那时起 guard() 拒绝列表域名进行一个完全没有请求的列表动作, 因此它继续使用网络剪切 :
import fs from "node:fs";
import { CrawlCheck, newRevocationStore } from "@crawlcheck/sdk";
const store = fs.existsSync("cc-revocations.json") ? JSON.parse(fs.readFileSync("cc-revocations.json", "utf8")) : newRevocationStore();
const client = new CrawlCheck({ revocationStore: store });
await client.syncRevocations(); // every poll_seconds (60), and before going offline
fs.writeFileSync("cc-revocations.json", JSON.stringify(client.revocations));
const g = await client.guard("pay.example.com", "transact");
g.revoked; // set when the held list refused it: { domain, actions, causes, since }
revokedFor(store, domain, action) 是相同的支票本身。 阅读和引用从未被本列表所取消.
在不指定域名的情况下抬头查看
new CrawlCheck({ privateLookups: true }) 制造 resolve() 财务报告和审定财务报表 resolveFor() 只发送sha256(域)的前2个十六进制字符;签名的答案从桶中取出,并在当地核实。 一个域名 CrawlCheck 从未提出过一个404 而不是一个及时的答案, 因为让一个域命名它. preflight() 财务报告和审定财务报表 guard() 仍然发送域:一个收件绑定在它上.
在您的 MCP 客户端中飞行
将 MCP 官方客户端包好 connect 财务报告和审定财务报表 callTool 在发送任何信息之前作出决定(建议:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { CrawlCheck, withPreflight, McpPreflightRefused } from "@crawlcheck/sdk";
const client = withPreflight(new Client({ name: "my-agent", version: "1.0.0" }), new CrawlCheck(), {
confirm: async (receipt) => askTheUser(receipt), // require_confirmation, and destructive tools with confirmDestructive
lock: approvedLock, // optional: refuse a server whose tools changed, and any tool outside the lock
});
try { await client.connect(new StreamableHTTPClientTransport(new URL(url))); }
catch (e) { if (e instanceof McpPreflightRefused) console.log(e.stage, e.why, e.receipt.decision); else throw e; }
block, (中文(简体) ), unsupported,不可核实的收据,或 require_confirmation 拒绝之前的连接 initialize。 。 。 .
工具接口连续性(1.11.0)
承诺,而且只有这一承诺:当您的政策需要重新批准时,你的代理人不会默默地着手修改工具定义(光谱) (中文(简体) ). 以锁文件存储每部分散列( Q)lock.parts = await lockParts(tools))所以一个变化被命名,然后选择一个模式:
const client = withPreflight(new Client(...), new CrawlCheck(), {
lock: approvedLock, // tools, tools_sha256, parts, server.url, approved_at
confirm: async (r) => askTheUser(r), // r.continuity is the record; r.tool names a paused tool
continuity: { mode: "observe", onRecord: (rec) => log.write(rec) }, // then "review", then "enforce"
});
| 模式 | 发生了什么事 |
|---|---|
observe | 没有被屏蔽; 每张支票都记录在政策上 将 已经这样做(would(中文(简体) ) |
review | 每次更改都会暂停对一个人的会话; 完整性失败仍然否认 |
enforce | 所应用的政策: 已更改或新工具被单独暂停(pause_tool(c) 其余的仍可使用 |
默认政策( E)CONTINUITY_DEFAULT_POLICY)被添加,被更改描述,被更改的schema和被更改的注释工具,更新已过期的证据,被暂停在无法到达的服务器或服务上,被中断或无法读取的工具列表,被扭曲的基线或出乎意料的政策版本,并在无效的签名,未公布或已退休的密钥,或不同的服务器上否认. 覆盖任何效果; 诚信类保留 deny 除非你设定 allow_integrity_override和记录说。 例外({ tool, class, until, by, reason })以 proceed_recorded从来没有像普通的通行证。 每张记录(crawlcheck-continuity-record标出基线、观察到的情况、每个事件、保险单的sha256、模式、结果及其本身 record_sha256它规定检查点的接口连续性:不是代码证明,不是判断工具无害,不是用户授权. continuityCheck(lock, tools, opts) 财务报告和审定财务报表 continuityFailure(cls, opts) 在没有客户端的情况下运行相同的逻辑; Python SDK 复制每个字节的记录字节( 共享金色文件) test/fixtures/continuity.json) (中文(简体) ). 其他客户端堆栈使用赤钩: mcpPreflight(cc, opts) 返回时 beforeConnect, (中文(简体) ), afterConnect 财务报告和审定财务报表 beforeToolCall。一个可运行的演示 examples/mcp-preflight-demo.mjs。 。 。 .
您的代理框架的连续性(1.12.0)
框架获取 MCP 服务器工具列表的相同检查, 与您批准的锁定文件相对应 。 没有 CrawlCheck 呼叫, 没有密钥, 没有新的依赖性 : 每个适配器都使用您已有的框架 .
import { withContinuity, loadMcpToolsWithContinuity } from "@crawlcheck/sdk";
// OpenAI Agents SDK (@openai/agents)
const server = new MCPServerStreamableHttp({ url });
await server.connect();
const agent = new Agent({ name: "a", instructions: "...", mcpServers: [withContinuity(server, lock, { mode: "observe" })] });
// LangChain (@langchain/mcp-adapters)
const client = new MultiServerMCPClient({ mcpServers: { shop: { url } } });
const tools = await loadMcpToolsWithContinuity("shop", client, lock, { mode: "observe" });
observe 记录各种差异(console.warn, (中文(简体) ), onRecord, (中文(简体) ), server.continuity.records 编号 : tools.continuity.records并传递工具通过. review 在任何更改中暂停整个服务器直至 confirm 说是. enforce 应用此政策: 拒绝代理商使用已修改或新工具, 并拒绝其调用, 直至 confirm({ tool, continuity }) 重新批准;其余仍可使用。 拒绝掷出 ContinuityRefused (与 .record) (中文(简体) ). 对这一确切的定义,人们记得一个 " 是 " ,因此,列出每个回合的工具的框架并不要求两次。 对于 CrewAI,使用 Python 软件包(crawlcheck.crewai.with_continuity) (中文(简体) ).
在信任它之前检查基线 (1.13. 0)
任何可以编辑您批准的锁文件的人都可以批准自己的工具. 所以每个门withPreflight 与 lock, (中文(简体) ), continuityGate, (中文(简体) ), withContinuity, (中文(简体) ), loadMcpToolsWithContinuity)检查了锁文件的签名一次,当它被创建时,在它比对任何东西之前:
baseline.trust | 含义 |
|---|---|
verified | 由 CrawlCheck 签名 (cc.mcpLock(url) 编号 : GET /api/v1/mcp/lock)带有CrawlCheck键. 包装了已公布的密钥标识(CRAWLCHECK_LOCK_KIDS; 通过 keyPolicy: await cc.publishedKeyPolicy() 以按键旋转。 这些锁文件携带 parts 签名内; parts 之后添加的不使用. |
operator_signed | 你签了 signLock 并传递了您的公用钥匙在 operatorKeys。当您自己编辑锁定文件时使用此工具,例如,将工具放下. |
unsigned | 无签名。 接受,除非 requireSignedBaseline (默认通过后) operatorKeys) (中文(简体) ). |
invalid | 签名不验证, 文件在签名后被更改, 或者密钥既不是 CrawlCheck 的, 也不是您的 . |
invalid,或 unsigned 当需要签名时, 是失败类 baseline_untrusted数字 : enforce 财务报告和审定财务报表 review 拒绝 (ContinuityRefused 编号 : McpPreflightRefused, (中文(简体) ), observe 记录下来然后继续. openContinuityGate(lock, opts) 启动时投掷; continuityGate 曝光情况 gate.ready 财务报告和审定财务报表 gate.baseline。每个记录名称 baseline.trust。每通电话都无法核实.
签名您的锁文件, 没有命令行 :
import { newOperatorKey, signLock, openContinuityGate } from "@crawlcheck/sdk";
const key = await newOperatorKey(); // once; store key.privateKey where the agent cannot read it
const signed = await signLock(lock, key.privateKey); // after you review (or edit) the lockfile; save signed
// at startup, with only the public key:
const gate = await openContinuityGate(signed, { mode: "enforce", operatorKeys: [key.publicKey] });
verifyLockBaseline(lock, opts) 单独运行相同的检查。 签名是Ed25519 "crawlcheck-lock-operator-v1\n" + sha256(canonical JSON of the lockfile without operator_signature); Python 包符号, 并验证字节相同.
不要相信API: 你自己检查证据
const v = await cc.verifyOffline(mr.subject.report_id); // downloads the bundle, verifies it HERE
v.checks; // manifest hash, Ed25519 signature, key id, record digest, Merkle path to the day's root,
// OpenTimestamps proof (Bitcoin), sealed roots over fetches, decisions and facts
ok: true 通过了, ok: false 失败, ok: null 无法运行和 why 说为什么 虚空绝不是传球.
补救收据(在宣布固定、部署、判决后、签字前):
import { verifyReceipt } from "@crawlcheck/sdk";
const rc = await cc.receipt("rc1:…");
const r = await verifyReceipt(rc); // hash, key id, signature, order
const ours = (await cc.publishedKeyIds()).includes(rc.signature.kid); // the one check offline cannot do
const accept = r.verified && ours;
证明验证人
const suite = await cc.conformance(); // 19 real bundles and receipts, valid and tampered, with expected outputs
suite.ok; // every fixture gave exactly its expected checks and verdict
npm test 在安装的软件包中运行符合套件,并对crawcheck.io进行活检.
抓取分隔视图
在CrawlCheck的透明日志中,每个解答的叶子名称,一旦合并,就带有其批次被签名的树头. 客户头都戴着 client.log (Plane JSON),并检查每个新的一个对接它的邻居:一个批次有两个头,或者一个头不与以前的一头连在一起,就是一个 叉头将两个签名的头作为证据. guard() 在客户持有时拒绝继续.
import fs from "node:fs";
import { CrawlCheck, newLogStore } from "@crawlcheck/sdk";
const store = fs.existsSync("cc-log.json") ? JSON.parse(fs.readFileSync("cc-log.json", "utf8")) : newLogStore();
const client = new CrawlCheck({ logStore: store });
await client.resolve("example.com"); // the answer's head is checked against the store
const r = await client.logCheck(); // current head + GitHub's witness co-signature + the chain down to your heads
console.log(r.summary); // "consistent: ..." or "SPLIT VIEW: ..."
fs.writeFileSync("cc-log.json", JSON.stringify(client.log));
logCheck 校验出外证人:一个"GitHub Actions"运行再检查链条,并用"GitHub"OIDC标志(RS256,GitHub's key)共同为最新头部签名,其受众为"头部文摘". 一个头 证人的链 并不包含显示作为一个分叉。 比目击者更新的头像被列作 unwitnessed。客户端也可以直接交换头: logHeads(store) 一边, client.logGossip(heads) 在另一个。 报告叉子 /api/v1/log/gossip (通过) { report: false } 跳过).
错误
拒绝的请求 CrawlCheckError 与 status, (中文(简体) ), body 财务报告和审定财务报表 locked (这需要域名许可).
需要节点20+或任何当前浏览器(WebCrypto Ed25519).