mcpField
N
Nota

Nota

远程服务
nota-ryo.vercel.app金融数据0今天更新

关于 Nota

Nota 是只读加密资产研究系统,基于 RYO 市场证据和独立核查生成可重放的交易决策。它结合 Agent 评议、风险定仓、可审计收据和结果追踪;客户端可通过 REST 或 MCP 连接 RYO。

主要功能

  1. 01收集 RYO 市场证据并进行独立核查
  2. 02对比 Agent 意见及其引用依据
  3. 03按 ATR 和账户风险计算模拟仓位
  4. 04根据已存证据重放决策
  5. 05依据 OKX K 线追踪并结算判断
  6. 06使用 OpenTimestamps 锚定收据和记录

适用场景

  1. 01查看可审计的模拟交易决策
  2. 02重放历史决策以核对记录
  3. 03根据后续价格追踪 RYO 交易计划
  4. 04定时运行市场检查并发送通知

MCP 相关

Nota 可通过 MCP JSON-RPC 而非 REST 连接 RYO,需设置 RYO_TRANSPORT=mcp。其 MCP 客户端执行初始化,并支持 JSON 与 SSE 响应。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://nota-ryo.vercel.app/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

9
参数类型必填说明
hoursinteger否回溯时间范围(小时,默认值为 24)
tokensarray否要跟踪的代号;默认值为找到的所有已知主要代币 cashtag、ticker 或名称
voicesarray是最多 20 个 ID,例如 tg:WatcherGuru、bs:handle.bsky.social 或 x:handle

详细介绍

Nota

一份可审计的 AI 交易观点。由一组专业 Agent 围绕实时 RYO 市场证据展开讨论,并记录其会执行的模拟交易,形成一份可回放的决策凭证: nota replay <id> 会根据存储的证据重建决策,并输出 identical: true;所有引用的数字都从证据中读取,而非由模型重新输入;在确定仓位规模之前,独立来源会先审查 RYO 自身的价格和指标。为 RYO-CHAN Hackathon 2026 打造。

参赛赛道:1 自主 Agent(议事团、凭证、watch 循环,以及议事团无法绕过的衍生品门控)、2 仪表板(以差异为先的凭证仪表板,以及 RYO Verdict Scorecard)、3 新技能 (narrative_convergence、news_verify、price_crosscheck、technicals_crosscheck、 positioning_check、move_base_rate、verdict_track_record、liquidity_check、crowd_odds,均在 RYO 的边界范围内)。

评审? https://nota-ryo.vercel.app/judges 为每个赛道提供一个页面:该查看什么,以及对应评分标准中的哪一条。仪表板可以基于最新的 RYO 证据实时运行议事团。Nota 不做什么,见 LIMITATIONS.md;这样设计的原因,见 DECISIONS.md。

Nota 的能力,超越了只有凭证和回放功能的 Agent:

  • 它会审查 RYO 本身。 Verdict Scorecard 每天锁定 RYO 对 25 种主流币的 deep_analysis 判定和交易计划,且此时结果尚未揭晓;之后会根据 OKX K 线结算每项计划。RYO 不会给自己评分,而且每次失误都会计入。
  • 它发现 RYO 数据中的缺陷,并设置门控。 某些衍生品字段在同一天对互不相关的代币显示相同数值。代码会阻止议事团使用这些字段,并指出相关代币。
  • 它能证明记录未被篡改。 每份凭证和锁定记录都通过 OpenTimestamps 锚定在 Bitcoin 上,CI 推送的每个账本快照都经过 Sigstore 认证。
  • 你可以故意让它出错。 /drill 会在离线状态下向真实流水线注入七种真实故障模式,并将每次拒绝与正常运行并列展示。

RYO 判定评分卡

每个 deep_analysis 答案都包含一个判定和一份交易计划(止损位距入场价 1.5 ATR,目标位为 +1R)。RYO 从不报告这两个价位最终的结果。nota lock 每天会为 25 种主流资产保存完整答案(20 小时内不会重复保存);之后,nota settle 会查询 OKX 的公开 K 线,判断在 24 小时和 72 小时内哪个价位先被触及:从锁定时间到第一个完整小时使用 1 分钟 K 线,之后使用小时 K 线;若某个小时内两个价位都被触及,则改用该小时自身的 1 分钟 K 线进行判定。RYO 不会给自己打分:止盈止损区间会根据锁定时 OKX 的价格重新锚定,两个价格相差超过 2% 的锁定记录会保留为 basis_mismatch,且永不结算。若某个时间窗口内缺少 OKX 从未发布的小时 K 线,系统会重试一天,之后将其保留为 unsettleable。判定组合、共振状态和 RYO 的动量门槛,分别按目标位优先触及率和期限收益率进行比较(包括未触及任一价位的计划):在每个锁定日内进行比较,并结合 Mantel-Haenszel 权重,避免数据失衡的某一天扭转结果方向;p 值则通过在重叠窗口组成的集群内打乱标签计算。只有在至少 10 个共同日期且 p < 0.10 时,才会判定差异显著;测试中使用模拟零假设检验该显著性水平。每次锁定失败都会计为一行记录,无论重试多少次,每种代币每天只记一行;若密钥失效,则在一次调用后停止运行,并记录一条 aborted 记录。页面还会根据 RYO 自己的表述,报告其答案中每个部分可用的频率。 /scorecard 会展示这些信息,并按紧急程度排序;/api/scorecard?horizon=24|72 提供原始记录,/api/scorecard.csv 则以 CSV 格式提供相同的表格(每条锁定记录和每个期限各占一行,包含失败记录)。页面还附带一个 schema.org Dataset 描述(JSON-LD),列出这两个下载文件。

以比特币为锚,而非以 Nota 的时钟为准。“在行情变动前锁定”只有在任何人(包括 Nota)都无法回填锁定时间时才有意义。nota stamp 会将每条有效锁定记录和每张收据的 SHA-256 值,按原样提交到三个公开的 OpenTimestamps 日历,并保存 .ots 证明;待日历生成证明后,之后的运行会将其替换为比特币认证,并核对该区块的 Merkle 根与 mempool.space 是否一致。评分卡和仪表板会根据保存的状态显示“Bitcoin block N”或“timestamp pending (submitted …)”,除此之外不会显示其他信息。要自行验证:

curl -o lock.json https://nota-ryo.vercel.app/api/scorecard/locks/<id>.json    # the row as stored
curl -o lock.json.ots https://nota-ryo.vercel.app/api/scorecard/locks/<id>.ots
ots verify lock.json.ots        # pip install opentimestamps-client; or drop both files on opentimestamps.org

收据也采用相同方式,可使用 /r/<id>.json 和 /r/<id>.ots。

第 0 天(2026-09-18):25 条中锁定 25 条,4 条为 CONFIRMED,21 条为 MIXED;其中 7 份计划做多,而 RYO 自己的判定为 cautious(XRP、DOGE、ADA、LINK、SUI、BCH、WIF)。

议会不得引用的内容

2026-09-18 探测的每个代币,其 deep_analysis.data.derivatives 都报告 funding 为 0.0,long/short ratio 为 null;此外,不相关代币的 24 h 未平仓合约变化完全相同(ETH、SOL、WIF 和 ONDO 均为 -10.44)。positioning_check 会逐项判定这些字段,不会猜测 RYO 未公开的定义:当天锁定的另外两个代币出现相同数值,则标记为 not_token_specific;与 OKX 以币本位计价的未平仓合约变化方向相反,且差异达到 3% 或以上,则标记为 conflicts_with_venue;BTC funding 恰好为 0,而 RYO 自己的情绪工具报告 BTC funding,则标记为 conflicts_with_ryo。被扣留的字段会以 withheld: <reason> 的形式传入提示词,并且不会保留对该字段的引用。scripts/gate_ab.py <id> 会在不启用 gate 的情况下重新运行回执对应的议会;首次运行(docs/gate-ab/cd5ada18b179.json)没有任何变化,但仍然予以发布。

Dashboard:30 秒摘要、按影响排序的变化、未平仓头寸、技能面板

更多截图(回放验证、回执卡片、手机布局)

从页面验证回放 用于链接预览的回执卡片 手机布局

截图由 scripts/screenshots.py 根据随附的演示账本生成。

不如直接观看: nota-ryo.vercel.app/demo ——一段 3:36 的讲解视频,附带可点击的文字稿;也可以直接查看 /demo.mp4 文件。

如何作出决策

gather ──────────► council ──► judge ──► risk (pure ATR math) ──► receipt ──► ledger ──► notify
 5 RYO tools        macro       weighs      entry / stop / target      id = hash(evidence,   Telegram
 + own skills       technician  opinions    or Blocked when price       model, prompts)      Discord
 (price_check,      narrative   by Brier    or ATR is missing
  voices, news)                 weights
  • 证据包:market_overview、monitor_market_sentiment_shift、deep_analysis、 analyze_token、compare_tokens(将该代币与 BTC/ETH 同类资产比较)。scan_market 驱动 nota scan,这是 RYO 推荐的筛选流程;--direction negative 会将其 filter_direction 设为筛选 做空候选标的的方向;对已扫描代币做出的决策会保留该代币自身的扫描行(排名、24 h 涨跌、 成交额、动量评分、established_asset、RYO 的理由),作为哈希包中的 scan 部分。工具调用失败时会生成一个状态为 error 的部分; 证据包仍会存在。自有技能会作为额外部分加入(默认包括 price_check、 technicals_check、positioning_check、liquidity 和 crowd_odds,使用 --voices 时加入 narrative_signal,使用 --news 时加入 news_check)。
  • Council:三个 Agent(宏观、技术分析、叙事)各自返回立场、 概率,以及指向证据中点分路径的引用。指向缺失值或 null 值的引用会在代码中被丢弃(将 x[0].y 标准化为 x.0.y 后),并下调意见等级。
  • 第三方文本是数据,而非指令:narrative_signal 中的帖子文本,以及 news_check 中的标题和 摘要,会以 {"untrusted": ...} 的形式传给 Council,同时剥除控制字符和双向文本字符;如果内容类似“忽略你的规则”,则会标记为 injection_suspect;并且会告知每个 Agent,这类文本是需要权衡的证据,绝不是需要遵循的请求。RYO 的代币档案文本(约 2.7 KB,在 deep_analysis 和每个 compare_tokens 行中重复出现)只展示一次,提供给叙事 Agent;其他 Agent 会在相同路径看到其状态和缺失输入,因此技术分析 Agent 的提示词缩短了 30% 以上(提示词版本 v4)。提示词版本 v5 为宏观 Agent 提供 liquidity(稳定币供应量和链上 TVL);没有 Agent 能看到 crowd_odds,它会作为市场价格保留,用于评估裁判。
  • 裁判:根据每个 Agent 的历史 Brier 分数为意见加权,并决定做多、做空或不交易。
  • RYO 自身的计划是证据,而非指令:deep_analysis.data.trade_plan 包含 RYO 的 ATR 预览(入场价、止损价、目标价、倍数、方法)。Nota 会独立计算仓位规模,然后在回执上报告差异:在已发布的 ETH 调用中,RYO 使用 1.5× ATR,在 2357.83 处止损,而此处的仓位计算使用 2.0×;因此止损价比入场价低 1.8%,第一个目标价则远 5.4%,方向相同。RYO 的 squeeze_risk 和 liquidation_pressure 也会与该对比一并列出。
  • 每份回执都记录 RYO 的判断:每份回执都会记录 ryo_view(deep_analysis 的判断、关键驱动因素、可能改变判断的因素、共识状态、analyze_token 的结论、compare_tokens 的选项)和 agrees_with_ryo(做多对应建设性/看涨/增持,做空对应谨慎/看跌/回避),并显示为“RYO 的判断:建设性(共识 CONFIRMED)- council:做多,一致”。二者都来自哈希包,因此重放时会进行对比;在这两项加入前存储的回执,重放结果仍完全一致。/api/scores.vs_ryo 和仪表板中的“Nota 与 RYO 对比”一行会说明 Council 是否胜过 RYO 自身的判断:统计双方都选择方向的已评分调用,比较命中率。
  • 风险:纯函数。止损 = 2×ATR(14),目标 = 3×ATR,仓位规模基于 1% 账户风险计算,且不超过账户的 20%。除非仓位门控未放行,否则 RYO 自身的衍生品 veto 会阻止模拟交易(“RYO 衍生品否决:<原因>”)。没有价格或没有 ATR 时会显示已阻止,绝不会猜测数值;如果 ATR 大到使止损价或目标价小于或等于零,也会如此:对于波动性如此高的工具,不适用固定倍数规则,回执也不得打印负价格。
  • 重放:大模型输出按 (evidence hash, role, prompt version, model) 缓存。 nota replay <id> 会精确复现回执;--fresh 会重新询问模型,并如实显示偏差。仪表板中的“验证重放”按钮只会检查缓存。
  • 校准:nota resolve --all 会针对七天期限已过的每项决策评分(每个 Agent 的 Brier 分数),以期限时的 OKX 小时收盘价为准,无论该周期运行得多晚;如果 OKX 无法提供该价格,则使用当前 RYO 价格或交易所中位价替代,并标注 late:<hours>h:。校准表只统计已到期的结果,报告其中有多少调用是独立的(每个代币每周一次),且在达到 20 个结果前不会显示。裁判的权重会按照 n/(n+20) 的比例逐渐向各 Agent 的 Brier 分数靠拢,因此五次评分调用不会让权重剧烈波动。除了 Brier 分数,还会与两个基准进行比较:代币自身的基准率(vs_base_rate),以及更严格的预测市场在决策时的 P(up)(vs_base_rate.vs_market,仪表板中的“Nota 与市场大众对比”):在相同已结算调用中,对比裁判的 Brier 分数与市场的 Brier 分数。
  • 自主运行:nota watch SOL,BTC --every 3600 --notify 会按计划做出决策、结算到期决策,并将每份新回执发布到 Telegram / Discord。--scan-top 3 会让循环每个周期都从 scan_market 中自行选择候选标的。
  • 模拟数据绝不用于交易:当 RYO 将主要证据标记为 data_mode: simulated 时,仓位计算会被阻止,回执也会明确说明。
  • 传输方式:默认使用 REST(/tools/{tool}/call),也可使用 MCP JSON-RPC(在相同基础 URL 上调用 tools/list、 tools/call),设置 RYO_TRANSPORT=mcp 即可。MCP 客户端会为每个客户端执行一次 initialize + notifications/initialized 握手,保留 RYO 的 serverInfo 和 协议版本,发送 Accept: application/json, text/event-stream,并同时读取 SSE 回复和 JSON 回复。nota health 会显示 whoami、密钥过期前的天数、握手信息和实时目录;检查 Nota 发送的每个参数是否符合 RYO 公布的输入架构(必需键、未知键、枚举值),并列出 Nota 未使用的已公布参数; nota health --strict 遇到上述任何问题或密钥将在 14 天内过期时都会以状态码 1 退出。

公共接口按公开接口对待

/api/skills/<name>/invoke 和 POST /mcp 故意不进行身份验证,因此它们面向陌生用户编写:

  • 语音 ID 会进入外发 URL,因此必须先验证。以前,../../evil 会解析为 https://t.me/evil,让调用方能够指定目标主机上的路径;如果跟随重定向,这就可能让此服务 开始抓取调用方指定的位置。账号名只能包含字母、数字、下划线、点和连字符,最多 64 个字符;其他内容都会在 构建请求前被拒绝。
  • 所有技能参数都会在同一处(nota.skills.invoke)根据技能自身声明的架构进行检查;REST、MCP 和 CLI 都会经过此处:类型错误、值不在枚举范围内、非有限数值、长度超过 64 个字符的字符串(新闻声明为 500 个字符)或超过 20 个 项目的数组,会分别返回 422、JSON-RPC -32602 或 CLI 用法错误,绝不会返回 500。在进入交易所 URL、提示词 或账本前,交易品种必须是 1 至 15 个字母或数字,因此 ../x 或 BTC?x 不会离开进程。GET /api/decisions 的 limit 范围为 1 至 200,支持者账号名必须为单行:@Abc 和 abc 代表同一位支持者,而 abc 会被拒绝。
  • MCP 上的 tools/call 与 REST 路由一样,按地址计量,每小时 60 个单位, 因为它会访问第三方 API。一次调用的费用大致取决于它发起的抓取次数:价格或技术指标检查为 1 个单位,news_verify 为 2 个单位,narrative_convergence 每个语音为 1 个单位(因此,调用 20 个语音会花费 20 个单位,而不是 1 个)。initialize、tools/list、resources/* 和仅访问账本的 verdict_track_record 都免费:它们不会访问进程外部。批处理会先整体检查,再扣费;被拒绝时会返回带有 Retry-After 的 JSON-RPC 429。设置了 DATABASE_URL 时,计数会存入 Postgres(hits 表),因此所有无服务器实例共用一份预算,而不是各自拥有一份;未设置时,计数按进程计算,随着运行持续清理,若地址数达到 10,000 则会清空。
  • 每个进程每五分钟最多抓取一次 Telegram、X 或 Bluesky 语音,以及四个 RSS 订阅源中的每一个;重复请求会使用缓存,抓取失败的结果绝不会缓存。
  • 每个响应都带有 X-Content-Type-Options: nosniff、Referrer-Policy、Permissions-Policy 和 Content-Security-Policy,且只允许此源:字体由本服务托管,没有页面会加载第三方脚本。由于页面将行为代码内联,脚本和样式仍允许使用 'unsafe-inline';这比用于防范脚本注入的 nonce 策略弱,因此页面插入的每个值都会先转义。/docs 不适用此策略,因为 Swagger UI 来自 CDN。/api/ 和 /r/ 下的只读 JSON、llms.txt、订阅源、字幕和 Agent 卡片允许任何源访问,技能调用路由也会响应 CORS 预检,因此其他位置的页面可以调用技能;/mcp 仍保留其 Origin 允许列表。每个页面都会对 HEAD 请求返回 GET 会发送的响应头;对于账本中不存在的 ID,/r/<id> 会返回带有 noindex 的 404。
  • /api/health 每个进程每分钟最多探测一次 RYO(超时后重试一次),并会说明探测时间(checked_at)、支持记录的写入位置(backing:postgres、ledger 或 none),以及账本的新鲜程度:最新的锁定、收据和结算记录;如果 36 小时内既未写入锁定记录也未写入收据,则会返回 stale: true。
  • JSON-RPC 批处理最多包含 25 条消息,请求体最大为 1 MB(在流式接收时检查,因此分块上传无法绕过限制);如果请求体嵌套过深而无法解析,则返回 -32700。每个 MCP 请求都会验证 Origin,这是传输规范安全章节的要求。所有拒绝请求的响应(包括传输层拒绝)都会以 JSON-RPC 错误响应体返回。
  • 不含 id 的消息是通知:它会收到 202,且不会执行任何操作,因此无法运行工具或消耗预算。JSON 类型错误的参数会返回 -32602;技能意外失败时,会返回一个注明工具名称的 isError 结果(详细信息会写入服务器日志,不会返回给调用方);技能会在工作线程中运行,因此某个缓慢的数据源不会阻塞端点。
  • 每个地址每小时最多可提交 30 次支持。托管部署上以前会返回 503,这意味着唯一能尝试的地方恰恰是唯一无法使用的地方:无服务器文件系统不可写,而那里的账本只是快照。现在,设置了 DATABASE_URL 时,支持记录会写入 Postgres(nota/backings.py);否则会写入账本自己的表,因此运行或测试时无需本地数据库。写入通过单条 INSERT ... ON CONFLICT (decision_id, handle) DO UPDATE 完成:读取账号名映射、修改其中一项再写回,会在两个人同时提交支持时丢失其中一人的立场;而会悄无声息地丢失某人投票的公开记录,比没有公开记录更糟。若完全没有可写入的位置,仍会返回 503;这正是保留此错误码的原因。
  • 账号名不能被他人接管。由于没有账户,首次使用某个账号名提交支持时,该账号名就会被认领,并一次性返回 edit_token;之后使用该账号名提交支持时,必须附带此令牌,否则会返回 409。系统只存储令牌的 SHA-256,并以恒定时间进行比较。控制面板会在认领该账号名的浏览器中保存令牌。

此代码强制执行的诚实规则

  • 收据中的每个数字都带有其来源路径、RYO as_of、data_mode 和追踪 ID。
  • null / unavailable 绝不会转换为 0(Envelope.get、first_present、风险逻辑以及每项技能)。
  • 已记录的固定数据保留 RYO 原始的 as_of 和 data_mode,并标记为 source: recorded。tests/fixtures/ 下的 RYO 信封也都是真实答复(记录于 2026-09-19;此外还有 tests/fixtures/recorded_0907/ 中的 2026-09-07 数据集,当时 SOL 的衍生品通道不可用;以及 tests/fixtures/ryo_errors/ 中 RYO 的真实拒绝答复)。只有来源为 live 或 recorded 的证据才能用于确定练习交易规模,或纳入 Brier 分数、基准率、来源或可靠性评分;其他内容只会显示,绝不计入。CLI 中没有伪造 LLM 模式。
  • RYO 接口为只读;练习交易仅存在于 nota.db 中。
  • 收据会说明成本:模型调用次数、缓存命中次数、提示词和补全 token 数、提供方自行报告的计费金额,以及耗时。这些数据全部由提供方报告,绝非根据本仓库必须持续维护准确的价格表推算得出——未报告的数字会显示为“未报告”,而只要有一次调用未报告,整个总额就会变为未知,而不是更低。spend 有意不纳入重放比较:缓存重建不会产生费用,因此该字段是测量值,而非可复现性声明。
  • 外部来源会说明自身的局限:Venice 网页搜索不带日期,X 镜像为非官方镜像,失败的 RSS 订阅源会列出,交易所价格绝不会替代 RYO 的数值。

运行

uv sync
cp .env.example .env            # RYO_MCP_KEY + an LLM key (Anthropic, or NOTA_LLM=openai for Venice/OpenRouter)
uv run nota health             # MCP health (no key) + whoami, key expiry, handshake, catalog check (with key)
uv run nota health --strict    # the same, exit 1 on an expiring key or an argument RYO would refuse
uv run nota llm-check --llm openai   # one 1-token completion; exit 2 when the key or balance is refused
uv run nota decide SOL         # live evidence + price cross-check, council, receipt
uv run nota decide SOL --voices tg:WatcherGuru,bs:decrypt.co,bs:unusualwhales.bsky.social --news --notify
uv run nota scan --top-n 5 --decide-top 2      # scan_market -> analyze_token -> council
uv run nota scan --direction negative          # RYO's losers shortlist, the funnel for a short
uv run nota watch SOL,BTC --every 3600 --notify
uv run nota replay <id>        # identical: True
uv run nota replay <id> --fresh
uv run nota resolve --all      # after 7 days: Brier scores per agent
uv run nota stamp              # OpenTimestamps: anchor new locks and receipts, upgrade proofs pending over 3 h
uv run nota export snapshot.json        # receipts + scorecard as one JSON (the ledger cycle writes data/snapshot.json)
uv run nota merge-db other.db  # add another snapshot's rows this ledger lacks (the cycle's push-conflict path)
uv run nota scores
uv run nota record SOL         # capture all six live tools into fixtures/recorded (all or nothing)
uv run nota decide SOL --source recorded   # replay those recordings without a RYO key (the council still needs an LLM key)
uv run nota positions                      # open practice positions vs the latest independent price
uv run nota serve                          # http://127.0.0.1:8000 overview, /app dashboard, /mcp
uv run nota skill spec                     # Track 3 definitions
uv run nota skill run price_crosscheck '{"symbol":"SOL","reference_price":150}'
uv run pytest -q

多 KOL Agent(Track 1 重点展示)

黑客马拉松的重点创意,端到端实现:最多选择 20 位加密货币领域意见领袖,让 Nota 找出他们提及的代币及其情绪、确信度和紧迫性,并且仅当可信的意见领袖达成一致且你设定的每条规则都通过时,才开立练习仓位。

uv run nota kol --voices x:handle,tg:WatcherGuru,bs:decrypt.co --min-voices 2 --min-sentiment 0.3 \
  --min-conviction 0.2 --tokens SOL,ETH --account 10000 --risk-pct 1 --max-positions 3
uv run nota kol --voices ... --watch --every 3600   # run every hour; each run is stored
uv run nota kol-replay <id>                         # identical: True, from the ledger alone

也可以在浏览器中打开 /kol(表单、每位意见领袖的覆盖情况、规则轨迹、仓位),或调用 POST /api/kol/run,传入 {"voices": [...], "rules": {...}, "limits": {...}};GET /api/kol 会列出已存储的运行记录,GET /api/kol/<id> 会重放其中一条。

  • **读取。**这些意见领袖的信息会经过 narrative_convergence 技能处理。x: 意见领袖会先尝试 X 自身的联合发布接口,再尝试 Tavily 搜索;通过 Tavily 读取的意见领袖会标记为 via tavily_search, coverage partial,无法读取的则标记为 unavailable 并附上原因。
  • **规则(nota/kol.py)。**由代码而非模型执行。按代币检查:意见领袖的观点达成一致(至少两位表达立场,且方向相同);表达立场的意见领袖数量 >= min_voices;|sentiment_mean| >= min_sentiment;conviction_mean >= min_conviction;还可选择要求 urgency_max >= min_urgency,并要求代币位于你的允许列表中。每条规则都会存储为 {rule, value, threshold, passed},其中 value 直接读取自信封。缺失的值会导致规则不通过,并保持为 null。
  • **仓位。**触发的信号会经过与 council 相同的 nota.risk 代码处理:RYO 的 deep_analysis 会给出价格和 ATR(14),止损设在相差 2 ATR 处,目标设在相差 3 ATR 处,仓位规模则根据你的账户和风险比例确定。没有 RYO 证据、没有 ATR、RYO 否决、代币已持有,或已达到 max_positions:信号仍会保留,但交易会被拒绝,并说明具体原因。RYO 只会查询可能填入空闲仓位的代币。
  • **重放。**运行记录会连同其叙事信封、规则和限制、起始持仓以及 RYO 证据包,一起存储在账本的 kol_runs 表中,因此 kol-replay 无需网络连接或密钥即可重新推导每项决策。
  • **托管演示。**快照为只读,因此该环境中的 /api/kol/run 会返回未存储的运行结果,并明确说明这一点。请求会根据获取的数据量按地址限流(每位意见领袖 1 个单位,每位 x: 意见领袖 2 个单位,每次可能的 RYO 查询 1 个单位)。

技能(Track 3)

全部 9 个工具都逐字段返回 RYO 的公开封装(docs/skills/SKILL-SPEC.md),并通过 RYO 自己的工具路径提供,因此将它们接入 RYO 只需注册路由,无需移植:GET /api/skills/(SkillDefinition 列表)、GET /api/skills/{name},以及接收 SkillCallRequest {name, args, conversation_id} 并返回 SkillCallResponse {name, status: success|error, result, latency_ms, xp, guard_decision} 的 POST /api/skills/{name}/invoke。仪表板的“运行工具”面板会根据这些定义构建表单并显示封装内容。contrib/positioning_check/ 是旗舰工具,打包为可直接接入 RYO 自有后端的组件:不导入 Nota,提供一个可纳入的 FastAPI 路由,以及独立的离线测试(参见其 README)。contrib/move_base_rate/ 以相同方式打包 move_base_rate:一个 OKX 来源,路由和测试布局相同。

  • narrative_convergence:最多 20 个声音(tg: 公开 Telegram 预览、bs: Bluesky 公开 API、x: 通过 X 自有的公开 syndication 端点——该端点为嵌入式时间线提供服务,并带有 Tavily 回退),使用 VADER 情绪分析,并结合加密货币词典,按每个代币逐条分析提及它的分句(“BTC pumping while ETH dumping”会被判读为两个相反的观点);统计完整单词形式的信念强度和紧迫性,并判断观点是否趋同:两个或更多声音给出净情绪,且方向一致。只有已知主流代币才会被视为代币,因此 $HODL 或“CEO”不算信号。沉默记为 null,而不是 0。x: 过去使用的 Nitter 于 2026 年 8 月收到停止侵权函,其公开镜像也已下线,因此该读取器当时宣称的数据源实际上无法响应;syndication 无需密钥、有日期且仍可用,每次故障都会报告为 unavailable,而不是猜测结果。尝试使用前,有一项值得了解的实测限制:syndication 的限流很严格,而且已进一步收紧。它首先限制了数据中心地址,因此托管演示中的 x: 返回 unavailable,但在普通网络连接下读取正常;截至 2026-09-10,普通网络连接也会收到 syndication HTTP 429。请将 x: 视为尽力而为,将 tg: / bs: 视为可靠读取器——这两者从两种网络环境下都能正常响应。设置 TAVILY_API_KEY 后,限流会触发基于搜索的回退,而封装结果会将其标记为无日期;未设置该密钥时,警告会明确说明这一点。
  • news_verify:获取 CoinDesk、Cointelegraph、The Block 和 Decrypt RSS 中带日期的标题,并使用 Tavily 或 Venice 网页搜索扩展覆盖面;统计独立域名数量,并附上 RYO analyze_token 上下文。标题会根据声明中的独特词语匹配,而不是只匹配“Bitcoin”和“price”;与声明倾向相反的标题会计入反证,因此结果可能为 disputed。没有搜索密钥时,标题仍会决定结果,状态则为 partial。
  • price_crosscheck:使用无需密钥的 CoinGecko、Coinbase、Kraken、Binance(公开数据镜像,以 USDT 作为美元代理)和 DefiLlama 现货价格,计算中位数、价差,以及参考价格(RYO 的价格)与各交易所价格的偏差;还会将 alternative.me 恐惧与贪婪指数与 RYO 的读数进行比较。与其他来源偏差超过 2% 的来源会标记为 outlier,并从中位数计算中排除,因此 CoinGecko 的代币符号搜索若匹配到其他代币,也不会影响价格。
  • technicals_crosscheck:使用 Wilder 方法,基于 200 根已收盘的 UTC 日线蜡烛图(优先使用 OKX,其次 Binance,再次为 CoinGecko 的 4 小时 OHLC 聚合为日线;此时会警告 30 天数据尚未收敛,且绝不使用当天尚未完成的蜡烛图),重新计算 RSI(14)、ATR(14) 和 1d/7d/30d 涨跌幅,并计算参考值(RYO 的 technicals.rsi_14 / atr_14)与独立计算结果的偏差。Technician 在每次决策中都会看到 technicals_check。
  • positioning_check:包含上述衍生品关卡,以及 OKX 永续合约溢价(资金费率处于 1 bp 的利息组成部分,并不能说明走势)、以币计的未平仓量变化、以过去 100 小时为区间计算的多空账户比率百分位数,以及作为第二个交易场所的 Hyperliquid 溢价。premium_consensus 要么是在所有交易场所都处于现货价格同一侧,要么是 venues_disagree,绝不会取平均值;它还会附带一句通俗的英文和日文说明。标题会引用两个交易场所的数据。不传入 RYO 区块时,它会自行请求 RYO 的 deep_analysis(需设置 RYO_MCP_KEY),并与今天的评分卡锁定结果进行比较。对于 BTC 和 ETH,它还会添加 Deribit 的 DVOL:期权市场隐含的 7 天波动幅度;结合 atr_stop_pct,当止损位于这一常规波动范围内时会发出警告。其他代币没有 DVOL,因此不会添加。
  • move_base_rate:统计在约 400 天的 OKX UTC 蜡烛图中,该代币在当前波动率三分位区间内,于 h 天内达到(或收盘突破)k 个 ATR 的频率;同时报告独立交易日数量,并通过按时间划分的留出集,在频率发生漂移时发出警告(其三分位数分界仅根据较早的日期确定,因此拟合过程不会看到留出集)。提供 RYO 的 atr_14_pct 后,会按 RYO 的 ATR 进行测量(为 OKX Wilder ATR 的 0.91-0.98 倍,并会打印该比率)。每个有评分的决策也会附带此基准频率,而 /api/scores.vs_base_rate 会为每个 Agent 给出 1 - Brier / Brier(base rate):大于零说明它比日历基准掌握了更多信息。
  • verdict_track_record:评分卡中该代币已结算的记录,按结论和共识状态分类,包含各自的分母、结论倾向与计划方向相反的计划(例如谨慎结论下的做多计划,或建设性结论下的做空计划),以及最近一次锁定结论的 trace id。
  • liquidity_check:使用无需密钥的 DefiLlama,报告 USD 稳定币总供应量和该代币所属链 DeFi TVL 的 7 天及 30 天变化(代表新增或流出的即时购买力),并附上各自最新一行数据的日期。BTC 和没有所属链的代币不会获得 TVL 数据,并会说明原因,绝不会使用邻近链的数据。宏观 Agent 将其读取为 liquidity。
  • crowd_odds:预测市场隐含的、在指定期限内价格高于当前价格的 P(概率)。优先使用 Polymarket 在今后 7 天的到期时间前后一天内到期的“ above ___ on ”阶梯市场(BTC、ETH、SOL、XRP),否则使用 Kalshi 的 KXD 阶梯市场(也包括 DOGE)。只有价差不超过 10 美分的双边订单簿才会计入,因此新阶梯市场中 0.5 的占位价格绝不会被读取;价格会按行权价调整为单调,并在现货价格处插值。没有可读取的阶梯市场时,结果为 market_p: null,绝不会假定为五五开。该结果会存储在每个数据包中,不会展示给任何 Agent,并会根据评判结果评分。

Nota 也是一个 MCP 服务(Track 3)

Nota 是 RYO 的 MCP 客户端。它也是一个 MCP 服务,因此 RYO、Claude Desktop、Cursor 或任何其他 MCP 主机都可以直接调用这九项技能,无需包装器:

// claude_desktop_config.json, or any MCP client that speaks Streamable HTTP
{ "mcpServers": { "nota": { "url": "https://nota-ryo.vercel.app/mcp" } } }
curl -s https://nota-ryo.vercel.app/mcp -H 'content-type: application/json'   -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools[].name'

curl -s https://nota-ryo.vercel.app/mcp -H 'content-type: application/json'   -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"technicals_crosscheck","arguments":{"symbol":"SOL"}}}'

它提供全部四种 MCP 原语,而不只是最简单的一种:

  • 工具:通过 tools/list 和 tools/call 调用这九项技能。每个 inputSchema 都由 REST 路由和仪表板表单使用的同一份定义生成。
  • 资源:提供 resources/list、resources/templates/list(nota://receipt/{id})和 resources/read,后者以 Markdown 和 JSON 两种格式返回收据。即使客户端从未调用此项目的 HTTP API,也仍可列出其决策并读取其中一项。
  • 提示词:提供 prompts/list 和 prompts/get。audit_a_token 会告知调用方的大模型对照独立来源核查 RYO,并附带诚实原则,包括 null 值必须保持为 null。read_a_receipt 会逐步查看一项已存储的决策。
  • 补全:completion/complete 会提供此部署实际持有的收据 ID 和符号,因此客户端无需猜测;且仅对引用的提示词或模板声明的参数提供补全。

每个工具都带有 title、annotations(readOnlyHint: true、destructiveHint: false)和 outputSchema,即 RYO 封装结构自身的 JSON Schema,让客户端在调用前就知道不会写入任何内容,以及返回数据的结构。列表每次分页 50 项,使用不透明的 cursor。

它还提供一个 MCP Apps 视图。每个工具都会在 _meta.ui.resourceUri 中链接到 ui://nota/receipt,而针对该 URI 的 resources/read 会返回一个独立完整的 HTML 页面(nota/static/mcp_app.html、 text/html;profile=mcp-app,CSP 允许列表为空:页面不会加载任何内容)。渲染 MCP Apps 的主机会与其执行 ui/initialize 握手,并传入工具结果;该视图会将封装结构显示为一张盖有印章的卡片,包含状态、as_of、各来源的可用性、标题、要点和警告,所有内容均以文本呈现,绝不使用标记语言。

Nota 已发布到官方 MCP 注册表,名称为 io.github.PugarHuda/nota(版本 0.1.0, 2026-09-10;此处的 server.json 为 0.2.0,描述了评分卡和衍生品关卡,并将在重新发布后生效),因此客户端无需获取 URL 也能找到它: curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.PugarHuda/nota"。

仓库根目录下的 server.json 是此服务在官方 MCP 注册表中的条目;部署会在 /.well-known/mcp/server.json 和 /server.json 提供该文件,因此描述与其中指定的端点不会出现偏差。注册表强制执行两条规则,这里也有相应测试:描述不得超过 100 个字符,且已发布的版本不可变——每次重新发布都需要新的 version,因此修改该文件中的任何内容都必须提升版本号。在仓库根目录运行 mcp-publisher login github && mcp-publisher publish 即可发布;mcp-publisher validate 会对照实时注册表检查文件,但不会发布。

GET /llms.txt 遵循 llms.txt 规范:生成一个页面,告知 Agent 此处提供的内容、如何调用 MCP 和 A2A 端点、评分卡、有哪些技能,以及账本中保存了哪些收据。页面列表会根据应用实际提供的路由筛选,因此不会与这些路由出现偏差。 A2A。 Nota 也是一个 Agent2Agent 1.0 Agent。/.well-known/agent-card.json 是它的 Agent Card (包含九项技能,每项都有标签和一个示例调用;一个 JSON-RPC 接口;不支持流式传输和推送),而 POST /a2a 接收带有 A2A-Version: 1.0 标头的 SendMessage(不带标头表示使用 0.3,按规范要求会被 VersionNotSupportedError 拒绝)。消息携带一个数据部分 {"skill": ..., "args": {...}},也可以是 price_crosscheck SOL 之类的文本;调用会经过与 REST 和 MCP 相同的 invoke 检查,答复是一个已完成的任务,其 artifact 为 envelope。参数错误会返回带有 google.rpc.BadRequest 详情的 -32602。每个任务都会在请求期间完成,因此不会存储任务:GetTask 会返回 TaskNotFoundError,流式传输、取消和推送配置则会返回 UnsupportedOperationError。它与 /mcp 共用 Origin 允许列表、1 MB 请求体上限和每个地址的技能用量限额。

开放数据与发现。 /feed.xml(Atom)和 /feed.json(JSON Feed 1.1)包含最新的 50 条收据,每条都包含其判定、降级部分,以及在结果确定后给出的结果和评判者的 Brier 分数;此外还包含所有已结算的评分卡计划。/api/outcomes.csv 每个已解决的决策占一行(各角色的 p_up_7d、基准率、实际结果、各角色的 Brier 分数)。/robots.txt 和 /sitemap.xml(包含每个页面、两种语言的 hreflang 备用页面以及每条收据)供爬虫使用,每个页面的 head 都会标明其规范 URL、绝对路径的 og:image 和订阅源。

仅一个端点,只接受 POST,无状态。它会协商客户端请求的协议版本 (2026-07-28、2025-11-25、2025-06-18、2025-03-26 或 RYO 自有的 2024-11-05;如果请求的是不认识的版本,则使用最新版本),通过 server/discover 返回版本、功能和 服务信息;对于不支持的 MCP-Protocol-Version 标头,会按照规范以 400 和 UnsupportedProtocolVersionError(-32022,并列出支持的版本)拒绝请求;按照传输规范要求,针对 DNS 重绑定验证 Origin 标头;对批量请求中的每项请求分别返回一个响应;当请求体仅包含通知时,返回无正文的 202 Accepted;对 GET 和 DELETE 返回 405,因为没有可打开的流,也没有可删除的会话。每个工具的 inputSchema 都由 REST 路由和仪表盘表单使用的同一技能定义生成,因此三者绝不会出现偏差。tools/call 会返回两次 RYO envelope:一次以文本形式供只读取文本的客户端使用,另一次以 structuredContent 形式供解析内容的客户端使用。

仪表板(Track 2)

nota serve 会在账本上公开一个只读 API(/api/decisions、/api/decisions/{id}、 /api/decisions/{id}/replay、/api/positions、/api/scores、/api/health、导出 /r/{id}.json 和 /r/{id}.md、位于 /docs 的 OpenAPI)和一个单页仪表板。从 /api/decisions/{id} 读取的回执还包含 requests(调用每个证据部分时使用的确切参数) 和 audit(Nota 的 ATR、RSI 和价格,以及 RYO 的对应数据和每个技能的警告阈值),两者 都从已存储的证据包中读取;首页的审计表由此填充,自身不存储任何数字。列表行包含 availability 和 failed_sections(RYO 出错或不可用的部分),首页据此选择失败面板中 显示的回执。

  • 三十秒摘要,位于每张回执顶部:现在该做什么(交易或阻止原因)、影响最大的单项变化及其重要性、根据最新独立价格,当前未平仓的模拟持仓会触及止损还是止盈,以及接下来会发生什么(何时评分,或评分结果)。
  • 变化内容:每张回执都会与同一标的的上一张回执进行差异比较,并按影响排序。判定翻转、交易解锁/阻止、可用性和模型变化排在最前;之后是风险引擎读取的数值(价格、ATR、RSI),按变动百分比排序;再之后是所有其他证据叶节点。变为 null 的值会显示为 null,绝不会显示为 0。
  • 降级模式:横幅会列出所有状态不是 ok 的证据部分;来源信息会按部分显示 as_of、data_mode 和 trace id。
  • 根据最新证据价格显示未平仓的模拟持仓及其与止损价的距离。
  • Agent 排行榜按 Brier 分数排序,并显示当前生效的裁判权重;裁判校准表会在决策完成后显示(已声明的 p_up_7d 区间与实际命中率)。
  • 两种语言,一个页面:/ 和 /ja 共用 landing.css 和 landing.js,因此只翻译文案,行为来自同一个对象,而非其副本。测试会关联这两个页面:章节 id 相同,都加载同一脚本,且都不得将回执 id 或证据哈希写入文件。
  • 哪些来源发挥了作用(/api/scores 中的 sources):对于每个证据部分,比较裁判在该部分有响应与无响应的决策上的平均 Brier 分数,并显示两者之差。它回答了 Agent 排行榜无法回答的问题——不是“哪个 Agent 是对的”,而是“有了这个信息源,判断是否会更好”。空分组的分数为 null,表中还包含 enough_to_read;在 20 个独立决策完成评分前,该值为 false:两个各含三个样本的均值之间的差异只是噪声,把它印成结论,就和把 null 转成零一样不妥。
  • 可在页面上验证回放(仅使用缓存输出,不会消耗额度)、分享到 X,并导出。
  • 人人都能使用:每个页面都有跳过链接和 <main> 地标、真正的按钮、可见的焦点指示;支持按 j/k 移动、按 Enter 打开、按 p 查看上一张回执、按 / 筛选、按 Esc 返回列表、按 ? 查看帮助。打开回执时,焦点会移至标题,标签页标题会显示回执名称,并播报一句话(回执本身不是实时区域);单列布局下,轻触会将回执滚动到视野内。宽表格会在各自可聚焦的区域中滚动,每个页面都能在 320 px 宽度下自适应重排,并且在任何页面选择的深色主题都会应用于所有页面。所有第三方内容在进入标记前都会转义。tests/test_a11y_axe.py 会通过 axe-playwright-python 调用 axe-core,在 1366 和 390 px 宽度下、使用两种主题检查全部五个页面;若存在任何严重或危急规则违规、缺少地标或滚动区域无法获得焦点,测试就会失败。
  • 每 30 秒轮询一次账本,因此无需重新加载页面,正在运行的 watch 循环也会显示出来。

仪表板只读取回执。没有回执支撑的数字不会显示。

SocialFi 层

  • 回执卡片:/r/<id>.png 根据回执渲染 1200×630 的卡片(Pillow,内置字体);/r/<id> 携带指向该卡片的 Open Graph 和 X 卡片标签,因此分享的永久链接会以回执的形式预览。Discord 通知也会嵌入同一张图片。
  • 支持:任何人都可以使用用户名支持或反对某个判断(POST /api/decisions/<id>/back,每个用户名对每张回执只能选择一种立场,以最新选择为准)。判断结果确定后,系统会根据结果为支持者评分(/api/backers):看涨且价格上涨时,表示赞同即为正确,表示反对即为错误;no_trade 判断不参与评分。无需账户:首次使用某个用户名支持时,会通过编辑令牌认领该用户名,令牌由此浏览器保存,因此其他人无法用该用户名发帖。账本会保留每次立场及其时间戳。
  • 公开推理动态(/feed,JSON 位于 /api/feed):最新回执以卡片形式展示,包括每个 Agent 的立场及其论点的首句、与裁决意见相左的 Agent(立场与行动所需立场不同;对于 no_trade,所有选择了方向的 Agent 都算在内)及裁决者自己的理由、支持人数,以及指向永久链接和卡片的 X 分享链接。
  • 声誉(/api/reputation):将支持者用户名和四个 Agent(宏观分析、技术分析、叙事分析、裁决者)纳入同一尺度,衡量他们的方向性判断与七日走势相符的比例,依据的是同一批已评分结果。支持者不提供概率,因此使用命中率而非 Brier 分数;Agent 的 Brier 分数也会一并列出。中性判断和 no_trade 判断不计入。一条记录包含 n、n_independent(校准规则:同一标的在七天内只算一次观察);只有在 20 个相互独立的周内做出 20 次判断后才会获得排名,在此之前会显示“样本太少,暂无法判断”。
  • 关注列表(POST /api/watchlist {handle, symbol, watch, token}、GET /api/watchlist):每个用户名对应一个公开列表,并按关注某个标的的用户名数量汇总。标的会通过 clean_symbol 处理;用户名认领、编辑令牌、每小时限流和只读规则均与支持功能相同,存储方式也相同(配置 DATABASE_URL 时使用 Postgres,否则使用账本)。每个用户名最多关注 50 个标的。
  • 个人资料(/u/<handle>,JSON 位于 /api/users/<handle>):展示某个用户名的支持记录及每条记录的评分、其声誉记录和关注列表。页面设为 noindex,因为用户名是一种认领。

每个列表初始为空,并会明确说明;这些页面上的内容都不是示例数据。

无需密钥即可评估

仓库附带一份账本快照,其中包含基于实时 RYO 证据生成的四条初始回执(2026-09-07,SOL / BTC / ETH,每条都标注了各自的来源),并会持续增长:每小时运行一次的周期任务(.github/workflows/ledger.yml,在 :15)会为已达到期限的内容评分并结算;08:23 UTC 的运行会锁定并做出判断(16:41 会重试失败的任务),每次运行都会将快照提交回仓库。快照中的每条回执都能通过验证,测试也会确认这一点:

uv sync   # on PowerShell, set the variable first: $env:NOTA_DB = "data/demo.db"
NOTA_DB=data/demo.db uv run nota replay b80b42835b01   # identical: True - verified with no key at all
NOTA_DB=data/demo.db uv run nota serve      # then open http://127.0.0.1:8000/app for the dashboard
NOTA_DB=data/demo.db uv run nota positions
uv run nota skill run price_crosscheck '{"symbol":"SOL"}'   # live exchanges, no key
uv run pytest -q                              # no network, no keys

第一行体现了这个项目的核心:缓存重放会根据账本自身的证据以及存储在旁边的模型输出重建回执,并以生成这些输出的模型为键,因此不会调用任何 API,也不会产生偏差。所有随项目发布的回执都能通过这种方式验证,包括记录来源的回执,因为缓存重放以生成输出的模型为键,而不是以当前配置的模型为键。--fresh 则恰好相反:它会使用今天的模型处理相同证据,并输出差异作为漂移结果。

理事会决策需要一个 LLM 密钥(Anthropic,或 Venice 等任何兼容 OpenAI 的提供商);实时 RYO 证据需要 builder 密钥;其他所有操作(包括验证)都无需这两种密钥。

CI,以及检查你获取的快照
  • .github/workflows/test.yml 会在每次推送和拉取请求时运行完整测试套件,包括 Playwright 浏览器测试;如果 requirements.txt(Vercel 安装的依赖)与 uv.lock 不一致,就会失败。只有 main 分支上的 test 通过后,deploy.yml 才会调用 Vercel 部署钩子。每个第三方操作都固定到一个提交 SHA,mcp-publisher 固定到一个发布版本,并在运行前检查其 sha256;Dependabot 每周提出升级建议。
  • 账本周期会将密钥限制在调用 RYO 或 LLM 的步骤中,在做出决定前用一个令牌运行 nota llm-check,避免失效的 LLM 密钥消耗 RYO 配额;决策循环会在首次失败时停止,并以 nota health --strict 结束,因此失效或即将过期的 RYO 密钥会导致运行失败。即使某个步骤失败或超时,快照也会提交;如果因 main 已更新而导致推送被拒绝,就会使用 nota merge-db(逐行合并两个 SQLite 文件,并以每张表的键为依据)解决冲突后重试;如果快照仍无法推送,就会作为运行产物保留。每个步骤都会将其锁定记录、结算或决策表写入运行摘要页。
  • 每个推送的快照都会通过 GitHub 工件证明使用 Sigstore 进行证明,并附上 data/snapshot.json(nota export:收据以及 24 小时和 72 小时的记分卡)。证明 URL 列在 data/attestations.json 中,最新的 URL 可在 /api/health 找到。要检查某份账本副本是否来自此仓库的工作流,且此后未被修改:
gh attestation verify data/demo.db --repo PugarHuda/nota

演示流程及其制作方式

/demo 提供带旁白的视频,旁边是按章节划分的文字稿:点击某一行即可跳转到对应位置,正在朗读的行始终显示在视野中。同样的章节也会作为 WebVTT 字幕提供,地址为 /demo.vtt(默认启用);页面的 og:video 使用绝对 URL,因此分享链接可直接内嵌播放。视频由三个步骤构建,每一步都会把实际时间传给下一步,而不是靠猜测:

uv run --with edge-tts python scripts/narration.py   # the voice, and it sets the pace
uv run python scripts/demo_video.py                  # Playwright records the real pages
cd video && npx remotion render                      # the two are composed
  1. scripts/narration.py 将朗读脚本按节拍保存,每个节拍由一个句子和它所对应的选择器组成。Microsoft 的 en-US-AndrewNeural 通过 edge-tts 进行朗读,无需密钥;随后由 ffprobe 测量生成的音频时长。所有时间都不是凭耳朵估算的。
  2. scripts/demo_video.py 使用 Playwright 操控应用,并针对 data/demo.db,让每个节拍的持续时间与对应音频的时长完全一致。它会绘制原始屏幕录制中没有的两样东西:一个会移动到当前讲解对象的光标,以及一个围绕该元素的边框,因此语音所指的部分始终明确。它会记录每个节拍实际开始的秒数——页面加载需要时间,而旁白不会等待——这份文件会同时供合成流程和 /demo 的文字稿读取。
  3. video/ 是 Remotion 合成项目,会根据记录的偏移量放置每一行,并渲染 MP4。

演示中的内容都不是预先编排的。验证按钮是在镜头前按下的,其结果就是 API 返回的内容;旁白中提到的每个数值,都是本次部署按需生成的。

托管演示

仪表板运行于 https://nota-ryo.vercel.app(Vercel,通过 main.py 自动检测到 FastAPI 框架;位于东京区域 hnd1;CSS、脚本、图像、字体和视频均缓存在 Vercel 的 CDN 上)。它使用 NOTA_READONLY=1 提供已提交的账本快照 data/demo.db(基于实时 RYO 证据的收据,每份都带有其追踪 ID):读取、回放验证、卡片、信息流和导出均可使用;备份功能也可用,会写入 Neon Postgres(DATABASE_URL),其中包含句柄声明和编辑令牌,因为无服务器文件系统无法写入。新决策和锁定会随账本周期的提交一同到达。设置 RYO_MCP_KEY 和 LLM 密钥后,仪表板的“实时运行 council”(POST /api/council/{symbol})会基于新证据召集 council,并返回收据,但不会存储收据。每个地址每小时最多运行 3 次,总计最多运行 20 次。包含实时 RYO 证据、watch 循环和通知在内的完整系统,可在任何具有可写磁盘的机器上通过 uv run nota serve 运行。

故障处理

亲眼看看故障如何发生:/drill(POST /api/drill {"scenario": ...},nota/drill.py)会注入七种故障之一(RYO 宕机、RYO 401、缺少 deep_analysis、速率受限且响应缓慢、交易所宕机、模型提供方宕机、RYO 部分返回且包含 null 值),并使用健康运行旁记录的固定数据,在离线状态下运行真实流水线。Drill 收据标记为 source: drill,且绝不会被存储。

  • RYO 客户端:遇到 429/503/网络故障时采用带抖动的指数退避;遵循以秒或 HTTP 日期表示的 Retry-After,但等待时间绝不会超过 60 秒;对于 4xx 参数错误绝不重试;记录 X-RateLimit-* 标头。RYO 还会为每个密钥设置一个每分钟六次工具调用的扇出桶(mcp_fanout);客户端会调整自身的工具调用节奏以适应限制(catalog、whoami 和 health 免费且不受节流),并将拒绝响应中的桶重置时间 reset_at 记录为 fanout_reset_at。通过 MCP 遇到速率限制时,响应为带有 isError 和 Retry-After 的 HTTP 200;客户端会像处理 REST 429 一样重试,而不会将其视为工具故障。超时按工具分别设置(deep_analysis 和 compare_tokens 为 120 秒,其他工具为 30 秒),调用超时后会重试一次。
  • 一次决策运行中的五项 RYO 读取会分三路并发执行;数据包按固定顺序组装,因此其哈希与逐项收集时完全相同。某个分区失败时会保留 RYO 的追踪 ID;评分卡锁定失败时也会保留追踪 ID及 HTTP 状态码。
  • LLM 客户端遇到超过一分钟的 Retry-After 时,不会一直等待,而是报错“rate limited for N s”。
  • 即使工具和技能失败,证据收集仍会继续;裁决者会获知哪些分区缺失。当主要证据(deep_analysis)缺失时,不会召集 council:收据的结果为 no_trade,模型调用次数为零,并会像其他收据一样存储且可回放。
  • SQLite 账本采用 WAL 模式;每次写入都按内容哈希实现幂等,因此重启后可以继续运行。
  • watch 能在某个交易标的、通知器或解析过程失败时继续运行。
  • RSS 使用 defusedxml 解析(避免不可信信息流中的实体展开)。
  • 部分 ISP 会通过 DNS 屏蔽交易所域名(在印度尼西亚观察到:Coinbase 和 Kraken 会解析到带有错误证书的屏蔽页面)。此时 price_crosscheck 会将这些来源报告为 unavailable,并使用剩余来源继续工作;托管在 Vercel 上的演示可以连接全部三个来源。构建本项目所用的机器也遇到了以相同方式屏蔽 Polymarket 和 Kalshi DNS 的情况;此时 crowd_odds 会返回 market_p: null,其解析器则根据通过 DNS over HTTPS 获取的响应编写(tests/fixtures/market/)。
  • nota stamp 需要三个 OpenTimestamps 日历之一提供响应;若都无响应,该主题会保持未盖时间戳状态,等待下次运行。只有当 mempool.space 的区块头与日历返回的 Bitcoin 路径一致时,才会采用该路径。

目录结构

main.py           Vercel entry: the same app over the read-only snapshot data/demo.db
nota/
  envelope.py     RYO public response contract + REST/MCP parsers
  ryo_client.py   RyoClient (httpx, paced, MCP handshake) + RecordedRyoClient + record()
  evidence.py     EvidencePack, ryo_args(), gather() (parallel, fixed order), candidate_symbols(), path lookups
  paths.py        RYO's recorded field paths for price, ATR, derivatives, Fear & Greed
  llm.py          LLM protocol, AnthropicLLM (messages.parse), OpenAICompatLLM (Venice/OpenRouter)
  council.py      role prompts, untrusted-text framing, Opinion/Verdict, citation validation, cached run_council()
  risk.py         size_trade(): PracticeTrade | Blocked (incl. RYO's derivatives veto)
  decide.py       gather -> council -> size -> receipt
  receipt.py      Receipt + markdown rendering
  replay.py       cached or --fresh replay, field-by-field diff
  calibration.py  resolve at the horizon, Brier per role, base-rate / crowd / RYO baselines
  scorecard.py    lock RYO's plans, settle on OKX candles, Mantel-Haenszel contrasts
  stamp.py        OpenTimestamps: .ots writer/parser, calendar submit, upgrade checked against mempool.space
  ledger.py       SQLite: evidence, llm_cache, decisions, outcomes, backings, locks, settlements, stamps; merge_from()
  backings.py     Postgres store for backings, handle claims and the shared rate limit
  api/            FastAPI, one APIRouter per area
    __init__.py   the app: HEAD handling, CSP and security headers, CORS, router mounting (pages last)
    common.py     shared helpers: ledger handle, absolute links, page templating, receipt loader, hourly budget
    receipts.py   decisions, impact-ranked diff, replay, positions, scores, health, /r/<id>.md|.json|.ots|.png
    scorecard.py  scorecard JSON, CSV, lock files and proofs, the /scorecard page
    agents.py     skills over REST, /mcp, /a2a, llms.txt, server.json, robots, sitemap, Atom and JSON feeds
    social.py     backings, watchlist, reputation board, reasoning feed, profiles
    live.py       on-demand runs: live council, failure drill, multi-KOL agent
    pages.py      HTML pages, fonts, images, walkthrough files, the /r/<id> permalink
  mcp_server.py   MCP server (tools, resources, prompts, completion, MCP Apps view)
  a2a.py          A2A 1.0 agent card and SendMessage
  card.py         receipt PNG card
  notify.py       Telegram Bot API + Discord webhook publishing
  cli.py          the `nota` command
  skills/         contract, sources (Telegram, Bluesky, X syndication, RSS, Tavily, Venice), narrative, news, price_check,
                  technicals, positioning, base_rate, track_record, liquidity (DefiLlama), crowd_odds (Polymarket, Kalshi)
  static/         landing.html + landing.ja.html (`/` and `/ja`), index.html (dashboard), scorecard.html,
                  demo.html + demo.mp4 + demo.json (walkthrough), mcp_app.html, landing.css + landing.js, fonts/, img/
data/             demo.db (the ledger snapshot); snapshot.json + attestations.json, written by the ledger cycle
fixtures/         recorded/: real RYO answers for `--source recorded`
scripts/          screenshots, narration, demo_video, font_subset, gate_ab, skill_spec_md, submission_pdf
video/            Remotion composition that puts the narration onto the recording
docs/             hackathon analysis, MCP builder guide copy, design spec, skill spec, submission form and notes
.github/          workflows (test, deploy, ledger, publish-mcp, probe) and dependabot.yml
tests/            pytest, no network (respx + the FakeLLM test double in tests/fakes.py)

已披露的第三方库

httpx、pydantic、anthropic、typer、python-dotenv、fastapi、uvicorn、vaderSentiment(MIT)、 defusedxml、pillow;开发依赖:pytest、respx、playwright、axe-playwright-python(MPL-2.0 axe-core;浏览器端到端测试位于 tests/test_dashboard_e2e.py,QA 测试位于 tests/test_qa_browser.py,需在运行 uv run playwright install chromium 后执行)、edge-tts 和 Remotion(仅用于演示视频,见下文)。数据来源: RYO MCP、t.me/s 预览、Bluesky 公共 AppView、X 公共 syndication、CoinDesk / Cointelegraph / The Block / Decrypt RSS、CoinGecko、Coinbase、Kraken、Binance(data-api.binance.vision)、DefiLlama coins、OKX 和 Hyperliquid 公共 API、alternative.me、Tavily 或 Venice 网络搜索。字体在 nota/static/fonts 目录下自托管,并通过允许列表提供:Dela Gothic One(拉丁文,以及用于 /ja 标题的 76 字符日文子集)和 BIZ UDPGothic / BIZ UDGothic(Morisawa),均采用 SIL Open Font License 1.1,并以拉丁文字子集形式取自 Google Fonts。

本项目未使用起始模板:仓库最初为空,所有应用代码均在黑客松期间编写。还有两项外部内容影响了开发过程,但并未纳入项目,现一并说明:taste-skill 设计规则集(Leon Lin,MIT)通过 npx skills add 安装,并在调整界面时阅读;它被加入 gitignore,而非随项目打包,因此没有相关文件随项目发布;docs/img 下的截图由 scripts/screenshots.py 根据本项目自己的仪表板生成,并非取自其他来源(scripts/demo_video.py 将录制内容写入 docs/demo/,该目录已加入 gitignore:仅最终文件 nota/static/demo.mp4 提交到了仓库)。

有三个工具用于制作演示视频,均不会随应用发布:edge-tts (GPL-3.0,使用 Microsoft 的公共神经语音,无需密钥)朗读旁白,Playwright 录制页面,而 Remotion(Remotion License——个人及三人或以下的公司可免费使用,超过此规模需付费;参见 https://remotion.dev/license)负责合成成片。它们是 video/ 的开发依赖,由 scripts/ 调用,访客不会收到 Remotion 或 edge-tts 代码,nota 也不会导入这些代码。旁白是人工撰写的,并非生成:语音是合成的,脚本不是。tests/fixtures/ 和 fixtures/recorded/ 下的 RYO 信封是通过 nota record 捕获的真实 RYO 响应,并标记为 source: recorded;tests/fixtures/x/ 中存有一份于 2026-09-07 从 X 公共 syndication 端点捕获的真实数据。

video/ 下的视频工具链仅用于构建,不会随部署的应用发布。其 package.json 将 ws(8.21+)和 webpack(5.104.1+)覆盖为已修补的版本。仍有一项未解决的安全公告:extract-zip 2.0.1,它由 @remotion/renderer 引入,用于解压 Remotion 将下载的 Chrome。目前没有已修补的版本,而本项目从不执行该路径,因为渲染过程会复用 Playwright 的 Chromium(video/remotion.config.ts)。

从未提交过任何密钥。最近一次于 2026-09-20 对完整提交历史(而不只是工作区)进行了核查:对本地 .env 和 .env.local 中每个密钥的准确值(builder 密钥、LLM 密钥、Neon 连接字符串和密码、Vercel 令牌)逐一搜索了所有提交的每个补丁,均未发现;此外,还搜索了 13 种凭据模式(RYO builder 密钥、Anthropic、OpenAI、OpenRouter、Venice、Tavily、Telegram 机器人令牌、Discord webhook、AWS、GitHub 和 Vercel 令牌、带密码的 Postgres URL、PEM 私钥)。唯一匹配项是 ryo_mcp_your_private_key,它是 RYO 自己的 builder 指南中引用的占位符,位于 docs/MCP-Builder-Guide.md。没有任何提交添加过 .env 或凭据文件。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。